19482: Fix context menu, breadcrumbs
[arvados-workbench2.git] / src / views-components / details-panel / workflow-details.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from 'react';
6 import { WorkflowIcon, StartIcon } from 'components/icon/icon';
7 import {
8     WorkflowResource, parseWorkflowDefinition, getWorkflowInputs,
9     getWorkflowOutputs, getWorkflow
10 } from 'models/workflow';
11 import { DetailsData } from "./details-data";
12 import { DetailsAttribute } from 'components/details-attribute/details-attribute';
13 import { ResourceWithName } from 'views-components/data-explorer/renderers';
14 import { formatDate } from "common/formatters";
15 import { Grid } from '@material-ui/core';
16 import { withStyles, StyleRulesCallback, WithStyles, Button } from '@material-ui/core';
17 import { openRunProcess } from "store/workflow-panel/workflow-panel-actions";
18 import { Dispatch } from 'redux';
19 import { connect } from 'react-redux';
20 import { ArvadosTheme } from 'common/custom-theme';
21 import { ProcessIOParameter } from 'views/process-panel/process-io-card';
22 import { formatInputData, formatOutputData } from 'store/process-panel/process-panel-actions';
23 import { AuthState } from 'store/auth/auth-reducer';
24 import { RootState } from 'store/store';
25 import { getPropertyChip } from "views-components/resource-properties-form/property-chip";
26
27 export interface WorkflowDetailsCardDataProps {
28     workflow?: WorkflowResource;
29 }
30
31 export interface WorkflowDetailsCardActionProps {
32     onClick: (wf: WorkflowResource) => () => void;
33 }
34
35 const mapDispatchToProps = (dispatch: Dispatch) => ({
36     onClick: (wf: WorkflowResource) =>
37         () => wf && dispatch<any>(openRunProcess(wf.uuid, wf.ownerUuid, wf.name)),
38 });
39
40 type CssRules = 'runButton' | 'propertyTag';
41
42 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
43     runButton: {
44         backgroundColor: theme.customs.colors.green700,
45         '&:hover': {
46             backgroundColor: theme.customs.colors.green800,
47         },
48         marginRight: "5px",
49         boxShadow: 'none',
50         padding: '2px 10px 2px 5px',
51         marginLeft: 'auto'
52     },
53     propertyTag: {
54         marginRight: theme.spacing.unit / 2,
55         marginBottom: theme.spacing.unit / 2
56     },
57 });
58
59 interface AuthStateDataProps {
60     auth: AuthState;
61 };
62
63 export interface RegisteredWorkflowPanelDataProps {
64     item: WorkflowResource;
65     workflowCollection: string;
66     inputParams: ProcessIOParameter[];
67     outputParams: ProcessIOParameter[];
68     gitprops: { [key: string]: string; };
69 };
70
71 export const getRegisteredWorkflowPanelData = (item: WorkflowResource, auth: AuthState): RegisteredWorkflowPanelDataProps => {
72     let inputParams: ProcessIOParameter[] = [];
73     let outputParams: ProcessIOParameter[] = [];
74     let workflowCollection = "";
75     const gitprops: { [key: string]: string; } = {};
76
77     // parse definition
78     const wfdef = parseWorkflowDefinition(item);
79
80     const inputs = getWorkflowInputs(wfdef);
81     if (inputs) {
82         inputs.forEach(elm => {
83             if (elm.default !== undefined && elm.default !== null) {
84                 elm.value = elm.default;
85             }
86         });
87         inputParams = formatInputData(inputs, auth);
88     }
89
90     const outputs = getWorkflowOutputs(wfdef);
91     if (outputs) {
92         outputParams = formatOutputData(outputs, {}, undefined, auth);
93     }
94
95     const wf = getWorkflow(wfdef);
96     if (wf) {
97         const REGEX = /keep:([0-9a-f]{32}\+\d+)\/.*/;
98         if (wf["steps"]) {
99             workflowCollection = wf["steps"][0].run.match(REGEX)[1];
100         }
101     }
102
103     for (const elm in wfdef) {
104         if (elm.startsWith("http://arvados.org/cwl#git")) {
105             gitprops[elm.substr(23)] = wfdef[elm]
106         }
107     }
108
109     return { item, workflowCollection, inputParams, outputParams, gitprops };
110 };
111
112 const mapStateToProps = (state: RootState): AuthStateDataProps => {
113     return { auth: state.auth };
114 };
115
116 export const WorkflowDetailsAttributes = connect(mapStateToProps, mapDispatchToProps)(
117     withStyles(styles)(
118         ({ workflow, onClick, auth, classes }: WorkflowDetailsCardDataProps & AuthStateDataProps & WorkflowDetailsCardActionProps & WithStyles<CssRules>) => {
119             if (!workflow) {
120                 return <Grid />
121             }
122
123             const data = getRegisteredWorkflowPanelData(workflow, auth);
124             return <Grid container>
125                 <Button onClick={workflow && onClick(workflow)} className={classes.runButton} variant='contained'
126                     data-cy='details-panel-run-btn' color='primary' size='small'>
127                     <StartIcon />
128                     Run Process
129                 </Button>
130                 <Grid item xs={12} >
131                     <DetailsAttribute
132                         label={"Workflow UUID"}
133                         linkToUuid={workflow?.uuid} />
134                 </Grid>
135                 <Grid item xs={12} >
136                     <DetailsAttribute
137                         label='Owner' linkToUuid={workflow?.ownerUuid}
138                         uuidEnhancer={(uuid: string) => <ResourceWithName uuid={uuid} />} />
139                 </Grid>
140                 <Grid item xs={12}>
141                     <DetailsAttribute label='Created at' value={formatDate(workflow?.createdAt)} />
142                 </Grid>
143                 <Grid item xs={12}>
144                     <DetailsAttribute label='Last modified' value={formatDate(workflow?.modifiedAt)} />
145                 </Grid>
146                 <Grid item xs={12} >
147                     <DetailsAttribute
148                         label='Last modified by user' linkToUuid={workflow?.modifiedByUserUuid}
149                         uuidEnhancer={(uuid: string) => <ResourceWithName uuid={uuid} />} />
150                 </Grid>
151                 <Grid item xs={12} md={12}>
152                     <DetailsAttribute label='Properties' />
153                     {Object.keys(data.gitprops).map(k =>
154                         getPropertyChip(k, data.gitprops[k], undefined, classes.propertyTag))}
155                 </Grid>
156             </Grid >;
157         }));
158
159 export class WorkflowDetails extends DetailsData<WorkflowResource> {
160     getIcon(className?: string) {
161         return <WorkflowIcon className={className} />;
162     }
163
164     getDetails() {
165         return <WorkflowDetailsAttributes workflow={this.item} />;
166     }
167 }