diff --git a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json index 65463ecf8..a975b1fbc 100644 --- a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json +++ b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json @@ -14,7 +14,7 @@ "{{total}} VM": "{{total}} VM", "{{total}} VM_plural": "{{total}} VMs", "{{total}} VMs": "{{total}} VMs", - "{{vmCount}} VMs selected ": "{{vmCount}} VMs selected ", + "{{vmCount}} VMs selected": "{{vmCount}} VMs selected", "{children}": "{children}", "24 hours": "24 hours", "31 days": "31 days", @@ -158,7 +158,6 @@ "Edit migration plan transfer network": "Edit migration plan transfer network", "Edit NetworkMap": "Edit NetworkMap", "Edit Plan": "Edit Plan", - "Edit plan name": "Edit plan name", "Edit Precopy interval (minutes)": "Edit Precopy interval (minutes)", "Edit Provider": "Edit Provider", "Edit Provider Credentials": "Edit Provider Credentials", @@ -424,7 +423,6 @@ "Select virtual machines": "Select virtual machines", "Select vSphere provider endpoint type.": "Select vSphere provider endpoint type.", "Selected columns will be displayed in the table.": "Selected columns will be displayed in the table.", - "Selected VMs": "Selected VMs", "Service account bearer token": "Service account bearer token", "Set cutover": "Set cutover", "Set default transfer network": "Set default transfer network", diff --git a/packages/forklift-console-plugin/src/components/page/StandardPage.style.css b/packages/forklift-console-plugin/src/components/page/StandardPage.style.css index e042ad13b..d3c4ce741 100644 --- a/packages/forklift-console-plugin/src/components/page/StandardPage.style.css +++ b/packages/forklift-console-plugin/src/components/page/StandardPage.style.css @@ -1,3 +1,9 @@ .forklift-page__main-title { padding-bottom: 0; } + +.forklift-page__toolbar-item__selected-count { + color: var(--pf-v5-global--Color--200); + margin-inline-start: auto; + align-self: center; +} diff --git a/packages/forklift-console-plugin/src/components/page/StandardPage.tsx b/packages/forklift-console-plugin/src/components/page/StandardPage.tsx index 2dcff99e9..140f4a251 100644 --- a/packages/forklift-console-plugin/src/components/page/StandardPage.tsx +++ b/packages/forklift-console-plugin/src/components/page/StandardPage.tsx @@ -224,6 +224,11 @@ export interface StandardPageProps { * Expanded ids */ expandedIds?: string[]; + + /** + * Label to show count of selected items + */ + selectedCountLabel?: (selectedIdCount: number) => string; } /** @@ -280,6 +285,8 @@ export function StandardPage({ toId, expandedIds, className, + selectedIds, + selectedCountLabel, }: StandardPageProps) { const { t } = useForkliftTranslation(); const [sortedData, setSortedData] = useState([]); @@ -412,6 +419,13 @@ export function StandardPage({ ))} + + {selectedCountLabel && ( + + {selectedCountLabel(selectedIds.length ?? 0)} + + )} + {showPagination && ( ({ = ({ namespace }) = // Get optional initial state context const { data } = useCreateVmMigrationData(); const history = useHistory(); - const startAtStep = data?.provider !== undefined ? 2 : 1; const [activeNamespace, setActiveNamespace] = useActiveNamespace(); const defaultNamespace = process?.env?.DEFAULT_NAMESPACE || 'default'; const projectName = @@ -59,6 +59,11 @@ export const PlanCreatePage: React.FC<{ namespace: string }> = ({ namespace }) = }); useSaveEffect(state, dispatch); + const isFirstStepValid = React.useMemo( + () => validateSourceProviderStep(state, filterState), + [state, filterState], + ); + const steps = [ { id: 'step-1', @@ -74,7 +79,7 @@ export const PlanCreatePage: React.FC<{ namespace: string }> = ({ namespace }) = selectedProvider={selectedProvider} /> ), - enableNext: filterState?.selectedVMs?.length > 0, + enableNext: isFirstStepValid, }, { id: 'step-2', @@ -93,7 +98,7 @@ export const PlanCreatePage: React.FC<{ namespace: string }> = ({ namespace }) = Object.values(state?.validation || []).some((validation) => validation === 'error') || state?.validation?.planName === 'default' ), - canJumpTo: filterState?.selectedVMs?.length > 0, + canJumpTo: isFirstStepValid, nextButtonText: 'Create migration plan', }, ]; @@ -116,7 +121,6 @@ export const PlanCreatePage: React.FC<{ namespace: string }> = ({ namespace }) = dispatch(startCreate()); }} onClose={() => history.goBack()} - startAtStep={startAtStep} /> diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/create/components/PlanCreateForm.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/create/components/PlanCreateForm.tsx index 72941d918..4916ba616 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/create/components/PlanCreateForm.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/create/components/PlanCreateForm.tsx @@ -5,6 +5,7 @@ import { VmData } from 'src/modules/Providers/views'; import { useCreateVmMigrationData } from 'src/modules/Providers/views/migrate'; import { PageAction, + setPlanName, setProjectName as setProjectNameAction, } from 'src/modules/Providers/views/migrate/reducer/actions'; import { CreateVmMigrationPageState } from 'src/modules/Providers/views/migrate/types'; @@ -19,6 +20,7 @@ import { PlanCreatePageState } from '../states'; import { ChipsToolbarProviders } from './ChipsToolbarProviders'; import { createProviderCardItems } from './createProviderCardItems'; import { FiltersToolbarProviders } from './FiltersToolbarProviders'; +import { PlanNameTextField } from './PlanNameTextField'; import { ProjectNameSelect } from './ProjectNameSelect'; export type PlanCreateFormProps = { @@ -40,6 +42,7 @@ export type PlanCreateFormProps = { export const PlanCreateForm: React.FC = ({ providers, filterState, + state, projectName, filterDispatch, dispatch, @@ -58,6 +61,17 @@ export const PlanCreateForm: React.FC = ({ return (
+ { + dispatch(setPlanName(value?.trim() ?? '')); + setData({ ...data, planName: value }); + }} + /> + ({ diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/create/components/PlanNameTextField.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/create/components/PlanNameTextField.tsx index 79ef68ffd..0b538d51d 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/create/components/PlanNameTextField.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/create/components/PlanNameTextField.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Validation } from 'src/modules/Providers'; -import { ForkliftTrans, useForkliftTranslation } from 'src/utils'; +import { useForkliftTranslation } from 'src/utils'; import { FormGroupWithHelpText } from '@kubev2v/common'; import { TextInput } from '@patternfly/react-core'; @@ -30,10 +30,8 @@ export const PlanNameTextField: React.FC = ({ fieldId="planName" {...(isUpdated && { validated: validated, - helperTextInvalid: ( - - Name is required and must be a unique within a namespace and valid Kubernetes name. - + helperTextInvalid: t( + 'Name is required and must be a unique within a namespace and valid Kubernetes name.', ), })} > diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/create/components/ProvidersVirtualMachinesList.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/create/components/ProvidersVirtualMachinesList.tsx index e1b730b7d..7ba8c2d63 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/create/components/ProvidersVirtualMachinesList.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/create/components/ProvidersVirtualMachinesList.tsx @@ -16,7 +16,17 @@ export const ProviderVirtualMachinesList: React.FC<{ initialSelectedIds?: string[]; showActions: boolean; className?: string; -}> = ({ title, name, namespace, onSelect, initialSelectedIds, showActions, className }) => { + selectedCountLabel?: (selectedIdCount: number) => string; +}> = ({ + title, + name, + namespace, + onSelect, + initialSelectedIds, + showActions, + className, + selectedCountLabel, +}) => { const [provider, providerLoaded, providerLoadError] = useK8sWatchResource({ groupVersionKind: ProviderModelGroupVersionKind, namespaced: true, @@ -37,6 +47,7 @@ export const ProviderVirtualMachinesList: React.FC<{ initialSelectedIds={initialSelectedIds} showActions={showActions} className={className} + selectedCountLabel={selectedCountLabel} /> ); }; diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/create/steps/SelectSourceProvider/MemoizedProviderVirtualMachinesList.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/create/steps/SelectSourceProvider/MemoizedProviderVirtualMachinesList.tsx index ef557cbcc..769b6776a 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/create/steps/SelectSourceProvider/MemoizedProviderVirtualMachinesList.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/create/steps/SelectSourceProvider/MemoizedProviderVirtualMachinesList.tsx @@ -10,6 +10,7 @@ export interface ProviderVirtualMachinesListProps { onSelect: (selectedVms: VmData[]) => void; initialSelectedIds: string[]; showActions: boolean; + selectedCountLabel?: (selectedIdCount: number) => string; } export const MemoizedProviderVirtualMachinesList = memo( @@ -20,6 +21,7 @@ export const MemoizedProviderVirtualMachinesList = memo( onSelect, initialSelectedIds, showActions, + selectedCountLabel, }: ProviderVirtualMachinesListProps) => { return ( ); }, diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/create/steps/SelectSourceProvider/SelectSourceProvider.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/create/steps/SelectSourceProvider/SelectSourceProvider.tsx index 88023b47d..23c19ef04 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/create/steps/SelectSourceProvider/SelectSourceProvider.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/create/steps/SelectSourceProvider/SelectSourceProvider.tsx @@ -71,6 +71,9 @@ export const SelectSourceProvider: React.FC<{ } initialSelectedIds={filterState.selectedVMs.map((vm) => vm.vm.id)} showActions={false} + selectedCountLabel={(selectedIdCount) => + t('{{vmCount}} VMs selected', { vmCount: selectedIdCount }) + } /> )} diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/create/utils.ts b/packages/forklift-console-plugin/src/modules/Plans/views/create/utils.ts new file mode 100644 index 000000000..96ba92817 --- /dev/null +++ b/packages/forklift-console-plugin/src/modules/Plans/views/create/utils.ts @@ -0,0 +1,11 @@ +import { CreateVmMigrationPageState } from 'src/modules/Providers/views/migrate/types'; + +import { PlanCreatePageState } from './states'; + +export const validateSourceProviderStep = ( + state: CreateVmMigrationPageState, + filterState: PlanCreatePageState, +) => + state.underConstruction.plan.metadata.name && + state.validation.planName !== 'error' && + filterState?.selectedVMs?.length > 0; diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OVirtVirtualMachinesList.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OVirtVirtualMachinesList.tsx index b8da16762..cc81075a6 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OVirtVirtualMachinesList.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OVirtVirtualMachinesList.tsx @@ -85,27 +85,11 @@ export const oVirtVmFieldsMetadataFactory: ResourceFieldFactory = (t) => [ }, ]; -export const OVirtVirtualMachinesList: React.FC = ({ - title, - obj, - loaded, - loadError, - onSelect, - initialSelectedIds, - showActions, - className, -}) => ( +export const OVirtVirtualMachinesList: React.FC = (props) => ( ); 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 ffe854cc6..09b3e64ea 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 @@ -73,27 +73,11 @@ export const openShiftVmFieldsMetadataFactory: ResourceFieldFactory = (t) => [ }, ]; -export const OpenShiftVirtualMachinesList: React.FC = ({ - title, - obj, - loaded, - loadError, - onSelect, - initialSelectedIds, - showActions, - className, -}) => ( +export const OpenShiftVirtualMachinesList: React.FC = (props) => ( ); diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OpenStackVirtualMachinesList.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OpenStackVirtualMachinesList.tsx index 7da4ae04d..391202cf0 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OpenStackVirtualMachinesList.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OpenStackVirtualMachinesList.tsx @@ -104,27 +104,11 @@ export const openStackVmFieldsMetadataFactory: ResourceFieldFactory = (t) => [ }, ]; -export const OpenStackVirtualMachinesList: React.FC = ({ - title, - obj, - loaded, - loadError, - onSelect, - initialSelectedIds, - showActions, - className, -}) => ( +export const OpenStackVirtualMachinesList: React.FC = (props) => ( ); diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OvaVirtualMachinesList.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OvaVirtualMachinesList.tsx index 7310c67f5..490ac301d 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OvaVirtualMachinesList.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/OvaVirtualMachinesList.tsx @@ -42,27 +42,11 @@ export const ovaVmFieldsMetadataFactory: ResourceFieldFactory = (t) => [ }, ]; -export const OvaVirtualMachinesList: React.FC = ({ - title, - obj, - loaded, - loadError, - onSelect, - initialSelectedIds, - showActions, - className, -}) => ( +export const OvaVirtualMachinesList: React.FC = (props) => ( ); diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/ProviderVirtualMachines.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/ProviderVirtualMachines.tsx index f8300ab91..558a03d5a 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/ProviderVirtualMachines.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/ProviderVirtualMachines.tsx @@ -24,6 +24,7 @@ export interface ProviderVirtualMachinesProps { initialSelectedIds?: string[]; showActions: boolean; className?: string; + selectedCountLabel?: (selectedIdCount: number) => string; } export const ProviderVirtualMachines: React.FC<{ name: string; namespace: string }> = ({ @@ -70,82 +71,20 @@ export const ProviderVirtualMachines: React.FC<{ name: string; namespace: string ); }; -export const ProviderVirtualMachinesListWrapper: React.FC = ({ - title, - obj, - loaded, - loadError, - onSelect, - initialSelectedIds, - showActions, - className, -}) => { - switch (obj?.provider?.spec?.type) { +export const ProviderVirtualMachinesListWrapper: React.FC = ( + props, +) => { + switch (props.obj?.provider?.spec?.type) { case 'openshift': - return ( - - ); + return ; case 'openstack': - return ( - - ); + return ; case 'ovirt': - return ( - - ); + return ; case 'vsphere': - return ( - - ); + return ; case 'ova': - return ( - - ); + return ; default: // unsupported provider or loading errors will be handled by parent page return <>; diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/VSphereVirtualMachinesList.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/VSphereVirtualMachinesList.tsx index f1bde2e04..fc7b08606 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/VSphereVirtualMachinesList.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/tabs/VirtualMachines/VSphereVirtualMachinesList.tsx @@ -86,16 +86,8 @@ export const vSphereVmFieldsMetadataFactory: ResourceFieldFactory = (t) => [ }, ]; -export const VSphereVirtualMachinesList: React.FC = ({ - title, - obj, - loaded, - loadError, - onSelect, - initialSelectedIds, - showActions, - className, -}) => { +export const VSphereVirtualMachinesList: React.FC = (props) => { + const { obj } = props; const [hostsDict, foldersDict] = useVSphereInventoryVms({ provider: obj.provider }, true, null); const { vmData } = obj; @@ -119,17 +111,11 @@ export const VSphereVirtualMachinesList: React.FC return ( ); }; 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 d306dbec3..d5c4eb0c7 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 @@ -33,6 +33,7 @@ export interface ProviderVirtualMachinesListProps { initialSelectedIds?: string[]; showActions: boolean; className?: string; + selectedCountLabel?: (selectedIdCount: number) => string; } export const toId = (item: VmData) => item.vm.id; @@ -47,6 +48,7 @@ export const ProviderVirtualMachinesList: FC = initialSelectedIds, showActions, className, + selectedCountLabel, }) => { const { t } = useForkliftTranslation(); @@ -97,6 +99,7 @@ export const ProviderVirtualMachinesList: FC = page={1} expandedIds={initialExpandedIds_} ExpandedComponent={ConcernsTable} + selectedCountLabel={selectedCountLabel} /> ); }; diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/components/PlansCreateForm.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/components/PlansCreateForm.tsx index bb61cdf2a..4d581ad85 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/components/PlansCreateForm.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/components/PlansCreateForm.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode, useState } from 'react'; +import React, { ReactNode } from 'react'; import { FilterableSelect } from 'src/components'; import SectionHeading from 'src/components/headers/SectionHeading'; import { ForkliftTrans, useForkliftTranslation } from 'src/utils/i18n'; @@ -15,13 +15,11 @@ import { DescriptionList, DescriptionListDescription, DescriptionListGroup, - DescriptionListTerm, Form, FormSelect, FormSelectOption, Stack, StackItem, - TextInput, } from '@patternfly/react-core'; import { DetailsItem, getIsTarget } from '../../../utils'; @@ -34,13 +32,11 @@ import { removeAlert, replaceNetworkMapping, replaceStorageMapping, - setPlanName, setPlanTargetNamespace, setPlanTargetProvider, } from '../reducer/actions'; import { CreateVmMigrationPageState, NetworkAlerts, StorageAlerts } from '../types'; -import { EditableDescriptionItem } from './EditableDescriptionItem'; import { MappingList } from './MappingList'; import { MappingListHeader } from './MappingListHeader'; import { StateAlerts } from './StateAlerts'; @@ -143,17 +139,9 @@ export const PlansCreateForm = ({ alerts, } = state; - const [isNameEdited, setIsNameEdited] = useState(true); - const networkMessages = buildNetworkMessages(t); const storageMessages = buildStorageMessages(t); - const onChangePlan: (value: string, event: React.FormEvent) => void = ( - value, - ) => { - dispatch(setPlanName(value?.trim() ?? '')); - }; - const onChangeTargetProvider: ( value: string, event: React.FormEvent, @@ -170,39 +158,6 @@ export const PlansCreateForm = ({ default: '1Col', }} > - {isNameEdited || validation.planName === 'error' ? ( - - - onChangePlan(v, e)} - /> - - - ) : ( - setIsNameEdited(true)} - isDisabled={flow.editingDone} - /> - )} - } /> - - {t('Selected VMs')} - - {t('{{vmCount}} VMs selected ', { vmCount: plan.spec.vms?.length ?? 0 })} - -