From: Janicki Artur Date: Fri, 6 Jul 2018 10:11:31 +0000 (+0200) Subject: create re-usable components: attribute, empty-state and icon, prepare panel for data X-Git-Tag: 1.2.0~54^2~5 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/76215c43cae99e1ce7964dcfafae59b2134f72b3 create re-usable components: attribute, empty-state and icon, prepare panel for data Feature #13765 Arvados-DCO-1.1-Signed-off-by: Janicki Artur --- diff --git a/src/components/attribute/attribute.tsx b/src/components/attribute/attribute.tsx index 131d629a..6d1c3bc3 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; class Attribute extends React.Component { + hasLink() { + return !!this.props.link; + } + render() { - const { label, children, classes } = this.props; + const { label, link, value, children, classes } = this.props; return - {label} - {children} - ; + {label} + { this.hasLink() ? ( + {value} + ) : ( + + {value} + {children} + + )} + ; } } -type CssRules = 'attribute' | 'label' | 'value'; +type CssRules = 'attribute' | 'label' | 'value' | 'link'; const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ attribute: { + height: '24px', display: 'flex', alignItems: 'center', marginBottom: theme.spacing.unit @@ -40,6 +54,10 @@ const styles: StyleRulesCallback = (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 00000000..b048e327 --- /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; + +class EmptyState extends React.Component { + + render() { + const { classes, message, details, icon, children } = this.props; + return ( + + + {message} + { details && {details} } + { children && {children} } + + ); + } + +} + +type CssRules = 'container' | 'icon'; +const styles: StyleRulesCallback = (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 00000000..b0b4e292 --- /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: , + folder: , + close: , + project: , + collection: , + process: +}); + +class IconBase extends React.Component { + 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 be257e83..f47dfa06 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, {}> { +type DetailsPanelProps = DetailsPanelDataProps & WithStyles; + +class DetailsPanel extends React.Component { state = { - tabsValue: 0, + tabsValue: 0 }; handleChange = (event: any, value: boolean) => { @@ -34,21 +39,24 @@ class DetailsPanel extends React.Component {children} - + 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 ( -
+ - + {renderHeader} + {/* TODO: renderHeader */} + Tutorial pipeline + {/* End */} - + @@ -58,28 +66,27 @@ class DetailsPanel extends React.Component {tabsValue === 0 && this.renderTabContainer( - Process - --- + {renderDetails} + + + - + Projects - me + + )} {tabsValue === 1 && this.renderTabContainer( - Process - --- - - - Projects - - me + {renderActivity} + )} -
+ ); } diff --git a/src/views/workbench/workbench.test.tsx b/src/views/workbench/workbench.test.tsx index 6edebaf0..4b52d0b9 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( - - - - - , + + + + + + + , div); ReactDOM.unmountComponentAtNode(div); }); diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx index 8cc5fc22..8315d5b0 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 { state = { anchorEl: null, @@ -132,7 +136,10 @@ class Workbench extends React.Component { } ] }, - isDetailsPanelOpened: false + isDetailsPanelOpened: false, + detailsPanelHeader: undefined, + detailsPanelDetails: undefined, + detailsPanelActivity: undefined, }; mainAppBarActions: MainAppBarActionProps = { @@ -202,7 +209,10 @@ class Workbench extends React.Component { -