[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