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