[ARVADOS-WORKBENCH2] updated: 1.4.1-370-g8edacc9b

Git user git at public.arvados.org
Wed Jun 24 21:46:09 UTC 2020


Summary of changes:
 src/components/tree/tree.tsx                       |   1 +
 src/components/tree/virtual-tree.tsx               | 240 ++++++++-------------
 .../collection-panel-files.ts                      |  48 ++---
 3 files changed, 114 insertions(+), 175 deletions(-)

       via  8edacc9b2dac6520ace9a2d420979bbeb5558a6f (commit)
      from  e92207c912aed73a07340b5fb2a9e2cb23e1da5f (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 8edacc9b2dac6520ace9a2d420979bbeb5558a6f
Author: Lucas Di Pentima <lucas at di-pentima.com.ar>
Date:   Wed Jun 24 18:45:31 2020 -0300

    15610: Code cleanup, styiling additions. (WIP)
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas at di-pentima.com.ar>

diff --git a/src/components/tree/tree.tsx b/src/components/tree/tree.tsx
index b5ce5ec5..28833b85 100644
--- a/src/components/tree/tree.tsx
+++ b/src/components/tree/tree.tsx
@@ -79,6 +79,7 @@ export interface TreeItem<T> {
     selected?: boolean;
     status: TreeItemStatus;
     items?: Array<TreeItem<T>>;
+    itemCount?: number;
     level?: number;
 }
 
diff --git a/src/components/tree/virtual-tree.tsx b/src/components/tree/virtual-tree.tsx
index 4615db4f..467969fa 100644
--- a/src/components/tree/virtual-tree.tsx
+++ b/src/components/tree/virtual-tree.tsx
@@ -3,15 +3,16 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from 'react';
+import * as 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 {FixedSizeTree as Tree} from 'react-vtree';
 
 import { ArvadosTheme } from '~/common/custom-theme';
-import { TreeItem } from './tree';
-// import { FileTreeData } from '../file-tree/file-tree-data';
+import { TreeItem, TreeProps, TreeItemStatus } from './tree';
+import { ListItem, Radio, Checkbox, CircularProgress, ListItemIcon } from '@material-ui/core';
+import { SidePanelRightArrowIcon } from '../icon/icon';
 
 type CssRules = 'list'
     | 'listItem'
@@ -70,28 +71,6 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     }
 });
 
-export interface TreeProps<T> {
-    disableRipple?: boolean;
-    currentItemUuid?: string;
-    items?: Array<TreeItem<T>>;
-    level?: number;
-    onContextMenu: (event: React.MouseEvent<HTMLElement>, item: TreeItem<T>) => void;
-    render: (item: TreeItem<T>, level?: number) => ReactElement<{}>;
-    showSelection?: boolean | ((item: TreeItem<T>) => boolean);
-    levelIndentation?: number;
-    itemRightPadding?: number;
-    toggleItemActive: (event: React.MouseEvent<HTMLElement>, item: TreeItem<T>) => void;
-    toggleItemOpen: (event: React.MouseEvent<HTMLElement>, item: TreeItem<T>) => void;
-    toggleItemSelection?: (event: React.MouseEvent<HTMLElement>, item: TreeItem<T>) => void;
-
-    /**
-     * When set to true use radio buttons instead of checkboxes for item selection.
-     * This does not guarantee radio group behavior (i.e item mutual exclusivity).
-     * Any item selection logic must be done in the toggleItemActive callback prop.
-     */
-    useRadioButtons?: boolean;
-}
-
 // export const RowA = <T, _>(items: TreeItem<T>[], render:any) => (index: number) => {
 //     return <div>
 //         {render(items[index])}
