Setup routing for process panel
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Wed, 29 Aug 2018 15:23:17 +0000 (17:23 +0200)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Wed, 29 Aug 2018 15:23:17 +0000 (17:23 +0200)
Feature #14099

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

src/routes/routes.ts
src/store/workbench/workbench-actions.ts
src/views-components/process-information-card/process-information-card.ts [deleted file]
src/views/process-panel/process-information-card.tsx
src/views/process-panel/process-panel-root.tsx [new file with mode: 0644]
src/views/process-panel/process-panel.tsx
src/views/workbench/workbench.tsx

index c46239e2a1cbe5deeff10fc60b42718181c82817..20dd1359b34b626f66ab3b0de959e85a2c28b38f 100644 (file)
@@ -3,19 +3,20 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import { History, Location } from 'history';
-import { RootStore } from '../store/store';
+import { RootStore } from '~/store/store';
 import { matchPath } from 'react-router';
 import { ResourceKind, RESOURCE_UUID_PATTERN, extractUuidKind } from '~/models/resource';
 import { getProjectUrl } from '../models/project';
 import { getCollectionUrl } from '~/models/collection';
-import { loadProject, loadFavorites, loadCollection } from '../store/workbench/workbench-actions';
+import { loadProject, loadFavorites, loadCollection } from '~/store/workbench/workbench-actions';
+import { loadProcess } from '~/store/processes/processes-actions';
 
 export const Routes = {
     ROOT: '/',
     TOKEN: '/token',
     PROJECTS: `/projects/:id(${RESOURCE_UUID_PATTERN})`,
     COLLECTIONS: `/collections/:id(${RESOURCE_UUID_PATTERN})`,
-    PROCESS: `/processes/:id(${RESOURCE_UUID_PATTERN})`,
+    PROCESSES: `/processes/:id(${RESOURCE_UUID_PATTERN})`,
     FAVORITES: '/favorites',
 };
 
@@ -56,7 +57,7 @@ export const matchCollectionRoute = (route: string) =>
     matchPath<ResourceRouteParams>(route, { path: Routes.COLLECTIONS });
 
 export const matchProcessRoute = (route: string) =>
-    matchPath<ResourceRouteParams>(route, { path: Routes.COLLECTIONS });
+    matchPath<ResourceRouteParams>(route, { path: Routes.PROCESSES });
 
 
 const handleLocationChange = (store: RootStore) => ({ pathname }: Location) => {
@@ -71,6 +72,6 @@ const handleLocationChange = (store: RootStore) => ({ pathname }: Location) => {
     } else if (favoriteMatch) {
         store.dispatch(loadFavorites());
     } else if (processMatch) {
-        store.dispatch(processMatch.params.id);
+        store.dispatch(loadProcess(processMatch.params.id));
     }
 };
index 8dc64a845e22d8fc68e72376d9060684635eefef..3c68c0004519b15a73fca9a9c5553b316e3a68e5 100644 (file)
@@ -28,6 +28,8 @@ import * as collectionCreateActions from '~/store/collections/collection-create-
 import * as collectionCopyActions from '~/store/collections/collection-copy-actions';
 import * as collectionUpdateActions from '~/store/collections/collection-update-actions';
 import * as collectionMoveActions from '~/store/collections/collection-move-actions';
+import * as processesActions from '../processes/processes-actions';
+import { getProcess } from '../processes/process';
 
 
 export const loadWorkbench = () =>
@@ -172,6 +174,17 @@ export const moveCollection = (data: MoveToFormDialogData) =>
         }
     };
 
