Merge branch 'master' into 13853-collection-view-info-card
authorJanicki Artur <artur.janicki@contractors.roche.com>
Mon, 30 Jul 2018 11:28:09 +0000 (13:28 +0200)
committerJanicki Artur <artur.janicki@contractors.roche.com>
Mon, 30 Jul 2018 11:28:09 +0000 (13:28 +0200)
refs #13853

Arvados-DCO-1.1-Signed-off-by: Janicki Artur <artur.janicki@contractors.roche.com>

20 files changed:
src/common/custom-theme.ts
src/components/icon/icon.tsx
src/index.tsx
src/models/collection.ts
src/models/project.ts
src/services/services.ts
src/store/collection-panel/collection-panel-action.ts [new file with mode: 0644]
src/store/collection-panel/collection-panel-reducer.ts [new file with mode: 0644]
src/store/context-menu/context-menu-reducer.ts
src/store/navigation/navigation-action.ts
src/store/store.ts
src/views-components/context-menu/action-sets/collection-action-set.ts [new file with mode: 0644]
src/views-components/context-menu/action-sets/favorite-action-set.ts
src/views-components/context-menu/action-sets/project-action-set.ts
src/views-components/context-menu/action-sets/resource-action-set.ts
src/views-components/context-menu/actions/favorite-action.tsx [moved from src/views-components/context-menu/action-sets/favorite-action.tsx with 89% similarity]
src/views-components/context-menu/context-menu.tsx
src/views/collection-panel/collection-panel.tsx [new file with mode: 0644]
src/views/project-panel/project-panel.tsx
src/views/workbench/workbench.tsx

index c85acd9089b0011ac2a819068b55d1ce5fd35688..e5d2e5e78ca80bed2cada42c923bd88d4461c96c 100644 (file)
@@ -16,11 +16,17 @@ interface ArvadosThemeOptions extends ThemeOptions {
 }
 
 export interface ArvadosTheme extends Theme {
-    customs: any;
+    customs: {
+        colors: Colors
+    };
+}
+
+interface Colors {
+    green700: string;
+    yellow700: string;
 }
 
 const red900 = red["900"];
-const yellow700 = yellow["700"];
 const purple800 = purple["800"];
 const grey200 = grey["200"];
 const grey300 = grey["300"];