@@ -100,65 +79,92 @@ export interface TreeProps<T> {
 
 // 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, _>(items: TreeItem<T>[], render: any) => (props: React.PropsWithChildren<ListChildComponentProps>) => {
-    const { index, style } = props;
-    const level = items[index].level || 0;
-    const levelIndentation = 20;
-    return <div style={style}>
-        <div style={{ paddingLeft: (level + 1) * levelIndentation,}}>
-            {typeof render === 'function'
-                ? items[index] && render(items[index]) || ''
-                : 'whoops'}
-        </div>
-    </div>;
-    // <div style={style} key={`item/${level}/${idx}`}>
-    //     <ListItem button className={listItem}
-    //         style={{
-    //             paddingLeft: (level + 1) * levelIndentation,
-    //             paddingRight: itemRightPadding,
-    //         }}
-    //         disableRipple={disableRipple}
-    //         onClick={event => toggleItemActive(event, it)}
-    //         selected={showSelection(it) && it.id === currentItemUuid}
-    //         onContextMenu={this.handleRowContextMenu(it)}>
-    //         {it.status === TreeItemStatus.PENDING ?
-    //             <CircularProgress size={10} className={loader} /> : null}
-    //         <i onClick={this.handleToggleItemOpen(it)}
-    //             className={toggableIconContainer}>
-    //             <ListItemIcon className={this.getToggableIconClassNames(it.open, it.active)}>
-    //                 {this.getProperArrowAnimation(it.status, it.items!)}
-    //             </ListItemIcon>
-    //         </i>
-    //         {showSelection(it) && !useRadioButtons &&
-    //             <Checkbox
-    //                 checked={it.selected}
-    //                 className={classes.checkbox}
-    //                 color="primary"
-    //                 onClick={this.handleCheckboxChange(it)} />}
-    //         {showSelection(it) && useRadioButtons &&
-    //             <Radio
-    //                 checked={it.selected}
-    //                 className={classes.checkbox}
-    //                 color="primary" />}
-    //         <div className={renderContainer}>
-    //             {render(it, level)}
-    //         </div>
-    //     </ListItem>
-    //     {it.items && it.items.length > 0 &&
-    //         <Collapse in={it.open} timeout="auto" unmountOnExit>
-    //             <Tree
-    //                 showSelection={this.props.showSelection}
-    //                 items={it.items}
-    //                 render={render}
-    //                 disableRipple={disableRipple}
-    //                 toggleItemOpen={toggleItemOpen}
-    //                 toggleItemActive={toggleItemActive}
-    //                 level={level + 1}
-    //                 onContextMenu={onContextMenu}
-    //                 toggleItemSelection={this.props.toggleItemSelection} />
-    //         </Collapse>}
-    // </div>
-};
+export const Row =  <T, _>(itemList: TreeItem<T>[], render: any) => withStyles(styles)(
+    (props: React.PropsWithChildren<ListChildComponentProps> & TreeProps<T> & WithStyles<CssRules>) => {
+        const { index, style } = 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 showSelection = typeof props.showSelection === 'function'
+            ? props.showSelection
+            : () => props.showSelection ? true : false;
+
+        const handleRowContextMenu = (item: TreeItem<T>) =>
+            (event: React.MouseEvent<HTMLElement>) =>
+                props.onContextMenu(event, item);
+
+        const handleToggleItemOpen = (item: TreeItem<T>) =>
+            (event: React.MouseEvent<HTMLElement>) => {
+                event.stopPropagation();
+                props.toggleItemOpen(event, item);
+            };
+
+        const getToggableIconClassNames = (isOpen?: boolean, isActive?: boolean) => {
+            const { iconOpen, iconClose, active, toggableIcon } = props.classes;
+            return classnames(toggableIcon, {
+                [iconOpen]: isOpen,
+                [iconClose]: !isOpen,
+                [active]: isActive
+            });
+        };
+
+        const isSidePanelIconNotNeeded = (status: string, itemCount: number) => {
+            return status === TreeItemStatus.PENDING ||
+                (status === TreeItemStatus.LOADED && itemCount === 0);
+        };
+
+        const getProperArrowAnimation = (status: string, itemCount: number) => {
+            return isSidePanelIconNotNeeded(status, itemCount) ? <span /> : <SidePanelRightArrowIcon style={{ fontSize: '14px' }} />;
+        };
+
+        const handleCheckboxChange = (item: TreeItem<T>) => {
+            const { toggleItemSelection } = props;
+            return toggleItemSelection
+                ? (event: React.MouseEvent<HTMLElement>) => {
+                    event.stopPropagation();
+                    toggleItemSelection(event, item);
+                }
+                : undefined;
+        };
+
+        return <div style={style}>
+            <ListItem button className={listItem}
+                style={{
+                    paddingLeft: (level + 1) * levelIndentation,
+                    paddingRight: itemRightPadding,
+                }}
+                disableRipple={disableRipple}
+                onClick={event => toggleItemActive(event, it)}
+                selected={showSelection(it) && it.id === currentItemUuid}
+                onContextMenu={handleRowContextMenu(it)}>
+                {it.status === TreeItemStatus.PENDING ?
+                    <CircularProgress size={10} className={loader} /> : null}
+                <i onClick={handleToggleItemOpen(it)}
+                    className={toggableIconContainer}>
+                    <ListItemIcon className={getToggableIconClassNames(it.open, it.active)}>
+                        {getProperArrowAnimation(it.status, it.itemCount!)}
+                    </ListItemIcon>
+                </i>
+                {showSelection(it) && !useRadioButtons &&
+                    <Checkbox
+                        checked={it.selected}
+                        className={classes.checkbox}
+                        color="primary"
+                        onClick={handleCheckboxChange(it)} />}
+                {showSelection(it) && useRadioButtons &&
+                    <Radio
+                        checked={it.selected}
+                        className={classes.checkbox}
+                        color="primary" />}
+                <div className={renderContainer}>
+                    {render(it, level)}
+                </div>
+            </ListItem>
+        </div>;
+    });
 
 export const VirtualList = <T, _>(height: number, width: number, items: TreeItem<T>[], render: any) =>
     <FixedSizeList
