Create basic cumulative projects picker
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Tue, 9 Oct 2018 14:37:18 +0000 (16:37 +0200)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Tue, 9 Oct 2018 14:37:18 +0000 (16:37 +0200)
Feature #13862

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

src/index.tsx
src/models/tree.ts
src/store/tree-picker/tree-picker-actions.ts
src/store/tree-picker/tree-picker-reducer.ts
src/views-components/projects-tree-picker/favorites-tree-picker.tsx
src/views-components/projects-tree-picker/generic-projects-tree-picker.tsx [new file with mode: 0644]
src/views-components/projects-tree-picker/home-tree-picker.tsx [moved from src/views-components/projects-tree-picker/user-projects-tree-picker.tsx with 82% similarity]
src/views-components/projects-tree-picker/projects-tree-picker.tsx
src/views-components/projects-tree-picker/shared-tree-picker.tsx [moved from src/views-components/projects-tree-picker/shared-projects-tree-picker.tsx with 73% similarity]
src/views/workbench/workbench.tsx

index 16cf86a36815874900ea5b109aaebf55b73c07c4..c1238a545fa3e9d15f1e91ca5fcbf2387b1155b6 100644 (file)
@@ -43,7 +43,7 @@ import { trashedCollectionActionSet } from '~/views-components/context-menu/acti
 import { ContainerRequestState } from '~/models/container-request';
 import { MountKind } from '~/models/mount-types';
 import { receiveTreePickerData, loadUserProject } from '~/store/tree-picker/tree-picker-actions';
-import { loadProject, loadCollection, initUserProject, initSharedProject, initFavoritesProject } from './store/tree-picker/tree-picker-actions';
+import { loadProject, loadCollection, initUserProject, initSharedProject, initFavoritesProject, initProjectsTreePicker } from './store/tree-picker/tree-picker-actions';
 import { ResourceKind } from '~/models/resource';
 
 const getBuildNumber = () => "BN-" + (process.env.REACT_APP_BUILD_NUMBER || "dev");
