From d67acb61910f605c62826a16e39aaddba5f3d04f Mon Sep 17 00:00:00 2001 From: yaacov Date: Sun, 22 Dec 2019 16:52:12 +0200 Subject: [PATCH 1/7] kubevirt: add list columns --- .../src/components/resource-link-popover.scss | 10 ++ .../src/components/resource-link-popover.tsx | 51 +++++++ .../kubevirt-plugin/src/components/vms/vm.tsx | 134 +++++++++++++++--- 3 files changed, 174 insertions(+), 21 deletions(-) create mode 100644 frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss create mode 100644 frontend/packages/kubevirt-plugin/src/components/resource-link-popover.tsx diff --git a/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss b/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss new file mode 100644 index 00000000000..ac2d15e66e6 --- /dev/null +++ b/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss @@ -0,0 +1,10 @@ +.kubevirt-resource-link-popover { + cursor: pointer; + text-decoration-line: underline; + text-decoration-style: dotted; + width: max-content; +} + +.kubevirt-resource-link-popover__disabled { + color: #737679; +} diff --git a/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.tsx b/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.tsx new file mode 100644 index 00000000000..64038c61393 --- /dev/null +++ b/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.tsx @@ -0,0 +1,51 @@ +import * as React from 'react'; +import { Popover, Button, Text } from '@patternfly/react-core'; +import { ArrowIcon } from '@patternfly/react-icons'; +import { resourcePath } from '@console/internal/components/utils'; + +import './resource-link-popover.scss'; + +export const ResourceLinkPopover: React.FC = ({ + kind, + name, + namespace, + className, + isDisabled, + message, + linkMessage, + children, +}) => ( + + {linkMessage} + + ) + } + > + + {message} + + +); + +export type ResourceLinkPopoverProps = { + kind?: string; + name: string; + namespace: string; + className?: string; + isDisabled?: boolean; + message: string; + linkMessage?: string; + children: React.ReactNode; +}; diff --git a/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx index 5c940c7aa75..7570b9d1188 100644 --- a/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import * as _ from 'lodash'; import * as classNames from 'classnames'; import { sortable } from '@patternfly/react-table'; import { @@ -9,30 +10,39 @@ import { K8sEntityMap, dimensifyHeader, dimensifyRow, + Status, } from '@console/shared'; -import { NamespaceModel, PodModel } from '@console/internal/models'; +import { NamespaceModel, PodModel, NodeModel } from '@console/internal/models'; import { Table, MultiListPage, TableRow, TableData } from '@console/internal/components/factory'; import { FirehoseResult, Kebab, ResourceLink } from '@console/internal/components/utils'; +import { fromNow } from '@console/internal/components/utils/datetime'; import { K8sResourceKind, PodKind } from '@console/internal/module/k8s'; +import { getPhase } from '@console/noobaa-storage-plugin/src/utils'; import { VMStatus } from '../vm-status/vm-status'; import { VirtualMachineInstanceMigrationModel, VirtualMachineInstanceModel, VirtualMachineModel, } from '../../models'; +import { ResourceLinkPopover } from '../resource-link-popover'; import { VMIKind, VMKind } from '../../types'; import { getMigrationVMIName, isMigrating } from '../../selectors/vmi-migration'; import { getBasicID, getLoadedData, getResource } from '../../utils'; import { getVMStatus } from '../../statuses/vm/vm'; +import { getVmiIpAddresses } from '../../selectors/vmi'; import { vmStatusFilter } from './table-filters'; import { menuActions } from './menu-actions'; import './vm.scss'; const tableColumnClasses = [ - classNames('col-lg-4', 'col-md-4', 'col-sm-6', 'col-xs-6'), - classNames('col-lg-4', 'col-md-4', 'hidden-sm', 'hidden-xs'), - classNames('col-lg-4', 'col-md-4', 'col-sm-6', 'col-xs-6'), + classNames('col-lg-2', 'col-md-2', 'col-sm-6', 'col-xs-6'), + classNames('col-lg-2', 'col-md-2', 'hidden-sm', 'hidden-xs'), + classNames('col-lg-2', 'col-md-2', 'hidden-sm', 'hidden-xs'), + classNames('col-lg-2', 'col-md-2', 'col-sm-3', 'col-xs-3'), + classNames('col-lg-2', 'col-md-2', 'hidden-sm', 'hidden-xs'), + classNames('col-lg-2', 'col-md-2', 'hidden-sm', 'hidden-xs'), + classNames('col-lg-2', 'col-md-2', 'col-sm-3', 'col-xs-3'), Kebab.columnClass, ]; @@ -44,6 +54,11 @@ const VMHeader = () => sortField: 'metadata.name', transforms: [sortable], }, + { + title: 'Instance', + sortFunc: 'string', + transforms: [sortable], + }, { title: 'Namespace', sortField: 'metadata.namespace', @@ -54,6 +69,20 @@ const VMHeader = () => sortFunc: 'string', transforms: [sortable], }, + { + title: 'Created', + sortField: 'metadata.creationTimestamp', + transforms: [sortable], + }, + { + title: 'Node', + sortFunc: 'string', + transforms: [sortable], + }, + { + title: 'IP Address', + sortFunc: 'string', + }, { title: '', }, @@ -62,42 +91,103 @@ const VMHeader = () => ); const VMRow: React.FC = ({ - obj: vm, + obj, customData: { pods, migrations, vmiLookup, migrationLookup }, index, key, style, }) => { const dimensify = dimensifyRow(tableColumnClasses); - const name = getName(vm); - const namespace = getNamespace(vm); - const uid = getUID(vm); - const lookupID = getBasicID(vm); - + const name = getName(obj); + const namespace = getNamespace(obj); + const uid = getUID(obj); + const lookupID = getBasicID(obj); const migration = migrationLookup[lookupID]; - const vmi = vmiLookup[lookupID]; - const vmStatus = getVMStatus({ vm, vmi, pods, migrations }); + + let vm = null; + let vmi = null; + let status = null; + let vmStatus = null; + let actions = [Kebab.factory.ModifyLabels, Kebab.factory.ModifyAnnotations, Kebab.factory.Delete]; + + if (obj.kind === VirtualMachineModel.kind) { + vm = obj as VMKind; + vmi = vmiLookup[lookupID]; + vmStatus = getVMStatus({ vm: vm as VMKind, vmi, pods, migrations }); + status = ; + actions = menuActions; + } else { + vmi = obj as VMIKind; + status = ; + } return ( - + {vm ? ( + + ) : ( + +
+ This VMI doesn’t have an owner VM since it might have been created outside of the + console. +
+
+ )} +
+ + {vmi ? ( + + ) : ( + +
+ This VMI is currently off. +
+ For further details please click its owner VM link below. +
+
+ )}
+ {status} + + {vmi && fromNow(vmi.metadata.creationTimestamp)} + - + {vmi && vmi.status.nodeName && ( + + )} + {vmi && getVmiIpAddresses(vmi)} { - return action(VirtualMachineModel, vm, { + options={actions.map((action) => + action(vm ? VirtualMachineModel : VirtualMachineInstanceModel, obj, { vmStatus, migration, vmi, - }); - })} + }), + )} key={`kebab-for-${uid}`} id={`kebab-for-${uid}`} /> @@ -171,7 +261,9 @@ export const VirtualMachinesPage: React.FC = (props) = }), ]; - const flatten = ({ vms }) => getLoadedData(vms, []); + const flatten = ({ vms, vmis }) => + _.unionBy(getLoadedData(vms, []), getLoadedData(vmis, []), getName); + const createAccessReview = skipAccessReview ? null : { model: VirtualMachineModel, namespace }; return ( @@ -192,7 +284,7 @@ export const VirtualMachinesPage: React.FC = (props) = }; type VMRowProps = { - obj: VMKind; + obj: VMKind | VMIKind; index: number; key: string; style: object; @@ -205,7 +297,7 @@ type VMRowProps = { }; type VMListProps = { - data: VMKind[]; + data: (VMKind | VMIKind)[]; resources: { pods: FirehoseResult; migrations: FirehoseResult; From 466cf4a3d39df171529a2d6af550b19fbca9f6b1 Mon Sep 17 00:00:00 2001 From: yaacov Date: Tue, 24 Dec 2019 17:05:23 +0200 Subject: [PATCH 2/7] use scss vars --- .../kubevirt-plugin/src/components/resource-link-popover.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss b/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss index ac2d15e66e6..ee539a52d43 100644 --- a/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss +++ b/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss @@ -6,5 +6,5 @@ } .kubevirt-resource-link-popover__disabled { - color: #737679; + color: var(--pf-global--disabled-color--200); } From 0a543f77a63cbdd750e40b58b3c3ca7debaedbf4 Mon Sep 17 00:00:00 2001 From: yaacov Date: Tue, 24 Dec 2019 17:27:17 +0200 Subject: [PATCH 3/7] don't use let null --- .../kubevirt-plugin/src/components/vms/vm.tsx | 14 +++++++------- .../kubevirt-plugin/src/selectors/vmi/basic.ts | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx index 7570b9d1188..0da117ab7e9 100644 --- a/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx @@ -29,7 +29,7 @@ import { VMIKind, VMKind } from '../../types'; import { getMigrationVMIName, isMigrating } from '../../selectors/vmi-migration'; import { getBasicID, getLoadedData, getResource } from '../../utils'; import { getVMStatus } from '../../statuses/vm/vm'; -import { getVmiIpAddresses } from '../../selectors/vmi'; +import { getVmiIpAddresses, getVMINodeName } from '../../selectors/vmi'; import { vmStatusFilter } from './table-filters'; import { menuActions } from './menu-actions'; @@ -104,10 +104,10 @@ const VMRow: React.FC = ({ const lookupID = getBasicID(obj); const migration = migrationLookup[lookupID]; - let vm = null; - let vmi = null; - let status = null; - let vmStatus = null; + let vm: VMKind; + let vmi: VMIKind; + let status: React.ReactNode; + let vmStatus; let actions = [Kebab.factory.ModifyLabels, Kebab.factory.ModifyAnnotations, Kebab.factory.Delete]; if (obj.kind === VirtualMachineModel.kind) { @@ -174,8 +174,8 @@ const VMRow: React.FC = ({ {vmi && fromNow(vmi.metadata.creationTimestamp)} - {vmi && vmi.status.nodeName && ( - + {getVMINodeName(vmi) && ( + )} {vmi && getVmiIpAddresses(vmi)} diff --git a/frontend/packages/kubevirt-plugin/src/selectors/vmi/basic.ts b/frontend/packages/kubevirt-plugin/src/selectors/vmi/basic.ts index d11bd5edc8e..a27fcf33b0e 100644 --- a/frontend/packages/kubevirt-plugin/src/selectors/vmi/basic.ts +++ b/frontend/packages/kubevirt-plugin/src/selectors/vmi/basic.ts @@ -24,3 +24,5 @@ export const isVMIRunning = (vmi: VMIKind) => vmi && vmi.status && vmi.status.ph export const getVMIInterfaces = (vmi: VMIKind) => (vmi && vmi.status && vmi.status.interfaces) || []; + +export const getVMINodeName = (vmi: VMIKind) => vmi && vmi.status && vmi.status.nodeName; From 40b00821249bbe70f10c327e3226bb2e62d86b8b Mon Sep 17 00:00:00 2001 From: yaacov Date: Tue, 24 Dec 2019 17:45:03 +0200 Subject: [PATCH 4/7] make gray gray again --- .../console-shared/src/components/status/statuses.tsx | 5 ++--- .../src/components/resource-link-popover.scss | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/frontend/packages/console-shared/src/components/status/statuses.tsx b/frontend/packages/console-shared/src/components/status/statuses.tsx index ee4950b7d68..affaf9b12c1 100644 --- a/frontend/packages/console-shared/src/components/status/statuses.tsx +++ b/frontend/packages/console-shared/src/components/status/statuses.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; -import { InfoCircleIcon, HourglassHalfIcon, InProgressIcon } from '@patternfly/react-icons'; +import { InfoCircleIcon, HourglassHalfIcon, InProgressIcon, SyncAltIcon } from '@patternfly/react-icons'; import { RedExclamationCircleIcon, - GreenCheckCircleIcon, YellowExclamationTriangleIcon, } from './icons'; import GenericStatus from './GenericStatus'; @@ -30,7 +29,7 @@ export const ProgressStatus: React.FC = (props) => ( ProgressStatus.displayName = 'ProgressStatus'; export const SuccessStatus: React.FC = (props) => ( - } /> + } /> ); SuccessStatus.displayName = 'SuccessStatus'; diff --git a/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss b/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss index ee539a52d43..bf087552e0a 100644 --- a/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss +++ b/frontend/packages/kubevirt-plugin/src/components/resource-link-popover.scss @@ -6,5 +6,5 @@ } .kubevirt-resource-link-popover__disabled { - color: var(--pf-global--disabled-color--200); + color: var(--pf-global--disabled-color--100); } From 05febc9f16220824ff00ab7083bb8a4b857c28ba Mon Sep 17 00:00:00 2001 From: yaacov Date: Tue, 24 Dec 2019 18:13:45 +0200 Subject: [PATCH 5/7] fix lint --- .../console-shared/src/components/status/statuses.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/packages/console-shared/src/components/status/statuses.tsx b/frontend/packages/console-shared/src/components/status/statuses.tsx index affaf9b12c1..858d61f6762 100644 --- a/frontend/packages/console-shared/src/components/status/statuses.tsx +++ b/frontend/packages/console-shared/src/components/status/statuses.tsx @@ -1,9 +1,11 @@ import * as React from 'react'; -import { InfoCircleIcon, HourglassHalfIcon, InProgressIcon, SyncAltIcon } from '@patternfly/react-icons'; import { - RedExclamationCircleIcon, - YellowExclamationTriangleIcon, -} from './icons'; + InfoCircleIcon, + HourglassHalfIcon, + InProgressIcon, + SyncAltIcon, +} from '@patternfly/react-icons'; +import { RedExclamationCircleIcon, YellowExclamationTriangleIcon } from './icons'; import GenericStatus from './GenericStatus'; import { StatusComponentProps } from './types'; import StatusIconAndText from './StatusIconAndText'; From b31403319ae171f318d8a246df30ab4f94c493b1 Mon Sep 17 00:00:00 2001 From: yaacov Date: Tue, 24 Dec 2019 21:58:25 +0200 Subject: [PATCH 6/7] fix sorting --- .../kubevirt-plugin/src/components/vms/vm.tsx | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx index 0da117ab7e9..e47c27029e0 100644 --- a/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx @@ -46,6 +46,9 @@ const tableColumnClasses = [ Kebab.columnClass, ]; +export const getStatus = (obj: VMKind | VMIKind) => + obj.kind === VirtualMachineModel.kind ? getVMStatus({ vm: obj as VMKind }) : getPhase(obj); + const VMHeader = () => dimensifyHeader( [ @@ -56,8 +59,6 @@ const VMHeader = () => }, { title: 'Instance', - sortFunc: 'string', - transforms: [sortable], }, { title: 'Namespace', @@ -66,7 +67,7 @@ const VMHeader = () => }, { title: 'Status', - sortFunc: 'string', + sortFunc: 'getStatus', transforms: [sortable], }, { @@ -76,12 +77,9 @@ const VMHeader = () => }, { title: 'Node', - sortFunc: 'string', - transforms: [sortable], }, { title: 'IP Address', - sortFunc: 'string', }, { title: '', @@ -170,9 +168,7 @@ const VMRow: React.FC = ({ {status} - - {vmi && fromNow(vmi.metadata.creationTimestamp)} - + {fromNow(obj.metadata.creationTimestamp)} {getVMINodeName(vmi) && ( @@ -262,7 +258,7 @@ export const VirtualMachinesPage: React.FC = (props) = ]; const flatten = ({ vms, vmis }) => - _.unionBy(getLoadedData(vms, []), getLoadedData(vmis, []), getName); + _.unionBy(getLoadedData(vms, []), getLoadedData(vmis, []), getUID); const createAccessReview = skipAccessReview ? null : { model: VirtualMachineModel, namespace }; From 117de0cdeb2fa071e22e5247b739cb7f5a49eecd Mon Sep 17 00:00:00 2001 From: yaacov Date: Sun, 29 Dec 2019 13:56:23 +0200 Subject: [PATCH 7/7] fix uid method to work with VM and VMI --- frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx index e47c27029e0..6f60b5e044a 100644 --- a/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx @@ -258,7 +258,11 @@ export const VirtualMachinesPage: React.FC = (props) = ]; const flatten = ({ vms, vmis }) => - _.unionBy(getLoadedData(vms, []), getLoadedData(vmis, []), getUID); + _.unionBy( + getLoadedData(vms, []), + getLoadedData(vmis, []), + (obj) => `${getName(obj)}-${getNamespace(obj)}`, + ); const createAccessReview = skipAccessReview ? null : { model: VirtualMachineModel, namespace };