@@ -32,7 +38,8 @@ const grey900 = grey["900"];
 const themeOptions: ArvadosThemeOptions = {
     customs: {
         colors: {
-            green700: green["700"]
+            green700: green["700"],
+            yellow700: yellow["700"]
         }
     },
     overrides: {
@@ -74,6 +81,21 @@ const themeOptions: ArvadosThemeOptions = {
             root: {
                 fontSize: '1.25rem'
             }
+        },
+        MuiCardHeader: {
+            avatar: {
+                display: 'flex',
+                alignItems: 'center'
+            },
+            title: {
+                color: grey700,
+                fontSize: '1.25rem'
+            }
+        },
+        MuiMenuItem: {
+            root: {
+                padding: '8px 16px'
+            }
         }
     },
     mixins: {
index e80fee8e97db18107cc186cf2819c6dfc9f0ed9c..f8e53d3e97d38f8522feaaaf4d5b5e4cc0df6c86 100644 (file)
@@ -14,6 +14,7 @@ import Close from '@material-ui/icons/Close';
 import ContentCopy from '@material-ui/icons/ContentCopy';
 import CreateNewFolder from '@material-ui/icons/CreateNewFolder';
 import Delete from '@material-ui/icons/Delete';
+import DeviceHub from '@material-ui/icons/DeviceHub';
 import Edit from '@material-ui/icons/Edit';
 import Folder from '@material-ui/icons/Folder';
 import GetApp from '@material-ui/icons/GetApp';
@@ -21,6 +22,7 @@ import Help from '@material-ui/icons/Help';
 import Inbox from '@material-ui/icons/Inbox';
 import Info from '@material-ui/icons/Info';
 import Input from '@material-ui/icons/Input';
+import LibraryBooks from '@material-ui/icons/LibraryBooks';
 import Menu from '@material-ui/icons/Menu';
 import MoreVert from '@material-ui/icons/MoreVert';
 import Notifications from '@material-ui/icons/Notifications';
@@ -30,16 +32,17 @@ import PersonAdd from '@material-ui/icons/PersonAdd';
 import PlayArrow from '@material-ui/icons/PlayArrow';
 import RateReview from '@material-ui/icons/RateReview';
 import Search from '@material-ui/icons/Search';
+import SettingsApplications from '@material-ui/icons/SettingsApplications';
 import Star from '@material-ui/icons/Star';
 import StarBorder from '@material-ui/icons/StarBorder';
 
 export type IconType = React.SFC<{ className?: string }>;
 
 export const AddFavoriteIcon: IconType = (props) => <StarBorder {...props} />;
-export const AdvancedIcon: IconType = (props) => <Folder {...props} />;
+export const AdvancedIcon: IconType = (props) => <SettingsApplications {...props} />;
 export const CustomizeTableIcon: IconType = (props) => <Menu {...props} />;
 export const CopyIcon: IconType = (props) => <ContentCopy {...props} />;
-export const CollectionIcon: IconType = (props) => <Folder {...props} />;
+export const CollectionIcon: IconType = (props) => <LibraryBooks {...props} />;
 export const CloseIcon: IconType = (props) => <Close {...props} />;
 export const DefaultIcon: IconType = (props) => <RateReview {...props} />;
 export const DetailsIcon: IconType = (props) => <Info {...props} />;
@@ -57,7 +60,7 @@ export const PaginationRightArrowIcon: IconType = (props) => <ChevronRight {...p
 export const ProcessIcon: IconType = (props) => <BubbleChart {...props} />;
 export const ProjectIcon: IconType = (props) => <Folder {...props} />;
 export const ProjectsIcon: IconType = (props) => <Inbox {...props} />;
-export const ProvenanceGraphIcon: IconType = (props) => <Folder {...props} />;
+export const ProvenanceGraphIcon: IconType = (props) => <DeviceHub {...props} />;
 export const RecentIcon: IconType = (props) => <AccessTime {...props} />;
 export const RemoveIcon: IconType = (props) => <Delete {...props} />;
 export const RemoveFavoriteIcon: IconType = (props) => <Star {...props} />;
index 77d5763b478cc3884d44c644fea7de6e3929a37c..b2c00f988c0d2ee4041cbd36c1e856bb06c1468c 100644 (file)
@@ -24,11 +24,13 @@ import { rootProjectActionSet } from "./views-components/context-menu/action-set
 import { projectActionSet } from "./views-components/context-menu/action-sets/project-action-set";
 import { resourceActionSet } from './views-components/context-menu/action-sets/resource-action-set';
 import { favoriteActionSet } from "./views-components/context-menu/action-sets/favorite-action-set";
+import { collectionActionSet } from './views-components/context-menu/action-sets/collection-action-set';
 
 addMenuActionSet(ContextMenuKind.ROOT_PROJECT, rootProjectActionSet);
 addMenuActionSet(ContextMenuKind.PROJECT, projectActionSet);
 addMenuActionSet(ContextMenuKind.RESOURCE, resourceActionSet);
 addMenuActionSet(ContextMenuKind.FAVORITE, favoriteActionSet);
+addMenuActionSet(ContextMenuKind.COLLECTION, collectionActionSet); 
 
 fetchConfig()
     .then(config => {
index 9cb8bb84f6d0963ac59eaf1db2d3276211ceedd8..0e96f7fd3dd6f1473f62d8c2a2e3226aa42f6507 100644 (file)
@@ -18,3 +18,7 @@ export interface CollectionResource extends Resource {
     deleteAt: string;
     isTrashed: boolean;
 }
+
+export const getCollectionUrl = (uuid: string) => {
+    return `/collections/${uuid}`;
+};
\ No newline at end of file
index eaf60904609974223e091bb244067e4da9b2b667..b919450774f687084a700d8b4d041772aa142669 100644 (file)
@@ -7,3 +7,7 @@ import { GroupResource, GroupClass } from "./group";
 export interface ProjectResource extends GroupResource {
     groupClass: GroupClass.PROJECT;
 }
+
+export const getProjectUrl = (uuid: string) => {
+    return `/projects/${uuid}`;
+};
index a08ed3cb3de4bbb0a89caa858cd5c5b3163c3551..e0d15cc40a40b855e599a76d151c70c4ef5a17cb 100644 (file)
@@ -13,4 +13,4 @@ export const authService = new AuthService(authClient, apiClient);
 export const groupsService = new GroupsService(apiClient);
 export const projectService = new ProjectService(apiClient);
 export const linkService = new LinkService(apiClient);
-export const favoriteService = new FavoriteService(linkService, groupsService);
+export const favoriteService = new FavoriteService(linkService, groupsService);
\ No newline at end of file
diff --git a/src/store/collection-panel/collection-panel-action.ts b/src/store/collection-panel/collection-panel-action.ts
new file mode 100644 (file)
index 0000000..3c66016
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { unionize, ofType, UnionOf } from "unionize";
+import { CommonResourceService } from "../../common/api/common-resource-service";
+import { apiClient } from "../../common/api/server-api";
+import { Dispatch } from "redux";
+import { ResourceKind } from "../../models/resource";
+import { CollectionResource } from "../../models/collection";
+
+export const collectionPanelActions = unionize({
+    LOAD_COLLECTION: ofType<{ uuid: string, kind: ResourceKind }>(),
+    LOAD_COLLECTION_SUCCESS: ofType<{ item: CollectionResource }>(),
+}, { tag: 'type', value: 'payload' });
+
+export type CollectionPanelAction = UnionOf<typeof collectionPanelActions>;
+
+export const loadCollection = (uuid: string, kind: ResourceKind) =>
+    (dispatch: Dispatch) => {
+        dispatch(collectionPanelActions.LOAD_COLLECTION({ uuid, kind }));
+        return new CommonResourceService(apiClient, "collections")
+            .get(uuid)
+            .then(item => {
+                dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: item as CollectionResource }));
+            });
+    };
+
+
+
diff --git a/src/store/collection-panel/collection-panel-reducer.ts b/src/store/collection-panel/collection-panel-reducer.ts
new file mode 100644 (file)
index 0000000..0dd233e
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { collectionPanelActions, CollectionPanelAction } from "./collection-panel-action";
+import { CollectionResource } from "../../models/collection";
+
+export interface CollectionPanelState {
+    item: CollectionResource | null;
+}
+
+const initialState = {
+    item: null
+};
+
+export const collectionPanelReducer = (state: CollectionPanelState = initialState, action: CollectionPanelAction) =>
+    collectionPanelActions.match(action, {
+        default: () => state,
+        LOAD_COLLECTION: () => state,
+        LOAD_COLLECTION_SUCCESS: ({ item }) => ({ ...state, item }),
+    });
index 7ce2b3e75449a705a1627cc4b62457eebc561d8b..8b51478d2bf980680be65249fab495ae5f7e9509 100644 (file)
@@ -2,7 +2,6 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { ResourceKind } from "../../models/resource";
 import { contextMenuActions, ContextMenuAction } from "./context-menu-actions";
 
 export interface ContextMenuState {
index 52086231742d8d9f37925c11cd41e95ef4395603..f8687ed754ad51f4604b4541361c5e3aff318fb5 100644 (file)
@@ -11,11 +11,13 @@ import { dataExplorerActions } from "../data-explorer/data-explorer-action";
 import { PROJECT_PANEL_ID } from "../../views/project-panel/project-panel";
 import { RootState } from "../store";
 import { Resource, ResourceKind } from "../../models/resource";
+import { getCollectionUrl } from "../../models/collection";
+import { getProjectUrl } from "../../models/project";
 
 export const getResourceUrl = <T extends Resource>(resource: T): string => {
     switch (resource.kind) {
-        case ResourceKind.PROJECT: return `/projects/${resource.uuid}`;
-        case ResourceKind.COLLECTION: return `/collections/${resource.uuid}`;
+        case ResourceKind.PROJECT: return getProjectUrl(resource.uuid);
+        case ResourceKind.COLLECTION: return getCollectionUrl(resource.uuid);
         default: return resource.href;
     }
 };
index ae07744219d8f6d7b2db8cac751ca375dd0e68f7..c5845d4827f28163f4ad3578b6863229427700ad 100644 (file)
@@ -18,6 +18,7 @@ import { favoritePanelMiddleware } from "./favorite-panel/favorite-panel-middlew
 import { reducer as formReducer } from 'redux-form';
 import { FavoritesState, favoritesReducer } from './favorites/favorites-reducer';
 import { snackbarReducer, SnackbarState } from './snackbar/snackbar-reducer';
+import { CollectionPanelState, collectionPanelReducer } from './collection-panel/collection-panel-reducer';
 
 const composeEnhancers =
     (process.env.NODE_ENV === 'development' &&
@@ -30,6 +31,7 @@ export interface RootState {
     router: RouterState;
     dataExplorer: DataExplorerState;
     sidePanel: SidePanelState;
+    collectionPanel: CollectionPanelState;
     detailsPanel: DetailsPanelState;
     contextMenu: ContextMenuState;
     favorites: FavoritesState;
@@ -42,6 +44,7 @@ const rootReducer = combineReducers({
     router: routerReducer,
     dataExplorer: dataExplorerReducer,
     sidePanel: sidePanelReducer,
+    collectionPanel: collectionPanelReducer,
     detailsPanel: detailsPanelReducer,
     contextMenu: contextMenuReducer,
     form: formReducer,
diff --git a/src/views-components/context-menu/action-sets/collection-action-set.ts b/src/views-components/context-menu/action-sets/collection-action-set.ts
new file mode 100644 (file)
index 0000000..0822b78
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ContextMenuActionSet } from "../context-menu-action-set";
+import { ToggleFavoriteAction } from "../actions/favorite-action";
+import { toggleFavorite } from "../../../store/favorites/favorites-actions";
+import { dataExplorerActions } from "../../../store/data-explorer/data-explorer-action";
+import { FAVORITE_PANEL_ID } from "../../../views/favorite-panel/favorite-panel";
+import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, ProvenanceGraphIcon, AdvancedIcon, RemoveIcon } from "../../../components/icon/icon";
+
+export const collectionActionSet: ContextMenuActionSet = [[
+    {
+        icon: RenameIcon,
+        name: "Edit collection",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: ShareIcon,
+        name: "Share",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: MoveToIcon,
+        name: "Move to",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        component: ToggleFavoriteAction,
+        execute: (dispatch, resource) => {
+            dispatch<any>(toggleFavorite(resource)).then(() => {
+                dispatch<any>(dataExplorerActions.REQUEST_ITEMS({ id: FAVORITE_PANEL_ID }));
+            });
+        }
+    },
+    {
+        icon: CopyIcon,
+        name: "Copy to project",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: DetailsIcon,
+        name: "View details",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: ProvenanceGraphIcon,
+        name: "Provenance graph",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: AdvancedIcon,
+        name: "Advanced",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: RemoveIcon,
+        name: "Remove",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    }
+]];
index 58cf6cce40ea4c04a7a8e4ad537cae2853f72abf..9682d4bf9a57778f8969239d320334aff9c616d5 100644 (file)
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import { ContextMenuActionSet } from "../context-menu-action-set";
-import { ToggleFavoriteAction } from "./favorite-action";
+import { ToggleFavoriteAction } from "../actions/favorite-action";
 import { toggleFavorite } from "../../../store/favorites/favorites-actions";
 import { dataExplorerActions } from "../../../store/data-explorer/data-explorer-action";
 import { FAVORITE_PANEL_ID } from "../../../views/favorite-panel/favorite-panel";
index efcc429c49af2c53a64424545b60c0b92c6eb017..25e0ba37315cbc9124471167b496a8e615e7f7ce 100644 (file)
@@ -5,7 +5,7 @@
 import { ContextMenuActionSet } from "../context-menu-action-set";
 import { projectActions } from "../../../store/project/project-action";
 import { NewProjectIcon } from "../../../components/icon/icon";
-import { ToggleFavoriteAction } from "./favorite-action";
+import { ToggleFavoriteAction } from "../actions/favorite-action";
 import { toggleFavorite } from "../../../store/favorites/favorites-actions";
 import { dataExplorerActions } from "../../../store/data-explorer/data-explorer-action";
 import { FAVORITE_PANEL_ID } from "../../../views/favorite-panel/favorite-panel";
index 891528367bca93f119412f1195d4a92808115a8a..9585a865e7405bed40b0725654bf0d9edd4fda69 100644 (file)
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import { ContextMenuActionSet } from "../context-menu-action-set";
-import { ToggleFavoriteAction } from "./favorite-action";
+import { ToggleFavoriteAction } from "../actions/favorite-action";
 import { toggleFavorite } from "../../../store/favorites/favorites-actions";
 
 export const resourceActionSet: ContextMenuActionSet = [[{
similarity index 89%
rename from src/views-components/context-menu/action-sets/favorite-action.tsx
rename to src/views-components/context-menu/actions/favorite-action.tsx
index a4cf4e3bba646a439ba307ea5783466149e91973..05e03fb34b754456c76a13787e5e15b02695b767 100644 (file)
@@ -4,7 +4,7 @@
 
 import * as React from "react";
 import { ListItemIcon, ListItemText } from "@material-ui/core";
-import { FavoriteIcon, AddFavoriteIcon, RemoveFavoriteIcon } from "../../../components/icon/icon";
+import { AddFavoriteIcon, RemoveFavoriteIcon } from "../../../components/icon/icon";
 import { connect } from "react-redux";
 import { RootState } from "../../../store/store";
 
index 5b1049c13ed0e52c51409b594244a46d234638c0..4ec702914169e27d839df59b8a7d94bb497d4b26 100644 (file)
@@ -59,5 +59,6 @@ export enum ContextMenuKind {
     ROOT_PROJECT = "RootProject",
     PROJECT = "Project",
     RESOURCE = "Resource",
-    FAVORITE = "Favorite"
+    FAVORITE = "Favorite",
+    COLLECTION = 'Collection'
 }
diff --git a/src/views/collection-panel/collection-panel.tsx b/src/views/collection-panel/collection-panel.tsx
new file mode 100644 (file)
index 0000000..b55e50c
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { 
+    StyleRulesCallback, WithStyles, withStyles, Card, 
+    CardHeader, IconButton, CardContent, Grid
+} from '@material-ui/core';
+import { connect } from 'react-redux';
+import { RouteComponentProps } from 'react-router';
+import { ArvadosTheme } from '../../common/custom-theme';
+import { RootState } from '../../store/store';
+import { MoreOptionsIcon, CollectionIcon } from '../../components/icon/icon';
+import { DetailsAttribute } from '../../components/details-attribute/details-attribute';
+import { CollectionResource } from '../../models/collection';
+
+type CssRules = 'card' | 'iconHeader';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+    card: {
+        marginBottom: '20px'
+    },
+    iconHeader: {
+        fontSize: '1.875rem',
+        color: theme.customs.colors.yellow700
+    }
+});
+
+interface CollectionPanelDataProps {
+    item: CollectionResource;
+}
+
+interface CollectionPanelActionProps {
+    onItemRouteChange: (collectionId: string) => void;
+    onContextMenu: (event: React.MouseEvent<HTMLElement>, item: CollectionResource) => void;
+}
+
+type CollectionPanelProps = CollectionPanelDataProps & CollectionPanelActionProps 
+                            & WithStyles<CssRules> & RouteComponentProps<{ id: string }>;
+
+export const CollectionPanel = withStyles(styles)(
+    connect((state: RootState) => ({ item: state.collectionPanel.item }))(
+        class extends React.Component<CollectionPanelProps> { 
+
+            render() {
+                const { classes, item, onContextMenu } = this.props;
+                return <div>
+                        <Card className={classes.card}>
+                            <CardHeader 
+                                avatar={ <CollectionIcon className={classes.iconHeader} /> }
+                                action={ 
+                                    <IconButton
+                                        aria-label="More options"
+                                        onClick={event => onContextMenu(event, item)}>
+                                        <MoreOptionsIcon />
+                                    </IconButton> 
+                                }
+                                title={item && item.name } />
+                            <CardContent>
+                                <Grid container direction="column">
+                                    <Grid item xs={6}>
+                                    <DetailsAttribute label='Collection UUID' value={item && item.uuid} />
+                                        <DetailsAttribute label='Content size' value='54 MB' />
+                                    <DetailsAttribute label='Owner' value={item && item.ownerUuid} />
+                                    </Grid>
+                                </Grid>
+                            </CardContent>
+                        </Card>
+
+                        <Card className={classes.card}>
+                            <CardHeader title="Tags" />
+                            <CardContent>
+                                <Grid container direction="column">
+                                    <Grid item xs={4}>
+                                        Tags
+                                    </Grid>
+                                </Grid>
+                            </CardContent>
+                        </Card>
+
+                        <Card className={classes.card}>
+                            <CardHeader title="Files" />
+                            <CardContent>
+                                <Grid container direction="column">
+                                    <Grid item xs={4}>
+                                        Tags
+                                    </Grid>
+                                </Grid>
+                            </CardContent>
+                        </Card>
+                    </div>;
+            }
+
+            componentWillReceiveProps({ match, item, onItemRouteChange }: CollectionPanelProps) {
+                if (!item || match.params.id !== item.uuid) {
+                    onItemRouteChange(match.params.id);
+                }
+            }
+
+        }
+    )
+);
\ No newline at end of file
index 17b0fd723db9f07f2c5c05d7e905aa6b6823bb71..81d84990a41b7ba1b9c54a4aefb2aba9b4df3353 100644 (file)
@@ -38,7 +38,7 @@ const renderName = (item: ProjectPanelItem) =>
             {renderIcon(item)}
         </Grid>
         <Grid item>
-            <Typography color="primary">
+            <Typography color="default">
                 {item.name}
             </Typography>
         </Grid>
index 3637528d49f8f8355dafe291a7b06e9155381e09..e25244018c8801f31f913c0af5aed526fdc6f49b 100644 (file)
@@ -28,7 +28,7 @@ import { authService } from '../../services/services';
 
 import { detailsPanelActions, loadDetails } from "../../store/details-panel/details-panel-action";
 import { contextMenuActions } from "../../store/context-menu/context-menu-actions";
-import { sidePanelData, SidePanelIdentifiers } from '../../store/side-panel/side-panel-reducer';
+import { SidePanelIdentifiers } from '../../store/side-panel/side-panel-reducer';
 import { ProjectResource } from '../../models/project';
 import { ResourceKind } from '../../models/resource';
 import { ContextMenu, ContextMenuKind } from "../../views-components/context-menu/context-menu";
@@ -36,6 +36,9 @@ import { FavoritePanel, FAVORITE_PANEL_ID } from "../favorite-panel/favorite-pan
 import { CurrentTokenDialog } from '../../views-components/current-token-dialog/current-token-dialog';
 import { dataExplorerActions } from '../../store/data-explorer/data-explorer-action';
 import { Snackbar } from '../../views-components/snackbar/snackbar';
+import { CollectionPanel } from '../collection-panel/collection-panel';
+import { loadCollection } from '../../store/collection-panel/collection-panel-action';
+import { getCollectionUrl } from '../../models/collection';
 
 const drawerWidth = 240;
 const appBarHeight = 100;
@@ -212,6 +215,7 @@ export const Workbench = withStyles(styles)(
                                 <Switch>
                                     <Route path="/projects/:id" render={this.renderProjectPanel} />
                                     <Route path="/favorites" render={this.renderFavoritePanel} />
+                                    <Route path="/collections/:id" render={this.renderCollectionPanel} />
                                 </Switch>
                             </div>
                             {user && <DetailsPanel />}
@@ -227,9 +231,21 @@ export const Workbench = withStyles(styles)(
                 );
             }
 
+            renderCollectionPanel = (props: RouteComponentProps<{ id: string }>) => <CollectionPanel 
+                onItemRouteChange={(collectionId) => this.props.dispatch<any>(loadCollection(collectionId, ResourceKind.COLLECTION))}
+                onContextMenu={(event, item) => {
+                    this.openContextMenu(event, {
+                        uuid: item.uuid,
+                        name: item.name,
+                        kind: ContextMenuKind.COLLECTION
+                    });
+                }}
+                {...props} />
+
             renderProjectPanel = (props: RouteComponentProps<{ id: string }>) => <ProjectPanel
                 onItemRouteChange={itemId => this.props.dispatch<any>(setProjectItem(itemId, ItemMode.ACTIVE))}
                 onContextMenu={(event, item) => {
+
                     const kind = item.kind === ResourceKind.PROJECT ? ContextMenuKind.PROJECT : ContextMenuKind.RESOURCE;
                     this.openContextMenu(event, {
                         uuid: item.uuid,
@@ -242,8 +258,15 @@ export const Workbench = withStyles(styles)(
                     this.props.dispatch<any>(loadDetails(item.uuid, item.kind as ResourceKind));
                 }}
                 onItemDoubleClick={item => {
-                    this.props.dispatch<any>(setProjectItem(item.uuid, ItemMode.ACTIVE));
-                    this.props.dispatch<any>(loadDetails(item.uuid, ResourceKind.PROJECT));
+                    switch (item.kind) {
+                        case ResourceKind.COLLECTION:
+                            this.props.dispatch<any>(loadCollection(item.uuid, item.kind as ResourceKind));
+                            this.props.dispatch(push(getCollectionUrl(item.uuid)));
+                        default: 
+                            this.props.dispatch<any>(setProjectItem(item.uuid, ItemMode.ACTIVE));
+                            this.props.dispatch<any>(loadDetails(item.uuid, item.kind as ResourceKind));
+                    }
+
                 }}
                 {...props} />
 
@@ -262,9 +285,16 @@ export const Workbench = withStyles(styles)(
                     this.props.dispatch<any>(loadDetails(item.uuid, item.kind as ResourceKind));
                 }}
                 onItemDoubleClick={item => {
-                    this.props.dispatch<any>(loadDetails(item.uuid, ResourceKind.PROJECT));
-                    this.props.dispatch<any>(setProjectItem(item.uuid, ItemMode.ACTIVE));
-                    this.props.dispatch<any>(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(SidePanelIdentifiers.PROJECTS));
+                    switch (item.kind) {
+                        case ResourceKind.COLLECTION:
+                            this.props.dispatch<any>(loadCollection(item.uuid, item.kind as ResourceKind));
+                            this.props.dispatch(push(getCollectionUrl(item.uuid)));
+                        default:
+                            this.props.dispatch<any>(loadDetails(item.uuid, ResourceKind.PROJECT));
+                            this.props.dispatch<any>(setProjectItem(item.uuid, ItemMode.ACTIVE));
+                            this.props.dispatch<any>(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(SidePanelIdentifiers.PROJECTS));
+                    }
+
                 }}
                 {...props} />