@@ -117,15 +117,10 @@ const initListener = (history: History, store: RootStore, services: ServiceRepos
             await store.dispatch(loadWorkbench());
             addRouteChangeHandlers(history, store);
             // createEnumCollectorWorkflow(services);
-            store.dispatch(initUserProject('testPicker1'));
-            store.dispatch(initUserProject('testPicker2'));
-            store.dispatch(initUserProject('testPicker3'));
-            store.dispatch(initSharedProject('testPicker4'));
-            store.dispatch(initSharedProject('testPicker5'));
-            store.dispatch(initSharedProject('testPicker6'));
-            store.dispatch(initFavoritesProject('testPicker7'));
-            store.dispatch(initFavoritesProject('testPicker8'));
-            store.dispatch(initFavoritesProject('testPicker9'));
+            store.dispatch(initProjectsTreePicker('testPicker1'));
+            store.dispatch(initProjectsTreePicker('testPicker2'));
+            store.dispatch(initProjectsTreePicker('testPicker3'));
+            
             // await store.dispatch(loadCollection(
             //     'c97qk-4zz18-9sn8ygaf62chkkd',
             //     'testPicker',
index 69d2e9376939f5a3d8ba6fa6180a1b1e0558b626..cce27b125a1053c053b6df04227bd0e4e23a52df 100644 (file)
@@ -109,6 +109,8 @@ export const mapIdsToNodes = (ids: string[]) => <T>(tree: Tree<T>) =>
 export const activateNode = (id: string) => <T>(tree: Tree<T>) =>
     mapTree(node => node.id === id ? { ...node, active: true } : { ...node, active: false })(tree);
 
+export const deactivateNode = <T>(tree: Tree<T>) =>
+    mapTree(node => node.active ? { ...node, active: false } : node)(tree);
 
 export const expandNode = (...ids: string[]) => <T>(tree: Tree<T>) =>
     mapTree(node => ids.some(id => id === node.id) ? { ...node, expanded: true } : node)(tree);
index 41ee62f8e1910e5fb1c274711c8138bda4489d8d..06f73c3407c7eec40d62cc6b0d45e50912e13ae8 100644 (file)
@@ -18,6 +18,7 @@ export const treePickerActions = unionize({
     LOAD_TREE_PICKER_NODE_SUCCESS: ofType<{ id: string, nodes: Array<TreeNode<any>>, pickerId: string }>(),
     TOGGLE_TREE_PICKER_NODE_COLLAPSE: ofType<{ id: string, pickerId: string }>(),
     ACTIVATE_TREE_PICKER_NODE: ofType<{ id: string, pickerId: string }>(),
+    DEACTIVATE_TREE_PICKER_NODE: ofType<{ pickerId: string }>(),
     TOGGLE_TREE_PICKER_NODE_SELECTION: ofType<{ id: string, pickerId: string }>(),
     EXPAND_TREE_PICKER_NODES: ofType<{ ids: string[], pickerId: string }>(),
     RESET_TREE_PICKER: ofType<{ pickerId: string }>()
@@ -25,6 +26,19 @@ export const treePickerActions = unionize({
 
 export type TreePickerAction = UnionOf<typeof treePickerActions>;
 
+export const getProjectsTreePickerIds = (pickerId: string) => ({
+    home: `${pickerId}_home`,
+    shared: `${pickerId}_shared`,
+    favorites: `${pickerId}_favorites`,
+});
+export const initProjectsTreePicker = (pickerId: string) => 
+async (dispatch: Dispatch, _: () => RootState, services: ServiceRepository) => {
+    const {home, shared, favorites} = getProjectsTreePickerIds(pickerId);
+    dispatch<any>(initUserProject(home));
+    dispatch<any>(initSharedProject(shared));
+    dispatch<any>(initFavoritesProject(favorites));
+};
+
 interface ReceiveTreePickerDataParams<T> {
     data: T[];
     extractNodeData: (value: T) => { id: string, value: T, status?: TreeNodeStatus };
index 69c49052b56aa038177b6a183106a9b4b7aebf84..2df567efeef0e0390272a7c5522473c31ad962f6 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { createTree, TreeNode, setNode, Tree, TreeNodeStatus, setNodeStatus, expandNode } from '~/models/tree';
+import { createTree, TreeNode, setNode, Tree, TreeNodeStatus, setNodeStatus, expandNode, deactivateNode } from '~/models/tree';
 import { TreePicker } from "./tree-picker";
 import { treePickerActions, TreePickerAction } from "./tree-picker-actions";
 import { compose } from "redux";
@@ -18,6 +18,8 @@ export const treePickerReducer = (state: TreePicker = {}, action: TreePickerActi
             updateOrCreatePicker(state, pickerId, toggleNodeCollapse(id)),
         ACTIVATE_TREE_PICKER_NODE: ({ id, pickerId }) =>
             updateOrCreatePicker(state, pickerId, activateNode(id)),
+        DEACTIVATE_TREE_PICKER_NODE: ({ pickerId }) =>
+            updateOrCreatePicker(state, pickerId, deactivateNode),
         TOGGLE_TREE_PICKER_NODE_SELECTION: ({ id, pickerId }) =>
             updateOrCreatePicker(state, pickerId, toggleNodeSelection(id)),
         RESET_TREE_PICKER: ({ pickerId }) =>
index 74cb16a25a1a0992da4d08dc0e804d06e2608319..09704066a17d4a4d50a8030bede397942fb8678e 100644 (file)
@@ -3,12 +3,12 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import { connect } from 'react-redux';
-import { ProjectsTreePicker, ProjectsTreePickerProps } from '~/views-components/projects-tree-picker/projects-tree-picker';
+import { ProjectsTreePicker, ProjectsTreePickerProps } from '~/views-components/projects-tree-picker/generic-projects-tree-picker';
 import { Dispatch } from 'redux';
 import { FavoriteIcon } from '~/components/icon/icon';
 import { loadFavoritesProject } from '~/store/tree-picker/tree-picker-actions';
 
-export const FavoritesProjectsTreePicker = connect(() => ({
+export const FavoritesTreePicker = connect(() => ({
     rootItemIcon: FavoriteIcon,
 }), (dispatch: Dispatch): Pick<ProjectsTreePickerProps, 'loadRootItem'> => ({
     loadRootItem: (_, pickerId, includeCollections, includeFiles) => {
diff --git a/src/views-components/projects-tree-picker/generic-projects-tree-picker.tsx b/src/views-components/projects-tree-picker/generic-projects-tree-picker.tsx
new file mode 100644 (file)
index 0000000..1ddbe3a
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { Dispatch } from "redux";
+import { connect } from "react-redux";
+import { TreeItem, TreeItemStatus } from '~/components/tree/tree';
+import { ProjectResource } from "~/models/project";
+import { treePickerActions } from "~/store/tree-picker/tree-picker-actions";
+import { ListItemTextIcon } from "~/components/list-item-text-icon/list-item-text-icon";
+import { ProjectIcon, InputIcon, IconType, CollectionIcon } from '~/components/icon/icon';
+import { loadProject, loadCollection } from '~/store/tree-picker/tree-picker-actions';
+import { GroupContentsResource } from '~/services/groups-service/groups-service';
+import { CollectionDirectory, CollectionFile, CollectionFileType } from '~/models/collection-file';
+import { ResourceKind } from '~/models/resource';
+import { TreePickerProps, TreePicker } from "~/views-components/tree-picker/tree-picker";
+
+export interface ProjectsTreePickerRootItem {
+    id: string;
+    name: string;
+}
+
+export type ProjectsTreePickerItem = ProjectsTreePickerRootItem | GroupContentsResource | CollectionDirectory | CollectionFile;
+type PickedTreePickerProps = Pick<TreePickerProps<ProjectsTreePickerItem>, 'onContextMenu' | 'toggleItemActive' | 'toggleItemOpen' | 'toggleItemSelection'>;
+
+export interface ProjectsTreePickerDataProps {
+    pickerId: string;
+    includeCollections?: boolean;
+    includeFiles?: boolean;
+    rootItemIcon: IconType;
+    loadRootItem: (item: TreeItem<ProjectsTreePickerRootItem>, pickerId: string, includeCollections?: boolean, inlcudeFiles?: boolean) => void;
+}
+
+export type ProjectsTreePickerProps = ProjectsTreePickerDataProps & Partial<PickedTreePickerProps>;
+
+const mapStateToProps = (_: any, { pickerId, rootItemIcon }: ProjectsTreePickerProps) => ({
+    render: renderTreeItem(rootItemIcon),
+    pickerId,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch, { loadRootItem, includeCollections, includeFiles, ...props }: ProjectsTreePickerProps): PickedTreePickerProps => ({
+    onContextMenu: () => { return; },
+    toggleItemActive: (event, item, pickerId) => {
+        dispatch(treePickerActions.ACTIVATE_TREE_PICKER_NODE({ id: item.id, pickerId }));
+        if (props.toggleItemActive) {
+            props.toggleItemActive(event, item, pickerId);
+        }
+    },
+    toggleItemOpen: (_, item, pickerId) => {
+        const { id, data, status } = item;
+        if (status === TreeItemStatus.INITIAL) {
+            if ('kind' in data) {
+                dispatch<any>(
+                    data.kind === ResourceKind.COLLECTION
+                        ? loadCollection(id, pickerId)
+                        : loadProject({ id, pickerId, includeCollections, includeFiles })
+                );
+            } else if (!('type' in data) && loadRootItem) {
+                loadRootItem(item as TreeItem<ProjectsTreePickerRootItem>, pickerId, includeCollections, includeFiles);
+            }
+        } else if (status === TreeItemStatus.LOADED) {
+            dispatch(treePickerActions.TOGGLE_TREE_PICKER_NODE_COLLAPSE({ id, pickerId }));
+        }
+    },
+    toggleItemSelection: (_, { id }, pickerId) => {
+        dispatch<any>(treePickerActions.TOGGLE_TREE_PICKER_NODE_SELECTION({ id, pickerId }));
+    },
+});
+
+export const ProjectsTreePicker = connect(mapStateToProps, mapDispatchToProps)(TreePicker);
+
+const getProjectPickerIcon = ({ data }: TreeItem<ProjectsTreePickerItem>, rootIcon: IconType): IconType => {
+    if ('kind' in data) {
+        switch (data.kind) {
+            case ResourceKind.COLLECTION:
+                return CollectionIcon;
+            default:
+                return ProjectIcon;
+        }
+    } else if ('type' in data) {
+        switch (data.type) {
+            case CollectionFileType.FILE:
+                return InputIcon;
+            default:
+                return ProjectIcon;
+        }
+    } else {
+        return rootIcon;
+    }
+};
+
+const renderTreeItem = (rootItemIcon: IconType) => (item: TreeItem<ProjectResource>) =>
+    <ListItemTextIcon
+        icon={getProjectPickerIcon(item, rootItemIcon)}
+        name={item.data.name}
+        isActive={item.active}
+        hasMargin={true} />;
similarity index 82%
rename from src/views-components/projects-tree-picker/user-projects-tree-picker.tsx
rename to src/views-components/projects-tree-picker/home-tree-picker.tsx
index 10a0b20865169f3730f3c8b1611153150180557d..45f0b5c037deb7834999864526960e584113aa02 100644 (file)
@@ -3,12 +3,12 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import { connect } from 'react-redux';
-import { ProjectsTreePicker, ProjectsTreePickerProps } from '~/views-components/projects-tree-picker/projects-tree-picker';
+import { ProjectsTreePicker, ProjectsTreePickerProps } from '~/views-components/projects-tree-picker/generic-projects-tree-picker';
 import { Dispatch } from 'redux';
 import { loadUserProject } from '~/store/tree-picker/tree-picker-actions';
 import { ProjectIcon } from '~/components/icon/icon';
 
-export const UserProjectsTreePicker = connect(() => ({
+export const HomeTreePicker = connect(() => ({
     rootItemIcon: ProjectIcon,
 }), (dispatch: Dispatch): Pick<ProjectsTreePickerProps, 'loadRootItem'> => ({
     loadRootItem: (_, pickerId, includeCollections, includeFiles) => {
index be030efff7691d33d7bae626319439201b04fa03..798281382772c6df5402e74d2425057d169f587a 100644 (file)
@@ -2,97 +2,28 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import * as React from "react";
-import { Dispatch } from "redux";
-import { connect } from "react-redux";
-import { TreeItem, TreeItemStatus } from '~/components/tree/tree';
-import { ProjectResource } from "~/models/project";
-import { treePickerActions } from "~/store/tree-picker/tree-picker-actions";
-import { ListItemTextIcon } from "~/components/list-item-text-icon/list-item-text-icon";
-import { ProjectIcon, InputIcon, IconType, CollectionIcon } from '~/components/icon/icon';
-import { loadProject, loadCollection } from '~/store/tree-picker/tree-picker-actions';
-import { GroupContentsResource } from '~/services/groups-service/groups-service';
-import { CollectionDirectory, CollectionFile, CollectionFileType } from '~/models/collection-file';
-import { ResourceKind } from '~/models/resource';
-import { TreePickerProps, TreePicker } from "~/views-components/tree-picker/tree-picker";
-
-export interface ProjectsTreePickerRootItem {
-    id: string;
-    name: string;
-}
-
-type ProjectsTreePickerItem = ProjectsTreePickerRootItem | GroupContentsResource | CollectionDirectory | CollectionFile;
-type PickedTreePickerProps = Pick<TreePickerProps<ProjectsTreePickerItem>, 'onContextMenu' | 'toggleItemActive' | 'toggleItemOpen' | 'toggleItemSelection'>;
-
-export interface ProjectsTreePickerDataProps {
+import * as React from 'react';
+import { Dispatch } from 'redux';
+import { connect } from 'react-redux';
+import { HomeTreePicker } from '~/views-components/projects-tree-picker/home-tree-picker';
+import { SharedTreePicker } from '~/views-components/projects-tree-picker/shared-tree-picker';
+import { FavoritesTreePicker } from '~/views-components/projects-tree-picker/favorites-tree-picker';
+import { getProjectsTreePickerIds, treePickerActions } from '~/store/tree-picker/tree-picker-actions';
+import { TreeItem } from '~/components/tree/tree';
+import { ProjectsTreePickerItem } from './generic-projects-tree-picker';
+
+export interface ProjectsTreePickerProps {
     pickerId: string;
     includeCollections?: boolean;
     includeFiles?: boolean;
-    rootItemIcon: IconType;
-    loadRootItem: (item: TreeItem<ProjectsTreePickerRootItem>, pickerId: string, includeCollections?: boolean, inlcudeFiles?: boolean) => void;
-}
-
-export interface ProjectsTreePickerActionProps {
+    toggleItemActive?: (event: React.MouseEvent<HTMLElement>, item: TreeItem<ProjectsTreePickerItem>, pickerId: string) => void;
 }
 
-export type ProjectsTreePickerProps = ProjectsTreePickerDataProps & ProjectsTreePickerActionProps;
-
-const mapStateToProps = (_: any, { pickerId, rootItemIcon }: ProjectsTreePickerProps) => ({
-    render: renderTreeItem(rootItemIcon),
-    pickerId,
-});
-
-const mapDispatchToProps = (dispatch: Dispatch, { loadRootItem, includeCollections, includeFiles }: ProjectsTreePickerProps): PickedTreePickerProps => ({
-    onContextMenu: () => { return; },
-    toggleItemActive: (_, { id }, pickerId) => {
-        dispatch(treePickerActions.ACTIVATE_TREE_PICKER_NODE({ id, pickerId }));
-    },
-    toggleItemOpen: (_, item, pickerId) => {
-        const { id, data, status } = item;
-        if (status === TreeItemStatus.INITIAL) {
-            if ('kind' in data) {
-                dispatch<any>(
-                    data.kind === ResourceKind.COLLECTION
-                        ? loadCollection(id, pickerId)
-                        : loadProject({ id, pickerId, includeCollections, includeFiles })
-                );
-            } else if (!('type' in data) && loadRootItem) {
-                loadRootItem(item as TreeItem<ProjectsTreePickerRootItem>, pickerId, includeCollections, includeFiles);
-            }
-        } else if (status === TreeItemStatus.LOADED) {
-            dispatch(treePickerActions.TOGGLE_TREE_PICKER_NODE_COLLAPSE({ id, pickerId }));
-        }
-    },
-    toggleItemSelection: (_, { id }, pickerId) => {
-        dispatch<any>(treePickerActions.TOGGLE_TREE_PICKER_NODE_SELECTION({ id, pickerId }));
-    },
-});
-
-export const ProjectsTreePicker = connect(mapStateToProps, mapDispatchToProps)(TreePicker);
-
-const getProjectPickerIcon = ({ data }: TreeItem<ProjectsTreePickerItem>, rootIcon: IconType): IconType => {
-    if ('kind' in data) {
-        switch (data.kind) {
-            case ResourceKind.COLLECTION:
-                return CollectionIcon;
-            default:
-                return ProjectIcon;
-        }
-    } else if ('type' in data) {
-        switch (data.type) {
-            case CollectionFileType.FILE:
-                return InputIcon;
-            default:
-                return ProjectIcon;
-        }
-    } else {
-        return rootIcon;
-    }
-};
-
-const renderTreeItem = (rootItemIcon: IconType) => (item: TreeItem<ProjectResource>) =>
-    <ListItemTextIcon
-        icon={getProjectPickerIcon(item, rootItemIcon)}
-        name={item.data.name}
-        isActive={item.active}
-        hasMargin={true} />;
+export const ProjectsTreePicker =  ({ pickerId, ...props }: ProjectsTreePickerProps) => {
+    const { home, shared, favorites } = getProjectsTreePickerIds(pickerId);
+    return <div>
+        <HomeTreePicker pickerId={home} {...props} />
+        <SharedTreePicker pickerId={shared} {...props} />
+        <FavoritesTreePicker pickerId={favorites} {...props} />
+    </div>;
+    };
similarity index 73%
rename from src/views-components/projects-tree-picker/shared-projects-tree-picker.tsx
rename to src/views-components/projects-tree-picker/shared-tree-picker.tsx
index 6a05c2aac9716cc02ab4eb7b9895fe060c28f5f1..a986b1bb8c35ea12595201f4366c30dd5369bf88 100644 (file)
@@ -3,12 +3,12 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import { connect } from 'react-redux';
-import { ProjectsTreePicker, ProjectsTreePickerProps } from '~/views-components/projects-tree-picker/projects-tree-picker';
+import { ProjectsTreePicker, ProjectsTreePickerProps } from '~/views-components/projects-tree-picker/generic-projects-tree-picker';
 import { Dispatch } from 'redux';
 import { ShareMeIcon } from '~/components/icon/icon';
-import { loadProject } from '../../store/tree-picker/tree-picker-actions';
+import { loadProject } from '~/store/tree-picker/tree-picker-actions';
 
-export const SharedProjectsTreePicker = connect(() => ({
+export const SharedTreePicker = connect(() => ({
     rootItemIcon: ShareMeIcon,
 }), (dispatch: Dispatch): Pick<ProjectsTreePickerProps, 'loadRootItem'> => ({
     loadRootItem: (_, pickerId, includeCollections, includeFiles) => {
index 6c02dd272b98ed422da91574124296496fb996a8..dd68cb8f8ca5ffc472a33fd7dd3616fbd5e32f68 100644 (file)
@@ -41,14 +41,10 @@ import { SharedWithMePanel } from '~/views/shared-with-me-panel/shared-with-me-p
 import { RunProcessPanel } from '~/views/run-process-panel/run-process-panel';
 import SplitterLayout from 'react-splitter-layout';
 import { WorkflowPanel } from '~/views/workflow-panel/workflow-panel';
-import { TreePicker } from '../../views-components/tree-picker/tree-picker';
-import { noop } from 'lodash';
-import { TreeItem } from '~/components/tree/tree';
-import { GroupContentsResource } from '~/services/groups-service/groups-service';
+import { HomeTreePicker } from '~/views-components/projects-tree-picker/home-tree-picker';
+import { SharedTreePicker } from '~/views-components/projects-tree-picker/shared-tree-picker';
+import { FavoritesTreePicker } from '../../views-components/projects-tree-picker/favorites-tree-picker';
 import { ProjectsTreePicker } from '~/views-components/projects-tree-picker/projects-tree-picker';
-import { UserProjectsTreePicker } from '~/views-components/projects-tree-picker/user-projects-tree-picker';
-import { SharedProjectsTreePicker } from '~/views-components/projects-tree-picker/shared-projects-tree-picker';
-import { FavoritesProjectsTreePicker } from '../../views-components/projects-tree-picker/favorites-tree-picker';
 
 type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
 
@@ -96,15 +92,12 @@ export const WorkbenchPanel =
                             <MainContentBar />
                         </Grid>
                         <Grid item xs className={classes.content}>
-                            <UserProjectsTreePicker pickerId='testPicker1'/>
-                            <UserProjectsTreePicker pickerId='testPicker2' includeCollections/>
-                            <UserProjectsTreePicker pickerId='testPicker3' includeCollections includeFiles/>
-                            <SharedProjectsTreePicker pickerId='testPicker4'/>
-                            <SharedProjectsTreePicker pickerId='testPicker5' includeCollections/>
-                            <SharedProjectsTreePicker pickerId='testPicker6' includeCollections includeFiles/>
-                            <FavoritesProjectsTreePicker pickerId='testPicker7'/>
-                            <FavoritesProjectsTreePicker pickerId='testPicker8' includeCollections/>
-                            <FavoritesProjectsTreePicker pickerId='testPicker9' includeCollections includeFiles/>
+                            <p>Projects only</p>
+                            <ProjectsTreePicker pickerId="testPicker1"/>
+                            <p>Collections included</p>
+                            <ProjectsTreePicker pickerId="testPicker2" includeCollections/>
+                            <p>Files included</p>
+                            <ProjectsTreePicker pickerId="testPicker3" includeCollections includeFiles toggleItemActive={(...args: any[]) => console.log(args)}/>
                             <Switch>
                                 <Route path={Routes.PROJECTS} component={ProjectPanel} />
                                 <Route path={Routes.COLLECTIONS} component={CollectionPanel} />