//
// SPDX-License-Identifier: AGPL-3.0
-import * as React from 'react';
-import * as classnames from "classnames";
+import React from 'react';
+import classnames from "classnames";
import { StyleRulesCallback, withStyles, WithStyles } from '@material-ui/core/styles';
import { ReactElement } from "react";
import { FixedSizeList, ListChildComponentProps } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";
-import { ArvadosTheme } from '~/common/custom-theme';
+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';
| 'iconOpen'
| 'toggableIcon'
| 'checkbox'
+ | 'virtualFileTree'
| 'virtualizedList';
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
list: {
padding: '3px 0px',
},
+ virtualFileTree: {
+ "&:last-child": {
+ paddingBottom: 20
+ }
+ },
virtualizedList: {
height: '200px',
},
}
});
-// export const RowA = <T, _>(items: TreeItem<T>[], render:any) => (index: number) => {
-// return <div>
-// {render(items[index])}
-// </div>;
-// };
+export interface VirtualTreeItem<T> extends TreeItem<T> {
+ itemCount?: number;
+ level?: number;
+}
// For some reason, on TSX files it isn't accepted just one generic param, so
// I'm using <T, _> as a workaround.
-export const Row = <T, _>(itemList: TreeItem<T>[], render: any) => withStyles(styles)(
- (props: React.PropsWithChildren<ListChildComponentProps> & TreeProps<T> & WithStyles<CssRules>) => {
- const { index, style } = props;
+// eslint-disable-next-line
+export const Row = <T, _>(itemList: VirtualTreeItem<T>[], render: any, treeProps: TreeProps<T>) => withStyles(styles)(
+ (props: React.PropsWithChildren<ListChildComponentProps> & WithStyles<CssRules>) => {
+ const { index, style, classes } = props;
const it = itemList[index];
const level = it.level || 0;
- const { classes, toggleItemActive, disableRipple, currentItemUuid, useRadioButtons } = props;
- const { listItem, loader, toggableIconContainer, renderContainer } = classes;
- const { levelIndentation = 20, itemRightPadding = 20 } = props;
+ const { toggleItemActive, disableRipple, currentItemUuid, useRadioButtons } = treeProps;
+ const { listItem, loader, toggableIconContainer, renderContainer, virtualFileTree } = classes;
+ 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<T>) =>
- (event: React.MouseEvent<HTMLElement>) =>
- props.onContextMenu(event, item);
+ const handleRowContextMenu = (item: VirtualTreeItem<T>) =>
+ (event: React.MouseEvent<HTMLElement>) => {
+ treeProps.onContextMenu(event, item);
+ };
- const handleToggleItemOpen = (item: TreeItem<T>) =>
+ const handleToggleItemOpen = (item: VirtualTreeItem<T>) =>
(event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation();
- props.toggleItemOpen(event, item);
+ treeProps.toggleItemOpen(event, item);
};
const getToggableIconClassNames = (isOpen?: boolean, isActive?: boolean) => {
return isSidePanelIconNotNeeded(status, itemCount) ? <span /> : <SidePanelRightArrowIcon style={{ fontSize: '14px' }} />;
};
- const handleCheckboxChange = (item: TreeItem<T>) => {
- const { toggleItemSelection } = props;
+ const handleCheckboxChange = (item: VirtualTreeItem<T>) => {
+ const { toggleItemSelection } = treeProps;
return toggleItemSelection
? (event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation();
: undefined;
};
- return <div style={style}>
+ return <div className={virtualFileTree} data-cy='virtual-file-tree' style={style}>
<ListItem button className={listItem}
style={{
paddingLeft: (level + 1) * levelIndentation,
</div>;
});
-export const VirtualList = <T, _>(height: number, width: number, items: TreeItem<T>[], render: any) =>
+const itemSize = 30;
+
+// eslint-disable-next-line
+export const VirtualList = <T, _>(height: number, width: number, items: VirtualTreeItem<T>[], render: any, treeProps: TreeProps<T>) =>
<FixedSizeList
height={height}
itemCount={items.length}
- itemSize={30}
+ itemSize={itemSize}
width={width}
>
- {Row(items, render)}
+ {Row(items, render, treeProps)}
</FixedSizeList>;
export const VirtualTree = withStyles(styles)(
class Component<T> extends React.Component<TreeProps<T> & WithStyles<CssRules>, {}> {
render(): ReactElement<any> {
const { items, render } = this.props;
-
- return <div className={this.props.classes.virtualizedList}><AutoSizer>
+ return <AutoSizer>
{({ height, width }) => {
- return VirtualList(height, width, items || [], render);
+ return VirtualList(height, width, items || [], render, this.props);
}}
- </AutoSizer></div>;
+ </AutoSizer>;
}
}
);