From f5d944707f126967ea59f3fb2dddceaca39702e9 Mon Sep 17 00:00:00 2001 From: swaroopar Date: Thu, 11 Apr 2024 08:41:06 +0000 Subject: [PATCH] fix availability zone display errors Signed-off-by: swaroopar --- .../order/common/AvailabilityZoneInfo.tsx | 5 +- .../AvailabilityZoneButton.tsx | 95 +++++++++++++++ .../AvailabilityZoneError.tsx | 32 +++++ .../AvailabilityZoneFormItem.tsx | 70 +++++++++++ .../AvailabilityZoneLoading.tsx | 11 ++ ...useGetAvailabilityZonesForRegionQuery.tsx} | 6 +- .../content/order/create/CreateService.tsx | 7 +- .../content/order/create/GoToSubmit.tsx | 7 +- .../order/create/SelectServiceForm.tsx | 109 +++++++++++------- .../formDataHelpers/deployParamsHelper.ts | 2 +- ...vailabilityZoneRequirementsForAService.ts} | 8 +- .../order/migrate/MigrateServiceSubmit.tsx | 9 +- .../order/migrate/SelectDestination.tsx | 80 +++++++------ 13 files changed, 348 insertions(+), 93 deletions(-) create mode 100644 src/components/content/order/common/availabilityzone/AvailabilityZoneButton.tsx create mode 100644 src/components/content/order/common/availabilityzone/AvailabilityZoneError.tsx create mode 100644 src/components/content/order/common/availabilityzone/AvailabilityZoneFormItem.tsx create mode 100644 src/components/content/order/common/availabilityzone/AvailabilityZoneLoading.tsx rename src/components/content/order/common/utils/{useAvailabilityZonesVariableQuery.tsx => useGetAvailabilityZonesForRegionQuery.tsx} (54%) rename src/components/content/order/formDataHelpers/{getAvailabilityZoneConfigs.ts => getAvailabilityZoneRequirementsForAService.ts} (74%) diff --git a/src/components/content/order/common/AvailabilityZoneInfo.tsx b/src/components/content/order/common/AvailabilityZoneInfo.tsx index 0268af155..12c7d2cbd 100644 --- a/src/components/content/order/common/AvailabilityZoneInfo.tsx +++ b/src/components/content/order/common/AvailabilityZoneInfo.tsx @@ -32,8 +32,7 @@ export const AvailabilityZoneInfo = ({ ? availabilityZoneConfigs.map((availabilityZone) => ( {availabilityZone.displayName}

} rules={[ { required: availabilityZone.mandatory, @@ -69,7 +68,7 @@ export const AvailabilityZoneInfo = ({ onChange={(e) => { onAvailabilityZoneChange(availabilityZone.varName, e); }} - value={selectAvailabilityZones[availabilityZone.varName]} + //value={selectAvailabilityZones[availabilityZone.varName]} > {'Not Selected'} diff --git a/src/components/content/order/common/availabilityzone/AvailabilityZoneButton.tsx b/src/components/content/order/common/availabilityzone/AvailabilityZoneButton.tsx new file mode 100644 index 000000000..940652985 --- /dev/null +++ b/src/components/content/order/common/availabilityzone/AvailabilityZoneButton.tsx @@ -0,0 +1,95 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: Huawei Inc. + */ + +import { AvailabilityZoneConfig } from '../../../../../xpanse-api/generated'; +import { Alert, Flex, Radio } from 'antd'; +import React from 'react'; + +export function AvailabilityZoneButton({ + availabilityZoneConfig, + availabilityZones, + selectRegion, + onAvailabilityZoneChange, + selectAvailabilityZones, +}: { + availabilityZoneConfig: AvailabilityZoneConfig; + availabilityZones: string[] | undefined; + selectRegion: string; + onAvailabilityZoneChange: (varName: string, availabilityZone: string | undefined) => void; + selectAvailabilityZones: Record; +}) { + const DEFAULT_OPTIONAL_AZ = 'Not Selected'; + function onChange(varName: string, availabilityZone: string) { + onAvailabilityZoneChange(varName, availabilityZone !== DEFAULT_OPTIONAL_AZ ? availabilityZone : undefined); + } + + return ( + <> + + {availabilityZoneConfig.mandatory ? ( + availabilityZones && availabilityZones.length > 0 ? ( + { + onChange(availabilityZoneConfig.varName, e.target.value as string); + }} + value={selectAvailabilityZones[availabilityZoneConfig.varName]} + > + {availabilityZones.map((availabilityZonesVariable) => ( + + {availabilityZonesVariable} + + ))} + + ) : ( + + ) + ) : ( + { + onChange(availabilityZoneConfig.varName, e.target.value as string); + }} + value={selectAvailabilityZones[availabilityZoneConfig.varName] ?? DEFAULT_OPTIONAL_AZ} + > + {availabilityZones && availabilityZones.length > 0 ? ( + <> + + {DEFAULT_OPTIONAL_AZ} + + {availabilityZones.map((availabilityZonesVariable) => ( + + {availabilityZonesVariable} + + ))} + ; + + ) : ( + + )} + + )} + + + ); +} diff --git a/src/components/content/order/common/availabilityzone/AvailabilityZoneError.tsx b/src/components/content/order/common/availabilityzone/AvailabilityZoneError.tsx new file mode 100644 index 000000000..ba00565c6 --- /dev/null +++ b/src/components/content/order/common/availabilityzone/AvailabilityZoneError.tsx @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: Huawei Inc. + */ + +import { ApiError, Response } from '../../../../../xpanse-api/generated'; +import { Alert } from 'antd'; +import { convertStringArrayToUnorderedList } from '../../../../utils/generateUnorderedList'; +import React from 'react'; + +export function AvailabilityZoneError({ error }: { error: Error }) { + if (error instanceof ApiError && error.body && 'details' in error.body) { + const response: Response = error.body as Response; + return ( + + ); + } else { + return ( + + ); + } +} diff --git a/src/components/content/order/common/availabilityzone/AvailabilityZoneFormItem.tsx b/src/components/content/order/common/availabilityzone/AvailabilityZoneFormItem.tsx new file mode 100644 index 000000000..5cb55efd2 --- /dev/null +++ b/src/components/content/order/common/availabilityzone/AvailabilityZoneFormItem.tsx @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: Huawei Inc. + */ + +import { AvailabilityZoneConfig, UserOrderableServiceVo } from '../../../../../xpanse-api/generated'; +import { Form } from 'antd'; +import React from 'react'; +import { AvailabilityZoneButton } from './AvailabilityZoneButton'; +import useGetAvailabilityZonesForRegionQuery from '../utils/useGetAvailabilityZonesForRegionQuery'; +import { AvailabilityZoneLoading } from './AvailabilityZoneLoading'; +import { AvailabilityZoneError } from './AvailabilityZoneError'; + +export function AvailabilityZoneFormItem({ + availabilityZoneConfig, + selectRegion, + onAvailabilityZoneChange, + selectAvailabilityZones, + selectCsp, +}: { + availabilityZoneConfig: AvailabilityZoneConfig; + selectRegion: string; + onAvailabilityZoneChange: (varName: string, availabilityZone: string | undefined) => void; + selectAvailabilityZones: Record; + selectCsp: UserOrderableServiceVo.csp; +}) { + const availabilityZonesVariableRequest = useGetAvailabilityZonesForRegionQuery(selectCsp, selectRegion); + + function getFormContent() { + if (availabilityZonesVariableRequest.isLoading || availabilityZonesVariableRequest.isFetching) { + return ; + } + if (availabilityZonesVariableRequest.isError) { + return ( + + ); + } + if (availabilityZonesVariableRequest.data) { + return ( + + ); + } + return null; + } + return ( + {availabilityZoneConfig.displayName}

} + required={availabilityZoneConfig.mandatory} + rules={[ + { + required: availabilityZoneConfig.mandatory, + message: availabilityZoneConfig.displayName + 'is required', + }, + { type: 'string' }, + ]} + > + {getFormContent()} +
+ ); +} diff --git a/src/components/content/order/common/availabilityzone/AvailabilityZoneLoading.tsx b/src/components/content/order/common/availabilityzone/AvailabilityZoneLoading.tsx new file mode 100644 index 000000000..04eb23882 --- /dev/null +++ b/src/components/content/order/common/availabilityzone/AvailabilityZoneLoading.tsx @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: Huawei Inc. + */ + +import { Skeleton } from 'antd'; +import React from 'react'; + +export function AvailabilityZoneLoading() { + return ; +} diff --git a/src/components/content/order/common/utils/useAvailabilityZonesVariableQuery.tsx b/src/components/content/order/common/utils/useGetAvailabilityZonesForRegionQuery.tsx similarity index 54% rename from src/components/content/order/common/utils/useAvailabilityZonesVariableQuery.tsx rename to src/components/content/order/common/utils/useGetAvailabilityZonesForRegionQuery.tsx index 8cbd25ce1..123fb502d 100644 --- a/src/components/content/order/common/utils/useAvailabilityZonesVariableQuery.tsx +++ b/src/components/content/order/common/utils/useGetAvailabilityZonesForRegionQuery.tsx @@ -4,11 +4,13 @@ */ import { useQuery } from '@tanstack/react-query'; -import { DeployRequest, ServiceService } from '../../../../../xpanse-api/generated'; +import { ServiceService, UserOrderableServiceVo } from '../../../../../xpanse-api/generated'; -export default function useAvailabilityZonesVariableQuery(csp: DeployRequest.csp, region: string) { +export default function useGetAvailabilityZonesForRegionQuery(csp: UserOrderableServiceVo.csp, region: string) { return useQuery({ queryKey: ['getExistingResourceNamesWithKind', csp, region], queryFn: () => ServiceService.getAvailabilityZones(csp, region), + gcTime: 60000, + staleTime: Infinity, }); } diff --git a/src/components/content/order/create/CreateService.tsx b/src/components/content/order/create/CreateService.tsx index a4d0aaac6..3b57bd95d 100644 --- a/src/components/content/order/create/CreateService.tsx +++ b/src/components/content/order/create/CreateService.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { useSearchParams } from 'react-router-dom'; -import { UserOrderableServiceVo } from '../../../../xpanse-api/generated'; +import { DeployedService } from '../../../../xpanse-api/generated'; import { Skeleton } from 'antd'; import ServicesLoadingError from '../query/ServicesLoadingError'; import userOrderableServicesQuery from '../query/userOrderableServicesQuery'; @@ -16,10 +16,7 @@ function CreateService(): React.JSX.Element { const [urlParams] = useSearchParams(); const serviceName = decodeURI(urlParams.get('serviceName') ?? ''); const categoryName = decodeURI(urlParams.get('catalog') ?? ''); - const orderableServicesQuery = userOrderableServicesQuery( - categoryName as UserOrderableServiceVo.category, - serviceName - ); + const orderableServicesQuery = userOrderableServicesQuery(categoryName as DeployedService.category, serviceName); if (orderableServicesQuery.isSuccess) { return ; diff --git a/src/components/content/order/create/GoToSubmit.tsx b/src/components/content/order/create/GoToSubmit.tsx index b46bbfa07..5130f8222 100644 --- a/src/components/content/order/create/GoToSubmit.tsx +++ b/src/components/content/order/create/GoToSubmit.tsx @@ -10,6 +10,7 @@ import { useNavigate } from 'react-router-dom'; import React from 'react'; import { orderPageRoute } from '../../../utils/constants'; import { OrderSubmitProps } from '../common/utils/OrderSubmitProps'; +import useGetAvailabilityZonesForRegionQuery from '../common/utils/useGetAvailabilityZonesForRegionQuery'; export default function GoToSubmit({ selectedVersion, @@ -20,6 +21,7 @@ export default function GoToSubmit({ selectedServiceHostingType, currentServiceProviderContactDetails, availabilityZones, + isDisableNextButton, }: { selectedVersion: string; selectedCsp: UserOrderableServiceVo.csp; @@ -29,9 +31,10 @@ export default function GoToSubmit({ versionMapper: Map; currentServiceProviderContactDetails: ServiceProviderContactDetails | undefined; availabilityZones: Record | undefined; + isDisableNextButton: boolean; }): React.JSX.Element { const navigate = useNavigate(); - + useGetAvailabilityZonesForRegionQuery(selectedCsp, region.name); const gotoOrderSubmit = function () { const orderSubmitParams: OrderSubmitProps = getDeployParams( versionMapper.get(selectedVersion) ?? [], @@ -59,7 +62,7 @@ export default function GoToSubmit({
-
diff --git a/src/components/content/order/create/SelectServiceForm.tsx b/src/components/content/order/create/SelectServiceForm.tsx index e47d79195..02d3a4fa5 100644 --- a/src/components/content/order/create/SelectServiceForm.tsx +++ b/src/components/content/order/create/SelectServiceForm.tsx @@ -4,7 +4,7 @@ */ import { To, useLocation, useSearchParams } from 'react-router-dom'; -import React, { useMemo, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { AvailabilityZoneConfig, Billing, @@ -34,9 +34,9 @@ import { BillingInfo } from '../common/BillingInfo'; import GoToSubmit from './GoToSubmit'; import { servicesSubPageRoute } from '../../../utils/constants'; import { OrderSubmitProps } from '../common/utils/OrderSubmitProps'; -import { getAvailabilityZoneConfigs } from '../formDataHelpers/getAvailabilityZoneConfigs'; -import { AvailabilityZoneInfo } from '../common/AvailabilityZoneInfo'; -import useAvailabilityZonesVariableQuery from '../common/utils/useAvailabilityZonesVariableQuery'; +import useGetAvailabilityZonesForRegionQuery from '../common/utils/useGetAvailabilityZonesForRegionQuery'; +import { getAvailabilityZoneRequirementsForAService } from '../formDataHelpers/getAvailabilityZoneRequirementsForAService'; +import { AvailabilityZoneFormItem } from '../common/availabilityzone/AvailabilityZoneFormItem'; export function SelectServiceForm({ services }: { services: UserOrderableServiceVo[] }): React.JSX.Element { const [urlParams] = useSearchParams(); @@ -69,14 +69,18 @@ export function SelectServiceForm({ services }: { services: UserOrderableService const versionList: { value: string; label: string }[] = getSortedVersionList(versionToServicesMap); const [selectVersion, setSelectVersion] = useState(serviceInfo ? serviceInfo.version : latestVersion); let cspList: UserOrderableServiceVo.csp[] = getCspListForVersion(selectVersion, versionToServicesMap); - const [selectCsp, setSelectCsp] = useState(serviceInfo ? serviceInfo.csp : cspList[0]); + const [selectCsp, setSelectCsp] = useState( + serviceInfo ? (serviceInfo.csp as UserOrderableServiceVo.csp) : cspList[0] + ); let serviceHostTypes: UserOrderableServiceVo.serviceHostingType[] = getAvailableServiceHostingTypes( selectCsp, versionToServicesMap.get(selectVersion) ); const [selectServiceHostType, setSelectServiceHostType] = useState( - serviceInfo ? serviceInfo.serviceHostingType : serviceHostTypes[0] + serviceInfo + ? (serviceInfo.serviceHostingType as UserOrderableServiceVo.serviceHostingType) + : serviceHostTypes[0] ); let areaList: Tab[] = convertAreasToTabs(selectCsp, selectServiceHostType, versionToServicesMap.get(selectVersion)); const [selectArea, setSelectArea] = useState(serviceInfo ? serviceInfo.area : areaList[0].key); @@ -87,35 +91,9 @@ export function SelectServiceForm({ services }: { services: UserOrderableService versionToServicesMap.get(selectVersion) ); const [selectRegion, setSelectRegion] = useState(serviceInfo ? serviceInfo.region : regionList[0].value); - - const availabilityZonesVariableRequest = useAvailabilityZonesVariableQuery(selectCsp, selectRegion); - const availabilityZoneConfigs: AvailabilityZoneConfig[] | undefined = getAvailabilityZoneConfigs( - selectCsp, - versionToServicesMap.get(selectVersion) - ); const [selectAvailabilityZones, setSelectAvailabilityZones] = useState>( serviceInfo?.availabilityZones ?? {} ); - const availabilityZones = useMemo(() => { - if (availabilityZoneConfigs && availabilityZonesVariableRequest.isSuccess) { - availabilityZoneConfigs.forEach((availabilityZone) => { - setSelectAvailabilityZones((prevState: Record) => ({ - ...prevState, - [availabilityZone.varName]: availabilityZone.mandatory - ? availabilityZonesVariableRequest.data[0] - : '', - })); - }); - return availabilityZonesVariableRequest.data; - } else { - return []; - } - }, [ - availabilityZoneConfigs, - availabilityZonesVariableRequest.isSuccess, - availabilityZonesVariableRequest.data, - setSelectAvailabilityZones, - ]); let flavorList: Flavor[] = getFlavorList(selectCsp, selectServiceHostType, versionToServicesMap.get(selectVersion)); const [selectFlavor, setSelectFlavor] = useState(serviceInfo ? serviceInfo.flavor : flavorList[0].value); @@ -125,6 +103,31 @@ export function SelectServiceForm({ services }: { services: UserOrderableService getContactServiceDetailsOfServiceByCsp(selectCsp, versionToServicesMap.get(selectVersion)); let currentBilling: Billing = getBilling(selectCsp, selectServiceHostType, versionToServicesMap.get(selectVersion)); + const getAvailabilityZonesForRegionQuery = useGetAvailabilityZonesForRegionQuery(selectCsp, selectRegion); + const availabilityZoneConfigs: AvailabilityZoneConfig[] = getAvailabilityZoneRequirementsForAService( + selectCsp, + services + ); + + // Side effect needed to update initial state when data from backend is available. + useEffect(() => { + if (!serviceInfo?.availabilityZones) { + if (getAvailabilityZonesForRegionQuery.isSuccess && getAvailabilityZonesForRegionQuery.data.length > 0) { + if (availabilityZoneConfigs.length > 0) { + const defaultSelection: Record = {}; + availabilityZoneConfigs.forEach((availabilityZoneConfig) => { + if (availabilityZoneConfig.mandatory) { + defaultSelection[availabilityZoneConfig.varName] = + getAvailabilityZonesForRegionQuery.data[0]; + } + }); + setSelectAvailabilityZones(defaultSelection); + } + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [getAvailabilityZonesForRegionQuery.isSuccess, getAvailabilityZonesForRegionQuery.data]); + const onChangeServiceHostingType = (serviceHostingType: UserOrderableServiceVo.serviceHostingType) => { location.state = undefined; setSelectServiceHostType(serviceHostingType); @@ -204,6 +207,24 @@ export function SelectServiceForm({ services }: { services: UserOrderableService setSelectServiceHostType(serviceHostTypes[0]); }; + function onAvailabilityZoneChange(varName: string, availabilityZone: string | undefined) { + if (availabilityZone !== undefined) { + setSelectAvailabilityZones((prevState: Record) => ({ + ...prevState, + [varName]: availabilityZone, + })); + } else { + const newAvailabilityZone = selectAvailabilityZones; + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete newAvailabilityZone[varName]; + setSelectAvailabilityZones({ ...newAvailabilityZone }); + } + } + + function isAvailabilityZoneRequired(): boolean { + return availabilityZoneConfigs.filter((availabilityZoneConfig) => availabilityZoneConfig.mandatory).length > 0; + } + return ( <>
@@ -269,14 +290,18 @@ export function SelectServiceForm({ services }: { services: UserOrderableService />
- {availabilityZonesVariableRequest.isSuccess ? ( - - ) : undefined} + {availabilityZoneConfigs.map((availabilityZoneConfig) => { + return ( + + ); + })}
@@ -291,6 +316,10 @@ export function SelectServiceForm({ services }: { services: UserOrderableService selectedServiceHostingType={selectServiceHostType} currentServiceProviderContactDetails={currentServiceProviderContactDetails} availabilityZones={selectAvailabilityZones} + isDisableNextButton={ + getAvailabilityZonesForRegionQuery.isError || + (isAvailabilityZoneRequired() && getAvailabilityZonesForRegionQuery.data?.length === 0) + } /> diff --git a/src/components/content/order/formDataHelpers/deployParamsHelper.ts b/src/components/content/order/formDataHelpers/deployParamsHelper.ts index b797833d2..b6e06d56d 100644 --- a/src/components/content/order/formDataHelpers/deployParamsHelper.ts +++ b/src/components/content/order/formDataHelpers/deployParamsHelper.ts @@ -42,7 +42,7 @@ export const getDeployParams = ( csp: service?.csp as DeployRequest.csp, flavor: selectFlavor, params: new Array(), - serviceHostingType: selectServiceHostingType, + serviceHostingType: selectServiceHostingType as DeployRequest.serviceHostingType, contactServiceDetails: currentContactServiceDetails ?? undefined, availabilityZones: availabilityZones, }; diff --git a/src/components/content/order/formDataHelpers/getAvailabilityZoneConfigs.ts b/src/components/content/order/formDataHelpers/getAvailabilityZoneRequirementsForAService.ts similarity index 74% rename from src/components/content/order/formDataHelpers/getAvailabilityZoneConfigs.ts rename to src/components/content/order/formDataHelpers/getAvailabilityZoneRequirementsForAService.ts index 984443a65..de4d009d0 100644 --- a/src/components/content/order/formDataHelpers/getAvailabilityZoneConfigs.ts +++ b/src/components/content/order/formDataHelpers/getAvailabilityZoneRequirementsForAService.ts @@ -5,15 +5,15 @@ import { AvailabilityZoneConfig, UserOrderableServiceVo } from '../../../../xpanse-api/generated'; -export function getAvailabilityZoneConfigs( +export function getAvailabilityZoneRequirementsForAService( selectCsp: UserOrderableServiceVo.csp, services: UserOrderableServiceVo[] | undefined -): AvailabilityZoneConfig[] | undefined { - let availabilityZoneConfigs: AvailabilityZoneConfig[] | undefined = undefined; +): AvailabilityZoneConfig[] { + let availabilityZoneConfigs: AvailabilityZoneConfig[] = []; if (services) { services.forEach((userOrderableServiceVo) => { if (userOrderableServiceVo.csp === selectCsp) { - availabilityZoneConfigs = userOrderableServiceVo.serviceAvailability; + availabilityZoneConfigs = userOrderableServiceVo.serviceAvailability ?? []; } }); } diff --git a/src/components/content/order/migrate/MigrateServiceSubmit.tsx b/src/components/content/order/migrate/MigrateServiceSubmit.tsx index eef8ff05f..46e5b43a3 100644 --- a/src/components/content/order/migrate/MigrateServiceSubmit.tsx +++ b/src/components/content/order/migrate/MigrateServiceSubmit.tsx @@ -32,7 +32,7 @@ import { useServiceDetailsPollingQuery, } from './useMigrateServiceQuery'; import useGetOrderableServiceDetailsQuery from '../../deployedServices/myServices/query/useGetOrderableServiceDetailsQuery'; -import { getAvailabilityZoneConfigs } from '../formDataHelpers/getAvailabilityZoneConfigs'; +import { getAvailabilityZoneRequirementsForAService } from '../formDataHelpers/getAvailabilityZoneRequirementsForAService'; import { MigrateServiceSubmitAvailabilityZoneInfo } from '../common/MigrateServiceSubmitAvailabilityZoneInfo'; import migrationStatus = ServiceMigrationDetails.migrationStatus; @@ -85,7 +85,7 @@ export const MigrateServiceSubmit = ({ ); const deployServiceDetailsQuery = useServiceDetailsPollingQuery( migrateServiceDetailsQuery.data?.newServiceId, - selectServiceHostingType, + selectServiceHostingType as DeployedService.serviceHostingType, migrateServiceDetailsQuery.data?.migrationStatus ); const destroyServiceDetailsQuery = useServiceDetailsPollingQuery( @@ -173,7 +173,10 @@ export const MigrateServiceSubmit = ({ {Object.keys(availabilityZones).length > 0 ? ( ) : undefined} diff --git a/src/components/content/order/migrate/SelectDestination.tsx b/src/components/content/order/migrate/SelectDestination.tsx index aa37ec64e..d852a9245 100644 --- a/src/components/content/order/migrate/SelectDestination.tsx +++ b/src/components/content/order/migrate/SelectDestination.tsx @@ -7,7 +7,7 @@ import CspSelect from '../formElements/CspSelect'; import { AvailabilityZoneConfig, Billing, UserOrderableServiceVo } from '../../../../xpanse-api/generated'; import { Button, Form, Space, StepProps, Tabs } from 'antd'; import { Tab } from 'rc-tabs/lib/interface'; -import React, { Dispatch, SetStateAction, useMemo, useState } from 'react'; +import React, { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react'; import { Region } from '../types/Region'; import { Flavor } from '../types/Flavor'; import { getAvailableServiceHostingTypes } from '../formDataHelpers/serviceHostingTypeHelper'; @@ -21,9 +21,9 @@ import '../../../../styles/service_order.css'; import { BillingInfo } from '../common/BillingInfo'; import { RegionInfo } from '../common/RegionInfo'; import { FlavorInfo } from '../common/FlavorInfo'; -import { AvailabilityZoneInfo } from '../common/AvailabilityZoneInfo'; -import useAvailabilityZonesVariableQuery from '../common/utils/useAvailabilityZonesVariableQuery'; -import { getAvailabilityZoneConfigs } from '../formDataHelpers/getAvailabilityZoneConfigs'; +import useGetAvailabilityZonesForRegionQuery from '../common/utils/useGetAvailabilityZonesForRegionQuery'; +import { getAvailabilityZoneRequirementsForAService } from '../formDataHelpers/getAvailabilityZoneRequirementsForAService'; +import { AvailabilityZoneFormItem } from '../common/availabilityzone/AvailabilityZoneFormItem'; export const SelectDestination = ({ userOrderableServiceVoList, @@ -82,31 +82,27 @@ export const SelectDestination = ({ ); const [selectRegion, setSelectRegion] = useState(currentRegion); - const availabilityZonesVariableRequest = useAvailabilityZonesVariableQuery(selectCsp, selectRegion); - const availabilityZoneConfigs: AvailabilityZoneConfig[] | undefined = getAvailabilityZoneConfigs( + const getAvailabilityZonesForRegionQuery = useGetAvailabilityZonesForRegionQuery(selectCsp, selectRegion); + const availabilityZoneConfigs: AvailabilityZoneConfig[] = getAvailabilityZoneRequirementsForAService( selectCsp, userOrderableServiceVoList ); - const availabilityZones = useMemo(() => { - if (availabilityZoneConfigs && availabilityZonesVariableRequest.isSuccess) { - availabilityZoneConfigs.forEach((availabilityZone) => { - setSelectAvailabilityZones((prevState: Record) => ({ - ...prevState, - [availabilityZone.varName]: availabilityZone.mandatory - ? availabilityZonesVariableRequest.data[0] - : '', - })); - }); - return availabilityZonesVariableRequest.data; - } else { - return []; + + // Side effect needed to update initial state when data from backend is available. + useEffect(() => { + if (getAvailabilityZonesForRegionQuery.isSuccess && getAvailabilityZonesForRegionQuery.data.length > 0) { + if (availabilityZoneConfigs.length > 0) { + const defaultSelection: Record = {}; + availabilityZoneConfigs.forEach((availabilityZoneConfig) => { + if (availabilityZoneConfig.mandatory) { + defaultSelection[availabilityZoneConfig.varName] = getAvailabilityZonesForRegionQuery.data[0]; + } + }); + setSelectAvailabilityZones(defaultSelection); + } } - }, [ - availabilityZoneConfigs, - availabilityZonesVariableRequest.isSuccess, - availabilityZonesVariableRequest.data, - setSelectAvailabilityZones, - ]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [getAvailabilityZonesForRegionQuery.isSuccess, getAvailabilityZonesForRegionQuery.data]); let flavorList: Flavor[] = getFlavorList(selectCsp, selectServiceHostType, userOrderableServiceVoList); const [selectFlavor, setSelectFlavor] = useState(currentFlavor); @@ -215,6 +211,20 @@ export const SelectDestination = ({ ); }; + function onAvailabilityZoneChange(varName: string, availabilityZone: string | undefined) { + if (availabilityZone !== undefined) { + setSelectAvailabilityZones((prevState: Record) => ({ + ...prevState, + [varName]: availabilityZone, + })); + } else { + const newAvailabilityZone = selectAvailabilityZones; + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete newAvailabilityZone[varName]; + setSelectAvailabilityZones({ ...newAvailabilityZone }); + } + } + return (
@@ -247,14 +257,18 @@ export const SelectDestination = ({ />
- {availabilityZonesVariableRequest.isSuccess ? ( - - ) : undefined} + {availabilityZoneConfigs.map((availabilityZoneConfig) => { + return ( + + ); + })}