diff --git a/packages/common/src/components/TableView/TableView.tsx b/packages/common/src/components/TableView/TableView.tsx index 67d52e076..c167e2962 100644 --- a/packages/common/src/components/TableView/TableView.tsx +++ b/packages/common/src/components/TableView/TableView.tsx @@ -32,7 +32,7 @@ export function TableView({ currentNamespace, Header, }: TableViewProps) { - const hasChildren = children.filter(Boolean).length > 0; + const hasChildren = children?.filter(Boolean)?.length > 0; const columnSignature = visibleColumns.map(({ resourceFieldId: id }) => id).join(); return ( diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OpenShiftVirtualMachinesList.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OpenShiftVirtualMachinesList.tsx index 81d5202f6..a03d8104c 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OpenShiftVirtualMachinesList.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OpenShiftVirtualMachinesList.tsx @@ -8,7 +8,7 @@ import { OpenShiftVirtualMachinesCells } from './OpenShiftVirtualMachinesRow'; import { ProviderVirtualMachinesProps } from './ProviderVirtualMachines'; import { getOpenShiftFeatureMap, getVmPowerState } from './utils'; -const openShiftVmFieldsMetadataFactory: ResourceFieldFactory = (t) => [ +export const openShiftVmFieldsMetadataFactory: ResourceFieldFactory = (t) => [ { resourceFieldId: 'name', jsonPath: '$.name', diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/components/ProviderVirtualMachinesList.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/components/ProviderVirtualMachinesList.tsx index e78d9cb54..7a23a3f94 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/components/ProviderVirtualMachinesList.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/components/ProviderVirtualMachinesList.tsx @@ -80,14 +80,14 @@ export const ProviderVirtualMachinesList: FC = ); }; -const concernsMatcher: ValueMatcher = { +export const concernsMatcher: ValueMatcher = { filterType: 'concerns', matchValue: (concerns: Concern[]) => (filter: string) => Array.isArray(concerns) && concerns.some(({ category, label }) => category === filter || label === filter), }; -const featuresMatcher: ValueMatcher = { +export const featuresMatcher: ValueMatcher = { filterType: 'features', matchValue: (features: { [key: string]: boolean }) => (filter: string) => !!features?.[filter], }; diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/PlansCreateForm.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/PlansCreateForm.tsx index 208d6b716..c687cd309 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/PlansCreateForm.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/PlansCreateForm.tsx @@ -1,70 +1,128 @@ import React, { useState } from 'react'; +import StandardPage from 'src/components/page/StandardPage'; import { useForkliftTranslation } from 'src/utils/i18n'; +import { EnumFilter, SearchableGroupedEnumFilter } from '@kubev2v/common'; import { ProviderModelGroupVersionKind } from '@kubev2v/types'; import { ResourceLink } from '@openshift-console/dynamic-plugin-sdk'; -import { DescriptionList, Form, FormGroup, TextInput } from '@patternfly/react-core'; +import { + Button, + DescriptionList, + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, + Drawer, + DrawerActions, + DrawerCloseButton, + DrawerContent, + DrawerContentBody, + DrawerHead, + DrawerPanelContent, + Form, + FormGroup, + TextInput, +} from '@patternfly/react-core'; import { DetailsItem } from '../../utils'; +import { concernsMatcher, featuresMatcher, VmData } from '../details'; import { PageAction, setPlanName } from './actions'; import { CreateVmMigrationPageState } from './reducer'; export const PlansCreateForm = ({ - state: { newPlan: plan, validation }, + state: { + newPlan: plan, + validation, + selectedVms, + vmFieldsFactory: [vmFieldsFactory, RowMapper], + }, dispatch, }: { state: CreateVmMigrationPageState; dispatch: (action: PageAction) => void; }) => { const { t } = useForkliftTranslation(); + const vmFields = vmFieldsFactory(t); const [isNameEdited, setIsNameEdited] = useState(false); + const [isVmDetails, setIsVmDetails] = useState(false); return ( - - {isNameEdited ? ( -
- - dispatch(setPlanName(value?.trim() ?? '', []))} + + + + + setIsVmDetails(false)} /> + + + + title={t('Selected VMs')} + dataSource={[selectedVms, true, false]} + fieldsMetadata={vmFields} + RowMapper={RowMapper} + namespace={plan.spec.provider?.source?.namespace} + extraSupportedFilters={{ + concerns: SearchableGroupedEnumFilter, + features: EnumFilter, + }} + extraSupportedMatchers={[concernsMatcher, featuresMatcher]} /> - -
- ) : ( - setIsNameEdited(true)} - /> - )} - + } - /> - -
+ > + + + {isNameEdited ? ( +
+ + dispatch(setPlanName(value?.trim() ?? ''))} + /> + +
+ ) : ( + setIsNameEdited(true)} + /> + )} + + } + /> + + {t('Selected VMs')} + + + + +
+
+ + ); }; diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/actions.ts b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/actions.ts index 5f97661c8..d04b7d4a8 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/actions.ts +++ b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/actions.ts @@ -25,7 +25,6 @@ export interface PageAction { export interface PlanName { name: string; - existingPlanNames: string[]; } export interface PlanDescription { @@ -71,14 +70,10 @@ export const setPlanDescription = ( payload: { description }, }); -export const setPlanName = ( - name: string, - existingPlanNames: string[], -): PageAction => ({ +export const setPlanName = (name: string): PageAction => ({ type: 'SET_NAME', payload: { name, - existingPlanNames, }, }); diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/reducer.ts b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/reducer.ts index 62143fc41..e4eda9040 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/reducer.ts +++ b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/reducer.ts @@ -1,28 +1,36 @@ +import { FC } from 'react'; import { Draft } from 'immer'; import { isProviderLocalOpenshift } from 'src/utils/resources'; import { v4 as randomId } from 'uuid'; -import { V1beta1Plan, V1beta1Provider } from '@kubev2v/types'; +import { DefaultRow, ResourceFieldFactory, RowProps, withTr } from '@kubev2v/common'; +import { ProviderType, V1beta1Plan, V1beta1Provider } from '@kubev2v/types'; import { validateK8sName, Validation } from '../../utils'; import { planTemplate } from '../create/templates'; import { toId, VmData } from '../details'; +import { openShiftVmFieldsMetadataFactory } from '../details/tabs/VirtualMachines/OpenShiftVirtualMachinesList'; +import { openStackVmFieldsMetadataFactory } from '../details/tabs/VirtualMachines/OpenStackVirtualMachinesList'; +import { ovaVmFieldsMetadataFactory } from '../details/tabs/VirtualMachines/OvaVirtualMachinesList'; +import { oVirtVmFieldsMetadataFactory } from '../details/tabs/VirtualMachines/OVirtVirtualMachinesList'; +import { OVirtVirtualMachinesCells } from '../details/tabs/VirtualMachines/OVirtVirtualMachinesRow'; +import { vSphereVmFieldsMetadataFactory } from '../details/tabs/VirtualMachines/VSphereVirtualMachinesList'; import { CreateVmMigration, PageAction, PlanAvailableProviders, PlanDescription, + PlanExistingPlans, PlanName, PlanTargetNamespace, PlanTargetProvider, SET_AVAILABLE_PROVIDERS, SET_DESCRIPTION, + SET_EXISTING_PLANS, SET_NAME, SET_TARGET_NAMESPACE, SET_TARGET_PROVIDER, - SET_EXISTING_PLANS, - PlanExistingPlans, } from './actions'; export interface CreateVmMigrationPageState { @@ -36,6 +44,7 @@ export interface CreateVmMigrationPageState { availableProviders: V1beta1Provider[]; selectedVms: VmData[]; existingPlans: V1beta1Plan[]; + vmFieldsFactory: [ResourceFieldFactory, FC>]; } const validateUniqueName = (name: string, existingPlanNames: string[]) => @@ -47,13 +56,16 @@ const actions: { action: PageAction, ) => CreateVmMigrationPageState; } = { - [SET_NAME]( - draft, - { payload: { name } }: PageAction, - ) { + [SET_NAME](draft, { payload: { name } }: PageAction) { draft.newPlan.metadata.name = name; draft.validation.name = - validateK8sName(name) && validateUniqueName(name, draft.existingPlans.map(plan => plan?.metadata?.name ?? '')) ? 'success' : 'error'; + validateK8sName(name) && + validateUniqueName( + name, + draft.existingPlans.map((plan) => plan?.metadata?.name ?? ''), + ) + ? 'success' + : 'error'; return draft; }, [SET_DESCRIPTION]( @@ -84,20 +96,27 @@ const actions: { draft, { payload: { availableProviders } }: PageAction, ) { + if (!availableProviders?.length) { + draft.availableProviders = []; + return draft; + } + + draft.availableProviders = availableProviders; const targetProvider = draft.newPlan.spec.provider.destination; + // set the default provider if none is set + // reset the provider if provider was removed if ( !targetProvider || !availableProviders.find((p) => p?.metadata?.name === targetProvider.name) ) { - // set the default provider if none is set - // reset the provider if provider was removed const firstHostProvider = availableProviders.find((p) => isProviderLocalOpenshift(p)); - draft.newPlan.spec.provider.destination = - firstHostProvider && getObjectRef(firstHostProvider); + // there might be no host (or other openshift) provider in the namespace + draft.newPlan.spec.provider.destination = firstHostProvider + ? getObjectRef(firstHostProvider) + : undefined; draft.newPlan.spec.targetNamespace = undefined; draft.validation.targetNamespace = 'default'; } - draft.availableProviders = availableProviders; return draft; }, [SET_EXISTING_PLANS]( @@ -168,4 +187,24 @@ export const createInitialState = ({ name: 'default', targetNamespace: 'default', }, + vmFieldsFactory: resourceFieldsForType(sourceProvider?.spec?.type as ProviderType), }); + +export const resourceFieldsForType = ( + type: ProviderType, +): [ResourceFieldFactory, FC>] => { + switch (type) { + case 'openshift': + return [openShiftVmFieldsMetadataFactory, DefaultRow]; + case 'openstack': + return [openStackVmFieldsMetadataFactory, DefaultRow]; + case 'ova': + return [ovaVmFieldsMetadataFactory, DefaultRow]; + case 'ovirt': + return [oVirtVmFieldsMetadataFactory, withTr(OVirtVirtualMachinesCells)]; + case 'vsphere': + return [vSphereVmFieldsMetadataFactory, DefaultRow]; + default: + return [() => [], DefaultRow]; + } +};