[ARVADOS-WORKBENCH2] updated: 1.2.1-1064-g93cb6b2
Git user
git at public.curoverse.com
Fri Nov 30 05:19:47 EST 2018
Summary of changes:
src/index.tsx | 2 +
src/models/virtual-machines.ts | 7 +-
src/services/auth-service/auth-service.ts | 3 +-
src/store/advanced-tab/advanced-tab.ts | 31 +++++-
src/store/context-menu/context-menu-actions.ts | 29 ++++--
src/store/repositories/repositories-actions.ts | 2 +-
.../virtual-machines/virtual-machines-actions.ts | 40 +++++++-
.../virtual-machines/virtual-machines-reducer.ts | 9 +-
...action-set.ts => virtual-machine-action-set.ts} | 8 +-
src/views-components/context-menu/context-menu.tsx | 3 +-
.../repository-remove-dialog.ts | 5 +-
.../attributes-dialog.tsx} | 26 ++---
.../remove-dialog.tsx} | 10 +-
.../virtual-machine-panel.tsx | 106 +++++++++++++--------
src/views/workbench/workbench.tsx | 4 +
15 files changed, 197 insertions(+), 88 deletions(-)
copy src/views-components/context-menu/action-sets/{ssh-key-action-set.ts => virtual-machine-action-set.ts} (69%)
copy src/views-components/{repository-attributes-dialog/repository-attributes-dialog.tsx => virtual-machines-dialog/attributes-dialog.tsx} (74%)
copy src/views-components/{process-remove-dialog/process-remove-dialog.tsx => virtual-machines-dialog/remove-dialog.tsx} (63%)
via 93cb6b20b9f7893c588d9679c7b904ee35238f1b (commit)
from 8623f430ea556381f8681c2aea00e43e64d3f6d1 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 93cb6b20b9f7893c588d9679c7b904ee35238f1b
Author: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
Date: Fri Nov 30 11:19:36 2018 +0100
context-menu-for-VMs
Feature #14498
Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
diff --git a/src/index.tsx b/src/index.tsx
index 801a56a..3ff8088 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -51,6 +51,7 @@ import { initAdvanceFormProjectsTree } from '~/store/search-bar/search-bar-actio
import { repositoryActionSet } from '~/views-components/context-menu/action-sets/repository-action-set';
import { sshKeyActionSet } from '~/views-components/context-menu/action-sets/ssh-key-action-set';
import { loadVocabulary } from '~/store/vocabulary/vocabulary-actions';
+import { virtualMachineActionSet } from '~/views-components/context-menu/action-sets/virtual-machine-action-set';
console.log(`Starting arvados [${getBuildInfo()}]`);
@@ -69,6 +70,7 @@ addMenuActionSet(ContextMenuKind.PROCESS_RESOURCE, processResourceActionSet);
addMenuActionSet(ContextMenuKind.TRASH, trashActionSet);
addMenuActionSet(ContextMenuKind.REPOSITORY, repositoryActionSet);
addMenuActionSet(ContextMenuKind.SSH_KEY, sshKeyActionSet);
+addMenuActionSet(ContextMenuKind.VIRTUAL_MACHINE, virtualMachineActionSet);
fetchConfig()
.then(({ config, apiHost }) => {
diff --git a/src/models/virtual-machines.ts b/src/models/virtual-machines.ts
index 0652c35..acc084a 100644
--- a/src/models/virtual-machines.ts
+++ b/src/models/virtual-machines.ts
@@ -8,11 +8,16 @@ export interface VirtualMachinesResource extends Resource {
hostname: string;
}
-export interface VirtualMachinesLoginsResource {
+export interface VirtualMachinesLoginsItems {
hostname: string;
username: string;
public_key: string;
user_uuid: string;
virtual_machine_uuid: string;
authorized_key_uuid: string;
+}
+
+export interface VirtualMachineLogins {
+ kind: string;
+ items: VirtualMachinesLoginsItems[];
}
\ No newline at end of file
diff --git a/src/services/auth-service/auth-service.ts b/src/services/auth-service/auth-service.ts
index 2c0c83d..b512fb2 100644
--- a/src/services/auth-service/auth-service.ts
+++ b/src/services/auth-service/auth-service.ts
@@ -61,8 +61,7 @@ export class AuthService {
const lastName = localStorage.getItem(USER_LAST_NAME_KEY);
const uuid = this.getUuid();
const ownerUuid = this.getOwnerUuid();
- const isAdmin = this.getIsAdmin();
- console.log(isAdmin);
+ const isAdmin = this.getIsAdmin();
return email && firstName && lastName && uuid && ownerUuid
? { email, firstName, lastName, uuid, ownerUuid, isAdmin }
diff --git a/src/store/advanced-tab/advanced-tab.ts b/src/store/advanced-tab/advanced-tab.ts
index b3c5164..2b7e883 100644
--- a/src/store/advanced-tab/advanced-tab.ts
+++ b/src/store/advanced-tab/advanced-tab.ts
@@ -16,6 +16,7 @@ import { ServiceRepository } from '~/services/services';
import { FilterBuilder } from '~/services/api/filter-builder';
import { RepositoryResource } from '~/models/repositories';
import { SshKeyResource } from '~/models/ssh-key';
+import { VirtualMachinesResource } from '~/models/virtual-machines';
export const ADVANCED_TAB_DIALOG = 'advancedTabDialog';
@@ -54,12 +55,17 @@ enum RepositoryData {
}
enum SshKeyData {
- SSH_KEY = 'authorized_keys',
+ SSH_KEY = 'authorized_key',
CREATED_AT = 'created_at'
}
-type AdvanceResourceKind = CollectionData | ProcessData | ProjectData | RepositoryData | SshKeyData;
-type AdvanceResourcePrefix = GroupContentsResourcePrefix | 'repositories' | 'authorized_keys';
+enum VirtualMachineData {
+ VIRTUAL_MACHINE = 'virtual_machine',
+ CREATED_AT = 'created_at'
+}
+
+type AdvanceResourceKind = CollectionData | ProcessData | ProjectData | RepositoryData | SshKeyData | VirtualMachineData;
+type AdvanceResourcePrefix = GroupContentsResourcePrefix | 'repositories' | 'authorized_keys' | 'virtual_machines';
export const openAdvancedTabDialog = (uuid: string, index?: number) =>
async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
@@ -90,6 +96,11 @@ export const openAdvancedTabDialog = (uuid: string, index?: number) =>
const advanceDataSshKey: AdvancedTabDialogData = advancedTabData(uuid, '', '', sshKeyApiResponse, dataSshKey, SshKeyData.SSH_KEY, 'authorized_keys', SshKeyData.CREATED_AT, dataSshKey.createdAt);
dispatch<any>(initAdvancedTabDialog(advanceDataSshKey));
break;
+ case ResourceKind.VIRTUAL_MACHINE:
+ const dataVirtualMachine = getState().virtualMachines.virtualMachines.items[index!];
+ const advanceDataVirtualMachine: AdvancedTabDialogData = advancedTabData(uuid, '', '', virtualMachineApiResponse, dataVirtualMachine, VirtualMachineData.VIRTUAL_MACHINE, 'virtual_machines', VirtualMachineData.CREATED_AT, dataVirtualMachine.createdAt);
+ dispatch<any>(initAdvancedTabDialog(advanceDataVirtualMachine));
+ break;
default:
dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Could not open advanced tab for this resource.", hideDuration: 2000, kind: SnackbarKind.ERROR }));
}
@@ -110,7 +121,7 @@ const getDataForAdvancedTab = (uuid: string) =>
const initAdvancedTabDialog = (data: AdvancedTabDialogData) => dialogActions.OPEN_DIALOG({ id: ADVANCED_TAB_DIALOG, data });
-const advancedTabData = (uuid: string, metadata: any, user: any, apiResponseKind: any, data: any, resourceKind: AdvanceResourceKind,
+const advancedTabData = (uuid: string, metadata: any, user: any, apiResponseKind: any, data: any, resourceKind: AdvanceResourceKind,
resourcePrefix: AdvanceResourcePrefix, resourceKindProperty: AdvanceResourceKind, property: any) => {
return {
uuid,
@@ -293,4 +304,16 @@ const sshKeyApiResponse = (apiResponse: SshKeyResource) => {
"created_at": "${createdAt}",
"expires_at": "${expiresAt}"`;
return response;
+};
+
+const virtualMachineApiResponse = (apiResponse: VirtualMachinesResource) => {
+ const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, hostname } = apiResponse;
+ const response = `"uuid": "${uuid}",
+"owner_uuid": "${ownerUuid}",
+"modified_by_client_uuid": ${stringify(modifiedByClientUuid)},
+"modified_by_user_uuid": ${stringify(modifiedByUserUuid)},
+"modified_at": ${stringify(modifiedAt)},
+"hostname": ${stringify(hostname)},
+"created_at": "${createdAt}"`;
+ return response;
};
\ No newline at end of file
diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts
index 5631a5e..0dbae18 100644
--- a/src/store/context-menu/context-menu-actions.ts
+++ b/src/store/context-menu/context-menu-actions.ts
@@ -15,6 +15,7 @@ import { extractUuidKind, ResourceKind } from '~/models/resource';
import { Process } from '~/store/processes/process';
import { RepositoryResource } from '~/models/repositories';
import { SshKeyResource } from '~/models/ssh-key';
+import { VirtualMachinesResource } from '~/models/virtual-machines';
export const contextMenuActions = unionize({
OPEN_CONTEXT_MENU: ofType<{ position: ContextMenuPosition, resource: ContextMenuResource }>(),
@@ -64,14 +65,26 @@ export const openCollectionFilesContextMenu = (event: React.MouseEvent<HTMLEleme
export const openRepositoryContextMenu = (event: React.MouseEvent<HTMLElement>, index: number, repository: RepositoryResource) =>
(dispatch: Dispatch, getState: () => RootState) => {
- dispatch<any>(openContextMenu(event, {
- name: '',
- uuid: repository.uuid,
- ownerUuid: repository.ownerUuid,
- kind: ResourceKind.REPOSITORY,
- menuKind: ContextMenuKind.REPOSITORY,
- index
- }));
+ dispatch<any>(openContextMenu(event, {
+ name: '',
+ uuid: repository.uuid,
+ ownerUuid: repository.ownerUuid,
+ kind: ResourceKind.REPOSITORY,
+ menuKind: ContextMenuKind.REPOSITORY,
+ index
+ }));
+ };
+
+export const openVirtualMachinesContextMenu = (event: React.MouseEvent<HTMLElement>, index: number, repository: VirtualMachinesResource) =>
+ (dispatch: Dispatch, getState: () => RootState) => {
+ dispatch<any>(openContextMenu(event, {
+ name: '',
+ uuid: repository.uuid,
+ ownerUuid: repository.ownerUuid,
+ kind: ResourceKind.VIRTUAL_MACHINE,
+ menuKind: ContextMenuKind.VIRTUAL_MACHINE,
+ index
+ }));
};
export const openSshKeyContextMenu = (event: React.MouseEvent<HTMLElement>, index: number, sshKey: SshKeyResource) =>
diff --git a/src/store/repositories/repositories-actions.ts b/src/store/repositories/repositories-actions.ts
index a672738..d617289 100644
--- a/src/store/repositories/repositories-actions.ts
+++ b/src/store/repositories/repositories-actions.ts
@@ -84,7 +84,7 @@ export const removeRepository = (uuid: string) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
await services.repositoriesService.delete(uuid);
- dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000 }));
+ dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
dispatch<any>(loadRepositoriesData());
};
diff --git a/src/store/virtual-machines/virtual-machines-actions.ts b/src/store/virtual-machines/virtual-machines-actions.ts
index 6f59c91..bb942bb 100644
--- a/src/store/virtual-machines/virtual-machines-actions.ts
+++ b/src/store/virtual-machines/virtual-machines-actions.ts
@@ -9,26 +9,36 @@ import { navigateToVirtualMachines } from "../navigation/navigation-action";
import { bindDataExplorerActions } from '~/store/data-explorer/data-explorer-action';
import { formatDate } from "~/common/formatters";
import { unionize, ofType, UnionOf } from "~/common/unionize";
-import { VirtualMachinesLoginsResource } from '~/models/virtual-machines';
+import { VirtualMachineLogins } from '~/models/virtual-machines';
import { FilterBuilder } from "~/services/api/filter-builder";
import { ListResults } from "~/services/common-service/common-resource-service";
+import { dialogActions } from '~/store/dialog/dialog-actions';
+import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
export const virtualMachinesActions = unionize({
SET_REQUESTED_DATE: ofType<string>(),
SET_VIRTUAL_MACHINES: ofType<ListResults<any>>(),
- SET_LOGINS: ofType<VirtualMachinesLoginsResource[]>(),
+ SET_LOGINS: ofType<VirtualMachineLogins>(),
SET_LINKS: ofType<ListResults<any>>()
});
export type VirtualMachineActions = UnionOf<typeof virtualMachinesActions>;
export const VIRTUAL_MACHINES_PANEL = 'virtualMachinesPanel';
+export const VIRTUAL_MACHINE_ATTRIBUTES_DIALOG = 'virtualMachineAttributesDialog';
+export const VIRTUAL_MACHINE_REMOVE_DIALOG = 'virtualMachineRemoveDialog';
export const openVirtualMachines = () =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
dispatch<any>(navigateToVirtualMachines);
};
+export const openVirtualMachineAttributes = (index: number) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const virtualMachineData = getState().virtualMachines.virtualMachines.items[index];
+ dispatch(dialogActions.OPEN_DIALOG({ id: VIRTUAL_MACHINE_ATTRIBUTES_DIALOG, data: { virtualMachineData } }));
+ };
+
const loadRequestedDate = () =>
(dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
const date = services.virtualMachineService.getRequestedDate();
@@ -47,9 +57,8 @@ export const loadVirtualMachinesData = () =>
});
dispatch(virtualMachinesActions.SET_VIRTUAL_MACHINES(virtualMachines));
dispatch(virtualMachinesActions.SET_LINKS(links));
- const getAllLogins = await services.virtualMachineService.getAllLogins();
- console.log(getAllLogins);
- dispatch(virtualMachinesActions.SET_LOGINS(getAllLogins));
+ const logins = await services.virtualMachineService.logins(virtualMachinesUuids[0]);
+ dispatch(virtualMachinesActions.SET_LOGINS(logins));
};
export const saveRequestedDate = () =>
@@ -59,6 +68,27 @@ export const saveRequestedDate = () =>
dispatch<any>(loadRequestedDate());
};
+export const openRemoveVirtualMachineDialog = (uuid: string) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(dialogActions.OPEN_DIALOG({
+ id: VIRTUAL_MACHINE_REMOVE_DIALOG,
+ data: {
+ title: 'Remove virtual machine',
+ text: 'Are you sure you want to remove this virtual machine?',
+ confirmButtonLabel: 'Remove',
+ uuid
+ }
+ }));
+ };
+
+export const removeVirtualMachine = (uuid: string) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
+ await services.virtualMachineService.delete(uuid);
+ dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
+ dispatch<any>(loadVirtualMachinesData());
+ };
+
const virtualMachinesBindedActions = bindDataExplorerActions(VIRTUAL_MACHINES_PANEL);
export const loadVirtualMachinesPanel = () =>
diff --git a/src/store/virtual-machines/virtual-machines-reducer.ts b/src/store/virtual-machines/virtual-machines-reducer.ts
index fa28417..475ad75 100644
--- a/src/store/virtual-machines/virtual-machines-reducer.ts
+++ b/src/store/virtual-machines/virtual-machines-reducer.ts
@@ -4,12 +4,12 @@
import { virtualMachinesActions, VirtualMachineActions } from '~/store/virtual-machines/virtual-machines-actions';
import { ListResults } from '~/services/common-service/common-resource-service';
-import { VirtualMachinesLoginsResource } from '~/models/virtual-machines';
+import { VirtualMachineLogins } from '~/models/virtual-machines';
interface VirtualMachines {
date: string;
virtualMachines: ListResults<any>;
- logins: VirtualMachinesLoginsResource[];
+ logins: VirtualMachineLogins;
links: ListResults<any>;
}
@@ -22,7 +22,10 @@ const initialState: VirtualMachines = {
itemsAvailable: 0,
items: []
},
- logins: [],
+ logins: {
+ kind: '',
+ items: []
+ },
links: {
kind: '',
offset: 0,
diff --git a/src/views-components/context-menu/action-sets/virtual-machine-action-set.ts b/src/views-components/context-menu/action-sets/virtual-machine-action-set.ts
new file mode 100644
index 0000000..bb04b8c
--- /dev/null
+++ b/src/views-components/context-menu/action-sets/virtual-machine-action-set.ts
@@ -0,0 +1,28 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set";
+import { AdvancedIcon, RemoveIcon, AttributesIcon } from "~/components/icon/icon";
+import { openAdvancedTabDialog } from '~/store/advanced-tab/advanced-tab';
+import { openVirtualMachineAttributes, openRemoveVirtualMachineDialog } from "~/store/virtual-machines/virtual-machines-actions";
+
+export const virtualMachineActionSet: ContextMenuActionSet = [[{
+ name: "Attributes",
+ icon: AttributesIcon,
+ execute: (dispatch, { index }) => {
+ dispatch<any>(openVirtualMachineAttributes(index!));
+ }
+}, {
+ name: "Advanced",
+ icon: AdvancedIcon,
+ execute: (dispatch, { uuid, index }) => {
+ dispatch<any>(openAdvancedTabDialog(uuid, index));
+ }
+}, {
+ name: "Remove",
+ icon: RemoveIcon,
+ execute: (dispatch, { uuid }) => {
+ dispatch<any>(openRemoveVirtualMachineDialog(uuid));
+ }
+}]];
diff --git a/src/views-components/context-menu/context-menu.tsx b/src/views-components/context-menu/context-menu.tsx
index af5aaa9..d08798f 100644
--- a/src/views-components/context-menu/context-menu.tsx
+++ b/src/views-components/context-menu/context-menu.tsx
@@ -70,5 +70,6 @@ export enum ContextMenuKind {
PROCESS_RESOURCE = 'ProcessResource',
PROCESS_LOGS = "ProcessLogs",
REPOSITORY = "Repository",
- SSH_KEY = "SshKey"
+ SSH_KEY = "SshKey",
+ VIRTUAL_MACHINE = "VirtualMachine"
}
diff --git a/src/views-components/repository-remove-dialog/repository-remove-dialog.ts b/src/views-components/repository-remove-dialog/repository-remove-dialog.ts
index 148e78b..ca51c84 100644
--- a/src/views-components/repository-remove-dialog/repository-remove-dialog.ts
+++ b/src/views-components/repository-remove-dialog/repository-remove-dialog.ts
@@ -1,20 +1,21 @@
// Copyright (C) The Arvados Authors. All rights reserved.
//
// SPDX-License-Identifier: AGPL-3.0
+
import { Dispatch, compose } from 'redux';
import { connect } from "react-redux";
import { ConfirmationDialog } from "~/components/confirmation-dialog/confirmation-dialog";
import { withDialog, WithDialogProps } from "~/store/dialog/with-dialog";
import { removeRepository, REPOSITORY_REMOVE_DIALOG } from '~/store/repositories/repositories-actions';
- const mapDispatchToProps = (dispatch: Dispatch, props: WithDialogProps<any>) => ({
+const mapDispatchToProps = (dispatch: Dispatch, props: WithDialogProps<any>) => ({
onConfirm: () => {
props.closeDialog();
dispatch<any>(removeRepository(props.data.uuid));
}
});
- export const RemoveRepositoryDialog = compose(
+export const RemoveRepositoryDialog = compose(
withDialog(REPOSITORY_REMOVE_DIALOG),
connect(null, mapDispatchToProps)
)(ConfirmationDialog);
\ No newline at end of file
diff --git a/src/views-components/virtual-machines-dialog/attributes-dialog.tsx b/src/views-components/virtual-machines-dialog/attributes-dialog.tsx
new file mode 100644
index 0000000..78b58da
--- /dev/null
+++ b/src/views-components/virtual-machines-dialog/attributes-dialog.tsx
@@ -0,0 +1,89 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, Grid } from "@material-ui/core";
+import { WithDialogProps } from "~/store/dialog/with-dialog";
+import { withDialog } from '~/store/dialog/with-dialog';
+import { VIRTUAL_MACHINE_ATTRIBUTES_DIALOG } from "~/store/virtual-machines/virtual-machines-actions";
+import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { compose } from "redux";
+import { VirtualMachinesResource } from "~/models/virtual-machines";
+
+type CssRules = 'rightContainer' | 'leftContainer' | 'spacing';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ rightContainer: {
+ textAlign: 'right',
+ paddingRight: theme.spacing.unit * 2,
+ color: theme.palette.grey["500"]
+ },
+ leftContainer: {
+ textAlign: 'left',
+ paddingLeft: theme.spacing.unit * 2
+ },
+ spacing: {
+ paddingTop: theme.spacing.unit * 2
+ },
+});
+
+interface VirtualMachineAttributesDataProps {
+ virtualMachineData: VirtualMachinesResource;
+}
+
+type VirtualMachineAttributesProps = VirtualMachineAttributesDataProps & WithStyles<CssRules>;
+
+export const VirtualMachineAttributesDialog = compose(
+ withDialog(VIRTUAL_MACHINE_ATTRIBUTES_DIALOG),
+ withStyles(styles))(
+ (props: WithDialogProps<VirtualMachineAttributesProps> & VirtualMachineAttributesProps) =>
+ <Dialog open={props.open}
+ onClose={props.closeDialog}
+ fullWidth
+ maxWidth="sm">
+ <DialogTitle>Attributes</DialogTitle>
+ <DialogContent>
+ <Typography variant="body2" className={props.classes.spacing}>
+ {props.data.virtualMachineData && attributes(props.data.virtualMachineData, props.classes)}
+ </Typography>
+ </DialogContent>
+ <DialogActions>
+ <Button
+ variant='flat'
+ color='primary'
+ onClick={props.closeDialog}>
+ Close
+ </Button>
+ </DialogActions>
+ </Dialog>
+ );
+
+const attributes = (virtualMachine: VirtualMachinesResource, classes: any) => {
+ const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, hostname } = virtualMachine;
+ return (
+ <span>
+ <Grid container direction="row">
+ <Grid item xs={5} className={classes.rightContainer}>
+ <Grid item>Hostname</Grid>
+ <Grid item>Owner uuid</Grid>
+ <Grid item>Created at</Grid>
+ <Grid item>Modified at</Grid>
+ <Grid item>Modified by user uuid</Grid>
+ <Grid item>Modified by client uuid</Grid>
+ <Grid item>uuid</Grid>
+ </Grid>
+ <Grid item xs={7} className={classes.leftContainer}>
+ <Grid item>{hostname}</Grid>
+ <Grid item>{ownerUuid}</Grid>
+ <Grid item>{createdAt}</Grid>
+ <Grid item>{modifiedAt}</Grid>
+ <Grid item>{modifiedByUserUuid}</Grid>
+ <Grid item>{modifiedByClientUuid}</Grid>
+ <Grid item>{uuid}</Grid>
+ </Grid>
+ </Grid>
+ </span>
+ );
+};
diff --git a/src/views-components/repository-remove-dialog/repository-remove-dialog.ts b/src/views-components/virtual-machines-dialog/remove-dialog.tsx
similarity index 53%
copy from src/views-components/repository-remove-dialog/repository-remove-dialog.ts
copy to src/views-components/virtual-machines-dialog/remove-dialog.tsx
index 148e78b..11ab9c4 100644
--- a/src/views-components/repository-remove-dialog/repository-remove-dialog.ts
+++ b/src/views-components/virtual-machines-dialog/remove-dialog.tsx
@@ -1,20 +1,21 @@
// Copyright (C) The Arvados Authors. All rights reserved.
//
// SPDX-License-Identifier: AGPL-3.0
+
import { Dispatch, compose } from 'redux';
import { connect } from "react-redux";
import { ConfirmationDialog } from "~/components/confirmation-dialog/confirmation-dialog";
import { withDialog, WithDialogProps } from "~/store/dialog/with-dialog";
-import { removeRepository, REPOSITORY_REMOVE_DIALOG } from '~/store/repositories/repositories-actions';
+import { VIRTUAL_MACHINE_REMOVE_DIALOG, removeVirtualMachine } from '~/store/virtual-machines/virtual-machines-actions';
- const mapDispatchToProps = (dispatch: Dispatch, props: WithDialogProps<any>) => ({
+const mapDispatchToProps = (dispatch: Dispatch, props: WithDialogProps<any>) => ({
onConfirm: () => {
props.closeDialog();
- dispatch<any>(removeRepository(props.data.uuid));
+ dispatch<any>(removeVirtualMachine(props.data.uuid));
}
});
- export const RemoveRepositoryDialog = compose(
- withDialog(REPOSITORY_REMOVE_DIALOG),
+export const RemoveVirtualMachineDialog = compose(
+ withDialog(VIRTUAL_MACHINE_REMOVE_DIALOG),
connect(null, mapDispatchToProps)
)(ConfirmationDialog);
\ No newline at end of file
diff --git a/src/views/virtual-machine-panel/virtual-machine-panel.tsx b/src/views/virtual-machine-panel/virtual-machine-panel.tsx
index 504910e..6c89554 100644
--- a/src/views/virtual-machine-panel/virtual-machine-panel.tsx
+++ b/src/views/virtual-machine-panel/virtual-machine-panel.tsx
@@ -4,20 +4,21 @@
import * as React from 'react';
import { connect } from 'react-redux';
-import { Grid, Typography, Button, Card, CardContent, TableBody, TableCell, TableHead, TableRow, Table, Tooltip } from '@material-ui/core';
+import { Grid, Typography, Button, Card, 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 { DefaultCodeSnippet } from '~/components/default-code-snippet/default-code-snippet';
import { Link } from 'react-router-dom';
-import { compose } from 'redux';
+import { compose, Dispatch } from 'redux';
import { saveRequestedDate, loadVirtualMachinesData } from '~/store/virtual-machines/virtual-machines-actions';
import { RootState } from '~/store/store';
import { ListResults } from '~/services/common-service/common-resource-service';
-import { HelpIcon } from '~/components/icon/icon';
-import { VirtualMachinesLoginsResource, VirtualMachinesResource } from '~/models/virtual-machines';
+import { HelpIcon, MoreOptionsIcon, AddIcon } from '~/components/icon/icon';
+import { VirtualMachineLogins, VirtualMachinesResource } from '~/models/virtual-machines';
import { Routes } from '~/routes/routes';
+import { openVirtualMachinesContextMenu } from '~/store/context-menu/context-menu-actions';
-type CssRules = 'button' | 'codeSnippet' | 'link' | 'linkIcon' | 'rightAlign' | 'cardWithoutMachines' | 'icon';
+type CssRules = 'button' | 'codeSnippet' | 'link' | 'linkIcon' | 'rightAlign' | 'cardWithoutMachines' | 'icon' | 'moreOptionsButton' | 'moreOptions';
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
button: {
@@ -55,26 +56,39 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
icon: {
textAlign: "right",
marginTop: theme.spacing.unit
- }
+ },
+ moreOptionsButton: {
+ padding: 0
+ },
+ moreOptions: {
+ textAlign: 'right',
+ '&:last-child': {
+ paddingRight: 0
+ }
+ },
});
const mapStateToProps = ({ virtualMachines, auth }: RootState) => {
return {
requestedDate: virtualMachines.date,
isAdmin: auth.user!.isAdmin,
+ logins: virtualMachines.logins,
...virtualMachines
};
};
-const mapDispatchToProps = {
- saveRequestedDate,
- loadVirtualMachinesData
-};
+const mapDispatchToProps = (dispatch: Dispatch): Pick<VirtualMachinesPanelActionProps, 'loadVirtualMachinesData' | 'saveRequestedDate' | 'onOptionsMenuOpen'> => ({
+ saveRequestedDate: () => dispatch<any>(saveRequestedDate()),
+ loadVirtualMachinesData: () => dispatch<any>(loadVirtualMachinesData()),
+ onOptionsMenuOpen: (event, index, virtualMachine) => {
+ dispatch<any>(openVirtualMachinesContextMenu(event, index, virtualMachine));
+ },
+});
interface VirtualMachinesPanelDataProps {
requestedDate: string;
virtualMachines: ListResults<any>;
- logins: VirtualMachinesLoginsResource[];
+ logins: VirtualMachineLogins;
links: ListResults<any>;
isAdmin: boolean;
}
@@ -82,6 +96,7 @@ interface VirtualMachinesPanelDataProps {
interface VirtualMachinesPanelActionProps {
saveRequestedDate: () => void;
loadVirtualMachinesData: () => string;
+ onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, index: number, virtualMachine: VirtualMachinesResource) => void;
}
type VirtualMachineProps = VirtualMachinesPanelActionProps & VirtualMachinesPanelDataProps & WithStyles<CssRules>;
@@ -95,12 +110,12 @@ export const VirtualMachinePanel = compose(
}
render() {
- const { virtualMachines, links } = this.props;
+ const { virtualMachines, links, isAdmin } = this.props;
return (
<Grid container spacing={16}>
{virtualMachines.itemsAvailable === 0 && <CardContentWithNoVirtualMachines {...this.props} />}
{virtualMachines.itemsAvailable > 0 && links.itemsAvailable > 0 && <CardContentWithVirtualMachines {...this.props} />}
- {<CardSSHSection {...this.props} />}
+ {!isAdmin && <CardSSHSection {...this.props} />}
</Grid>
);
}
@@ -133,24 +148,35 @@ const CardContentWithVirtualMachines = (props: VirtualMachineProps) =>
<Grid item xs={12}>
<Card>
<CardContent>
- <div className={props.classes.rightAlign}>
- <Button variant="contained" color="primary" className={props.classes.button} onClick={props.saveRequestedDate}>
- SEND REQUEST FOR SHELL ACCESS
- </Button>
- {props.requestedDate &&
- <Typography variant="body1">
- A request for shell access was sent on {props.requestedDate}
- </Typography>}
- </div>
- <div className={props.classes.icon}>
- <a href="https://doc.arvados.org/user/getting_started/vm-login-with-webshell.html" target="_blank" className={props.classes.linkIcon}>
- <Tooltip title="Access VM using webshell">
- <HelpIcon />
- </Tooltip>
- </a>
- </div>
- {console.log(props.isAdmin)}
- {props.isAdmin ? adminVirtualMachinesTable(props) : userVirtualMachinesTable(props)}
+ {props.isAdmin ?
+ <span>
+ <div className={props.classes.rightAlign}>
+ <Button variant="contained" color="primary" className={props.classes.button} onClick={props.saveRequestedDate}>
+ <AddIcon /> NEW VIRTUAL MACHINE
+ </Button>
+ </div>
+ {adminVirtualMachinesTable(props)}
+ </span> :
+ <span>
+ <div className={props.classes.rightAlign}>
+ <Button variant="contained" color="primary" className={props.classes.button} onClick={props.saveRequestedDate}>
+ SEND REQUEST FOR SHELL ACCESS
+ </Button>
+ {props.requestedDate &&
+ <Typography variant="body1">
+ A request for shell access was sent on {props.requestedDate}
+ </Typography>}
+ </div>
+ <div className={props.classes.icon}>
+ <a href="https://doc.arvados.org/user/getting_started/vm-login-with-webshell.html" target="_blank" className={props.classes.linkIcon}>
+ <Tooltip title="Access VM using webshell">
+ <HelpIcon />
+ </Tooltip>
+ </a>
+ </div>
+ {userVirtualMachinesTable(props)}
+ </span>
+ }
</CardContent>
</Card>
</Grid>;
@@ -188,19 +214,21 @@ const adminVirtualMachinesTable = (props: VirtualMachineProps) =>
<TableCell>Uuid</TableCell>
<TableCell>Host name</TableCell>
<TableCell>Logins</TableCell>
- <TableCell/>
+ <TableCell />
</TableRow>
</TableHead>
<TableBody>
- {props.virtualMachines.items.map((it, index) =>
+ {props.logins.items.length > 0 && props.virtualMachines.items.map((it, index) =>
<TableRow key={index}>
<TableCell>{it.uuid}</TableCell>
- <TableCell>shell</TableCell>
- <TableCell>ssh {getUsername(props.links, it)}@shell.arvados</TableCell>
- <TableCell>
- <a href={`https://workbench.c97qk.arvadosapi.com${it.href}/webshell/${getUsername(props.links, it)}`} target="_blank" className={props.classes.link}>
- Log in as {getUsername(props.links, it)}
- </a>
+ <TableCell>{props.logins.items[0].hostname}</TableCell>
+ <TableCell>["{props.logins.items[0].username}"]</TableCell>
+ <TableCell className={props.classes.moreOptions}>
+ <Tooltip title="More options" disableFocusListener>
+ <IconButton onClick={event => props.onOptionsMenuOpen(event, index, it)} className={props.classes.moreOptionsButton}>
+ <MoreOptionsIcon />
+ </IconButton>
+ </Tooltip>
</TableCell>
</TableRow>
)}
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index 3914f64..3fc514a 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -59,6 +59,8 @@ import { CreateSshKeyDialog } from '~/views-components/dialog-forms/create-ssh-k
import { PublicKeyDialog } from '~/views-components/ssh-keys-dialog/public-key-dialog';
import { RemoveSshKeyDialog } from '~/views-components/ssh-keys-dialog/remove-dialog';
import { AttributesSshKeyDialog } from '~/views-components/ssh-keys-dialog/attributes-dialog';
+import { VirtualMachineAttributesDialog } from '~/views-components/virtual-machines-dialog/attributes-dialog';
+import { RemoveVirtualMachineDialog } from '~/views-components/virtual-machines-dialog/remove-dialog';
type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
@@ -164,6 +166,7 @@ export const WorkbenchPanel =
<RemoveProcessDialog />
<RemoveRepositoryDialog />
<RemoveSshKeyDialog />
+ <RemoveVirtualMachineDialog />
<RenameFileDialog />
<RepositoryAttributesDialog />
<RepositoriesSampleGitDialog />
@@ -173,5 +176,6 @@ export const WorkbenchPanel =
<UpdateCollectionDialog />
<UpdateProcessDialog />
<UpdateProjectDialog />
+ <VirtualMachineAttributesDialog />
</Grid>
);
\ No newline at end of file
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list