Merge branch 'master' into 14582-missing-output-link-inside-process-views
[arvados-workbench2.git] / src / views / virtual-machine-panel / virtual-machine-admin-panel.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 { connect } from 'react-redux';
7 import { Grid, Card, CardContent, TableBody, TableCell, TableHead, TableRow, Table, Tooltip, IconButton } from '@material-ui/core';
8 import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
9 import { ArvadosTheme } from '~/common/custom-theme';
10 import { compose, Dispatch } from 'redux';
11 import { loadVirtualMachinesAdminData } from '~/store/virtual-machines/virtual-machines-actions';
12 import { RootState } from '~/store/store';
13 import { ListResults } from '~/services/common-service/common-service';
14 import { MoreOptionsIcon } from '~/components/icon/icon';
15 import { VirtualMachineLogins, VirtualMachinesResource } from '~/models/virtual-machines';
16 import { openVirtualMachinesContextMenu } from '~/store/context-menu/context-menu-actions';
17
18 type CssRules = 'moreOptionsButton' | 'moreOptions';
19
20 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
21     moreOptionsButton: {
22         padding: 0
23     },
24     moreOptions: {
25         textAlign: 'right',
26         '&:last-child': {
27             paddingRight: 0
28         }
29     },
30 });
31
32 const mapStateToProps = ({ virtualMachines }: RootState) => {
33     return {
34         logins: virtualMachines.logins,
35         ...virtualMachines
36     };
37 };
38
39 const mapDispatchToProps = (dispatch: Dispatch): Pick<VirtualMachinesPanelActionProps, 'loadVirtualMachinesData' | 'onOptionsMenuOpen'> => ({
40     loadVirtualMachinesData: () => dispatch<any>(loadVirtualMachinesAdminData()),
41     onOptionsMenuOpen: (event, virtualMachine) => {
42         dispatch<any>(openVirtualMachinesContextMenu(event, virtualMachine));
43     },
44 });
45
46 interface VirtualMachinesPanelDataProps {
47     virtualMachines: ListResults<any>;
48     logins: VirtualMachineLogins;
49 }
50
51 interface VirtualMachinesPanelActionProps {
52     loadVirtualMachinesData: () => string;
53     onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, virtualMachine: VirtualMachinesResource) => void;
54 }
55
56 type VirtualMachineProps = VirtualMachinesPanelActionProps & VirtualMachinesPanelDataProps & WithStyles<CssRules>;
57
58 export const VirtualMachineAdminPanel = compose(
59     withStyles(styles),
60     connect(mapStateToProps, mapDispatchToProps))(
61         class extends React.Component<VirtualMachineProps> {
62             componentDidMount() {
63                 this.props.loadVirtualMachinesData();
64             }
65
66             render() {
67                 const { virtualMachines } = this.props;
68                 return (
69                     <Grid container spacing={16}>
70                         {virtualMachines.itemsAvailable > 0 && <CardContentWithVirtualMachines {...this.props} />}
71                     </Grid>
72                 );
73             }
74         }
75     );
76
77 const CardContentWithVirtualMachines = (props: VirtualMachineProps) =>
78     <Grid item xs={12}>
79         <Card>
80             <CardContent>
81                 {virtualMachinesTable(props)}
82             </CardContent>
83         </Card>
84     </Grid>;
85
86 const virtualMachinesTable = (props: VirtualMachineProps) =>
87     <Table>
88         <TableHead>
89             <TableRow>
90                 <TableCell>Uuid</TableCell>
91                 <TableCell>Host name</TableCell>
92                 <TableCell>Logins</TableCell>
93                 <TableCell />
94             </TableRow>
95         </TableHead>
96         <TableBody>
97             {props.logins.items.length > 0 && props.virtualMachines.items.map((it, index) =>
98                 <TableRow key={index}>
99                     <TableCell>{it.uuid}</TableCell>
100                     <TableCell>{it.hostname}</TableCell>
101                     <TableCell>["{props.logins.items[0].username}"]</TableCell>
102                     <TableCell className={props.classes.moreOptions}>
103                         <Tooltip title="More options" disableFocusListener>
104                             <IconButton onClick={event => props.onOptionsMenuOpen(event, it)} className={props.classes.moreOptionsButton}>
105                                 <MoreOptionsIcon />
106                             </IconButton>
107                         </Tooltip>
108                     </TableCell>
109                 </TableRow>
110             )}
111         </TableBody>
112     </Table>;