+export const loadProcess = (uuid: string) =>
+    async (dispatch: Dispatch, getState: () => RootState) => {
+        await dispatch<any>(processesActions.loadProcess(uuid));
+        const process = getProcess(uuid)(getState().resources);
+        if (process) {
+            await dispatch<any>(activateSidePanelTreeItem(process.containerRequest.ownerUuid));
+            dispatch<any>(setCollectionBreadcrumbs(process.containerRequest.ownerUuid));
+            dispatch(loadDetailsPanel(uuid));
+        }
+    };
+
 export const resourceIsNotLoaded = (uuid: string) =>
     snackbarActions.OPEN_SNACKBAR({
         message: `Resource identified by ${uuid} is not loaded.`
diff --git a/src/views-components/process-information-card/process-information-card.ts b/src/views-components/process-information-card/process-information-card.ts
deleted file mode 100644 (file)
index bf9172d..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import { Dispatch } from 'redux';
-import { openProcessContextMenu } from '~/store/context-menu/context-menu-actions';
-import { connect } from 'react-redux';
-import { RootState } from '~/store/store';
-import { ProcessInformationCard as InformationCardComponent, ProcessInformationCardDataProps } from '~/views/process-panel/process-information-card';
-
-type InformationCardActionProps = Pick<ProcessInformationCardDataProps, 'onContextMenu'>;
-
-const mapStateToProps = (state: RootState) => ({
-    // todo: change for processPanel
-    item: state.collectionPanel.item
-});
-
-const mapDispatchToProps = (dispatch: Dispatch): InformationCardActionProps => ({
-    onContextMenu: (event: React.MouseEvent<HTMLElement>) => {
-        dispatch<any>(openProcessContextMenu(event));
-    }
-});
-
-export const ProcessInformationCard = connect(mapStateToProps, mapDispatchToProps)(InformationCardComponent);
\ No newline at end of file
index a50490c9bf25ee8b68c2b0be0d6d415ef5b9112f..53c56ca2807e9b2585a5aa5aac6275041b4675fe 100644 (file)
@@ -10,6 +10,8 @@ import {
 import { ArvadosTheme } from '~/common/custom-theme';
 import { MoreOptionsIcon, ProcessIcon } from '~/components/icon/icon';
 import { DetailsAttribute } from '~/components/details-attribute/details-attribute';
+import { Process } from '~/store/processes/process';
+import { getProcessStatus } from '../../store/processes/process';
 
 type CssRules = 'card' | 'iconHeader' | 'label' | 'value' | 'chip' | 'headerText' | 'link' | 'content' | 'title' | 'avatar';
 
@@ -66,14 +68,14 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
 });
 
 export interface ProcessInformationCardDataProps {
-    item: any;
+    process: Process;
     onContextMenu: (event: React.MouseEvent<HTMLElement>) => void;
 }
 
 type ProcessInformationCardProps = ProcessInformationCardDataProps & WithStyles<CssRules>;
 
 export const ProcessInformationCard = withStyles(styles)(
-    ({ classes, onContextMenu }: ProcessInformationCardProps) =>
+    ({ classes, process, onContextMenu }: ProcessInformationCardProps) =>
         <Card className={classes.card}>
             <CardHeader
                 classes={{
@@ -83,7 +85,7 @@ export const ProcessInformationCard = withStyles(styles)(
                 avatar={<ProcessIcon className={classes.iconHeader} />}
                 action={
                     <div>
-                        <Chip label="Complete" className={classes.chip} />
+                        <Chip label={getProcessStatus(process)} className={classes.chip} />
                         <IconButton
                             aria-label="More options"
                             onClick={event => onContextMenu(event)}>
@@ -92,22 +94,22 @@ export const ProcessInformationCard = withStyles(styles)(
                     </div>
                 }
                 title={
-                    <Tooltip title="Pipeline template that generates a config file from a template">
+                    <Tooltip title={process.containerRequest.name}>
                         <Typography noWrap variant="title">
-                            Pipeline template that generates a config file from a template
+                           {process.containerRequest.name}
                         </Typography>
                     </Tooltip>
                 }
-                subheader="(no-description)" />
+                subheader={process.containerRequest.description} />
             <CardContent className={classes.content}>
                 <Grid container>
                     <Grid item xs={6}>
                         <DetailsAttribute classLabel={classes.label} classValue={classes.value}
-                            label='From' value="1:25 PM 3/23/2018" />
+                            label='From' value={process.container ? process.container.startedAt : 'N/A'} />
                         <DetailsAttribute classLabel={classes.label} classValue={classes.value}
-                            label='To' value='1:25 PM 3/23/2018' />
+                            label='To' value={process.container ? process.container.finishedAt : 'N/A'} />
                         <DetailsAttribute classLabel={classes.label} classValue={classes.link}
-                            label='Workflow' value='FastQC MultiQC' />
+                            label='Workflow' value='???' />
                     </Grid>
                     <Grid item xs={6}>
                         <DetailsAttribute classLabel={classes.link} label='Outputs' />
diff --git a/src/views/process-panel/process-panel-root.tsx b/src/views/process-panel/process-panel-root.tsx
new file mode 100644 (file)
index 0000000..c7ac938
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { Grid } from '@material-ui/core';
+import { ProcessInformationCard } from './process-information-card';
+import { DefaultView } from '~/components/default-view/default-view';
+import { ProcessIcon } from '~/components/icon/icon';
+import { Process } from '~/store/processes/process';
+
+export interface ProcessPanelRootDataProps {
+    process?: Process;
+}
+
+export interface ProcessPanelRootActionProps {
+    onContextMenu: (event: React.MouseEvent<HTMLElement>) => void;
+}
+
+export type ProcessPanelRootProps = ProcessPanelRootDataProps & ProcessPanelRootActionProps;
+
+export const ProcessPanelRoot = (props: ProcessPanelRootProps) =>
+    props.process
+        ? <Grid container>
+            <Grid item xs={7}>
+                <ProcessInformationCard
+                    process={props.process}
+                    onContextMenu={props.onContextMenu} />
+            </Grid>
+        </Grid>
+        : <Grid container
+            alignItems='center'
+            justify='center'>
+            <DefaultView
+                icon={ProcessIcon}
+                messages={['Process not found']} />
+        </Grid>;
index f416f7b2ed5c068bb045da94e1d8b17ed68451c0..421945fed7f1756c1a6f8794b6e5e018d2a27b42 100644 (file)
@@ -3,17 +3,27 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from 'react';
-import { ProcessInformationCard } from '~/views-components/process-information-card/process-information-card';
-import { Grid } from '@material-ui/core';
+import { RootState } from '~/store/store';
+import { connect } from 'react-redux';
+import { getProcess } from '~/store/processes/process';
+import { Dispatch } from 'redux';
+import { openProcessContextMenu } from '~/store/context-menu/context-menu-actions';
+import { matchProcessRoute } from '~/routes/routes';
+import { ProcessPanelRootDataProps, ProcessPanelRootActionProps, ProcessPanelRoot } from './process-panel-root';
 
-export class ProcessPanel extends React.Component {
-    render() {
-        return <div>
-            <Grid container>
-                <Grid item xs={7}>
-                    <ProcessInformationCard />
-                </Grid>
-            </Grid>
-        </div>;
+const mapStateToProps = ({ router, resources }: RootState): ProcessPanelRootDataProps => {
+    const pathname = router.location ? router.location.pathname : '';
+    const match = matchProcessRoute(pathname);
+    const uuid = match ? match.params.id : '';
+    return {
+        process: getProcess(uuid)(resources)
+    };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch): ProcessPanelRootActionProps => ({
+    onContextMenu: (event: React.MouseEvent<HTMLElement>) => {
+        dispatch<any>(openProcessContextMenu(event));
     }
-}
\ No newline at end of file
+});
+
+export const ProcessPanel = connect(mapStateToProps, mapDispatchToProps)(ProcessPanelRoot);
index 1d53842b422bcbcb4484b6607c355d46fa5d8445..860fb7ae2521fbbc5e5af6f9e56a1f4eded4ca86 100644 (file)
@@ -166,7 +166,7 @@ export const Workbench = withStyles(styles)(
                                     <Route path={Routes.PROJECTS} component={ProjectPanel} />
                                     <Route path={Routes.COLLECTIONS} component={CollectionPanel} />
                                     <Route path={Routes.FAVORITES} component={FavoritePanel} />
-                                    <Route path={Routes.PROCESS} component={ProcessPanel} />
+                                    <Route path={Routes.PROCESSES} component={ProcessPanel} />
                                 </Switch>
                             </div>
                             {user && <DetailsPanel />}