diff --git a/frontend/packages/kubevirt-plugin/src/components/vms/types.ts b/frontend/packages/kubevirt-plugin/src/components/vms/types.ts
new file mode 100644
index 00000000000..49e6cba4201
--- /dev/null
+++ b/frontend/packages/kubevirt-plugin/src/components/vms/types.ts
@@ -0,0 +1,60 @@
+import { K8sResourceKind, ObjectMetadata } from '@console/internal/module/k8s';
+
+// https://kubevirt.io/api-reference/master/definitions.html#_v1_virtualmachineinstancespec
+export type VMISpec = {
+ affinity: any;
+ dnsConfig: any;
+ dnsPolicy: string;
+ domain?: any;
+ evictionStrategy: any;
+ hostname: string;
+ livenessProbe: any;
+ networks?: any[];
+ nodeSelector: any;
+ readinessProbe: any;
+ subdomain: string;
+ terminationGracePeriodSeconds: number;
+ tolerations: any[];
+ volumes?: any[];
+};
+
+// https://kubevirt.io/api-reference/master/definitions.html#_v1_virtualmachineinstancestatus
+export type VMIStatus = {
+ conditions: any[];
+ interfaces: any[];
+ migrationMethod: string;
+ migrationState: any;
+ nodeName: string;
+ phase: string;
+ reason: string;
+};
+
+export type VMIKind = {
+ spec: VMISpec;
+ status: VMIStatus;
+} & K8sResourceKind;
+
+export type VMITemplate = {
+ metadata?: ObjectMetadata;
+ spec?: VMISpec;
+};
+
+export type VMSpec = {
+ template: VMITemplate;
+ running?: boolean;
+ runStrategy?: any;
+ dataVolumeTemplates?: any[];
+};
+
+export type VMStatus = {
+ conditions?: any[];
+ created?: boolean;
+ ready?: boolean;
+ stateChangeRequests?: any[];
+};
+
+// https://kubevirt.io/api-reference/master/definitions.html#_v1_virtualmachine
+export type VMKind = {
+ spec: VMSpec;
+ status: VMStatus;
+} & K8sResourceKind;
diff --git a/frontend/packages/kubevirt-plugin/src/components/vms/vm-details-page.tsx b/frontend/packages/kubevirt-plugin/src/components/vms/vm-details-page.tsx
new file mode 100644
index 00000000000..be61269f584
--- /dev/null
+++ b/frontend/packages/kubevirt-plugin/src/components/vms/vm-details-page.tsx
@@ -0,0 +1,56 @@
+import * as React from 'react';
+
+import { navFactory } from '@console/internal/components/utils';
+
+import { DetailsPage } from '@console/internal/components/factory';
+import { K8sResourceKindReference } from '@console/internal/module/k8s';
+
+import { VMDetailsFirehose } from './vm-details';
+
+// import { VmEvents } from './vm-events';
+// import VmConsolesConnected from '../vmconsoles';
+// import { Nic } from '../nic';
+// import { Disk } from '../disk';
+// import { menuActions } from './menu-actions';
+
+export const VirtualMachinesDetailsPage = (props: VirtualMachinesDetailsPageProps) => {
+ /* TODO(mlibra): pages will be transferred one by one in follow-ups
+ const consolePage = {
+ href: 'consoles',
+ name: 'Consoles',
+ component: VmConsolesConnected,
+ };
+
+ const nicsPage = {
+ href: 'nics',
+ name: 'Network Interfaces',
+ component: VmNic,
+ };
+
+ const disksPage = {
+ href: 'disks',
+ name: 'Disks',
+ component: VmDisk,
+ };
+ */
+
+ const pages = [
+ navFactory.details(VMDetailsFirehose),
+ navFactory.editYaml(),
+ // consolePage,
+ // navFactory.events(VmEvents),
+ // nicsPage,
+ // disksPage,
+ ];
+
+ const menuActions = undefined; // TODO(mlibra): menuActions
+
+ return ;
+};
+
+type VirtualMachinesDetailsPageProps = {
+ name: string;
+ namespace: string;
+ kind: K8sResourceKindReference;
+ match: any;
+};
diff --git a/frontend/packages/kubevirt-plugin/src/components/vms/vm-details.tsx b/frontend/packages/kubevirt-plugin/src/components/vms/vm-details.tsx
new file mode 100644
index 00000000000..2e8c87ee079
--- /dev/null
+++ b/frontend/packages/kubevirt-plugin/src/components/vms/vm-details.tsx
@@ -0,0 +1,86 @@
+import * as React from 'react';
+import * as _ from 'lodash';
+
+import { getResource, getServicesForVm } from 'kubevirt-web-ui-components';
+
+import {
+ Firehose,
+ StatusBox,
+ ScrollToTopOnMount,
+ SectionHeading,
+} from '@console/internal/components/utils';
+
+import { PodKind } from '@console/internal/module/k8s';
+import { PodModel, ServiceModel } from '@console/internal/models';
+
+import { ServicesList } from '@console/internal/components/service';
+import { VMKind, VMIKind } from './types';
+import { VirtualMachineInstanceModel, VirtualMachineInstanceMigrationModel } from '../../models';
+import { VMResourceSummary, VMDetailsList } from './vm-resource';
+
+export const VMDetailsFirehose = ({ obj: vm }: { obj: VMKind }) => {
+ const { name, namespace } = vm.metadata;
+
+ const vmiRes = getResource(VirtualMachineInstanceModel, {
+ name,
+ namespace,
+ isList: false,
+ prop: 'vmi',
+ optional: true,
+ });
+
+ const resources = [
+ vmiRes,
+ getResource(PodModel, { namespace, prop: 'pods' }),
+ getResource(VirtualMachineInstanceMigrationModel, { namespace, prop: 'migrations' }),
+ getResource(ServiceModel, { namespace, prop: 'services' }),
+ ];
+
+ return (
+
+
+
+
+
+ );
+};
+
+const VMDetails = (props: VMDetailsProps) => {
+ const { vm, ...restProps } = props;
+ const flatResources = {
+ vm,
+ vmi: _.get(props, 'vmi.data'),
+ pods: _.get(props, 'pods.data'),
+ migrations: _.get(props, 'migrations.data'),
+ };
+
+ const vmServicesData = getServicesForVm(_.get(props, 'services', {}).data, vm);
+
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+type VMDetailsProps = {
+ vm: VMKind;
+ pods?: PodKind[];
+ migrations?: any[];
+ vmi?: VMIKind;
+};
diff --git a/frontend/packages/kubevirt-plugin/src/components/vms/vm-resource.tsx b/frontend/packages/kubevirt-plugin/src/components/vms/vm-resource.tsx
new file mode 100644
index 00000000000..02660e0d614
--- /dev/null
+++ b/frontend/packages/kubevirt-plugin/src/components/vms/vm-resource.tsx
@@ -0,0 +1,98 @@
+import * as React from 'react';
+
+import {
+ getDescription,
+ getOperatingSystemName,
+ getOperatingSystem,
+ getVmStatus,
+ getVmiIpAddresses,
+ getWorkloadProfile,
+ getVmTemplate,
+ getTemplateDisplayName,
+ getNodeName,
+ getFlavor,
+ VmStatuses,
+ BootOrder,
+ isVmOff,
+ getBootableDevicesInOrder,
+} from 'kubevirt-web-ui-components';
+
+import { ResourceSummary, NodeLink, ResourceLink } from '@console/internal/components/utils';
+import { PodKind } from '@console/internal/module/k8s';
+import { getName, getNamespace, DASH } from '@console/shared';
+import { PodModel } from '@console/internal/models';
+
+import { VMKind, VMIKind } from './types';
+
+export const VMResourceSummary = ({ vm }: VMResourceSummaryProps) => {
+ const template = getVmTemplate(vm);
+ const templateLink = template && getTemplateDisplayName(template); // TODO(mlibra): link to a template detail, once implemented
+
+ return (
+
+ Description
+ {getDescription(vm)}
+ Operating System
+ {getOperatingSystemName(vm) || getOperatingSystem(vm) || DASH}
+ Template
+ {templateLink || DASH}
+
+ );
+};
+
+export const VMDetailsList = ({ vm, vmi, pods, migrations }: VMResourceListProps) => {
+ const vmStatus = getVmStatus(vm, pods, migrations);
+ const { launcherPod } = vmStatus;
+ const sortedBootableDevices = getBootableDevicesInOrder(vm);
+ const nodeName = getNodeName(launcherPod);
+ const vmIsOff = isVmOff(vmStatus);
+ const ipAddresses = vmIsOff ? [] : getVmiIpAddresses(vmi);
+
+ return (
+
+ - Status
+ -
+
+
+ - Pod
+ -
+ {launcherPod ? (
+
+ ) : (
+ DASH
+ )}
+
+ - Boot Order
+ -
+ {sortedBootableDevices.length > 0 ? (
+
+ ) : (
+ DASH
+ )}
+
+ - IP Address
+ - {ipAddresses.length > 0 ? ipAddresses.join(', ') : DASH}
+ - Node
+ - {}
+ - Flavour
+ - {getFlavor(vm) || DASH}
+ - Workload Profile
+ - {getWorkloadProfile(vm) || DASH}
+
+ );
+};
+
+type VMResourceSummaryProps = {
+ vm: VMKind;
+};
+
+type VMResourceListProps = {
+ vm: VMKind;
+ pods?: PodKind[];
+ migrations?: any[];
+ vmi?: VMIKind;
+};
diff --git a/frontend/packages/kubevirt-plugin/src/components/vm.tsx b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx
similarity index 99%
rename from frontend/packages/kubevirt-plugin/src/components/vm.tsx
rename to frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx
index 1aeb6d84990..7c227e7968a 100644
--- a/frontend/packages/kubevirt-plugin/src/components/vm.tsx
+++ b/frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx
@@ -26,7 +26,7 @@ import {
VirtualMachineModel,
// VirtualMachineInstanceModel,
// VirtualMachineInstanceMigrationModel,
-} from '../models';
+} from '../../models';
// import { openCreateVmWizard } from '../modals/create-vm-modal';
// import { menuActions } from './menu-actions';
diff --git a/frontend/packages/kubevirt-plugin/src/plugin.ts b/frontend/packages/kubevirt-plugin/src/plugin.ts
index 2d47bea2663..baefbe7795d 100644
--- a/frontend/packages/kubevirt-plugin/src/plugin.ts
+++ b/frontend/packages/kubevirt-plugin/src/plugin.ts
@@ -12,6 +12,8 @@ import {
import * as models from './models';
import { yamlTemplates } from './yaml-templates';
+import './style.scss';
+
type ConsumedExtensions =
| ResourceNSNavItem
| ResourceListPage
@@ -53,7 +55,7 @@ const plugin: Plugin = [
properties: {
model: models.VirtualMachineModel,
loader: () =>
- import('./components/vm' /* webpackChunkName: "kubevirt-virtual-machines" */).then(
+ import('./components/vms/vm' /* webpackChunkName: "kubevirt-virtual-machines" */).then(
(m) => m.VirtualMachinesPage,
),
},
@@ -65,13 +67,16 @@ const plugin: Plugin = [
template: yamlTemplates.getIn([models.VirtualMachineModel, 'default']),
},
},
- // {
- // type: 'Page/Resource/Details',
- // properties: {
- // model: VirtualMachineModel,
- // loader: () => import('./components/vm-detail' /* webpackChunkName: "kubevirt-virtual-machines" */).then(m => m.VirtualMachinesDetailsPage),
- // },
- // },
+ {
+ type: 'Page/Resource/Details',
+ properties: {
+ model: models.VirtualMachineModel,
+ loader: () =>
+ import(
+ './components/vms/vm-details-page' /* webpackChunkName: "kubevirt-virtual-machine-details" */
+ ).then((m) => m.VirtualMachinesDetailsPage),
+ },
+ },
];
export default plugin;
diff --git a/frontend/packages/kubevirt-plugin/src/style.scss b/frontend/packages/kubevirt-plugin/src/style.scss
new file mode 100644
index 00000000000..559dc1db2f1
--- /dev/null
+++ b/frontend/packages/kubevirt-plugin/src/style.scss
@@ -0,0 +1 @@
+@import '~kubevirt-web-ui-components/dist/sass/components';