Skip to content

Commit 8058201

Browse files
committed
fix: Calculate initial region plans for dedicated properly
https://harperdb.atlassian.net/browse/STUDIO-499
1 parent 333fde3 commit 8058201

File tree

2 files changed

+61
-51
lines changed

2 files changed

+61
-51
lines changed

src/features/clusters/upsert/ClusterForm.tsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import { PriceDisplay } from '@/features/clusters/upsert/PriceDisplay';
1313
import { UpsertClusterSchema } from '@/features/clusters/upsert/upsertClusterSchema';
1414
import { SchemaPlan, SchemaRegion, SchemaRegionPlan } from '@/lib/api.gen';
1515
import { Organization } from '@/lib/api.patch';
16+
import { sortByField } from '@/lib/arrays/sort/byField';
17+
import { groupThenKeyBy } from '@/lib/groupThenKeyBy';
1618
import { collapseKebabsToMaxLength } from '@/lib/string/collapseKebabsToMaxLength';
1719
import { stringsShareAPrefix } from '@/lib/string/stringsShareAPrefix';
1820
import { toKebabCase } from '@/lib/string/to-kebab-case';
@@ -33,9 +35,8 @@ interface ClusterFormProps {
3335
organization: Organization;
3436
organizationId: string;
3537
planTypes: SchemaPlan[];
36-
regionLocations: SchemaRegion[];
37-
regionNameToLatencyToRegion: Record<string, Record<string, SchemaRegion>>;
38-
setOnlyShowAvailableHosts: (value: boolean) => void;
38+
regionLocationsColocated: SchemaRegion[];
39+
regionLocationsDedicated: SchemaRegion[];
3940
setSavedClusterState: (value: null | ({ clusterId?: string } & z.infer<typeof UpsertClusterSchema>)) => void;
4041
startOffOnBilling: boolean;
4142
}
@@ -48,9 +49,8 @@ export function ClusterForm({
4849
organization,
4950
organizationId,
5051
planTypes,
51-
regionLocations,
52-
regionNameToLatencyToRegion,
53-
setOnlyShowAvailableHosts,
52+
regionLocationsColocated,
53+
regionLocationsDedicated,
5454
setSavedClusterState,
5555
startOffOnBilling,
5656
}: ClusterFormProps) {
@@ -63,6 +63,11 @@ export function ClusterForm({
6363

6464
const [confirmingPaymentDetails, setConfirmingPaymentDetails] = useState(startOffOnBilling);
6565

66+
const colocatedRegionNameToLatencyToRegion = useMemo<Record<string, Record<string, SchemaRegion>>>(() =>
67+
groupThenKeyBy(regionLocationsColocated?.sort(sortByField('latencyDescription')) || [], 'region', 'latencyDescription'), [regionLocationsColocated]);
68+
const dedicatedRegionNameToLatencyToRegion = useMemo<Record<string, Record<string, SchemaRegion>>>(() =>
69+
groupThenKeyBy(regionLocationsDedicated?.sort(sortByField('latencyDescription')) || [], 'region', 'latencyDescription'), [regionLocationsDedicated]);
70+
6671
const refineZod = useCallback((data: z.infer<typeof UpsertClusterSchema>, ctx: z.RefinementCtx) => {
6772
const names = new Set();
6873
const selectedPlan = deploymentToPerformanceToPlan?.[data.deploymentDescription]?.[data.performanceDescription];
@@ -88,6 +93,10 @@ export function ClusterForm({
8893
message: 'Only one free cluster is allowed per organization.',
8994
});
9095
}
96+
const regionNameToLatencyToRegion = selectedPlan?.deploymentDescription !== 'Dedicated'
97+
? colocatedRegionNameToLatencyToRegion
98+
: dedicatedRegionNameToLatencyToRegion;
99+
91100
for (let i = 0; i < data.regionPlans.length; i++) {
92101
const regionPlan = data.regionPlans[i];
93102
const region = regionNameToLatencyToRegion[regionPlan.regionName]?.[regionPlan.latencyDescription];
@@ -126,7 +135,7 @@ export function ClusterForm({
126135
}
127136
}
128137
}
129-
}, [alreadyUsingFree, deploymentToPerformanceToPlan, regionNameToLatencyToRegion]);
138+
}, [alreadyUsingFree, colocatedRegionNameToLatencyToRegion, dedicatedRegionNameToLatencyToRegion, deploymentToPerformanceToPlan]);
130139

