Skip to content

Commit

Permalink
Bug 2104859: Add "Copy SSH command" to VM actions
Browse files Browse the repository at this point in the history
Add "Copy SSH command" option to kebab menu for the actions in the VM
list, also to Actions button in the VM details view/tabs.

Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2104859
  • Loading branch information
hstastna committed Aug 12, 2022
1 parent af4e4ec commit 287c27d
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 4 deletions.
2 changes: 1 addition & 1 deletion locales/en/plugin__kubevirt-plugin.json
Expand Up @@ -201,7 +201,7 @@
"Container disk": "Container disk",
"Container Image": "Container Image",
"Copied": "Copied",
"Copy SSH Command": "Copy SSH Command",
"Copy SSH command": "Copy SSH command",
"Copy template's boot source disk": "Copy template's boot source disk",
"Copy to clipboard": "Copy to clipboard",
"Cores": "Cores",
Expand Down
10 changes: 10 additions & 0 deletions src/views/virtualmachines/actions/VirtualMachineActionFactory.tsx
Expand Up @@ -11,6 +11,7 @@ import { LabelsModal } from '@kubevirt-utils/components/LabelsModal/LabelsModal'
import { ModalComponent } from '@kubevirt-utils/components/ModalProvider/ModalProvider';
import { asAccessReview } from '@kubevirt-utils/resources/shared';
import { Action, k8sPatch } from '@openshift-console/dynamic-plugin-sdk';
import { CopyIcon } from '@patternfly/react-icons';

import { printableVMStatus } from '../utils';

Expand Down Expand Up @@ -154,6 +155,15 @@ export const VirtualMachineActionFactory = {
// ),
// };
// },
copySSHCommand: (command: string, disabled: boolean, t: TFunction): Action => {
return {
id: 'vm-action-copy-ssh',
label: t('Copy SSH command'),
icon: <CopyIcon />,
disabled: disabled,
cta: () => command && navigator.clipboard.writeText(command),
};
},
editLabels: (
vm: V1VirtualMachine,
createModal: (modal: ModalComponent) => void,
Expand Down
@@ -0,0 +1,73 @@
import * as React from 'react';

import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { getContentScrollableElement } from '@kubevirt-utils/utils/utils';
import { Action } from '@openshift-console/dynamic-plugin-sdk';
// import { LazyActionMenu } from '@openshift-console/dynamic-plugin-sdk-internal';
import {
Dropdown,
DropdownItem,
DropdownPosition,
DropdownToggle,
KebabToggle,
} from '@patternfly/react-core';

import useVirtualMachineActionsProvider from '../../hooks/useVirtualMachineActionsProvider';

type VirtualMachinesInsanceActionsProps = { vm: V1VirtualMachine; isKebabToggle?: boolean };

const VirtualMachineActions: React.FC<VirtualMachinesInsanceActionsProps> = ({
vm,
isKebabToggle,
}) => {
const { t } = useKubevirtTranslation();
// TODO: use LazyActionMenu when fixed
// return (
// <LazyActionMenu
// variant={variant}
// key={vm?.metadata?.name}
// context={{ [VirtualMachineModelRef]: vm }}
// />
// );
const [isOpen, setIsOpen] = React.useState(false);
const [actions] = useVirtualMachineActionsProvider(vm);

const handleClick = (action: Action) => {
if (typeof action?.cta === 'function') {
action?.cta();
setIsOpen(false);
}
};

return (
<Dropdown
menuAppendTo={getContentScrollableElement}
data-test-id="virtual-machine-actions"
isPlain={isKebabToggle}
isOpen={isOpen}
position={DropdownPosition.right}
toggle={
isKebabToggle ? (
<KebabToggle onToggle={setIsOpen} />
) : (
<DropdownToggle onToggle={setIsOpen}>{t('Actions')}</DropdownToggle>
)
}
dropdownItems={actions?.map((action) => (
<DropdownItem
data-test-id={`${action.id}`}
key={action?.id}
onClick={() => handleClick(action)}
isDisabled={action?.disabled}
description={action?.description}
>
{action?.label}
{action?.icon && <span className="text-muted"> {action.icon}</span>}
</DropdownItem>
))}
/>
);
};

export default VirtualMachineActions;
Expand Up @@ -2,8 +2,11 @@ import * as React from 'react';

import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt';
import { useModal } from '@kubevirt-utils/components/ModalProvider/ModalProvider';
import useSSHService from '@kubevirt-utils/components/SSHAccess/useSSHService';
import useSSHCommand from '@kubevirt-utils/components/UserCredentials/useSSHCommand';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { VirtualMachineModelRef } from '@kubevirt-utils/models';
import { useVMIAndPodsForVM } from '@kubevirt-utils/resources/vm';
import { vmimStatuses } from '@kubevirt-utils/resources/vmim/statuses';
import { Action, useK8sModel } from '@openshift-console/dynamic-plugin-sdk';

Expand All @@ -18,11 +21,14 @@ const useVirtualMachineActionsProvider: UseVirtualMachineActionsProvider = (vm)
const { t } = useKubevirtTranslation();
const { createModal } = useModal();
const vmim = useVirtualMachineInstanceMigration(vm);
const [sshService] = useSSHService(vm);
const { vmi } = useVMIAndPodsForVM(vm?.metadata?.name, vm?.metadata?.namespace);
const { command } = useSSHCommand(vmi, sshService);

const [, inFlight] = useK8sModel(VirtualMachineModelRef);
const actions: Action[] = React.useMemo(() => {
const printableStatus = vm?.status?.printableStatus;
const { Stopped, Paused, Migrating } = printableVMStatus;
const { Stopped, Paused, Migrating, Running } = printableVMStatus;

const startOrStop =
printableStatus === Stopped
Expand All @@ -39,18 +45,24 @@ const useVirtualMachineActionsProvider: UseVirtualMachineActionsProvider = (vm)
printableStatus === Paused
? VirtualMachineActionFactory.unpause(vm, t)
: VirtualMachineActionFactory.pause(vm, t);

return [
startOrStop,
VirtualMachineActionFactory.restart(vm, t),
pauseOrUnpause,
VirtualMachineActionFactory.clone(vm, createModal, t),
migrateOrCancelMigration,
// VirtualMachineActionFactory.openConsole(vm),
VirtualMachineActionFactory.copySSHCommand(
command,
printableStatus !== Running || !sshService,
t,
),
VirtualMachineActionFactory.editLabels(vm, createModal, t),
VirtualMachineActionFactory.editAnnotations(vm, createModal, t),
VirtualMachineActionFactory.delete(vm, createModal, t),
];
}, [vm, vmim, createModal, t]);
}, [vm, vmim, command, sshService, createModal, t]);

