Merge branch '15230-fed-collection-crash' refs #15230
[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 = (state: RootState) => {
33     return {
34         logins: state.virtualMachines.logins,
35         userUuid: state.auth.user!.uuid,
36         ...state.virtualMachines
37     };
38 };
39
40 const mapDispatchToProps = (dispatch: Dispatch): Pick<VirtualMachinesPanelActionProps, 'loadVirtualMachinesData' | 'onOptionsMenuOpen'> => ({
41     loadVirtualMachinesData: () => dispatch<any>(loadVirtualMachinesAdminData()),
42     onOptionsMenuOpen: (event, virtualMachine) => {
43         dispatch<any>(openVirtualMachinesContextMenu(event, virtualMachine));
44     },
45 });
46
47 interface VirtualMachinesPanelDataProps {
48     virtualMachines: ListResults<any>;
49     logins: VirtualMachineLogins;
50     userUuid: string;
51 }
52
53 interface VirtualMachinesPanelActionProps {
54     loadVirtualMachinesData: () => string;
55     onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, virtualMachine: VirtualMachinesResource) => void;
56 }
57
58 type VirtualMachineProps = VirtualMachinesPanelActionProps & VirtualMachinesPanelDataProps & WithStyles<CssRules>;
59
60 export const VirtualMachineAdminPanel = compose(
61     withStyles(styles),
62     connect(mapStateToProps, mapDispatchToProps))(
63         class extends React.Component<VirtualMachineProps> {
64             componentDidMount() {
65                 this.props.loadVirtualMachinesData();
66             }
67
68             render() {
69                 const { virtualMachines } = this.props;
70                 return (
71                     <Grid container spacing={16}>
72                         {virtualMachines.itemsAvailable > 0 && <CardContentWithVirtualMachines {...this.props} />}
73                     </Grid>
74                 );
75             }
76         }
77     );
78
79 const CardContentWithVirtualMachines = (props: VirtualMachineProps) =>
80     <Grid item xs={12}>
81         <Card>
82             <CardContent>
83                 {virtualMachinesTable(props)}
84             </CardContent>
85         </Card>
86     </Grid>;
87
88 const virtualMachinesTable = (props: VirtualMachineProps) =>
89     <Table>
90         <TableHead>
91             <TableRow>
92                 <TableCell>Uuid</TableCell>
93                 <TableCell>Host name</TableCell>
94                 <TableCell>Logins</TableCell>
95                 <TableCell />
96             </TableRow>
97         </TableHead>
98         <TableBody>
99             {props.logins.items.length > 0 && props.virtualMachines.items.map((it, index) =>
100                 <TableRow key={index}>
101                     <TableCell>{it.uuid}</TableCell>
102                     <TableCell>{it.hostname}</TableCell>
103                     <TableCell>["{props.logins.items.map(it => it.userUuid === props.userUuid ? it.username : '')}"]</TableCell>
104                     <TableCell className={props.classes.moreOptions}>
105                         <Tooltip title="More options" disableFocusListener>
106                             <IconButton onClick={event => props.onOptionsMenuOpen(event, it)} className={props.classes.moreOptionsButton}>
107                                 <MoreOptionsIcon />
108                             </IconButton>
109                         </Tooltip>
110                     </TableCell>
111                 </TableRow>
112             )}
113         </TableBody>
114     </Table>;