//
// SPDX-License-Identifier: AGPL-3.0
-import * as React from 'react';
+import React from 'react';
import { connect } from 'react-redux';
-import { Grid, Card, CardContent, TableBody, TableCell, TableHead, TableRow, Table, Tooltip, IconButton } from '@material-ui/core';
+import { Grid, Card, Chip, CardContent, TableBody, TableCell, TableHead, TableRow, Table, Tooltip, IconButton } from '@material-ui/core';
import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
-import { ArvadosTheme } from '~/common/custom-theme';
+import { ArvadosTheme } from 'common/custom-theme';
import { compose, Dispatch } from 'redux';
-import { loadVirtualMachinesAdminData } from '~/store/virtual-machines/virtual-machines-actions';
-import { RootState } from '~/store/store';
-import { ListResults } from '~/services/common-service/common-service';
-import { MoreOptionsIcon } from '~/components/icon/icon';
-import { VirtualMachineLogins, VirtualMachinesResource } from '~/models/virtual-machines';
-import { openVirtualMachinesContextMenu } from '~/store/context-menu/context-menu-actions';
+import { loadVirtualMachinesAdminData, openAddVirtualMachineLoginDialog, openRemoveVirtualMachineLoginDialog, openEditVirtualMachineLoginDialog } from 'store/virtual-machines/virtual-machines-actions';
+import { RootState } from 'store/store';
+import { ListResults } from 'services/common-service/common-service';
+import { MoreOptionsIcon, AddUserIcon } from 'components/icon/icon';
+import { VirtualMachineLogins, VirtualMachinesResource } from 'models/virtual-machines';
+import { openVirtualMachinesContextMenu } from 'store/context-menu/context-menu-actions';
+import { ResourceUuid, VirtualMachineHostname, VirtualMachineLogin } from 'views-components/data-explorer/renderers';
-type CssRules = 'moreOptionsButton' | 'moreOptions';
+type CssRules = 'moreOptionsButton' | 'moreOptions' | 'chipsRoot';
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
moreOptionsButton: {
paddingRight: 0
}
},
+ chipsRoot: {
+ margin: `0px -${theme.spacing.unit / 2}px`,
+ },
});
-const mapStateToProps = ({ virtualMachines }: RootState) => {
+const mapStateToProps = (state: RootState) => {
return {
- logins: virtualMachines.logins,
- ...virtualMachines
+ userUuid: state.auth.user!.uuid,
+ ...state.virtualMachines
};
};
-const mapDispatchToProps = (dispatch: Dispatch): Pick<VirtualMachinesPanelActionProps, 'loadVirtualMachinesData' | 'onOptionsMenuOpen'> => ({
+const mapDispatchToProps = (dispatch: Dispatch): Pick<VirtualMachinesPanelActionProps, 'loadVirtualMachinesData' | 'onOptionsMenuOpen' | 'onAddLogin' | 'onDeleteLogin' | 'onLoginEdit'> => ({
loadVirtualMachinesData: () => dispatch<any>(loadVirtualMachinesAdminData()),
onOptionsMenuOpen: (event, virtualMachine) => {
dispatch<any>(openVirtualMachinesContextMenu(event, virtualMachine));
},
+ onAddLogin: (uuid: string) => {
+ dispatch<any>(openAddVirtualMachineLoginDialog(uuid));
+ },
+ onDeleteLogin: (uuid: string) => {
+ dispatch<any>(openRemoveVirtualMachineLoginDialog(uuid));
+ },
+ onLoginEdit: (uuid: string) => {
+ dispatch<any>(openEditVirtualMachineLoginDialog(uuid));
+ },
});
interface VirtualMachinesPanelDataProps {
virtualMachines: ListResults<any>;
logins: VirtualMachineLogins;
+ links: ListResults<any>;
+ userUuid: string;
}
interface VirtualMachinesPanelActionProps {
loadVirtualMachinesData: () => string;
onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, virtualMachine: VirtualMachinesResource) => void;
+ onAddLogin: (uuid: string) => void;
+ onDeleteLogin: (uuid: string) => void;
+ onLoginEdit: (uuid: string) => void;
}
type VirtualMachineProps = VirtualMachinesPanelActionProps & VirtualMachinesPanelDataProps & WithStyles<CssRules>;
</Grid>;
const virtualMachinesTable = (props: VirtualMachineProps) =>
- <Table>
+ <Table data-cy="vm-admin-table">
<TableHead>
<TableRow>
<TableCell>Uuid</TableCell>
<TableCell>Host name</TableCell>
<TableCell>Logins</TableCell>
<TableCell />
+ <TableCell />
</TableRow>
</TableHead>
<TableBody>
- {props.logins.items.length > 0 && props.virtualMachines.items.map((it, index) =>
+ {props.virtualMachines.items.map((machine, index) =>
<TableRow key={index}>
- <TableCell>{it.uuid}</TableCell>
- <TableCell>{it.hostname}</TableCell>
- <TableCell>["{props.logins.items[0].username}"]</TableCell>
+ <TableCell><ResourceUuid uuid={machine.uuid} /></TableCell>
+ <TableCell><VirtualMachineHostname uuid={machine.uuid} /></TableCell>
+ <TableCell>
+ <Grid container spacing={8} className={props.classes.chipsRoot}>
+ {props.links.items.filter((link) => (link.headUuid === machine.uuid)).map((permission, i) => (
+ <Grid item key={i}>
+ <Chip label={<VirtualMachineLogin linkUuid={permission.uuid} />} onDelete={event => props.onDeleteLogin(permission.uuid)} onClick={event => props.onLoginEdit(permission.uuid)} />
+ </Grid>
+ ))}
+ </Grid>
+ </TableCell>
+ <TableCell>
+ <Tooltip title="Add Login Permission" disableFocusListener>
+ <IconButton onClick={event => props.onAddLogin(machine.uuid)} className={props.classes.moreOptionsButton}>
+ <AddUserIcon />
+ </IconButton>
+ </Tooltip>
+ </TableCell>
<TableCell className={props.classes.moreOptions}>
<Tooltip title="More options" disableFocusListener>
- <IconButton onClick={event => props.onOptionsMenuOpen(event, it)} className={props.classes.moreOptionsButton}>
+ <IconButton onClick={event => props.onOptionsMenuOpen(event, machine)} className={props.classes.moreOptionsButton}>
<MoreOptionsIcon />
</IconButton>
</Tooltip>