[ARVADOS-WORKBENCH2] created: 1.1.4-224-g76215c4
Git user
git at public.curoverse.com
Tue Jul 10 02:30:32 EDT 2018
at 76215c43cae99e1ce7964dcfafae59b2134f72b3 (commit)
commit 76215c43cae99e1ce7964dcfafae59b2134f72b3
Author: Janicki Artur <artur.janicki at contractors.roche.com>
Date: Fri Jul 6 12:11:31 2018 +0200
create re-usable components: attribute, empty-state and icon, prepare panel for data
Feature #13765
Arvados-DCO-1.1-Signed-off-by: Janicki Artur <artur.janicki at contractors.roche.com>
diff --git a/src/components/attribute/attribute.tsx b/src/components/attribute/attribute.tsx
index 131d629..6d1c3bc 100644
--- a/src/components/attribute/attribute.tsx
+++ b/src/components/attribute/attribute.tsx
@@ -9,26 +9,40 @@ import { ArvadosTheme } from 'src/common/custom-theme';
interface AttributeDataProps {
label: string;
+ value?: string;
+ link?: string;
}
type AttributeProps = AttributeDataProps & WithStyles<CssRules>;
class Attribute extends React.Component<AttributeProps> {
+ hasLink() {
+ return !!this.props.link;
+ }
+
render() {
- const { label, children, classes } = this.props;
+ const { label, link, value, children, classes } = this.props;
return <Typography component="div" className={classes.attribute}>
- <span className={classes.label}>{label}</span>
- <span className={classes.value}>{children}</span>
- </Typography>;
+ <Typography component="span" className={classes.label}>{label}</Typography>
+ { this.hasLink() ? (
+ <a href='{link}' className={classes.link} target='_blank'>{value}</a>
+ ) : (
+ <Typography component="span" className={classes.value}>
+ {value}
+ {children}
+ </Typography>
+ )}
+ </Typography>;
}
}
-type CssRules = 'attribute' | 'label' | 'value';
+type CssRules = 'attribute' | 'label' | 'value' | 'link';
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
attribute: {
+ height: '24px',
display: 'flex',
alignItems: 'center',
marginBottom: theme.spacing.unit
@@ -40,6 +54,10 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
value: {
display: 'flex',
alignItems: 'center'
+ },
+ link: {
+ color: theme.palette.primary.main,
+ textDecoration: 'none'
}
});
diff --git a/src/components/empty-state/empty-state.tsx b/src/components/empty-state/empty-state.tsx
new file mode 100644
index 0000000..b048e32
--- /dev/null
+++ b/src/components/empty-state/empty-state.tsx
@@ -0,0 +1,46 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import Typography from '@material-ui/core/Typography';
+import { WithStyles, withStyles, StyleRulesCallback } from '@material-ui/core/styles';
+import { ArvadosTheme } from 'src/common/custom-theme';
+import IconBase from '../icon/icon';
+
+export interface EmptyStateDataProps {
+ message: string;
+ icon: string;
+ details?: string;
+}
+
+type EmptyStateProps = EmptyStateDataProps & WithStyles<CssRules>;
+
+class EmptyState extends React.Component<EmptyStateProps, {}> {
+
+ render() {
+ const { classes, message, details, icon, children } = this.props;
+ return (
+ <Typography className={classes.container} component="div">
+ <IconBase icon={icon} className={classes.icon} />
+ <Typography variant="body1" gutterBottom>{message}</Typography>
+ { details && <Typography gutterBottom>{details}</Typography> }
+ { children && <Typography gutterBottom>{children}</Typography> }
+ </Typography>
+ );
+ }
+
+}
+
+type CssRules = 'container' | 'icon';
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ container: {
+ textAlign: 'center'
+ },
+ icon: {
+ color: theme.palette.grey["500"],
+ fontSize: '72px'
+ }
+});
+
+export default withStyles(styles)(EmptyState);
\ No newline at end of file
diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx
new file mode 100644
index 0000000..b0b4e29
--- /dev/null
+++ b/src/components/icon/icon.tsx
@@ -0,0 +1,41 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import * as classnames from "classnames";
+import CloseAnnouncement from '@material-ui/icons/Announcement';
+import CloseIcon from '@material-ui/icons/Close';
+import FolderIcon from '@material-ui/icons/Folder';
+
+interface IconBaseDataProps {
+ icon: string;
+ className?: string;
+}
+
+type IconBaseProps = IconBaseDataProps;
+
+interface IconBaseState {
+ icon: string;
+}
+
+const getSpecificIcon = (props: any) => ({
+ announcement: <CloseAnnouncement className={props.className} />,
+ folder: <FolderIcon className={props.className} />,
+ close: <CloseIcon className={props.className} />,
+ project: <i className={classnames([props.className, 'fas fa-folder fa-lg'])} />,
+ collection: <i className="fas fa-archive fa-lg" />,
+ process: <i className="fas fa-cogs fa-lg" />
+});
+
+class IconBase extends React.Component<IconBaseProps, IconBaseState> {
+ state = {
+ icon: '',
+ };
+
+ render() {
+ return getSpecificIcon(this.props)[this.props.icon];
+ }
+}
+
+export default IconBase;
\ No newline at end of file
diff --git a/src/views-components/details-panel/details-panel.tsx b/src/views-components/details-panel/details-panel.tsx
index be257e8..f47dfa0 100644
--- a/src/views-components/details-panel/details-panel.tsx
+++ b/src/views-components/details-panel/details-panel.tsx
@@ -5,8 +5,6 @@
import * as React from 'react';
import Drawer from '@material-ui/core/Drawer';
import IconButton from "@material-ui/core/IconButton";
-import CloseIcon from '@material-ui/icons/Close';
-import FolderIcon from '@material-ui/icons/Folder';
import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
import { ArvadosTheme } from '../../common/custom-theme';
import Attribute from '../../components/attribute/attribute';
@@ -15,15 +13,22 @@ import Tab from '@material-ui/core/Tab';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
import * as classnames from "classnames";
+import EmptyState from '../../components/empty-state/empty-state';
+import IconBase from '../../components/icon/icon';
-export interface DetailsPanelProps {
+export interface DetailsPanelDataProps {
onCloseDrawer: () => void;
isOpened: boolean;
+ renderHeader?: React.ComponentType<{}>;
+ renderDetails?: React.ComponentType<{}>;
+ renderActivity?: React.ComponentType<{}>;
}
-class DetailsPanel extends React.Component<DetailsPanelProps & WithStyles<CssRules>, {}> {
+type DetailsPanelProps = DetailsPanelDataProps & WithStyles<CssRules>;
+
+class DetailsPanel extends React.Component<DetailsPanelProps, {}> {
state = {
- tabsValue: 0,
+ tabsValue: 0
};
handleChange = (event: any, value: boolean) => {
@@ -34,21 +39,24 @@ class DetailsPanel extends React.Component<DetailsPanelProps & WithStyles<CssRul
<Typography className={this.props.classes.tabContainer} component="div">
{children}
</Typography>
-
+
render() {
- const { classes, onCloseDrawer, isOpened } = this.props;
- const { tabsValue } = this.state;
+ const { classes, onCloseDrawer, isOpened, renderHeader, renderDetails, renderActivity } = this.props;
+ const { tabsValue } = this.state;
return (
- <div className={classnames([classes.container, { [classes.opened]: isOpened }])}>
+ <Typography component="div" className={classnames([classes.container, { [classes.opened]: isOpened }])}>
<Drawer variant="permanent" anchor="right" classes={{ paper: classes.drawerPaper }}>
<Typography component="div" className={classes.headerContainer}>
<Grid container alignItems='center' justify='space-around'>
- <i className="fas fa-cogs fa-lg" />
+ {renderHeader}
+ {/* TODO: renderHeader */}
+ <IconBase icon='process' />
<Typography variant="title">
Tutorial pipeline
</Typography>
+ {/* End */}
<IconButton color="inherit" onClick={onCloseDrawer}>
- <CloseIcon />
+ <IconBase icon='close' />
</IconButton>
</Grid>
</Typography>
@@ -58,28 +66,27 @@ class DetailsPanel extends React.Component<DetailsPanelProps & WithStyles<CssRul
</Tabs>
{tabsValue === 0 && this.renderTabContainer(
<Grid container direction="column">
- <Attribute label="Type">Process</Attribute>
- <Attribute label="Size">---</Attribute>
+ {renderDetails}
+ <EmptyState icon='announcement'
+ message='Select a file or folder to view its details.' />
+ <Attribute label='Type' value='Process' />
+ <Attribute label='Size' value='---' />
<Attribute label="Location">
- <FolderIcon />
+ <IconBase icon='folder' />
Projects
</Attribute>
- <Attribute label="Owner">me</Attribute>
+ <Attribute label='Outputs' link='http://www.google.pl' value='New output as link' />
+ <Attribute label='Owner' value='me' />
</Grid>
)}
{tabsValue === 1 && this.renderTabContainer(
<Grid container direction="column">
- <Attribute label="Type">Process</Attribute>
- <Attribute label="Size">---</Attribute>
- <Attribute label="Location">
- <FolderIcon />
- Projects
- </Attribute>
- <Attribute label="Owner">me</Attribute>
+ {renderActivity}
+ <EmptyState icon='announcement' message='Select a file or folder to view its details.' />
</Grid>
)}
</Drawer>
- </div>
+ </Typography>
);
}
diff --git a/src/views/workbench/workbench.test.tsx b/src/views/workbench/workbench.test.tsx
index 6edebaf..4b52d0b 100644
--- a/src/views/workbench/workbench.test.tsx
+++ b/src/views/workbench/workbench.test.tsx
@@ -9,6 +9,8 @@ import { Provider } from "react-redux";
import configureStore from "../../store/store";
import createBrowserHistory from "history/createBrowserHistory";
import { ConnectedRouter } from "react-router-redux";
+import { MuiThemeProvider } from '@material-ui/core/styles';
+import { CustomTheme } from '../../common/custom-theme';
const history = createBrowserHistory();
@@ -25,11 +27,13 @@ it('renders without crashing', () => {
sidePanel: []
}, createBrowserHistory());
ReactDOM.render(
- <Provider store={store}>
- <ConnectedRouter history={history}>
- <Workbench/>
- </ConnectedRouter>
- </Provider>,
+ <MuiThemeProvider theme={CustomTheme}>
+ <Provider store={store}>
+ <ConnectedRouter history={history}>
+ <Workbench/>
+ </ConnectedRouter>
+ </Provider>
+ </MuiThemeProvider>,
div);
ReactDOM.unmountComponentAtNode(div);
});
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index 8cc5fc2..8315d5b 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -101,8 +101,12 @@ interface WorkbenchState {
anonymousMenu: NavMenuItem[]
};
isDetailsPanelOpened: boolean;
+ detailsPanelHeader: React.ComponentType<{}> | undefined;
+ detailsPanelDetails: React.ComponentType<{}> | undefined;
+ detailsPanelActivity: React.ComponentType<{}> | undefined;
}
+
class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
state = {
anchorEl: null,
@@ -132,7 +136,10 @@ class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
}
]
},
- isDetailsPanelOpened: false
+ isDetailsPanelOpened: false,
+ detailsPanelHeader: undefined,
+ detailsPanelDetails: undefined,
+ detailsPanelActivity: undefined,
};
mainAppBarActions: MainAppBarActionProps = {
@@ -202,7 +209,10 @@ class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
<Route path="/projects/:id" render={this.renderProjectPanel} />
</Switch>
</div>
- <DetailsPanel
+ <DetailsPanel
+ renderHeader={this.state.detailsPanelHeader}
+ renderDetails={this.state.detailsPanelDetails}
+ renderActivity={this.state.detailsPanelActivity}
isOpened={this.state.isDetailsPanelOpened}
onCloseDrawer={this.mainAppBarActions.onDetailsPanelToggle} />
</main>
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list