Skip to content

Commit

Permalink
Merge pull request #875 from rszwajko/migrateBtnV11
Browse files Browse the repository at this point in the history
Add a fast Create Plan page - step 4
  • Loading branch information
yaacov authored Jan 31, 2024
2 parents 4e1f873 + bb199ba commit f5c19d2
Show file tree
Hide file tree
Showing 8 changed files with 430 additions and 226 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ interface MappingListProps {
availableDestinations: string[];
replaceMapping: (val: { current: Mapping; next: Mapping }) => void;
deleteMapping: (mapping: Mapping) => void;
addMapping: (mapping: Mapping) => void;
addMapping: () => void;
usedSourcesLabel: string;
generalSourcesLabel: string;
noSourcesLabel: string;
Expand Down Expand Up @@ -80,13 +80,7 @@ export const MappingList: FC<MappingListProps> = ({
))}
</DataList>
<Button
onClick={() =>
addMapping({
source: usedSources?.[0]?.label ?? generalSources?.[0]?.label,
// assume that the default exists and is first in the list
destination: availableDestinations?.[0],
})
}
onClick={addMapping}
type="button"
variant="link"
isDisabled={allMapped || isDisabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import { DetailsItem, getIsTarget } from '../../utils';
import { concernsMatcher, featuresMatcher, VmData } from '../details';

import {
addNetworkMapping,
deleteNetworkMapping,
PageAction,
replaceNetworkMapping,
replaceStorageMapping,
Expand Down Expand Up @@ -249,17 +251,17 @@ export const PlansCreateForm = ({
namespace={netMap.metadata?.namespace}
name={netMap.metadata?.name}
className="forklift-page-resource-link-in-description-item"
linkTo={flow.netMapCreated}
linkTo={false}
/>
</span>
</DescriptionListTerm>
<DescriptionListDescription className="forklift-page-mapping-list">
<MappingList
addMapping={(newMapping) => dispatch(replaceNetworkMapping({ next: newMapping }))}
addMapping={() => dispatch(addNetworkMapping())}
replaceMapping={({ current, next }) =>
dispatch(replaceNetworkMapping({ current, next }))
}
deleteMapping={(current) => dispatch(replaceNetworkMapping({ current }))}
deleteMapping={(current) => dispatch(deleteNetworkMapping({ ...current }))}
availableDestinations={targetNetworks}
sources={sourceNetworks}
mappings={networkMappings}
Expand All @@ -279,17 +281,17 @@ export const PlansCreateForm = ({
namespace={storageMap.metadata?.namespace}
name={storageMap.metadata?.name}
className="forklift-page-resource-link-in-description-item"
linkTo={flow.storageMapCreated}
linkTo={false}
/>
</span>
</DescriptionListTerm>
<DescriptionListDescription className="forklift-page-mapping-list">
<MappingList
addMapping={(newMapping) => dispatch(replaceStorageMapping({ next: newMapping }))}
addMapping={() => dispatch(addNetworkMapping())}
replaceMapping={({ current, next }) =>
dispatch(replaceStorageMapping({ current, next }))
}
deleteMapping={(current) => dispatch(replaceStorageMapping({ current }))}
deleteMapping={() => undefined}
availableDestinations={targetStorages}
sources={[]}
mappings={storageMappings}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,169 +1,22 @@
import React, { FC, useEffect, useRef } from 'react';
import React, { FC } from 'react';
import { useHistory } from 'react-router';
import SectionHeading from 'src/components/headers/SectionHeading';
import { useForkliftTranslation } from 'src/utils/i18n';
import { useImmerReducer } from 'use-immer';

import {
NetworkMapModel,
NetworkMapModelGroupVersionKind,
PlanModelGroupVersionKind,
ProviderModelGroupVersionKind,
ProviderModelRef,
V1beta1NetworkMap,
V1beta1Plan,
V1beta1Provider,
} from '@kubev2v/types';
import { k8sCreate, useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk';
import { Button, Flex, FlexItem, PageSection } from '@patternfly/react-core';
import { Alert, Button, Flex, FlexItem, PageSection } from '@patternfly/react-core';

import { useToggle } from '../../hooks';
import { useNamespaces } from '../../hooks/useNamespaces';
import { useOpenShiftNetworks, useSourceNetworks } from '../../hooks/useNetworks';
import { useNicProfiles } from '../../hooks/useNicProfiles';
import { getResourceUrl } from '../../utils';

import {
setAvailableProviders,
setAvailableSourceNetworks,
setAvailableTargetNamespaces,
setAvailableTargetNetworks,
setExistingNetMaps,
setExistingPlans,
setNetMap,
setNicProfiles,
startCreate,
} from './actions';
import { startCreate } from './actions';
import { PlansCreateForm } from './PlansCreateForm';
import { useCreateVmMigrationData } from './ProvidersCreateVmMigrationContext';
import { reducer } from './reducer';
import { createInitialState } from './stateHelpers';
import { useFetchEffects } from './useFetchEffects';
import { useSaveEffect } from './useSaveEffect';

const ProvidersCreateVmMigrationPage: FC<{
namespace: string;
}> = ({ namespace }) => {
const ProvidersCreateVmMigrationPage: FC = () => {
const { t } = useForkliftTranslation();
const history = useHistory();
const [state, dispatch, emptyContext] = useFetchEffects();
useSaveEffect(state, dispatch);

const { data: { selectedVms = [], provider: sourceProvider = undefined } = {} } =
useCreateVmMigrationData();
// error state - the page was entered directly without choosing the VMs
const emptyContext = !selectedVms?.length || !sourceProvider;
// error recovery - redirect to provider list
useEffect(() => {
if (emptyContext) {
history.push(
getResourceUrl({
reference: ProviderModelRef,
namespace: namespace,
}),
);
}
}, [emptyContext]);

const [state, dispatch] = useImmerReducer(
reducer,
{ namespace, sourceProvider, selectedVms },
createInitialState,
);
const {
workArea: { targetProvider },
} = state;

const [providers, providersLoaded, providerError] = useK8sWatchResource<V1beta1Provider[]>({
groupVersionKind: ProviderModelGroupVersionKind,
namespaced: true,
isList: true,
namespace,
});
useEffect(
() => dispatch(setAvailableProviders(providers, providersLoaded, providerError)),
[providers],
);

const [plans, plansLoaded, plansError] = useK8sWatchResource<V1beta1Plan[]>({
groupVersionKind: PlanModelGroupVersionKind,
namespaced: true,
isList: true,
namespace,
});
useEffect(
() => dispatch(setExistingPlans(plans, plansLoaded, plansError)),
[plans, plansLoaded, plansError],
);

const [netMaps, netMapsLoaded, netMapsError] = useK8sWatchResource<V1beta1NetworkMap[]>({
groupVersionKind: NetworkMapModelGroupVersionKind,
namespaced: true,
isList: true,
namespace,
});
useEffect(
() => dispatch(setExistingNetMaps(netMaps, netMapsLoaded, netMapsError)),
[netMaps, netMapsLoaded, netMapsError],
);

const [namespaces, nsLoading, nsError] = useNamespaces(targetProvider);
useEffect(
() => dispatch(setAvailableTargetNamespaces(namespaces, nsLoading, nsError)),
[namespaces, nsLoading, nsError],
);

const [targetNetworks, targetNetworksLoading, targetNetworksError] =
useOpenShiftNetworks(targetProvider);
useEffect(
() =>
dispatch(
setAvailableTargetNetworks(targetNetworks, targetNetworksLoading, targetNetworksError),
),
[targetNetworks, targetNetworksLoading, targetNetworksError],
);

const [sourceNetworks, sourceNetworksLoading, sourceNetworksError] =
useSourceNetworks(sourceProvider);
useEffect(
() =>
dispatch(
setAvailableSourceNetworks(sourceNetworks, sourceNetworksLoading, sourceNetworksError),
),
[sourceNetworks, sourceNetworksLoading, sourceNetworksError],
);

const [nicProfiles, nicProfilesLoading, nicProfilesError] = useNicProfiles(sourceProvider);
useEffect(
() => dispatch(setNicProfiles(nicProfiles, nicProfilesLoading, nicProfilesError)),
[nicProfiles, nicProfilesLoading, nicProfilesError],
);

const mounted = useRef(true);
useEffect(
() => () => {
mounted.current = false;
},
[],
);

useEffect(() => {
if (!state.flow.editingDone || !mounted.current) {
return;
}
const create = async (netMap: V1beta1NetworkMap) => {
const created = await k8sCreate({
model: NetworkMapModel,
data: netMap,
});
if (mounted.current) {
dispatch(setNetMap({ netMap: created }));
}
};

create(state.underConstruction.netMap).catch((error) => {
dispatch(setNetMap({ error }));
});
}, [state.flow.editingDone, state.underConstruction.netMap]);

const [isLoading, toggleIsLoading] = useToggle();
const onUpdate = toggleIsLoading;
const isLoading = state.flow.editingDone && !state.flow.apiError;

if (emptyContext) {
// display empty node and wait for redirect triggered from useEffect
Expand All @@ -177,7 +30,16 @@ const ProvidersCreateVmMigrationPage: FC<{
<SectionHeading text={t('Create Plan')} />

<PlansCreateForm state={state} dispatch={dispatch} />

{state.flow.apiError && (
<Alert
className="co-alert co-alert--margin-top"
isInline
variant="danger"
title={t('Error')}
>
{state.flow.apiError.message || state.flow.apiError.toString()}
</Alert>
)}
<Flex>
<FlexItem>
<Button
Expand All @@ -192,7 +54,7 @@ const ProvidersCreateVmMigrationPage: FC<{
</Button>
</FlexItem>
<FlexItem>
<Button variant="secondary" onClick={onUpdate} isDisabled={true} isLoading={isLoading}>
<Button variant="secondary" isDisabled={true} isLoading={isLoading}>
{t('Create and start')}
</Button>
</FlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ export const SET_EXISTING_PLANS = 'SET_EXISTING_PLANS';
export const SET_AVAILABLE_TARGET_NAMESPACES = 'SET_AVAILABLE_TARGET_NAMESPACES';
export const REPLACE_NETWORK_MAPPING = 'REPLACE_NETWORK_MAPPING';
export const REPLACE_STORAGE_MAPPING = 'REPLACE_STORAGE_MAPPING';
export const ADD_NETWORK_MAPPING = 'ADD_NETWORK_MAPPING';
export const DELETE_NETWORK_MAPPING = 'DELETE_NETWORK_MAPPING';
export const SET_AVAILABLE_TARGET_NETWORKS = 'SET_AVAILABLE_TARGET_NETWORKS';
export const SET_AVAILABLE_SOURCE_NETWORKS = 'SET_AVAILABLE_SOURCE_NETWORKS';
export const SET_NICK_PROFILES = 'SET_NICK_PROFILES';
export const SET_EXISTING_NET_MAPS = 'SET_EXISTING_NET_MAPS';
export const START_CREATE = 'START_CREATE';
export const SET_NET_MAP = 'SET_NET_MAP';
export const SET_ERROR = 'SET_ERROR';

export type CreateVmMigration =
| typeof SET_NAME
Expand All @@ -40,13 +42,15 @@ export type CreateVmMigration =
| typeof SET_EXISTING_PLANS
| typeof SET_AVAILABLE_TARGET_NAMESPACES
| typeof REPLACE_NETWORK_MAPPING
| typeof ADD_NETWORK_MAPPING
| typeof DELETE_NETWORK_MAPPING
| typeof REPLACE_STORAGE_MAPPING
| typeof SET_AVAILABLE_TARGET_NETWORKS
| typeof SET_AVAILABLE_SOURCE_NETWORKS
| typeof SET_NICK_PROFILES
| typeof SET_EXISTING_NET_MAPS
| typeof START_CREATE
| typeof SET_NET_MAP;
| typeof SET_ERROR;

export interface PageAction<S, T> {
type: S;
Expand Down Expand Up @@ -113,14 +117,13 @@ export interface PlanNickProfiles {
error?: Error;
}

export interface PlanCrateNetMap {
netMap?: V1beta1NetworkMap;
error?: Error;
export interface PlanError {
error: Error;
}

export interface PlanMapping {
current?: Mapping;
next?: Mapping;
current: Mapping;
next: Mapping;
}

// action creators
Expand Down Expand Up @@ -209,6 +212,11 @@ export const replaceStorageMapping = ({
payload: { current, next },
});

export const addNetworkMapping = (): PageAction<CreateVmMigration, unknown> => ({
type: 'ADD_NETWORK_MAPPING',
payload: {},
});

export const replaceNetworkMapping = ({
current,
next,
Expand All @@ -217,6 +225,14 @@ export const replaceNetworkMapping = ({
payload: { current, next },
});

export const deleteNetworkMapping = ({
source,
destination,
}: Mapping): PageAction<CreateVmMigration, Mapping> => ({
type: 'DELETE_NETWORK_MAPPING',
payload: { source, destination },
});

export const setAvailableTargetNetworks = (
availableTargetNetworks: OpenShiftNetworkAttachmentDefinition[],
loading: boolean,
Expand Down Expand Up @@ -249,10 +265,7 @@ export const startCreate = (): PageAction<CreateVmMigration, unknown> => ({
payload: {},
});

export const setNetMap = ({
netMap,
error,
}: PlanCrateNetMap): PageAction<CreateVmMigration, PlanCrateNetMap> => ({
type: 'SET_NET_MAP',
payload: { netMap, error },
export const setError = (error: Error): PageAction<CreateVmMigration, PlanError> => ({
type: 'SET_ERROR',
payload: { error },
});
Loading

0 comments on commit f5c19d2

Please sign in to comment.