return React.useMemo(() => [actions, !inFlight, undefined], [actions, inFlight]);
};
Expand Down
Expand Up @@ -29,6 +29,7 @@ describe('useVirtualMachineActionsProvider tests', () => {
'vm-action-pause',
'vm-action-clone',
'vm-action-migrate',
'vm-action-copy-ssh',
'vm-action-edit-labels',
'vm-action-edit-annotations',
'vm-action-delete',
Expand All @@ -52,6 +53,7 @@ describe('useVirtualMachineActionsProvider tests', () => {
'vm-action-pause',
'vm-action-clone',
'vm-action-migrate',
'vm-action-copy-ssh',
'vm-action-edit-labels',
'vm-action-edit-annotations',
'vm-action-delete',
Expand All @@ -75,6 +77,7 @@ describe('useVirtualMachineActionsProvider tests', () => {
'vm-action-unpause',
'vm-action-clone',
'vm-action-migrate',
'vm-action-copy-ssh',
'vm-action-edit-labels',
'vm-action-edit-annotations',
'vm-action-delete',
Expand All @@ -98,6 +101,7 @@ describe('useVirtualMachineActionsProvider tests', () => {
'vm-action-pause',
'vm-action-clone',
'vm-action-cancel-migrate',
'vm-action-copy-ssh',
'vm-action-edit-labels',
'vm-action-edit-annotations',
'vm-action-delete',
Expand Down
Expand Up @@ -44,7 +44,7 @@ const VirtualMachinesOverviewTabDetailsTitle: React.FC<
key="copy"
isDisabled={!isMachineRunning || !sshService}
>
{t('Copy SSH Command')}{' '}
{t('Copy SSH command')}{' '}
<span className="text-muted">
<CopyIcon />
</span>
Expand Down

0 comments on commit 287c27d

Please sign in to comment.