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'
}
});
-// 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;
+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 { 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<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();
</div>;
});
-export const VirtualList = <T, _>(height: number, width: number, items: TreeItem<T>[], render: any) =>
+const itemSize = 30;
+
+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)(
+export const VirtualTree = (maxElements: number) => 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>
+ // Virtual list viewport's maximum height
+ const itemsQty = items && items.length || 0;
+ const viewportHeight = min([itemsQty, maxElements])! * itemSize;
+
+ return <div style={{height: viewportHeight}}><AutoSizer>
{({ height, width }) => {
- return VirtualList(height, width, items || [], render);
+ return VirtualList(height, width, items || [], render, this.props);
}}
</AutoSizer></div>;
}
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));
};
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,
},
});
-
export const CollectionPanelFiles = connect(memoizedMapStateToProps(), mapDispatchToProps)(Component);
-export const collectionItemToList = (level: number) => (tree: Tree<CollectionPanelDirectory | CollectionPanelFile>) =>
+const collectionItemToList = (level: number) => (tree: Tree<CollectionPanelDirectory | CollectionPanelFile>) =>
(id: string): TreeItem<FileTreeData>[] => {
const node: TreeNode<CollectionPanelDirectory | CollectionPanelFile> = getNode(id)(tree) || initTreeNode({
id: '',
level,
};
- const treeItemChilds = [].concat.apply([], node.children.map(collectionItemToList(level+1)(tree)));
+ const treeItemChilds = treeItem.open
+ ? [].concat.apply([], node.children.map(collectionItemToList(level+1)(tree)))
+ : [];
return [
treeItem,
...treeItemChilds,
];
};
-
-const collectionItemToTreeItem = (tree: Tree<CollectionPanelDirectory | CollectionPanelFile>) =>
- (id: string): TreeItem<FileTreeData> => {
- const node: TreeNode<CollectionPanelDirectory | CollectionPanelFile> = 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
- };
- };