4b658452175ad96b8a323d3fca34686feaa5a78b
[arvados-workbench2.git] / src / views / workflow-panel / registered-workflow-panel.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 {
7     StyleRulesCallback,
8     WithStyles,
9     withStyles,
10     Grid,
11     Tooltip,
12     Typography,
13     Card,
14     CardHeader,
15     IconButton,
16 } from '@material-ui/core';
17 import { Dispatch } from "redux";
18 import { connect, DispatchProp } from "react-redux";
19 import { RouteComponentProps } from 'react-router';
20 import { ArvadosTheme } from 'common/custom-theme';
21 import { RootState } from 'store/store';
22 import { WorkflowIcon, MoreOptionsIcon } from 'components/icon/icon';
23 import { WorkflowResource } from 'models/workflow';
24 import { ProcessOutputCollectionFiles } from 'views/process-panel/process-output-collection-files';
25 import { WorkflowDetailsAttributes, RegisteredWorkflowPanelDataProps, getRegisteredWorkflowPanelData } from 'views-components/details-panel/workflow-details';
26 import { getResource } from 'store/resources/resources';
27 import { openContextMenu, resourceUuidToContextMenuKind } from 'store/context-menu/context-menu-actions';
28 import { MPVContainer, MPVPanelContent, MPVPanelState } from 'components/multi-panel-view/multi-panel-view';
29 import { ProcessIOCard, ProcessIOCardType } from 'views/process-panel/process-io-card';
30
31 type CssRules = 'root'
32     | 'button'
33     | 'infoCard'
34     | 'propertiesCard'
35     | 'filesCard'
36     | 'iconHeader'
37     | 'tag'
38     | 'label'
39     | 'value'
40     | 'link'
41     | 'centeredLabel'
42     | 'warningLabel'
43     | 'collectionName'
44     | 'readOnlyIcon'
45     | 'header'
46     | 'title'
47     | 'avatar';
48
49 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
50     root: {
51         width: '100%',
52     },
53     button: {
54         cursor: 'pointer'
55     },
56     infoCard: {
57         paddingLeft: theme.spacing.unit * 2,
58         paddingRight: theme.spacing.unit * 2,
59         paddingBottom: theme.spacing.unit * 2,
60     },
61     propertiesCard: {
62         padding: 0,
63     },
64     filesCard: {
65         padding: 0,
66     },
67     iconHeader: {
68         fontSize: '1.875rem',
69         color: theme.customs.colors.greyL
70     },
71     tag: {
72         marginRight: theme.spacing.unit / 2,
73         marginBottom: theme.spacing.unit / 2
74     },
75     label: {
76         fontSize: '0.875rem',
77     },
78     centeredLabel: {
79         fontSize: '0.875rem',
80         textAlign: 'center'
81     },
82     warningLabel: {
83         fontStyle: 'italic'
84     },
85     collectionName: {
86         flexDirection: 'column',
87     },
88     value: {
89         textTransform: 'none',
90         fontSize: '0.875rem'
91     },
92     link: {
93         fontSize: '0.875rem',
94         color: theme.palette.primary.main,
95         '&:hover': {
96             cursor: 'pointer'
97         }
98     },
99     readOnlyIcon: {
100         marginLeft: theme.spacing.unit,
101         fontSize: 'small',
102     },
103     header: {
104         paddingTop: theme.spacing.unit,
105         paddingBottom: theme.spacing.unit,
106     },
107     title: {
108         overflow: 'hidden',
109         paddingTop: theme.spacing.unit * 0.5,
110         color: theme.customs.colors.green700,
111     },
112     avatar: {
113         alignSelf: 'flex-start',
114         paddingTop: theme.spacing.unit * 0.5
115     },
116 });
117
118 type RegisteredWorkflowPanelProps = RegisteredWorkflowPanelDataProps & DispatchProp & WithStyles<CssRules>
119
120 export const RegisteredWorkflowPanel = withStyles(styles)(connect(
121     (state: RootState, props: RouteComponentProps<{ id: string }>) => {
122         const item = getResource<WorkflowResource>(props.match.params.id)(state.resources);
123         if (item) {
124             return getRegisteredWorkflowPanelData(item, state.auth);
125         }
126         return { item, inputParams: [], outputParams: [], workflowCollection: "", gitprops: {} };
127     })(
128         class extends React.Component<RegisteredWorkflowPanelProps> {
129             render() {
130                 const { classes, item, inputParams, outputParams, workflowCollection } = this.props;
131                 const panelsData: MPVPanelState[] = [
132                     { name: "Details" },
133                     { name: "Inputs" },
134                     { name: "Outputs" },
135                     { name: "Files" },
136                 ];
137                 return item
138                     ? <MPVContainer className={classes.root} spacing={8} direction="column" justify-content="flex-start" wrap="nowrap" panelStates={panelsData}>
139                         <MPVPanelContent xs="auto" data-cy='registered-workflow-info-panel'>
140                             <Card className={classes.infoCard}>
141                                 <CardHeader
142                                     className={classes.header}
143                                     classes={{
144                                         content: classes.title,
145                                         avatar: classes.avatar,
146                                     }}
147                                     avatar={<WorkflowIcon className={classes.iconHeader} />}
148                                     title={
149                                         <Tooltip title={item.name} placement="bottom-start">
150                                             <Typography noWrap variant='h6'>
151                                                 {item.name}
152                                             </Typography>
153                                         </Tooltip>
154                                     }
155                                     subheader={
156                                         <Tooltip title={item.description || '(no-description)'} placement="bottom-start">
157                                             <Typography noWrap variant='body1' color='inherit'>
158                                                 {item.description || '(no-description)'}
159                                             </Typography>
160                                         </Tooltip>}
161                                     action={
162                                         <Tooltip title="More options" disableFocusListener>
163                                             <IconButton
164                                                 aria-label="More options"
165                                                 onClick={event => this.handleContextMenu(event)}>
166                                                 <MoreOptionsIcon />
167                                             </IconButton>
168                                         </Tooltip>}
169
170                                 />
171
172                                 <Grid container justify="space-between">
173                                     <Grid item xs={12}>
174                                         <WorkflowDetailsAttributes workflow={item} />
175                                     </Grid>
176                                 </Grid>
177                             </Card>
178                         </MPVPanelContent>
179                         <MPVPanelContent forwardProps xs data-cy="process-inputs">
180                             <ProcessIOCard
181                                 label={ProcessIOCardType.INPUT}
182                                 params={inputParams}
183                                 raw={{}}
184                                 showParams={true}
185                             />
186                         </MPVPanelContent>
187                         <MPVPanelContent forwardProps xs data-cy="process-outputs">
188                             <ProcessIOCard
189                                 label={ProcessIOCardType.OUTPUT}
190                                 params={outputParams}
191                                 raw={{}}
192                                 showParams={true}
193                             />
194                         </MPVPanelContent>
195                         <MPVPanelContent xs>
196                             <Card className={classes.filesCard}>
197                                 <ProcessOutputCollectionFiles isWritable={false} currentItemUuid={workflowCollection} />
198                             </Card>
199                         </MPVPanelContent>
200                     </MPVContainer>
201                     : null;
202             }
203
204             handleContextMenu = (event: React.MouseEvent<any>) => {
205                 const { uuid, ownerUuid, name, description,
206                     kind } = this.props.item;
207                 const menuKind = this.props.dispatch<any>(resourceUuidToContextMenuKind(uuid));
208                 const resource = {
209                     uuid,
210                     ownerUuid,
211                     name,
212                     description,
213                     kind,
214                     menuKind,
215                 };
216                 // Avoid expanding/collapsing the panel
217                 event.stopPropagation();
218                 this.props.dispatch<any>(openContextMenu(event, resource));
219             }
220         }
221     )
222 );