From 287c27dec54bfd1242d41920fca5dcebc3385d71 Mon Sep 17 00:00:00 2001 From: Hilda Stastna Date: Mon, 8 Aug 2022 18:51:31 +0200 Subject: [PATCH] Bug 2104859: Add "Copy SSH command" to VM actions 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 --- locales/en/plugin__kubevirt-plugin.json | 2 +- .../actions/VirtualMachineActionFactory.tsx | 10 +++ .../VirtualMachineActions.tsx | 73 +++++++++++++++++++ .../hooks/useVirtualMachineActionsProvider.ts | 16 +++- .../useVirtualMachineActionsProvider.test.tsx | 4 + ...VirtualMachinesOverviewTabDetailsTitle.tsx | 2 +- 6 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 src/views/virtualmachines/actions/components/VirtualMachineActions/VirtualMachineActions.tsx diff --git a/locales/en/plugin__kubevirt-plugin.json b/locales/en/plugin__kubevirt-plugin.json index 26a7019de3..25438d880b 100644 --- a/locales/en/plugin__kubevirt-plugin.json +++ b/locales/en/plugin__kubevirt-plugin.json @@ -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", diff --git a/src/views/virtualmachines/actions/VirtualMachineActionFactory.tsx b/src/views/virtualmachines/actions/VirtualMachineActionFactory.tsx index 374d39dcfe..8cee2a76a9 100644 --- a/src/views/virtualmachines/actions/VirtualMachineActionFactory.tsx +++ b/src/views/virtualmachines/actions/VirtualMachineActionFactory.tsx @@ -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'; @@ -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: , + disabled: disabled, + cta: () => command && navigator.clipboard.writeText(command), + }; + }, editLabels: ( vm: V1VirtualMachine, createModal: (modal: ModalComponent) => void, diff --git a/src/views/virtualmachines/actions/components/VirtualMachineActions/VirtualMachineActions.tsx b/src/views/virtualmachines/actions/components/VirtualMachineActions/VirtualMachineActions.tsx new file mode 100644 index 0000000000..099dc3a6d9 --- /dev/null +++ b/src/views/virtualmachines/actions/components/VirtualMachineActions/VirtualMachineActions.tsx @@ -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 = ({ + vm, + isKebabToggle, +}) => { + const { t } = useKubevirtTranslation(); + // TODO: use LazyActionMenu when fixed + // return ( + // + // ); + const [isOpen, setIsOpen] = React.useState(false); + const [actions] = useVirtualMachineActionsProvider(vm); + + const handleClick = (action: Action) => { + if (typeof action?.cta === 'function') { + action?.cta(); + setIsOpen(false); + } + }; + + return ( + + ) : ( + {t('Actions')} + ) + } + dropdownItems={actions?.map((action) => ( + handleClick(action)} + isDisabled={action?.disabled} + description={action?.description} + > + {action?.label} + {action?.icon && {action.icon}} + + ))} + /> + ); +}; + +export default VirtualMachineActions; diff --git a/src/views/virtualmachines/actions/hooks/useVirtualMachineActionsProvider.ts b/src/views/virtualmachines/actions/hooks/useVirtualMachineActionsProvider.ts index 0fad3ccb6e..13be25285b 100644 --- a/src/views/virtualmachines/actions/hooks/useVirtualMachineActionsProvider.ts +++ b/src/views/virtualmachines/actions/hooks/useVirtualMachineActionsProvider.ts @@ -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'; @@ -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 @@ -39,6 +45,7 @@ const useVirtualMachineActionsProvider: UseVirtualMachineActionsProvider = (vm) printableStatus === Paused ? VirtualMachineActionFactory.unpause(vm, t) : VirtualMachineActionFactory.pause(vm, t); + return [ startOrStop, VirtualMachineActionFactory.restart(vm, t), @@ -46,11 +53,16 @@ const useVirtualMachineActionsProvider: UseVirtualMachineActionsProvider = (vm) 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]); }; diff --git a/src/views/virtualmachines/actions/tests/useVirtualMachineActionsProvider.test.tsx b/src/views/virtualmachines/actions/tests/useVirtualMachineActionsProvider.test.tsx index cb5ed6c71f..340c5a85ad 100644 --- a/src/views/virtualmachines/actions/tests/useVirtualMachineActionsProvider.test.tsx +++ b/src/views/virtualmachines/actions/tests/useVirtualMachineActionsProvider.test.tsx @@ -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', @@ -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', @@ -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', @@ -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', diff --git a/src/views/virtualmachines/details/tabs/overview/components/VirtualMachinesOverviewTabDetails/components/VirtualMachinesOverviewTabDetailsTitle.tsx b/src/views/virtualmachines/details/tabs/overview/components/VirtualMachinesOverviewTabDetails/components/VirtualMachinesOverviewTabDetailsTitle.tsx index a4ae74cd66..a11cba86b1 100644 --- a/src/views/virtualmachines/details/tabs/overview/components/VirtualMachinesOverviewTabDetails/components/VirtualMachinesOverviewTabDetailsTitle.tsx +++ b/src/views/virtualmachines/details/tabs/overview/components/VirtualMachinesOverviewTabDetails/components/VirtualMachinesOverviewTabDetailsTitle.tsx @@ -44,7 +44,7 @@ const VirtualMachinesOverviewTabDetailsTitle: React.FC< key="copy" isDisabled={!isMachineRunning || !sshService} > - {t('Copy SSH Command')}{' '} + {t('Copy SSH command')}{' '}