Merge branch '22204-group-sharing' refs #22204
[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, Typography } 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' | 'workflowName';
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         height: "50vh",
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         height: "50vh",
41         marginTop: theme.spacing(1),
42     },
43     inputsTable: {
44         tableLayout: 'fixed',
45     },
46     workflowName: {
47         minHeight: "4rem",
48     }
49 });
50
51 type WorkflowDetailsCardProps = WorkflowDetailsCardDataProps & WithStyles<CssRules>;
52
53 export const WorkflowDetailsCard = withStyles(styles)(
54     class extends React.Component<WorkflowDetailsCardProps> {
55         state = {
56             value: 0,
57         };
58
59         handleChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
60             this.setState({ value });
61         }
62
63         render() {
64             const { classes, workflow } = this.props;
65             const { value } = this.state;
66             return <div className={classes.root}>
67                 <Typography className={classes.workflowName} variant='h6'>
68                     {workflow && workflow.name}
69                 </Typography>
70                 <Tabs value={value} onChange={this.handleChange} centered={true}>
71                     <Tab className={classes.tab} label="Description" />
72                     <Tab className={classes.tab} label="Inputs" />
73                     <Tab className={classes.tab} label="Details" />
74                 </Tabs>
75                 {value === 0 && <CardContent className={classes.descriptionTab}>
76                     {workflow ? <div dangerouslySetInnerHTML={{ __html: workflow.description || '(no-description)' }}></div> : (
77                         <DataTableDefaultView
78                             icon={WorkflowIcon}
79                             messages={['Please select a workflow to see its description.']} />
80                     )}
81                 </CardContent>}
82                 {value === 1 && <CardContent className={classes.inputTab}>
83                     {workflow
84                     ? this.renderInputsTable()
85                     : <DataTableDefaultView
86                           icon={WorkflowIcon}
87                           messages={['Please select a workflow to see its inputs.']} />
88                     }
89                 </CardContent>}
90                 {value === 2 && <CardContent className={classes.descriptionTab}>
91                     {workflow
92                     ? <WorkflowDetailsAttributes workflow={workflow} />
93                     : <DataTableDefaultView
94                           icon={WorkflowIcon}
95                           messages={['Please select a workflow to see its details.']} />
96                     }
97                 </CardContent>}
98             </div>;
99         }
100
101         get inputs() {
102             if (this.props.workflow) {
103                 const definition = parseWorkflowDefinition(this.props.workflow);
104                 if (definition) {
105                     return getWorkflowInputs(definition);
106                 }
107             }
108             return undefined;
109         }
110
111         renderInputsTable() {
112             return <Table className={this.props.classes.inputsTable}>
113                 <TableHead>
114                     <TableRow>
115                         <TableCell>Label</TableCell>
116                         <TableCell>Type</TableCell>
117                         <TableCell>Description</TableCell>
118                     </TableRow>
119                 </TableHead>
120                 <TableBody>
121                     {this.inputs && this.inputs.map(input =>
122                         <TableRow key={input.id}>
123                             <TableCell>{getInputLabel(input)}</TableCell>
124                             <TableCell>{stringifyInputType(input)}</TableCell>
125                             <TableCell>{input.doc}</TableCell>
126                         </TableRow>)}
127                 </TableBody>
128             </Table>;
129         }
130     });