[ARVADOS-WORKBENCH2] updated: 1.1.4-142-g5fd5db8

Git user git at public.curoverse.com
Tue Jun 26 02:09:41 EDT 2018


Summary of changes:
 package.json                                       |   4 +-
 src/components/context-menu/context-menu.test.tsx  |  34 +--
 src/components/context-menu/context-menu.tsx       |  15 +-
 .../data-explorer/data-explorer.test.tsx           | 130 ++++++++++++
 src/components/data-explorer/data-explorer.tsx     | 149 +++++++++++++
 .../data-table-filters/data-table-filters.test.tsx |  68 ++++++
 .../data-table-filters/data-table-filters.tsx      | 188 +++++++++++++++++
 src/components/data-table/data-column.ts           |  20 +-
 src/components/data-table/data-table.test.tsx      | 100 ++++++++-
 src/components/data-table/data-table.tsx           |  88 +++++---
 .../search-input.test.tsx}                         |  50 ++---
 .../search-input.tsx}                              |  50 ++---
 src/components/side-panel/side-panel.tsx           | 113 ++++++++++
 src/components/tree/tree.tsx                       |  83 ++++----
 src/index.tsx                                      |   3 +-
 src/store/navigation/navigation-action.ts          |  20 +-
 src/store/project/project-action.ts                |  26 ++-
 src/store/project/project-reducer.test.ts          | 154 ++++++++++++--
 src/store/project/project-reducer.ts               |  27 ++-
 src/store/side-panel/side-panel-action.ts          |  17 ++
 src/store/side-panel/side-panel-reducer.test.ts    |  81 ++++++++
 src/store/side-panel/side-panel-reducer.ts         |  86 ++++++++
 src/store/store.ts                                 |   8 +-
 .../data-explorer/data-explorer.tsx                | 230 ---------------------
 .../project-explorer-item.ts}                      |   2 +-
 .../project-explorer/project-explorer.tsx          | 229 ++++++++++++++++++++
 .../project-tree/project-tree.test.tsx             |  14 +-
 src/views-components/project-tree/project-tree.tsx |  64 +++---
 src/views/data-explorer/data-explorer.tsx          |  63 ------
 .../project-panel-selectors.ts}                    |  10 +-
 src/views/project-panel/project-panel.tsx          |  48 +++++
 src/views/workbench/workbench.test.tsx             |   2 +-
 src/views/workbench/workbench.tsx                  |  69 +++++--
 yarn.lock                                          |  14 +-
 34 files changed, 1706 insertions(+), 553 deletions(-)
 create mode 100644 src/components/data-explorer/data-explorer.test.tsx
 create mode 100644 src/components/data-explorer/data-explorer.tsx
 create mode 100644 src/components/data-table-filters/data-table-filters.test.tsx
 create mode 100644 src/components/data-table-filters/data-table-filters.tsx
 copy src/components/{search-bar/search-bar.test.tsx => search-input/search-input.test.tsx} (52%)
 copy src/components/{search-bar/search-bar.tsx => search-input/search-input.tsx} (63%)
 create mode 100644 src/components/side-panel/side-panel.tsx
 create mode 100644 src/store/side-panel/side-panel-action.ts
 create mode 100644 src/store/side-panel/side-panel-reducer.test.ts
 create mode 100644 src/store/side-panel/side-panel-reducer.ts
 delete mode 100644 src/views-components/data-explorer/data-explorer.tsx
 rename src/views-components/{data-explorer/data-item.ts => project-explorer/project-explorer-item.ts} (93%)
 create mode 100644 src/views-components/project-explorer/project-explorer.tsx
 delete mode 100644 src/views/data-explorer/data-explorer.tsx
 rename src/views/{data-explorer/data-explorer-selectors.ts => project-panel/project-panel-selectors.ts} (84%)
 create mode 100644 src/views/project-panel/project-panel.tsx

       via  5fd5db805554d3eddd46cc911a5108fbb74b3cfc (commit)
       via  0af46f7944bde95f634080a1d6b15ae9c585890a (commit)
       via  744ad03a10d96b457a8172ce812d000e64fdffe0 (commit)
       via  a292318d2307543333fd5c2ea06610c6b82b0566 (commit)
       via  c90e813adcec89899d9db95843295a84fb058c3e (commit)
       via  ae7d952a97542c2cfc12f6f41ab0de93af278919 (commit)
       via  5e88476747d9fb0c77ef76d63430192fa4b77f22 (commit)
       via  0ab4372cd072b9fd8f619158615a32b19a52f208 (commit)
       via  9fdaf676b641f794c73e8604e498b7d803fd1110 (commit)
       via  cc9505ee86539329d5ae0c4809aa293c54c2a25c (commit)
       via  06a247fec429a11fb27c0ebf50ba9c31ffc8d0c2 (commit)
       via  e2ea1359533664ead0ae9b810fe56bf518846c78 (commit)
       via  ac57fa77b04d290285388036f7929631e05965e4 (commit)
       via  152a17b28656fe498d3b3bbf21d5994e9ccd34ab (commit)
       via  f0c4e703bd7bdcf90265c96d6f714bf831f6947a (commit)
       via  a21b35b41a8e69a4a1e287ce069dbc65c5c534f2 (commit)
       via  9e4aa2fd44835698c0a3e6f321a2cf88b6f11939 (commit)
       via  3015426750f11fdc97d55a29f2a662e2f272f5d4 (commit)
       via  bca77b4dbbc90bc60de06bd90a20e9a46c02fcfa (commit)
       via  5925c0eb9468ffca9419e47ae333501968b4e24e (commit)
       via  fd79729916cf6ddf27063b1865d39a36abb9e038 (commit)
       via  1a9eb2261e6030ba78078e2a206bad27653f2475 (commit)
       via  7444429308f438fb2e29188db8f208223ed39128 (commit)
      from  6e44781d01db889030cc5f7819aa7f15fe837e19 (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 5fd5db805554d3eddd46cc911a5108fbb74b3cfc
Merge: 6e44781 0af46f7
Author: Daniel Kos <daniel.kos at contractors.roche.com>
Date:   Tue Jun 26 08:09:29 2018 +0200

    Merge branch 'origin/master' into 13666-data-explorer-mapper
    
    Feature #13666
    
    # Conflicts:
    #       src/components/tree/tree.tsx
    #       src/store/project/project-reducer.ts
    #       src/views-components/data-explorer/data-explorer.tsx
    #       src/views-components/project-explorer/project-explorer-item.ts
    #       src/views-components/project-tree/project-tree.tsx
    #       src/views/data-explorer/data-explorer-selectors.ts
    #       src/views/data-explorer/data-explorer.tsx
    #       src/views/workbench/workbench.tsx
    
    Arvados-DCO-1.1-Signed-off-by: Daniel Kos <daniel.kos at contractors.roche.com>

diff --cc src/store/navigation/navigation-action.ts
index 80318ec,0000000..6d1754d
mode 100644,000000..100644
--- a/src/store/navigation/navigation-action.ts
+++ b/src/store/navigation/navigation-action.ts
@@@ -1,47 -1,0 +1,65 @@@
 +// Copyright (C) The Arvados Authors. All rights reserved.
 +//
 +// SPDX-License-Identifier: AGPL-3.0
 +
 +import { Dispatch } from "redux";
 +import projectActions, { getProjectList } from "../project/project-action";
 +import { push } from "react-router-redux";
 +import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
 +import { getCollectionList } from "../collection/collection-action";
 +import { findTreeItem } from "../project/project-reducer";
 +import { Project } from "../../models/project";
 +import { Resource, ResourceKind } from "../../models/resource";
++import sidePanelActions from "../side-panel/side-panel-action";
 +
 +export const getResourceUrl = (resource: Resource): string => {
 +    switch (resource.kind) {
 +        case ResourceKind.LEVEL_UP: return `/projects/${resource.ownerUuid}`;
 +        case ResourceKind.PROJECT: return `/projects/${resource.uuid}`;
 +        case ResourceKind.COLLECTION: return `/collections/${resource.uuid}`;
 +        default:
 +            return "#";
 +    }
 +};
 +
 +export const setProjectItem = (projects: Array<TreeItem<Project>>, itemId: string, itemKind: ResourceKind) => (dispatch: Dispatch) => {
 +
 +    const openProjectItem = (resource: Resource) => {
-         dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(resource.uuid));
++        dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(resource.uuid));
++        dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(resource.uuid));
++        dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(resource.uuid));
 +        dispatch(push(getResourceUrl({...resource, kind: itemKind})));
 +    };
 +    const treeItem = findTreeItem(projects, itemId);
 +
 +    if (treeItem) {
 +        if (treeItem.status === TreeItemStatus.Loaded) {
 +            openProjectItem(treeItem.data);
 +        } else {
 +            dispatch<any>(getProjectList(itemId))
 +                .then(() => openProjectItem(treeItem.data));
 +        }
 +        dispatch<any>(getCollectionList(itemId));
 +
 +        // if (item.type === ResourceKind.PROJECT || item.type === ResourceKind.LEVEL_UP) {
 +        //     this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(item.uuid));
 +        // }
 +        // this.props.dispatch<any>(getCollectionList(item.uuid));
 +
 +    }
 +};
