// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 import * as React from 'react'; import { List, ListItem, ListItemIcon, Collapse, Checkbox } from "@material-ui/core"; import { StyleRulesCallback, withStyles, WithStyles } from '@material-ui/core/styles'; import { ReactElement } from "react"; import CircularProgress from '@material-ui/core/CircularProgress'; import * as classnames from "classnames"; import { ArvadosTheme } from '~/common/custom-theme'; import { SidePanelRightArrowIcon } from '../icon/icon'; type CssRules = 'list' | 'listItem' | 'active' | 'loader' | 'toggableIconContainer' | 'iconClose' | 'renderContainer' | 'iconOpen' | 'toggableIcon' | 'checkbox'; const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ list: { padding: '3px 0px' }, listItem: { padding: '3px 0px', }, loader: { position: 'absolute', transform: 'translate(0px)', top: '3px' }, toggableIconContainer: { color: theme.palette.grey["700"], height: '14px', width: '14px', }, toggableIcon: { fontSize: '14px' }, renderContainer: { flex: 1 }, active: { color: theme.palette.primary.main, }, iconClose: { transition: 'all 0.1s ease', }, iconOpen: { transition: 'all 0.1s ease', transform: 'rotate(90deg)', }, checkbox: { width: theme.spacing.unit * 3, height: theme.spacing.unit * 3, margin: `0 ${theme.spacing.unit}px`, padding: 0, color: theme.palette.grey["500"], } }); export enum TreeItemStatus { INITIAL = 'initial', PENDING = 'pending', LOADED = 'loaded' } export interface TreeItem { data: T; id: string; open: boolean; active: boolean; selected?: boolean; status: TreeItemStatus; items?: Array>; } export interface TreeProps { disableRipple?: boolean; items?: Array>; level?: number; onContextMenu: (event: React.MouseEvent, item: TreeItem) => void; render: (item: TreeItem, level?: number) => ReactElement<{}>; showSelection?: boolean | ((item: TreeItem) => boolean); levelIndentation?: number; toggleItemActive: (event: React.MouseEvent, item: TreeItem) => void; toggleItemOpen: (event: React.MouseEvent, item: TreeItem) => void; toggleItemSelection?: (event: React.MouseEvent, item: TreeItem) => void; } 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, disableRipple } = this.props; const { list, listItem, loader, toggableIconContainer, renderContainer } = classes; const isCheckboxVisible = typeof this.props.showSelection === 'function' ? this.props.showSelection : () => this.props.showSelection ? true : false; const { levelIndentation = 20 } = this.props; return {items && items.map((it: TreeItem, idx: number) =>
toggleItemActive(event, it)} onContextMenu={this.handleRowContextMenu(it)}> {it.status === TreeItemStatus.PENDING ? : null} {this.getProperArrowAnimation(it.status, it.items!)} { isCheckboxVisible(it) && }
{render(it, level)}
{it.items && it.items.length > 0 && }
)}
; } getProperArrowAnimation = (status: string, items: Array>) => { return this.isSidePanelIconNotNeeded(status, items) ? : ; } isSidePanelIconNotNeeded = (status: string, items: Array>) => { return status === TreeItemStatus.PENDING || (status === TreeItemStatus.LOADED && !items) || (status === TreeItemStatus.LOADED && items && 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 }); } handleRowContextMenu = (item: TreeItem) => (event: React.MouseEvent) => this.props.onContextMenu(event, item) handleCheckboxChange = (item: TreeItem) => { const { toggleItemSelection } = this.props; return toggleItemSelection ? (event: React.MouseEvent) => { event.stopPropagation(); toggleItemSelection(event, item); } : undefined; } handleToggleItemOpen = (item: TreeItem) => (event: React.MouseEvent) => { event.stopPropagation(); this.props.toggleItemOpen(event, item); } } );