@@ -183,69 +189,3 @@ export const VirtualTree = withStyles(styles)(
         }
     }
 );
-
-// const treeWalkerWithTree = (tree: Array<TreeItem<FileTreeData>>) => function* treeWalker(refresh: any) {
-//     const stack = [];
-
-//     // Remember all the necessary data of the first node in the stack.
-//     stack.push({
-//       nestingLevel: 0,
-//       node: tree,
-//     });
-
-//     // Walk through the tree until we have no nodes available.
-//     while (stack.length !== 0) {
-//         const {
-//             node: {items = [], id, name},
-//             nestingLevel,
-//         } = stack.pop()!;
-
-//         // Here we are sending the information about the node to the Tree component
-//         // and receive an information about the openness state from it. The
-//         // `refresh` parameter tells us if the full update of the tree is requested;
-//         // basing on it we decide to return the full node data or only the node
-//         // id to update the nodes order.
-//         const isOpened = yield refresh
-//             ? {
-//                 id,
-//                 isLeaf: items.length === 0,
-//                 isOpenByDefault: true,
-//                 name,
-//                 nestingLevel,
-//             }
-//             : id;
-
-//         // Basing on the node openness state we are deciding if we need to render
-//         // the child nodes (if they exist).
-//         if (children.length !== 0 && isOpened) {
-//             // Since it is a stack structure, we need to put nodes we want to render
-//             // first to the end of the stack.
-//             for (let i = children.length - 1; i >= 0; i--) {
-//                 stack.push({
-//                     nestingLevel: nestingLevel + 1,
-//                     node: children[i],
-//                 });
-//             }
-//         }
-//     }
-// };
-
-// // Node component receives all the data we created in the `treeWalker` +
-// // internal openness state (`isOpen`), function to change internal openness
-// // state (`toggle`) and `style` parameter that should be added to the root div.
-// const Node = ({data: {isLeaf, name}, isOpen, style, toggle}) => (
-//     <div style={style}>
-//         {!isLeaf && (
-//         <button type="button" onClick={toggle}>
-//             {isOpen ? '-' : '+'}
-//         </button>
-//         )}
-//         <div>{name}</div>
-//     </div>
-// );
-
-// export const Example = () => (
-//     <Tree treeWalker={treeWalker} itemSize={30} height={150} width={300}>
-//         {Node}
-//     </Tree>
-// );
\ No newline at end of file
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 e0798086..3cc3569d 100644
--- a/src/views-components/collection-panel-files/collection-panel-files.ts
+++ b/src/views-components/collection-panel-files/collection-panel-files.ts
@@ -34,10 +34,7 @@ const memoizedMapStateToProps = () => {
             prevState = state.collectionPanelFiles;
             prevTree = [].concat.apply(
                 [], getNodeChildrenIds('')(state.collectionPanelFiles)
-                    .map(collectionItemToList(0)(state.collectionPanelFiles)))
-                .map(nodeToTreeItem);
-            // prevTree = getNodeChildrenIds('')(state.collectionPanelFiles)
-            //     .map(collectionItemToTreeItem(state.collectionPanelFiles));
+                    .map(collectionItemToList(0)(state.collectionPanelFiles)));
         }
         return {
             items: prevTree,
@@ -92,10 +89,29 @@ export const collectionItemToList = (level: number) => (tree: Tree<CollectionPan
                 collapsed: true
             }
         });
-        const childs = [].concat.apply([], node.children.map(collectionItemToList(level+1)(tree)));
+
+        const treeItem = {
+            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: [], // Not used in this case as we're converting a tree to a list.
+            itemCount: node.children.length,
+            open: node.value.type === CollectionFileType.DIRECTORY ? !node.value.collapsed : false,
+            selected: node.value.selected,
+            status: TreeItemStatus.LOADED,
+            level,
+        };
+
+        const treeItemChilds = [].concat.apply([], node.children.map(collectionItemToList(level+1)(tree)));
+
         return [
-            {...node, level},
-            ...childs,
+            treeItem,
+            ...treeItemChilds,
         ];
     };
 
@@ -126,21 +142,3 @@ const collectionItemToTreeItem = (tree: Tree<CollectionPanelDirectory | Collecti
             status: TreeItemStatus.LOADED
         };
     };
-
-const nodeToTreeItem = (node: TreeNode<CollectionPanelDirectory | CollectionPanelFile>): TreeItem<FileTreeData> => {
-    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: [],
-        open: node.value.type === CollectionFileType.DIRECTORY ? !node.value.collapsed : false,
-        selected: node.value.selected,
-        status: TreeItemStatus.LOADED,
-        level: node.level,
-    });
-};
\ No newline at end of file

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list