++
++    // toggleProjectTreeItemActive = (itemId: string, status: TreeItemStatus) => {
++    //     if (status === TreeItemStatus.Loaded) {
++    //         this.openProjectItem(itemId);
++    //         this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
++    //         this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
++    //     } else {
++    //         this.props.dispatch<any>(getProjectList(itemId))
++    //             .then(() => {
++    //                 this.openProjectItem(itemId);
++    //                 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
++    //                 this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
++    //             });
++    //     }
++    // }
diff --cc src/store/project/project-reducer.test.ts
index 8082809,e8d6afc..65a856b
--- a/src/store/project/project-reducer.test.ts
+++ b/src/store/project/project-reducer.test.ts
@@@ -39,26 -38,149 +39,154 @@@ describe('project-reducer', () => 
          const projects = [project, project];
          const state = projectsReducer(initialState, actions.PROJECTS_SUCCESS({ projects, parentItemId: undefined }));
          expect(state).toEqual([{
+             active: false,
+             open: false,
+             id: "test123",
+             items: [],
+             data: project,
+             status: 0
+         }, {
+             active: false,
+             open: false,
+             id: "test123",
+             items: [],
+             data: project,
+             status: 0
+         }
+         ]);
+     });
+ 
+     it('should remove activity on projects list', () => {
 -        const initialState = [
 -            {
++        const initialState = {
++            items: [{
+                 data: {
+                     name: 'test',
+                     href: 'href',
+                     createdAt: '2018-01-01',
+                     modifiedAt: '2018-01-01',
+                     ownerUuid: 'owner-test123',
+                     uuid: 'test123',
 -                    kind: 'example'
++                    kind: ResourceKind.PROJECT
+                 },
+                 id: "1",
+                 open: true,
+                 active: true,
+                 status: 1
 -            }
 -        ];
 -        const project = [
 -            {
++            }],
++            currentItemId: "1"
++        };
++        const project = {
++            items: [{
+                 data: {
+                     name: 'test',
+                     href: 'href',
+                     createdAt: '2018-01-01',
+                     modifiedAt: '2018-01-01',
+                     ownerUuid: 'owner-test123',
+                     uuid: 'test123',
 -                    kind: 'example'
++                    kind: ResourceKind.PROJECT
+                 },
+                 id: "1",
+                 open: true,
                  active: false,
-                 open: false,
-                 id: "test123",
-                 items: [],
-                 data: project,
-                 status: 0
-             }, {
+                 status: 1
 -            }
 -        ];
++            }],
++            currentItemId: "1"
++        };
+ 
+         const state = projectsReducer(initialState, actions.RESET_PROJECT_TREE_ACTIVITY(initialState[0].id));
+         expect(state).toEqual(project);
+     });
+ 
+     it('should toggle project tree item activity', () => {
 -        const initialState = [
 -            {
++        const initialState = {
++            items: [{
+                 data: {
+                     name: 'test',
+                     href: 'href',
+                     createdAt: '2018-01-01',
+                     modifiedAt: '2018-01-01',
+                     ownerUuid: 'owner-test123',
+                     uuid: 'test123',
 -                    kind: 'example'
++                    kind: ResourceKind.PROJECT
+                 },
+                 id: "1",
+                 open: true,
                  active: false,
+                 status: 1
 -            }
 -        ];
 -        const project = [
 -            {
++            }],
++            currentItemId: "1"
++        };
++        const project = {
++            items: [{
+                 data: {
+                     name: 'test',
+                     href: 'href',
+                     createdAt: '2018-01-01',
+                     modifiedAt: '2018-01-01',
+                     ownerUuid: 'owner-test123',
+                     uuid: 'test123',
 -                    kind: 'example'
++                    kind: ResourceKind.PROJECT
+                 },
+                 id: "1",
+                 open: true,
+                 active: true,
+                 status: 1
 -            }
 -        ];
++            }],
++            currentItemId: "1"
++        };
+ 
+         const state = projectsReducer(initialState, actions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(initialState[0].id));
+         expect(state).toEqual(project);
+     });
+ 
+ 
+     it('should close project tree item ', () => {
 -        const initialState = [
 -            {
++        const initialState = {
++            items: [{
+                 data: {
+                     name: 'test',
+                     href: 'href',
+                     createdAt: '2018-01-01',
+                     modifiedAt: '2018-01-01',
+                     ownerUuid: 'owner-test123',
+                     uuid: 'test123',
 -                    kind: 'example'
++                    kind: ResourceKind.PROJECT
+                 },
+                 id: "1",
+                 open: true,
+                 active: false,
+                 status: 1,
+                 toggled: false,
 -            }
 -        ];
 -        const project = [
 -            {
++            }],
++            currentItemId: "1"
++        };
++        const project = {
++            items: [{
+                 data: {
+                     name: 'test',
+                     href: 'href',
+                     createdAt: '2018-01-01',
+                     modifiedAt: '2018-01-01',
+                     ownerUuid: 'owner-test123',
+                     uuid: 'test123',
 -                    kind: 'example'
++                    kind: ResourceKind.PROJECT
+                 },
+                 id: "1",
                  open: false,
-                 id: "test123",
-                 items: [],
-                 data: project,
-                 status: 0
-             }
-         ]);
+                 active: false,
+                 status: 1,
+                 toggled: true
 -            }
 -        ];
++            }],
++            currentItemId: "1"
++        };
+ 
+         const state = projectsReducer(initialState, actions.TOGGLE_PROJECT_TREE_ITEM_OPEN(initialState[0].id));
+         expect(state).toEqual(project);
      });
  });
  
  describe("findTreeBranch", () => {
--
      const createTreeItem = (id: string, items?: Array<TreeItem<string>>): TreeItem<string> => ({
          id,
          items,
diff --cc src/store/project/project-reducer.ts
index a40d48d,48db05d..39d194d
--- a/src/store/project/project-reducer.ts
+++ b/src/store/project/project-reducer.ts
@@@ -5,12 -7,8 +7,11 @@@ import * as _ from "lodash"
  import { Project } from "../../models/project";
  import actions, { ProjectAction } from "./project-action";
  import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
- import * as _ from "lodash";
  
 -export type ProjectState = Array<TreeItem<Project>>;
 +export type ProjectState = {
 +    items: Array<TreeItem<Project>>,
 +    currentItemId: string
 +};
  
  export function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
      let item;
@@@ -84,50 -69,44 +85,68 @@@ function updateProjectTree(tree: Array<
      return items;
  }
  
 -const projectsReducer = (state: ProjectState = [], action: ProjectAction) => {
 +const projectsReducer = (state: ProjectState = { items: [], currentItemId: "" }, action: ProjectAction) => {
      return actions.match(action, {
 -        CREATE_PROJECT: project => [...state, project],
 +        CREATE_PROJECT: project => ({
 +            ...state,
 +            items: state.items.concat({
 +                id: project.uuid,
 +                open: false,
 +                active: false,
 +                status: TreeItemStatus.Loaded,
 +                toggled: false,
 +                items: [],
 +                data: project
 +            })
 +        }),
          REMOVE_PROJECT: () => state,
          PROJECTS_REQUEST: itemId => {
 -            const tree = _.cloneDeep(state);
 -            const item = findTreeItem(tree, itemId);
 +            const items = _.cloneDeep(state.items);
 +            const item = findTreeItem(items, itemId);
              if (item) {
                  item.status = TreeItemStatus.Pending;
 +                state.items = items;
              }
 -            return tree;
 +            return state;
          },
          PROJECTS_SUCCESS: ({ projects, parentItemId }) => {
 -            return updateProjectTree(state, projects, parentItemId);
 +            return {
 +                ...state,
 +                items: updateProjectTree(state.items, projects, parentItemId)
 +            };
          },
-         TOGGLE_PROJECT_TREE_ITEM: itemId => {
+         TOGGLE_PROJECT_TREE_ITEM_OPEN: itemId => {
 -            const tree = _.cloneDeep(state);
 -            const item = findTreeItem(tree, itemId);
 +            const items = _.cloneDeep(state.items);
-             resetTreeActivity(items);
 +            const item = findTreeItem(items, itemId);
              if (item) {
+                 item.toggled = true;
                  item.open = !item.open;
+             }
 -            return tree;
++            return {
++                ...state,
++                items
++            };
+         },
+         TOGGLE_PROJECT_TREE_ITEM_ACTIVE: itemId => {
 -            const tree = _.cloneDeep(state);
 -            resetTreeActivity(tree);
 -            const item = findTreeItem(tree, itemId);
++            const items = _.cloneDeep(state.items);
++            resetTreeActivity(items);
++            const item = findTreeItem(items, itemId);
+             if (item) {
                  item.active = true;
-                 item.toggled = true;
              }
 -            return tree;
 +            return {
 +                items,
 +                currentItemId: itemId
 +            };
          },
+         RESET_PROJECT_TREE_ACTIVITY: () => {
 -            const tree = _.cloneDeep(state);
 -            resetTreeActivity(tree);
 -            return tree;
++            const items = _.cloneDeep(state.items);
++            resetTreeActivity(items);
++            return {
++                ...state,
++                items
++            };
+         },
          default: () => state
      });
  };
diff --cc src/store/store.ts
index 6053e03,6089caf..40b24a0
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@@ -6,9 -6,11 +6,11 @@@ import { createStore, applyMiddleware, 
  import { routerMiddleware, routerReducer, RouterState } from "react-router-redux";
  import thunkMiddleware from 'redux-thunk';
  import { History } from "history";
+ 
  import projectsReducer, { ProjectState } from "./project/project-reducer";
+ import sidePanelReducer, { SidePanelState } from './side-panel/side-panel-reducer';
  import authReducer, { AuthState } from "./auth/auth-reducer";
 -import collectionsReducer from "./collection/collection-reducer";
 +import collectionsReducer, { CollectionState } from "./collection/collection-reducer";
  
  const composeEnhancers =
      (process.env.NODE_ENV === 'development' &&
@@@ -18,8 -20,8 +20,9 @@@
  export interface RootState {
      auth: AuthState;
      projects: ProjectState;
 +    collections: CollectionState;
      router: RouterState;
+     sidePanel: SidePanelState;
  }
  
  const rootReducer = combineReducers({
diff --cc src/views-components/project-explorer/project-explorer-item.ts
index cde2bd9,055c22c..4fa3d3d
--- a/src/views-components/project-explorer/project-explorer-item.ts
+++ b/src/views-components/project-explorer/project-explorer-item.ts
@@@ -2,13 -2,10 +2,13 @@@
  //
  // SPDX-License-Identifier: AGPL-3.0
  
 +import { getResourceKind, Resource, ResourceKind } from "../../models/resource";
 +
- export interface DataItem {
+ export interface ProjectExplorerItem {
      uuid: string;
      name: string;
 -    type: string;
 +    kind: ResourceKind;
 +    url: string;
      owner: string;
      lastModified: string;
      fileSize?: number;
diff --cc src/views-components/project-explorer/project-explorer.tsx
index 0000000,4931c09..1018ef5
mode 000000,100644..100644
--- a/src/views-components/project-explorer/project-explorer.tsx
+++ b/src/views-components/project-explorer/project-explorer.tsx
@@@ -1,0 -1,224 +1,229 @@@
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+ 
+ import * as React from 'react';
+ import { ProjectExplorerItem } from './project-explorer-item';
+ import { Grid, Typography } from '@material-ui/core';
+ import { formatDate, formatFileSize } from '../../common/formatters';
+ import DataExplorer from '../../components/data-explorer/data-explorer';
+ import { DataColumn, toggleSortDirection, resetSortDirection } from '../../components/data-table/data-column';
+ import { DataTableFilterItem } from '../../components/data-table-filters/data-table-filters';
+ import { ContextMenuAction } from '../../components/context-menu/context-menu';
++import { ResourceKind } from "../../models/resource";
+ 
+ export interface ProjectExplorerContextActions {
+     onAddToFavourite: (item: ProjectExplorerItem) => void;
+     onCopy: (item: ProjectExplorerItem) => void;
+     onDownload: (item: ProjectExplorerItem) => void;
+     onMoveTo: (item: ProjectExplorerItem) => void;
+     onRemove: (item: ProjectExplorerItem) => void;
+     onRename: (item: ProjectExplorerItem) => void;
+     onShare: (item: ProjectExplorerItem) => void;
+ }
+ 
+ interface ProjectExplorerProps {
+     items: ProjectExplorerItem[];
++    onRowClick: (item: ProjectExplorerItem) => void;
+ }
+ 
+ interface ProjectExplorerState {
+     columns: Array<DataColumn<ProjectExplorerItem>>;
+     searchValue: string;
+     page: number;
+     rowsPerPage: number;
+ }
+ 
+ class ProjectExplorer extends React.Component<ProjectExplorerProps, ProjectExplorerState> {
+     state: ProjectExplorerState = {
+         searchValue: "",
+         page: 0,
+         rowsPerPage: 10,
+         columns: [{
+             name: "Name",
+             selected: true,
+             sortDirection: "asc",
+             render: renderName
+         }, {
+             name: "Status",
+             selected: true,
+             filters: [{
+                 name: "In progress",
+                 selected: true
+             }, {
+                 name: "Complete",
+                 selected: true
+             }],
+             render: renderStatus
+         }, {
+             name: "Type",
+             selected: true,
+             filters: [{
+                 name: "Collection",
+                 selected: true
+             }, {
+                 name: "Group",
+                 selected: true
+             }],
 -            render: item => renderType(item.type)
++            render: item => renderType(item.kind)
+         }, {
+             name: "Owner",
+             selected: true,
+             render: item => renderOwner(item.owner)
+         }, {
+             name: "File size",
+             selected: true,
+             sortDirection: "none",
+             render: item => renderFileSize(item.fileSize)
+         }, {
+             name: "Last modified",
+             selected: true,
+             render: item => renderDate(item.lastModified)
+         }]
+     };
+ 
+     contextMenuActions = [[{
+         icon: "fas fa-users fa-fw",
+         name: "Share"
+     }, {
+         icon: "fas fa-sign-out-alt fa-fw",
+         name: "Move to"
+     }, {
+         icon: "fas fa-star fa-fw",
+         name: "Add to favourite"
+     }, {
+         icon: "fas fa-edit fa-fw",
+         name: "Rename"
+     }, {
+         icon: "fas fa-copy fa-fw",
+         name: "Make a copy"
+     }, {
+         icon: "fas fa-download fa-fw",
+         name: "Download"
+     }], [{
+         icon: "fas fa-trash-alt fa-fw",
+         name: "Remove"
+     }
+     ]];
+ 
+     render() {
+         return <DataExplorer
+             items={this.props.items}
+             columns={this.state.columns}
+             contextActions={this.contextMenuActions}
+             searchValue={this.state.searchValue}
+             page={this.state.page}
+             rowsPerPage={this.state.rowsPerPage}
+             onColumnToggle={this.toggleColumn}
+             onFiltersChange={this.changeFilters}
 -            onRowClick={console.log}
++            onRowClick={this.props.onRowClick}
+             onSortToggle={this.toggleSort}
+             onSearch={this.search}
+             onContextAction={this.executeAction}
+             onChangePage={this.changePage}
+             onChangeRowsPerPage={this.changeRowsPerPage} />;
+     }
+ 
+     toggleColumn = (toggledColumn: DataColumn<ProjectExplorerItem>) => {
+         this.setState({
+             columns: this.state.columns.map(column =>
+                 column.name === toggledColumn.name
+                     ? { ...column, selected: !column.selected }
+                     : column
+             )
+         });
+     }
+ 
+     toggleSort = (toggledColumn: DataColumn<ProjectExplorerItem>) => {
+         this.setState({
+             columns: this.state.columns.map(column =>
+                 column.name === toggledColumn.name
+                     ? toggleSortDirection(column)
+                     : resetSortDirection(column)
+             )
+         });
+     }
+ 
+     changeFilters = (filters: DataTableFilterItem[], updatedColumn: DataColumn<ProjectExplorerItem>) => {
+         this.setState({
+             columns: this.state.columns.map(column =>
+                 column.name === updatedColumn.name
+                     ? { ...column, filters }
+                     : column
+             )
+         });
+     }
+ 
+     executeAction = (action: ContextMenuAction, item: ProjectExplorerItem) => {
+         alert(`Executing ${action.name} on ${item.name}`);
+     }
+ 
+     search = (searchValue: string) => {
+         this.setState({ searchValue });
+     }
+ 
+     changePage = (page: number) => {
+         this.setState({ page });
+     }
+ 
+     changeRowsPerPage = (rowsPerPage: number) => {
+         this.setState({ rowsPerPage });
+     }
+ }
+ 
+ const renderName = (item: ProjectExplorerItem) =>
+     <Grid
+         container
+         alignItems="center"
+         wrap="nowrap"
+         spacing={16}>
+         <Grid item>
+             {renderIcon(item)}
+         </Grid>
+         <Grid item>
+             <Typography color="primary">
+                 {item.name}
+             </Typography>
+         </Grid>
+     </Grid>;
+ 
++
+ const renderIcon = (item: ProjectExplorerItem) => {
 -    switch (item.type) {
 -        case "arvados#group":
 -            return <i className="fas fa-folder fa-lg" />;
 -        case "arvados#groupList":
 -            return <i className="fas fa-th fa-lg" />;
++    switch (item.kind) {
++        case ResourceKind.LEVEL_UP:
++            return <i className="icon-level-up" style={{fontSize: "1rem"}}/>;
++        case ResourceKind.PROJECT:
++            return <i className="fas fa-folder fa-lg"/>;
++        case ResourceKind.COLLECTION:
++            return <i className="fas fa-th fa-lg"/>;
+         default:
+             return <i />;
+     }
+ };
+ 
+ const renderDate = (date: string) =>
+     <Typography noWrap>
+         {formatDate(date)}
+     </Typography>;
+ 
+ const renderFileSize = (fileSize?: number) =>
+     <Typography noWrap>
+         {formatFileSize(fileSize)}
+     </Typography>;
+ 
+ const renderOwner = (owner: string) =>
+     <Typography noWrap color="primary">
+         {owner}
+     </Typography>;
+ 
+ const renderType = (type: string) =>
+     <Typography noWrap>
+         {type}
+     </Typography>;
+ 
+ const renderStatus = (item: ProjectExplorerItem) =>
+     <Typography noWrap align="center">
+         {item.status || "-"}
+     </Typography>;
+ 
+ export default ProjectExplorer;
diff --cc src/views/project-panel/project-panel-selectors.ts
index ceb87d2,610f2fa..c798ec3
--- a/src/views/project-panel/project-panel-selectors.ts
+++ b/src/views/project-panel/project-panel-selectors.ts
@@@ -4,55 -4,12 +4,55 @@@
  
  import { TreeItem } from "../../components/tree/tree";
  import { Project } from "../../models/project";
- import { DataItem } from "../../views-components/data-explorer/data-item";
 +import { findTreeItem } from "../../store/project/project-reducer";
 +import { ResourceKind } from "../../models/resource";
 +import { Collection } from "../../models/collection";
 +import { getResourceUrl } from "../../store/navigation/navigation-action";
+ import { ProjectExplorerItem } from "../../views-components/project-explorer/project-explorer-item";
  
- export const projectExplorerItems = (projects: Array<TreeItem<Project>>, treeItemId: string, collections: Array<Collection>): DataItem[] => {
-     const dataItems: DataItem[] = [];
 -export const mapProjectTreeItem = (item: TreeItem<Project>): ProjectExplorerItem => ({
 -    name: item.data.name,
 -    type: item.data.kind,
 -    owner: item.data.ownerUuid,
 -    lastModified: item.data.modifiedAt,
 -    uuid: item.data.uuid
 -});
++export const projectExplorerItems = (projects: Array<TreeItem<Project>>, treeItemId: string, collections: Array<Collection>): ProjectExplorerItem[] => {
++    const dataItems: ProjectExplorerItem[] = [];
 +
 +    const treeItem = findTreeItem(projects, treeItemId);
 +    if (treeItem) {
 +        dataItems.push({
 +            name: "..",
 +            url: getResourceUrl(treeItem.data),
 +            kind: ResourceKind.LEVEL_UP,
 +            owner: treeItem.data.ownerUuid,
 +            uuid: treeItem.data.uuid,
 +            lastModified: treeItem.data.modifiedAt
 +        });
 +
 +        if (treeItem.items) {
 +            treeItem.items.forEach(p => {
 +                const item = {
 +                    name: p.data.name,
 +                    kind: ResourceKind.PROJECT,
 +                    url: getResourceUrl(treeItem.data),
 +                    owner: p.data.ownerUuid,
 +                    uuid: p.data.uuid,
 +                    lastModified: p.data.modifiedAt
-                 } as DataItem;
++                } as ProjectExplorerItem;
 +
 +                dataItems.push(item);
 +            });
 +        }
 +    }
 +
 +    collections.forEach(c => {
 +        const item = {
 +            name: c.name,
 +            kind: ResourceKind.COLLECTION,
 +            url: getResourceUrl(c),
 +            owner: c.ownerUuid,
 +            uuid: c.uuid,
 +            lastModified: c.modifiedAt
-         } as DataItem;
++        } as ProjectExplorerItem;
 +
 +        dataItems.push(item);
 +    });
 +
 +    return dataItems;
 +};
 +
diff --cc src/views/project-panel/project-panel.tsx
index 0000000,f9e6c8b..68cbc8e
mode 000000,100644..100644
--- a/src/views/project-panel/project-panel.tsx
+++ b/src/views/project-panel/project-panel.tsx
@@@ -1,0 -1,34 +1,48 @@@
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+ 
+ import * as React from 'react';
 -import { RouteComponentProps } from 'react-router-dom';
 -import { DispatchProp, connect } from 'react-redux';
 -import { ProjectState, findTreeItem } from '../../store/project/project-reducer';
 -import ProjectExplorer from '../../views-components/project-explorer/project-explorer';
++import { RouteComponentProps } from 'react-router';
++import { ProjectState } from '../../store/project/project-reducer';
+ import { RootState } from '../../store/store';
 -import { mapProjectTreeItem } from './project-panel-selectors';
++import { connect, DispatchProp } from 'react-redux';
++import { CollectionState } from "../../store/collection/collection-reducer";
++import { setProjectItem } from "../../store/navigation/navigation-action";
++import ProjectExplorer, { ProjectExplorerContextActions } from "../../views-components/project-explorer/project-explorer";
++import { projectExplorerItems } from "./project-panel-selectors";
++import { ProjectExplorerItem } from "../../views-components/project-explorer/project-explorer-item";
+ 
+ interface ProjectPanelDataProps {
+     projects: ProjectState;
++    collections: CollectionState;
+ }
+ 
+ type ProjectPanelProps = ProjectPanelDataProps & RouteComponentProps<{ name: string }> & DispatchProp;
+ 
+ class ProjectPanel extends React.Component<ProjectPanelProps> {
 -
+     render() {
 -        const project = findTreeItem(this.props.projects, this.props.match.params.name);
 -        const projectItems = project && project.items || [];
++        const items = projectExplorerItems(
++            this.props.projects.items,
++            this.props.projects.currentItemId,
++            this.props.collections
++        );
+         return (
 -            <ProjectExplorer items={projectItems.map(mapProjectTreeItem)} />
++            <ProjectExplorer
++                items={items}
++                onRowClick={this.goToItem}
++            />
+         );
+     }
++
++    goToItem = (item: ProjectExplorerItem) => {
++        this.props.dispatch<any>(setProjectItem(this.props.projects.items, item.uuid, item.kind));
++    }
+ }
+ 
+ export default connect(
+     (state: RootState) => ({
 -        projects: state.projects
++        projects: state.projects,
++        collections: state.collections
+     })
+ )(ProjectPanel);
diff --cc src/views/workbench/workbench.tsx
index aed2815,4f9843c..b6a8457
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@@ -11,19 -10,18 +10,21 @@@ import { Route, Switch } from "react-ro
  import authActions from "../../store/auth/auth-action";
  import { User } from "../../models/user";
  import { RootState } from "../../store/store";
 -import MainAppBar, { MainAppBarActionProps, MainAppBarMenuItem } from '../../views-components/main-app-bar/main-app-bar';
 +import MainAppBar, {
 +    MainAppBarActionProps,
 +    MainAppBarMenuItem
 +} from '../../views-components/main-app-bar/main-app-bar';
  import { Breadcrumb } from '../../components/breadcrumbs/breadcrumbs';
  import { push } from 'react-router-redux';
 -import projectActions, { getProjectList } from "../../store/project/project-action";
  import ProjectTree from '../../views-components/project-tree/project-tree';
 -import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
 +import { TreeItem } from "../../components/tree/tree";
  import { Project } from "../../models/project";
  import { getTreePath } from '../../store/project/project-reducer';
- import DataExplorer from '../data-explorer/data-explorer';
- import { setProjectItem } from "../../store/navigation/navigation-action";
+ import ProjectPanel from '../project-panel/project-panel';
+ import sidePanelActions from '../../store/side-panel/side-panel-action';
 -import { projectService } from '../../services/services';
+ import SidePanel, { SidePanelItem } from '../../components/side-panel/side-panel';
 +import { ResourceKind } from "../../models/resource";
++import { setProjectItem } from "../../store/navigation/navigation-action";
  
  const drawerWidth = 240;
  const appBarHeight = 102;
@@@ -67,8 -67,8 +70,9 @@@ const styles: StyleRulesCallback<CssRul
  
  interface WorkbenchDataProps {
      projects: Array<TreeItem<Project>>;
 +    currentProjectId: string;
      user?: User;
+     sidePanelItems: SidePanelItem[];
  }
  
  interface WorkbenchActionProps {
@@@ -136,15 -139,60 +140,24 @@@ class Workbench extends React.Component
          onMenuItemClick: (menuItem: NavMenuItem) => menuItem.action()
      };
  
 -    toggleProjectTreeItemOpen = (itemId: string, status: TreeItemStatus) => {
 -        if (status === TreeItemStatus.Loaded) {
 -            this.openProjectItem(itemId);
 -            this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId));
 -            this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
 -        } else {
 -            this.props.dispatch<any>(getProjectList(itemId))
 -                .then(() => {
 -                    this.openProjectItem(itemId);
 -                    this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId));
 -                    this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
 -                });
 -        }
 -    }
 -
 -    toggleProjectTreeItemActive = (itemId: string, status: TreeItemStatus) => {
 -        if (status === TreeItemStatus.Loaded) {
 -            this.openProjectItem(itemId);
 -            this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
 -            this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
 -        } else {
 -            this.props.dispatch<any>(getProjectList(itemId))
 -                .then(() => {
 -                    this.openProjectItem(itemId);
 -                    this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
 -                    this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
 -                });
 -        }
 -    }
 -
+     toggleSidePanelOpen = (itemId: string) => {
+         this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(itemId));
+     }
+ 
+     toggleSidePanelActive = (itemId: string) => {
+         this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(itemId));
 -        this.props.dispatch(projectActions.RESET_PROJECT_TREE_ACTIVITY(itemId));
 -    }
 -
 -    openProjectItem = (itemId: string) => {
 -        const branch = getTreePath(this.props.projects, itemId);
 -        this.setState({
 -            breadcrumbs: branch.map(item => ({
 -                label: item.data.name,
 -                itemId: item.data.uuid,
 -                status: item.status
 -            }))
 -        });
 -        this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
 -        this.props.dispatch(push(`/project/${itemId}`));
++        // this.props.dispatch(projectActions.RESET_PROJECT_TREE_ACTIVITY(itemId));
+     }
+ 
      render() {
 -        const { classes, user, projects, sidePanelItems } = this.props;
 +        const branch = getTreePath(this.props.projects, this.props.currentProjectId);
 +        const breadcrumbs = branch.map(item => ({
 +            label: item.data.name,
 +            itemId: item.data.uuid,
 +            status: item.status
 +        }));
 +
 +        const { classes, user } = this.props;
          return (
              <div className={classes.root}>
                  <div className={classes.appBar}>
@@@ -156,19 -204,23 +169,30 @@@
                          {...this.mainAppBarActions}
                      />
                  </div>
-                 {user && <Drawer
-                     variant="permanent"
-                     classes={{
-                         paper: classes.drawerPaper,
-                     }}>
-                     <div className={classes.toolbar} />
-                     <ProjectTree
-                         projects={this.props.projects}
-                         toggleProjectTreeItem={itemId =>
-                             this.props.dispatch<any>(
-                                 setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT)
-                             )}/>
-                 </Drawer>}
+                 {user &&
+                     <Drawer
+                         variant="permanent"
+                         classes={{
+                             paper: classes.drawerPaper,
+                         }}>
+                         <div className={classes.toolbar} />
+                         <SidePanel
+                             toggleOpen={this.toggleSidePanelOpen}
+                             toggleActive={this.toggleSidePanelActive}
 -                            sidePanelItems={sidePanelItems}>
++                            sidePanelItems={this.props.sidePanelItems}>
+                             <ProjectTree
 -                                projects={projects}
 -                                toggleOpen={this.toggleProjectTreeItemOpen}
 -                                toggleActive={this.toggleProjectTreeItemActive} />
++                                projects={this.props.projects}
++                                toggleOpen={itemId =>
++                                    this.props.dispatch<any>(
++                                        setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT)
++                                    )}
++                                toggleActive={itemId =>
++                                    this.props.dispatch<any>(
++                                        setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT)
++                                    )}
++                            />
+                         </SidePanel>
+                     </Drawer>}
                  <main className={classes.contentWrapper}>
                      <div className={classes.content}>
                          <Switch>
@@@ -180,12 -232,12 +204,21 @@@
          );
      }
  }
++/*
++                    <ProjectTree
++                        projects={this.props.projects}
++                        toggleProjectTreeItem={itemId =>
++                            this.props.dispatch<any>(
++                                setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT)
++                            )}/>
++*/
  
  export default connect<WorkbenchDataProps>(
      (state: RootState) => ({
 -        projects: state.projects,
 +        projects: state.projects.items,
 +        currentProjectId: state.projects.currentItemId,
-         user: state.auth.user
+         user: state.auth.user,
 -        sidePanelItems: state.sidePanel,
++        sidePanelItems: state.sidePanel
      })
  )(
      withStyles(styles)(Workbench)

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list