Merge branch 'master' into 13969-advanced-tab
[arvados-workbench2.git] / src / views / workflow-panel / workflow-description-card.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import {
7     StyleRulesCallback,
8     WithStyles,
9     withStyles,
10     CardContent,
11     Tab,
12     Tabs,
13     Table,
14     TableHead,
15     TableCell,
16     TableBody,
17     TableRow
18 } from '@material-ui/core';
19 import { ArvadosTheme } from '~/common/custom-theme';
20 import { WorkflowIcon } from '~/components/icon/icon';
21 import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
22 import { WorkflowResource, parseWorkflowDefinition, getWorkflowInputs, getInputLabel, stringifyInputType } from '~/models/workflow';
23 import { WorkflowGraph } from "~/views/workflow-panel/workflow-graph";
24
25 export type CssRules = 'root' | 'tab' | 'inputTab' | 'descriptionTab' | 'inputsTable';
26
27 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
28     root: {
29         height: '100%'
30     },
31     tab: {
32         minWidth: '33%'
33     },
34     inputTab: {
35         overflow: 'auto',
36         maxHeight: '300px',
37         marginTop: theme.spacing.unit,
38         '&:last-child': {
39             paddingBottom: theme.spacing.unit / 2,
40         }
41     },
42     descriptionTab: {
43         overflow: 'auto',
44         maxHeight: '300px',
45         marginTop: theme.spacing.unit,
46     },
47     inputsTable: {
48         tableLayout: 'fixed',
49     },
50 });
51
52 interface WorkflowDetailsCardDataProps {
53     workflow?: WorkflowResource;
54 }
55
56 type WorkflowDetailsCardProps = WorkflowDetailsCardDataProps & WithStyles<CssRules>;
57
58 export const WorkflowDetailsCard = withStyles(styles)(
59     class extends React.Component<WorkflowDetailsCardProps> {
60         state = {
61             value: 0,
62         };
63
64         handleChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
65             this.setState({ value });
66         }
67
68         render() {
69             const { classes, workflow } = this.props;
70             const { value } = this.state;
71             return <div className={classes.root}>
72                 <Tabs value={value} onChange={this.handleChange} centered={true}>
73                     <Tab className={classes.tab} label="Description" />
74                     <Tab className={classes.tab} label="Inputs" />
75                     <Tab className={classes.tab} label="Graph" />
76                 </Tabs>
77                 {value === 0 && <CardContent className={classes.descriptionTab}>
78                     {workflow ? <div>
79                         {workflow.description}
80                     </div> : (
81                             <DataTableDefaultView
82                                 icon={WorkflowIcon}
83                                 messages={['Please select a workflow to see its description.']} />
84                         )}
85                 </CardContent>}
86                 {value === 1 && <CardContent className={classes.inputTab}>
87                     {workflow
88                         ? this.renderInputsTable()
89                         : <DataTableDefaultView
90                             icon={WorkflowIcon}
91                             messages={['Please select a workflow to see its inputs.']} />
92                     }
93                 </CardContent>}
94                 {value === 2 && <CardContent className={classes.inputTab}>
95                     {workflow
96                         ? <WorkflowGraph workflow={workflow} />
97                         : <DataTableDefaultView
98                             icon={WorkflowIcon}
99                             messages={['Please select a workflow to see its visualisation.']} />
100                     }
101                 </CardContent>}
102             </div>;
103         }
104
105         get inputs() {
106             if (this.props.workflow) {
107                 const definition = parseWorkflowDefinition(this.props.workflow);
108                 if (definition) {
109                     return getWorkflowInputs(definition);
110                 }
111             }
112             return;
113         }
114
115         renderInputsTable() {
116             return <Table className={this.props.classes.inputsTable}>
117                 <TableHead>
118                     <TableRow>
119                         <TableCell>Label</TableCell>
120                         <TableCell>Type</TableCell>
121                         <TableCell>Description</TableCell>
122                     </TableRow>
123                 </TableHead>
124                 <TableBody>
125                     {this.inputs && this.inputs.map(input =>
126                         <TableRow key={input.id}>
127                             <TableCell>{getInputLabel(input)}</TableCell>
128                             <TableCell>{stringifyInputType(input)}</TableCell>
129                             <TableCell>{input.doc}</TableCell>
130                         </TableRow>)}
131                 </TableBody>
132             </Table>;
133         }
134     });