131140
const form = useForm({
132141
mode: 'onChange',
@@ -149,9 +158,12 @@ export function ClusterForm({
149158
const selectedRegionPlans = form.watch('regionPlans');
150159
const selectedInstances = form.watch('instances');
151160

152-
useEffect(function syncRegionsWithSelectedDeploymentType() {
153-
setOnlyShowAvailableHosts(selectedDeployment !== 'Dedicated');
154-
}, [organizationId, selectedDeployment, setOnlyShowAvailableHosts]);
161+
const regionNameToLatencyToRegion = selectedDeployment !== 'Dedicated'
162+
? colocatedRegionNameToLatencyToRegion
163+
: dedicatedRegionNameToLatencyToRegion;
164+
const regionLocations = selectedDeployment !== 'Dedicated'
165+
? regionLocationsColocated
166+
: regionLocationsDedicated;
155167

156168
useEffect(function syncInstancesAndRegionsWithSelfManagedSelection() {
157169
const values = form.getValues();

src/features/clusters/upsert/index.tsx

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,32 @@ import {
1010
} from '@/features/clusters/upsert/lib/calculateDefaultDeploymentPerformanceAndRegionPlans';
1111
import { UpsertClusterSchema } from '@/features/clusters/upsert/upsertClusterSchema';
1212
import { useLocalStorage } from '@/hooks/useLocalStorage';
13-
import { SchemaPlan, SchemaRegion } from '@/lib/api.gen';
13+
import { SchemaPlan } from '@/lib/api.gen';
1414
import { Cluster, Organization } from '@/lib/api.patch';
1515
import { sortByField } from '@/lib/arrays/sort/byField';
1616
import { groupThenKeyBy } from '@/lib/groupThenKeyBy';
1717
import { LocalStorageKeys } from '@/lib/storage/localStorageKeys';
1818
import { useQuery } from '@tanstack/react-query';
1919
import { useParams, useRouteContext } from '@tanstack/react-router';
20-
import { useMemo, useState } from 'react';
20+
import { useMemo } from 'react';
2121
import { z } from 'zod';
2222

2323
export function UpsertCluster() {
2424
const { organizationId, clusterId }: { organizationId: string; clusterId?: string } = useParams({ strict: false });
25-
const [onlyShowAvailableHosts, setOnlyShowAvailableHosts] = useState(true);
26-
const { organization, cluster }: { organization: Organization; cluster?: Cluster } = useRouteContext({ strict: false });
25+
const { organization, cluster }: {
26+
organization: Organization;
27+
cluster?: Cluster
28+
} = useRouteContext({ strict: false });
2729
const [savedClusterState, setSavedClusterState] = useLocalStorage<null | ({
2830
clusterId?: string
2931
} & z.infer<typeof UpsertClusterSchema>)>(LocalStorageKeys.SavedClusterState, null);
3032

3133
const { data: planTypes } = useQuery(getPlanTypesOptions(organizationId));
32-
const { data: regionLocationsAvailableHosts } = useQuery(getRegionLocationsOptions({
34+
const { data: regionLocationsColocated } = useQuery(getRegionLocationsOptions({
3335
availableHosts: true,
3436
organizationId,
3537
}));
36-
const { data: regionLocationsAll } = useQuery(getRegionLocationsOptions({ organizationId }));
37-
const regionLocations = onlyShowAvailableHosts ? regionLocationsAvailableHosts : regionLocationsAll;
38+
const { data: regionLocationsDedicated } = useQuery(getRegionLocationsOptions({ organizationId }));
3839

3940
const alreadyUsingFree = useMemo(() => {
4041
for (const orgCluster of organization?.clusters ?? []) {
@@ -55,55 +56,53 @@ export function UpsertCluster() {
5556

5657
const deploymentToPerformanceToPlan = useMemo<Record<string, Record<string, SchemaPlan>>>(() =>
5758
groupThenKeyBy(planTypes?.sort(sortByField('priceUsd')) || [], 'deploymentDescription', 'performanceDescription'), [planTypes]);
58-
const regionNameToLatencyToRegion = useMemo<Record<string, Record<string, SchemaRegion>>>(() =>
59-
groupThenKeyBy(regionLocations?.sort(sortByField('latencyDescription')) || [], 'region', 'latencyDescription'), [regionLocations]);
6059

6160
const defaultValues = useMemo<null | z.infer<typeof UpsertClusterSchema>>(() => {
6261
if (savedClusterState) {
6362
return savedClusterState;
6463
}
65-
if (!planTypes || !regionLocationsAvailableHosts || !regionLocationsAll || (clusterId && !cluster)) {
64+
if (!planTypes || !regionLocationsColocated || !regionLocationsDedicated || (clusterId && !cluster)) {
6665
return null;
6766
}
6867

6968
const selectedPlan = planTypes?.find(planType => planType.id === cluster?.plans?.[0].planId);
7069

7170
const regionPlans: z.infer<typeof UpsertClusterSchema.shape.regionPlans> = [];
7271
const instances: z.infer<typeof UpsertClusterSchema.shape.instances> = [];
73-
const regionLocations = onlyShowAvailableHosts ? regionLocationsAvailableHosts : regionLocationsAll;
72+
const regionLocations = selectedPlan?.deploymentDescription !== 'Dedicated'
73+
? regionLocationsColocated
74+
: regionLocationsDedicated;
7475
const defaults = calculateDefaultDeploymentPerformanceAndRegionPlans(planTypes, regionLocations, alreadyUsingFree);
7576

7677
let isSelfManaged = false;
77-
if (planTypes && regionLocations) {
78-
if (cluster) {
79-
if (cluster.plans) {
80-
for (const plan of cluster.plans) {
81-
if (plan.regionId) {
82-
const selectedRegion = regionLocations.find(regionLocation => regionLocation.id === plan.regionId);
83-
if (selectedRegion) {
84-
regionPlans.push({
85-
regionName: selectedRegion.region,
86-
latencyDescription: selectedRegion.latencyDescription,
87-
});
88-
}
78+
if (cluster) {
79+
if (cluster.plans) {
80+
for (const plan of cluster.plans) {
81+
if (plan.regionId) {
82+
const selectedRegion = regionLocations.find(regionLocation => regionLocation.id === plan.regionId);
83+
if (selectedRegion) {
84+
regionPlans.push({
85+
regionName: selectedRegion.region,
86+
latencyDescription: selectedRegion.latencyDescription,
87+
});
8988
}
9089
}
9190
}
92-
if (!regionPlans.length && cluster.instances) {
93-
for (const instance of cluster.instances) {
94-
if (instance.status !== 'REMOVED') {
95-
isSelfManaged = true;
96-
instances.push({
97-
fqdn: instance.instanceFqdn,
98-
port: instance.operationsApiPort,
99-
secure: instance.operationsApiSecure ? 'true' : 'false',
100-
});
101-
}
91+
}
92+
if (!regionPlans.length && cluster.instances) {
93+
for (const instance of cluster.instances) {
94+
if (instance.status !== 'REMOVED') {
95+
isSelfManaged = true;
96+
instances.push({
97+
fqdn: instance.instanceFqdn,
98+
port: instance.operationsApiPort,
99+
secure: instance.operationsApiSecure ? 'true' : 'false',
100+
});
102101
}
103102
}
104-
} else if (defaults) {
105-
regionPlans.push(...defaults.regionPlans);
106103
}
104+
} else if (defaults) {
105+
regionPlans.push(...defaults.regionPlans);
107106
}
108107
if (!isSelfManaged && !regionPlans.length) {
109108
regionPlans.push({ regionName: '', latencyDescription: '' });
@@ -119,9 +118,9 @@ export function UpsertCluster() {
119118
instances,
120119
regionPlans,
121120
};
122-
}, [alreadyUsingFree, cluster, clusterId, onlyShowAvailableHosts, planTypes, regionLocationsAll, regionLocationsAvailableHosts, savedClusterState]);
121+
}, [alreadyUsingFree, cluster, clusterId, planTypes, regionLocationsColocated, regionLocationsDedicated, savedClusterState]);
123122

124-
const isLoading = !defaultValues || !organization || !planTypes || !regionLocations;
123+
const isLoading = !defaultValues || !organization || !planTypes || !regionLocationsColocated || !regionLocationsDedicated;
125124
if (isLoading) {
126125
return (
127126
<SubNavSimpleLayout>
@@ -148,18 +147,17 @@ export function UpsertCluster() {
148147
return (
149148
<SubNavSimpleLayout>
150149
<ClusterForm
150+
alreadyUsingFree={alreadyUsingFree}
151151
clusterId={clusterId}
152152
defaultValues={defaultValues}
153153
deploymentToPerformanceToPlan={deploymentToPerformanceToPlan}
154154
organization={organization}
155155
organizationId={organizationId}
156156
planTypes={planTypes}
157-
regionLocations={regionLocations}
158-
regionNameToLatencyToRegion={regionNameToLatencyToRegion}
159-
setOnlyShowAvailableHosts={setOnlyShowAvailableHosts}
157+
regionLocationsColocated={regionLocationsColocated}
158+
regionLocationsDedicated={regionLocationsDedicated}
160159
setSavedClusterState={setSavedClusterState}
161160
startOffOnBilling={!!savedClusterState}
162-
alreadyUsingFree={alreadyUsingFree}
163161
/>
164162
</SubNavSimpleLayout>
165163
);

0 commit comments

Comments
 (0)