[ARVADOS-WORKBENCH2] created: 1.1.4-427-gc01f423
Git user
git at public.curoverse.com
Fri Jul 27 07:00:32 EDT 2018
at c01f42311966c4d13413ee34dd6c97d5e5ac8b7f (commit)
commit c01f42311966c4d13413ee34dd6c97d5e5ac8b7f
Author: Janicki Artur <artur.janicki at contractors.roche.com>
Date: Fri Jul 27 13:00:16 2018 +0200
init collection view with routing and store
Feature #13853
Arvados-DCO-1.1-Signed-off-by: Janicki Artur <artur.janicki at contractors.roche.com>
diff --git a/src/common/actions.ts b/src/common/actions.ts
new file mode 100644
index 0000000..9ab6fd4
--- /dev/null
+++ b/src/common/actions.ts
@@ -0,0 +1,11 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export const goToProject = (uuid: string) => {
+ return `/projects/${uuid}`;
+};
+
+export const goToCollection = (uuid: string) => {
+ return `/collections/${uuid}`;
+};
\ No newline at end of file
diff --git a/src/common/custom-theme.ts b/src/common/custom-theme.ts
index c85acd9..e5d2e5e 100644
--- a/src/common/custom-theme.ts
+++ b/src/common/custom-theme.ts
@@ -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: {
diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx
index e80fee8..cc3108a 100644
--- a/src/components/icon/icon.tsx
+++ b/src/components/icon/icon.tsx
@@ -21,6 +21,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';
@@ -39,7 +40,7 @@ export const AddFavoriteIcon: IconType = (props) => <StarBorder {...props} />;
export const AdvancedIcon: IconType = (props) => <Folder {...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} />;
diff --git a/src/store/collection-panel/collection-panel-action.ts b/src/store/collection-panel/collection-panel-action.ts
new file mode 100644
index 0000000..c2684e0
--- /dev/null
+++ b/src/store/collection-panel/collection-panel-action.ts
@@ -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 { Dispatch } from "redux";
+import { serverApi } from "../../common/api/server-api";
+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(serverApi, "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
index 0000000..0dd233e
--- /dev/null
+++ b/src/store/collection-panel/collection-panel-reducer.ts
@@ -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 }),
+ });
diff --git a/src/store/navigation/navigation-action.ts b/src/store/navigation/navigation-action.ts
index 50f6e20..0cb6983 100644
--- a/src/store/navigation/navigation-action.ts
+++ b/src/store/navigation/navigation-action.ts
@@ -11,11 +11,12 @@ 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 { goToProject, goToCollection } from "../../common/actions";
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 goToProject(resource.uuid);
+ case ResourceKind.Collection: return goToCollection(resource.uuid);
default: return resource.href;
}
};
diff --git a/src/store/store.ts b/src/store/store.ts
index ae07744..c5845d4 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -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/collection-panel/collection-panel.tsx b/src/views/collection-panel/collection-panel.tsx
new file mode 100644
index 0000000..99c4e00
--- /dev/null
+++ b/src/views/collection-panel/collection-panel.tsx
@@ -0,0 +1,187 @@
+// 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, MenuItem, Menu, ListItemIcon, ListItemText, Typography
+} 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, ShareIcon, RenameIcon, AddFavoriteIcon, MoveToIcon,
+ CopyIcon, ProvenanceGraphIcon, DetailsIcon, AdvancedIcon, RemoveIcon
+} 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
+ }
+});
+
+const MENU_OPTIONS = [
+ {
+ title: 'Edit collection',
+ icon: RenameIcon
+ },
+ {
+ title: 'Share',
+ icon: ShareIcon
+ },
+ {
+ title: 'Move to',
+ icon: MoveToIcon
+ },
+ {
+ title: 'Add to favorites',
+ icon: AddFavoriteIcon
+ },
+ {
+ title: 'Copy to project',
+ icon: CopyIcon
+ },
+ {
+ title: 'View details',
+ icon: DetailsIcon
+ },
+ {
+ title: 'Provenance graph',
+ icon: ProvenanceGraphIcon
+ },
+ {
+ title: 'Advanced',
+ icon: AdvancedIcon
+ },
+ {
+ title: 'Remove',
+ icon: RemoveIcon
+ }
+];
+
+interface CollectionPanelDataProps {
+ item: CollectionResource;
+}
+
+interface CollectionPanelActionProps {
+ onItemRouteChange: (collectionId: string) => 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> {
+
+ state = {
+ anchorEl: undefined
+ };
+
+ showMenu = (event: any) => {
+ this.setState({ anchorEl: event.currentTarget });
+ }
+
+ closeMenu = () => {
+ this.setState({ anchorEl: undefined });
+ }
+
+ displayMenuAction = () => {
+ return <IconButton
+ aria-label="More options"
+ aria-owns={this.state.anchorEl ? 'submenu' : undefined}
+ aria-haspopup="true"
+ onClick={this.showMenu}>
+ <MoreOptionsIcon />
+ </IconButton>;
+ }
+
+ render() {
+ const { anchorEl } = this.state;
+ const { classes, item } = this.props;
+ return <div>
+ <Card className={classes.card}>
+ <CardHeader
+ avatar={ <CollectionIcon className={classes.iconHeader} /> }
+ action={
+ <IconButton
+ aria-label="More options"
+ aria-owns={anchorEl ? 'submenu' : undefined}
+ aria-haspopup="true"
+ onClick={this.showMenu}>
+ <MoreOptionsIcon />
+ </IconButton>
+ }
+ title={item && item.name } />
+ <CardContent>
+ <Menu
+ id="submenu"
+ anchorEl={anchorEl}
+ open={Boolean(anchorEl)}
+ onClose={this.closeMenu}>
+ {MENU_OPTIONS.map((option) => (
+ <MenuItem key={option.title}>
+ <ListItemIcon>
+ <option.icon />
+ </ListItemIcon>
+ <ListItemText inset primary={
+ <Typography variant='body1'>
+ {option.title}
+ </Typography>
+ }/>
+ </MenuItem>
+ ))}
+ </Menu>
+ <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
diff --git a/src/views/project-panel/project-panel.tsx b/src/views/project-panel/project-panel.tsx
index c2b42a5..2ddc1b0 100644
--- a/src/views/project-panel/project-panel.tsx
+++ b/src/views/project-panel/project-panel.tsx
@@ -38,7 +38,7 @@ const renderName = (item: ProjectPanelItem) =>
{renderIcon(item)}
</Grid>
<Grid item>
- <Typography color="primary">
+ <Typography color="default">
{item.name}
</Typography>
</Grid>
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index 8e2cb57..f39c779 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -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 { goToCollection } from '../../common/actions';
+import { loadCollection } from '../../store/collection-panel/collection-panel-action';
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,6 +231,10 @@ export const Workbench = withStyles(styles)(
);
}
+ renderCollectionPanel = (props: RouteComponentProps<{ id: string }>) => <CollectionPanel
+ onItemRouteChange={(collectionId) => this.props.dispatch<any>(loadCollection(collectionId, ResourceKind.Collection))}
+ {...props} />
+
renderProjectPanel = (props: RouteComponentProps<{ id: string }>) => <ProjectPanel
onItemRouteChange={itemId => this.props.dispatch<any>(setProjectItem(itemId, ItemMode.ACTIVE))}
onContextMenu={(event, item) => {
@@ -242,8 +250,14 @@ 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(goToCollection(item.uuid)));
+ default:
+ this.props.dispatch<any>(setProjectItem(item.uuid, ItemMode.ACTIVE));
+ this.props.dispatch<any>(loadDetails(item.uuid, item.kind as ResourceKind));
+ }
}}
{...props} />
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list