diff --git a/dashboard/src/lib/hooks/useNodeGroups.ts b/dashboard/src/lib/hooks/useNodeGroups.ts new file mode 100644 index 0000000000..138cd347d1 --- /dev/null +++ b/dashboard/src/lib/hooks/useNodeGroups.ts @@ -0,0 +1,68 @@ +import { useQuery } from "@tanstack/react-query"; + +import { useClusterFormContext } from "../../main/home/infrastructure-dashboard/ClusterFormContextProvider"; +import { CloudProviderAzure } from "../clusters/constants"; +import type { + AWSRegion, + AzureRegion, + ClientMachineType, + GCPRegion, +} from "../clusters/types"; + +type TUseMachineTypeList = { + machineTypes: ClientMachineType[]; + isLoading: boolean; +}; +export const useMachineTypeList = ({ + cloudProvider, + cloudProviderCredentialIdentifier, + region, +}: { + cloudProvider?: string; + cloudProviderCredentialIdentifier?: string; + region?: AWSRegion | GCPRegion | AzureRegion; +}): TUseMachineTypeList => { + const { availableMachineTypes } = useClusterFormContext(); + + const { data: machineTypes = [], isLoading } = useQuery( + [ + "availableMachineTypes", + region, + cloudProvider, + cloudProviderCredentialIdentifier, + ], + async () => { + if (!cloudProvider || !cloudProviderCredentialIdentifier || !region) { + return []; + } + try { + const machineTypes = await availableMachineTypes( + cloudProvider, + cloudProviderCredentialIdentifier, + region + ); + const machineTypesNames = machineTypes.map( + (machineType) => machineType.name + ); + + return CloudProviderAzure.machineTypes.filter((mt) => + machineTypesNames.includes(mt.name) + ); + } catch (err) { + // fallback to default machine types if api call fails + return CloudProviderAzure.machineTypes.filter((mt) => + mt.supportedRegions.includes(region) + ); + } + }, + { + enabled: + !!cloudProvider && !!cloudProviderCredentialIdentifier && !!region, + } + ); + + return { + machineTypes, + isLoading, + }; +}; diff --git a/dashboard/src/main/home/infrastructure-dashboard/forms/azure/ConfigureAKSCluster.tsx b/dashboard/src/main/home/infrastructure-dashboard/forms/azure/ConfigureAKSCluster.tsx index e6be9b986d..5d5a4c1a65 100644 --- a/dashboard/src/main/home/infrastructure-dashboard/forms/azure/ConfigureAKSCluster.tsx +++ b/dashboard/src/main/home/infrastructure-dashboard/forms/azure/ConfigureAKSCluster.tsx @@ -1,5 +1,4 @@ import React, { useContext, useEffect, useState } from "react"; -import { useQuery } from "@tanstack/react-query"; import { Controller, useFormContext } from "react-hook-form"; import Loading from "components/Loading"; @@ -14,10 +13,10 @@ import { CloudProviderAzure } from "lib/clusters/constants"; import type { ClientClusterContract, ClientMachineType, - MachineType, NodeGroupType, } from "lib/clusters/types"; import { useIntercom } from "lib/hooks/useIntercom"; +import { useMachineTypeList } from "lib/hooks/useNodeGroups"; import { Context } from "shared/Context"; import { valueExists } from "shared/util"; @@ -29,13 +28,9 @@ import { BackButton, Img } from "../CreateClusterForm"; type Props = { goBack: () => void; - availableMachineTypes: (region: string) => Promise; }; -const ConfigureAKSCluster: React.FC = ({ - goBack, - availableMachineTypes, -}) => { +const ConfigureAKSCluster: React.FC = ({ goBack }) => { const [currentStep, _setCurrentStep] = useState(100); // hack to show all steps const [customSetupRequired, setCustomSetupRequired] = useState(false); @@ -63,6 +58,16 @@ const ConfigureAKSCluster: React.FC = ({ const region = watch("cluster.config.region"); const clusterId = watch("cluster.clusterId"); const nodeGroups = watch("cluster.config.nodeGroups"); + const cloudProviderCredentialIdentifier = watch( + "cluster.cloudProviderCredentialsId" + ); + + const { machineTypes, isLoading: areMachineTypesLoading } = + useMachineTypeList({ + cloudProvider: "azure", + cloudProviderCredentialIdentifier, + region, + }); const defaultNodeGroupType = ( nodeGroupType: NodeGroupType, @@ -124,36 +129,15 @@ const ConfigureAKSCluster: React.FC = ({ }; }; - const { data: machineTypes, status: machineTypesStatus } = useQuery( - ["availableMachineTypes", region], - async () => { - try { - const machineTypes = await availableMachineTypes(region); - const machineTypesNames = machineTypes.map( - (machineType) => machineType.name - ); - - return CloudProviderAzure.machineTypes.filter((mt) => - machineTypesNames.includes(mt.name) - ); - } catch (err) { - // fallback to default machine types if api call fails - return CloudProviderAzure.machineTypes.filter((mt) => - mt.supportedRegions.includes(region) - ); - } - } - ); - const regionValid = - machineTypesStatus !== "loading" && + !areMachineTypesLoading && machineTypes && (!customSetupRequired || user?.isPorterUser); useEffect(() => { if ( clusterId || // if cluster has already been provisioned, don't change instance types that have been set - machineTypesStatus === "loading" || + areMachineTypesLoading || !machineTypes || // if machine types are still loading, don't change instance types !nodeGroups || nodeGroups.length === 0 // wait until node groups are loaded @@ -188,7 +172,7 @@ const ConfigureAKSCluster: React.FC = ({ instanceTypeReplaced && setValue(`cluster.config.nodeGroups`, substituteBadInstanceTypes); - }, [machineTypes, machineTypesStatus, region]); + }, [machineTypes, areMachineTypesLoading, region]); return (
@@ -248,7 +232,7 @@ const ConfigureAKSCluster: React.FC = ({ )} /> - {machineTypesStatus === "loading" ? ( + {areMachineTypesLoading ? ( diff --git a/dashboard/src/main/home/infrastructure-dashboard/forms/azure/CreateAKSClusterForm.tsx b/dashboard/src/main/home/infrastructure-dashboard/forms/azure/CreateAKSClusterForm.tsx index 7bda2a09d8..ff68679ab1 100644 --- a/dashboard/src/main/home/infrastructure-dashboard/forms/azure/CreateAKSClusterForm.tsx +++ b/dashboard/src/main/home/infrastructure-dashboard/forms/azure/CreateAKSClusterForm.tsx @@ -3,7 +3,7 @@ import { useFormContext } from "react-hook-form"; import { match } from "ts-pattern"; import { CloudProviderAzure } from "lib/clusters/constants"; -import { MachineType, type ClientClusterContract } from "lib/clusters/types"; +import { type ClientClusterContract } from "lib/clusters/types"; import { useClusterAnalytics } from "lib/hooks/useClusterAnalytics"; import { useClusterFormContext } from "../../ClusterFormContextProvider"; @@ -20,20 +20,12 @@ const CreateAKSClusterForm: React.FC = ({ projectId, projectName, }) => { - const { availableMachineTypes } = useClusterFormContext(); - const [step, setStep] = useState<"permissions" | "cluster">("permissions"); const { setValue, reset } = useFormContext(); const { setCurrentContract } = useClusterFormContext(); const { reportToAnalytics } = useClusterAnalytics(); - const { watch } = useFormContext(); - - const cloudProviderCredentialIdentifier = watch( - "cluster.cloudProviderCredentialsId" - ); - useEffect(() => { const truncatedProjectName = projectName .substring(0, 24) @@ -110,13 +102,6 @@ const CreateAKSClusterForm: React.FC = ({ setStep("permissions"); setValue("cluster.cloudProviderCredentialsId", ""); }} - availableMachineTypes={async (region: string) => { - return await availableMachineTypes( - "azure", - cloudProviderCredentialIdentifier, - region - ); - }} /> )) .exhaustive(); diff --git a/dashboard/src/main/home/infrastructure-dashboard/tabs/overview/AKSClusterOverview.tsx b/dashboard/src/main/home/infrastructure-dashboard/tabs/overview/AKSClusterOverview.tsx index 5072754cbd..626310bd49 100644 --- a/dashboard/src/main/home/infrastructure-dashboard/tabs/overview/AKSClusterOverview.tsx +++ b/dashboard/src/main/home/infrastructure-dashboard/tabs/overview/AKSClusterOverview.tsx @@ -1,21 +1,32 @@ import React from "react"; import { Controller, useFormContext } from "react-hook-form"; +import Loading from "components/Loading"; import Container from "components/porter/Container"; import Select from "components/porter/Select"; import Spacer from "components/porter/Spacer"; import Text from "components/porter/Text"; import { CloudProviderAzure } from "lib/clusters/constants"; import { type ClientClusterContract } from "lib/clusters/types"; +import { useMachineTypeList } from "lib/hooks/useNodeGroups"; import NodeGroups from "../../shared/NodeGroups"; const AKSClusterOverview: React.FC = () => { const { control, watch } = useFormContext(); + const cloudProviderCredentialIdentifier = watch( + "cluster.cloudProviderCredentialsId" + ); const region = watch("cluster.config.region"); const cidrRange = watch("cluster.config.cidrRange"); + const { machineTypes, isLoading } = useMachineTypeList({ + cloudProvider: "azure", + cloudProviderCredentialIdentifier, + region, + }); + return ( <> @@ -73,12 +84,16 @@ const AKSClusterOverview: React.FC = () => { - - mt.supportedRegions.includes(region) - )} - isDefaultExpanded={false} - /> + {isLoading || !machineTypes ? ( + + + + ) : ( + + )} ); };