Merge branch '14434-display-workflow-name'
authorPawel Kromplewski <pawel.kromplewski@contractors.roche.com>
Tue, 18 Dec 2018 13:25:31 +0000 (14:25 +0100)
committerPawel Kromplewski <pawel.kromplewski@contractors.roche.com>
Tue, 18 Dec 2018 13:25:31 +0000 (14:25 +0100)
refs #14434

Arvados-DCO-1.1-Signed-off-by: Pawel Kromplewski <pawel.kromplewski@contractors.roche.com>

src/common/formatters.ts
src/components/details-attribute/details-attribute.tsx
src/store/process-panel/process-panel-actions.ts
src/views/process-panel/process-information-card.tsx
src/views/process-panel/process-panel-root.tsx
src/views/process-panel/process-panel.tsx

index ae50ee8adda3ace82a380b0714961e3ea4fb4394..60e6cd59c53e284a929cd6143c618020537ffd3a 100644 (file)
@@ -4,7 +4,7 @@
 
 import { PropertyValue } from "~/models/search-bar";
 
-export const formatDate = (isoDate?: string) => {
+export const formatDate = (isoDate?: string | null) => {
     if (isoDate) {
         const date = new Date(isoDate);
         const text = date.toLocaleString();
index 78b4341d173046972385cad95e584cb735138085..d255d14b1b7538f9bcce620ed705c827d8caef8e 100644 (file)
@@ -48,17 +48,22 @@ interface DetailsAttributeDataProps {
     lowercaseValue?: boolean;
     link?: string;
     children?: React.ReactNode;
+    onValueClick?: () => void;
 }
 
 type DetailsAttributeProps = DetailsAttributeDataProps & WithStyles<CssRules>;
 
 export const DetailsAttribute = withStyles(styles)(
-    ({ label, link, value, children, classes, classLabel, classValue, lowercaseValue }: DetailsAttributeProps) =>
+    ({ label, link, value, children, classes, classLabel, classValue, lowercaseValue, onValueClick }: DetailsAttributeProps) =>
         <Typography component="div" className={classes.attribute}>
             <Typography component="span" className={classnames([classes.label, classLabel])}>{label}</Typography>
             { link
                 ? <a href={link} className={classes.link} target='_blank'>{value}</a>
-                : <Typography component="span" className={classnames([classes.value, classValue, { [classes.lowercaseValue]: lowercaseValue }])}>
+                : <Typography
+                    onClick={onValueClick}
+                    component="span"
+                    className={classnames([classes.value, classValue, { [classes.lowercaseValue]: lowercaseValue }])}
+                >
                     {value}
                     {children}
                 </Typography> }
index 2aa914af2ae505c8faaf08ff75b54c50fe17224c..42a718bd69a9b4a4fde1f9217c36812d08a44829 100644 (file)
@@ -8,9 +8,10 @@ import { Dispatch } from 'redux';
 import { ProcessStatus } from '~/store/processes/process';
 import { RootState } from '~/store/store';
 import { ServiceRepository } from "~/services/services";
-import { navigateToCollection } from '~/store/navigation/navigation-action';
+import { navigateToCollection, navigateToWorkflows } from '~/store/navigation/navigation-action';
 import { snackbarActions } from '~/store/snackbar/snackbar-actions';
 import { SnackbarKind } from '../snackbar/snackbar-actions';
+import { showWorkflowDetails } from '~/store/workflow-panel/workflow-panel-actions';
 
 export const procesPanelActions = unionize({
     SET_PROCESS_PANEL_FILTERS: ofType<string[]>(),
@@ -37,6 +38,12 @@ export const navigateToOutput = (uuid: string) =>
         }
     };
 
+export const openWorkflow = (uuid: string) =>
+    (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        dispatch<any>(navigateToWorkflows);
+        dispatch<any>(showWorkflowDetails(uuid));
+    };
+
 export const initProcessPanelFilters = procesPanelActions.SET_PROCESS_PANEL_FILTERS([
     ProcessStatus.QUEUED,
     ProcessStatus.COMPLETED,
index 7f3e025f8dc7e97a7f1b7616a09d9013949260b1..52f13987d9fdf214853ec58e292d413dc6a228c7 100644 (file)
@@ -13,7 +13,7 @@ import { DetailsAttribute } from '~/components/details-attribute/details-attribu
 import { Process } from '~/store/processes/process';
 import { getProcessStatus, getProcessStatusColor } from '~/store/processes/process';
 import { formatDate } from '~/common/formatters';
-
+import { openWorkflow } from "~/store/process-panel/process-panel-actions";
 
 type CssRules = 'card' | 'iconHeader' | 'label' | 'value' | 'chip' | 'link' | 'content' | 'title' | 'avatar';
 
@@ -70,29 +70,33 @@ export interface ProcessInformationCardDataProps {
     onContextMenu: (event: React.MouseEvent<HTMLElement>) => void;
     openProcessInputDialog: (uuid: string) => void;
     navigateToOutput: (uuid: string) => void;
+    navigateToWorkflow: (uuid: string) => void;
 }
 
 type ProcessInformationCardProps = ProcessInformationCardDataProps & WithStyles<CssRules, true>;
 
 export const ProcessInformationCard = withStyles(styles, { withTheme: true })(
-    ({ classes, process, onContextMenu, theme, openProcessInputDialog, navigateToOutput }: ProcessInformationCardProps) =>
-        <Card className={classes.card}>
+    ({ classes, process, onContextMenu, theme, openProcessInputDialog, navigateToOutput, navigateToWorkflow }: ProcessInformationCardProps) => {
+        const { container } = process;
+        const startedAt = container ? formatDate(container.startedAt) : 'N/A';
+        const finishedAt = container ? formatDate(container.finishedAt) : 'N/A';
+        return <Card className={classes.card}>
             <CardHeader
                 classes={{
                     content: classes.title,
                     avatar: classes.avatar
                 }}
-                avatar={<ProcessIcon className={classes.iconHeader} />}
+                avatar={<ProcessIcon className={classes.iconHeader}/>}
                 action={
                     <div>
                         <Chip label={getProcessStatus(process)}
-                            className={classes.chip}
-                            style={{ backgroundColor: getProcessStatusColor(getProcessStatus(process), theme as ArvadosTheme) }} />
+                              className={classes.chip}
+                              style={{backgroundColor: getProcessStatusColor(getProcessStatus(process), theme as ArvadosTheme)}}/>
                         <Tooltip title="More options" disableFocusListener>
                             <IconButton
                                 aria-label="More options"
                                 onClick={event => onContextMenu(event)}>
-                                <MoreOptionsIcon />
+                                <MoreOptionsIcon/>
                             </IconButton>
                         </Tooltip>
                     </div>
@@ -109,28 +113,34 @@ export const ProcessInformationCard = withStyles(styles, { withTheme: true })(
                         <Typography noWrap variant="body2" color='inherit'>
                             {getDescription(process)}
                         </Typography>
-                    </Tooltip>} />
+                    </Tooltip>}/>
             <CardContent className={classes.content}>
                 <Grid container>
                     <Grid item xs={6}>
                         <DetailsAttribute classLabel={classes.label} classValue={classes.value}
-                            label='From' value={process.container ? formatDate(process.container.startedAt!) : 'N/A'} />
+                                          label='From'
+                                          value={process.container ? formatDate(startedAt) : 'N/A'}/>
                         <DetailsAttribute classLabel={classes.label} classValue={classes.value}
-                            label='To' value={process.container ? formatDate(process.container.finishedAt!) : 'N/A'} />
-                        <DetailsAttribute classLabel={classes.label} classValue={classes.link}
-                            label='Workflow' value='???' />
+                                          label='To'
+                                          value={process.container ? formatDate(finishedAt) : 'N/A'}/>
+                        {process.containerRequest.properties.templateUuid &&
+                        <DetailsAttribute label='Workflow' classLabel={classes.label} classValue={classes.link}
+                                          value={process.containerRequest.properties.templateUuid}
+                                          onValueClick={() => navigateToWorkflow(process.containerRequest.properties.templateUuid)}
+                        />}
                     </Grid>
                     <Grid item xs={6}>
                         <span onClick={() => navigateToOutput(process.containerRequest.outputUuid!)}>
-                            <DetailsAttribute classLabel={classes.link} label='Outputs' />
+                            <DetailsAttribute classLabel={classes.link} label='Outputs'/>
                         </span>
                         <span onClick={() => openProcessInputDialog(process.containerRequest.uuid)}>
-                            <DetailsAttribute classLabel={classes.link} label='Inputs' />
+                            <DetailsAttribute classLabel={classes.link} label='Inputs'/>
                         </span>
                     </Grid>
                 </Grid>
             </CardContent>
-        </Card>
+        </Card>;
+    }
 );
 
 const getDescription = (process: Process) =>
index 73f71e5e0a139b0fbbe007213b0f1d6705070868..5fb6390c3a9737e4f27830299a8dd1835a4c650f 100644 (file)
@@ -24,6 +24,7 @@ export interface ProcessPanelRootActionProps {
     onToggle: (status: string) => void;
     openProcessInputDialog: (uuid: string) => void;
     navigateToOutput: (uuid: string) => void;
+    navigateToWorkflow: (uuid: string) => void;
 }
 
 export type ProcessPanelRootProps = ProcessPanelRootDataProps & ProcessPanelRootActionProps;
@@ -36,7 +37,9 @@ export const ProcessPanelRoot = ({ process, ...props }: ProcessPanelRootProps) =
                     process={process}
                     onContextMenu={event => props.onContextMenu(event, process)}
                     openProcessInputDialog={props.openProcessInputDialog}
-                    navigateToOutput={props.navigateToOutput} />
+                    navigateToOutput={props.navigateToOutput}
+                    navigateToWorkflow={props.navigateToWorkflow}
+            />
             </Grid>
             <Grid item sm={12} md={5}>
                 <SubprocessesCard
index 5672469677a3d29c5150a39f955ae71078d8c022..b389528033d89dfd282995610592bc76724a57ee 100644 (file)
@@ -11,7 +11,7 @@ import { matchProcessRoute } from '~/routes/routes';
 import { ProcessPanelRootDataProps, ProcessPanelRootActionProps, ProcessPanelRoot } from './process-panel-root';
 import { ProcessPanel as ProcessPanelState} from '~/store/process-panel/process-panel';
 import { groupBy } from 'lodash';
-import { toggleProcessPanelFilter, navigateToOutput } from '~/store/process-panel/process-panel-actions';
+import { toggleProcessPanelFilter, navigateToOutput, openWorkflow } from '~/store/process-panel/process-panel-actions';
 import { openProcessInputDialog } from '~/store/processes/process-input-actions';
 
 const mapStateToProps = ({ router, resources, processPanel }: RootState): ProcessPanelRootDataProps => {
@@ -35,7 +35,8 @@ const mapDispatchToProps = (dispatch: Dispatch): ProcessPanelRootActionProps =>
         dispatch<any>(toggleProcessPanelFilter(status));
     },
     openProcessInputDialog: (uuid) => dispatch<any>(openProcessInputDialog(uuid)),
-    navigateToOutput: (uuid) => dispatch<any>(navigateToOutput(uuid))
+    navigateToOutput: (uuid) => dispatch<any>(navigateToOutput(uuid)),
+    navigateToWorkflow: (uuid) => dispatch<any>(openWorkflow(uuid))
 });
 
 export const ProcessPanel = connect(mapStateToProps, mapDispatchToProps)(ProcessPanelRoot);