Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as React from 'react';
import { InfoCircleIcon, HourglassHalfIcon, InProgressIcon } from '@patternfly/react-icons';
import {
RedExclamationCircleIcon,
GreenCheckCircleIcon,
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';
Expand All @@ -30,7 +31,7 @@ export const ProgressStatus: React.FC<StatusComponentProps> = (props) => (
ProgressStatus.displayName = 'ProgressStatus';

export const SuccessStatus: React.FC<StatusComponentProps> = (props) => (
<StatusIconAndText {...props} icon={<GreenCheckCircleIcon />} />
<StatusIconAndText {...props} icon={<SyncAltIcon />} />
);
SuccessStatus.displayName = 'SuccessStatus';

Expand Down
Original file line number Diff line number Diff line change
@@ -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: var(--pf-global--disabled-color--100);
}
Original file line number Diff line number Diff line change
@@ -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<ResourceLinkPopoverProps> = ({
kind,
name,
namespace,
className,
isDisabled,
message,
linkMessage,
children,
}) => (
<Popover
headerContent={name}
bodyContent={children}
position="right"
footerContent={
linkMessage && (
<Button variant="link" component="a" href={resourcePath(kind, name, namespace)} isInline>
{linkMessage} <ArrowIcon />
</Button>
)
}
>
<Text
className={
isDisabled
? `${className} kubevirt-resource-link-popover kubevirt-resource-link-popover__disabled`
: `${className} kubevirt-resource-link-popover`
}
>
{message}
</Text>
</Popover>
);

export type ResourceLinkPopoverProps = {
kind?: string;
name: string;
namespace: string;
className?: string;
isDisabled?: boolean;
message: string;
linkMessage?: string;
children: React.ReactNode;
};
136 changes: 114 additions & 22 deletions frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -9,33 +10,45 @@ 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, getVMINodeName } 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'),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@matthewcarleton hi, I'm doing here a "14 spans" size tabls ... it works ... is it OK ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
];

export const getStatus = (obj: VMKind | VMIKind) =>
obj.kind === VirtualMachineModel.kind ? getVMStatus({ vm: obj as VMKind }) : getPhase(obj);

const VMHeader = () =>
dimensifyHeader(
[
Expand All @@ -44,16 +57,30 @@ const VMHeader = () =>
sortField: 'metadata.name',
transforms: [sortable],
},
{
title: 'Instance',
},
{
title: 'Namespace',
sortField: 'metadata.namespace',
transforms: [sortable],
},
{
title: 'Status',
sortFunc: 'string',
sortFunc: 'getStatus',
transforms: [sortable],
},
{
title: 'Created',
sortField: 'metadata.creationTimestamp',
transforms: [sortable],
},
{
title: 'Node',
},
{
title: 'IP Address',
},
{
title: '',
},
Expand All @@ -62,42 +89,101 @@ const VMHeader = () =>
);

const VMRow: React.FC<VMRowProps> = ({
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: 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) {
vm = obj as VMKind;
vmi = vmiLookup[lookupID];
vmStatus = getVMStatus({ vm: vm as VMKind, vmi, pods, migrations });
status = <VMStatus vm={vm} vmi={vmi} pods={pods} migrations={migrations} />;
actions = menuActions;
} else {
vmi = obj as VMIKind;
status = <Status status={getPhase(vmi)} />;
}

return (
<TableRow id={uid} index={index} trKey={key} style={style}>
<TableData className={dimensify()}>
<ResourceLink kind={VirtualMachineModel.kind} name={name} namespace={namespace} />
{vm ? (
<ResourceLink kind={VirtualMachineModel.kind} name={name} namespace={namespace} />
) : (
<ResourceLinkPopover
kind={VirtualMachineInstanceModel.kind}
name={name}
namespace={namespace}
isDisabled
message="No VM"
linkMessage="VMI Dedatails page"
>
<div>
This VMI doesn’t have an owner VM since it might have been created outside of the
console.
</div>
</ResourceLinkPopover>
)}
</TableData>
<TableData className={dimensify()}>
{vmi ? (
<ResourceLink
kind={VirtualMachineInstanceModel.kind}
name={getName(vmi)}
namespace={namespace}
/>
) : (
<ResourceLinkPopover
kind={VirtualMachineModel.kind}
name={name}
namespace={namespace}
isDisabled
message="No Instance"
linkMessage="VM Dedatails page"
>
<div>
This VMI is currently off.
<br />
For further details please click its owner VM link below.
</div>
</ResourceLinkPopover>
)}
</TableData>
<TableData className={dimensify()}>
<ResourceLink kind={NamespaceModel.kind} name={namespace} title={namespace} />
</TableData>
<TableData className={dimensify()}>{status}</TableData>
<TableData className={dimensify()}>{fromNow(obj.metadata.creationTimestamp)}</TableData>
<TableData className={dimensify()}>
<VMStatus vm={vm} vmi={vmi} pods={pods} migrations={migrations} />
{getVMINodeName(vmi) && (
<ResourceLink kind={NodeModel.kind} name={getVMINodeName(vmi)} namespace={namespace} />
)}
</TableData>
<TableData className={dimensify()}>{vmi && getVmiIpAddresses(vmi)}</TableData>
<TableData className={dimensify(true)}>
<Kebab
options={menuActions.map((action) => {
return action(VirtualMachineModel, vm, {
options={actions.map((action) =>
action(vm ? VirtualMachineModel : VirtualMachineInstanceModel, obj, {
vmStatus,
migration,
vmi,
});
})}
}),
)}
key={`kebab-for-${uid}`}
id={`kebab-for-${uid}`}
/>
Expand Down Expand Up @@ -171,7 +257,13 @@ export const VirtualMachinesPage: React.FC<VirtualMachinesPageProps> = (props) =
}),
];

const flatten = ({ vms }) => getLoadedData(vms, []);
const flatten = ({ vms, vmis }) =>
_.unionBy(
getLoadedData(vms, []),
getLoadedData(vmis, []),
(obj) => `${getName(obj)}-${getNamespace(obj)}`,
);

const createAccessReview = skipAccessReview ? null : { model: VirtualMachineModel, namespace };

return (
Expand All @@ -192,7 +284,7 @@ export const VirtualMachinesPage: React.FC<VirtualMachinesPageProps> = (props) =
};

type VMRowProps = {
obj: VMKind;
obj: VMKind | VMIKind;
index: number;
key: string;
style: object;
Expand All @@ -205,7 +297,7 @@ type VMRowProps = {
};

type VMListProps = {
data: VMKind[];
data: (VMKind | VMIKind)[];
resources: {
pods: FirehoseResult<PodKind[]>;
migrations: FirehoseResult<K8sResourceKind[]>;
Expand Down
2 changes: 2 additions & 0 deletions frontend/packages/kubevirt-plugin/src/selectors/vmi/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;