feat: enhance AssignNode functionality with zone redundancy options and update API integration

This commit is contained in:
Adekabang 2025-07-31 02:16:04 -04:00
parent d6847884e0
commit 4de96071d4
4 changed files with 89 additions and 14 deletions

View File

@ -23,6 +23,8 @@ const defaultValues: AssignNodeSchema = {
capacityUnit: "GB",
isGateway: false,
tags: [],
zoneRedundancyType: "atLeast",
zoneRedundancyAtLeast: 1,
};
const AssignNodeDialog = () => {
@ -36,6 +38,10 @@ const AssignNodeDialog = () => {
defaultValues,
});
const isGateway = useWatch({ control: form.control, name: "isGateway" });
const zoneRedundancyType = useWatch({
control: form.control,
name: "zoneRedundancyType",
});
const assignNode = useAssignNode({
onSuccess() {
@ -106,10 +112,20 @@ const AssignNodeDialog = () => {
? calculateCapacity(values.capacity, values.capacityUnit)
: null;
const data = {
id: values.nodeId,
zone: values.zone,
capacity,
tags: values.tags,
parameters: {
zoneRedundancy:
values.zoneRedundancyType === "maximum"
? ("maximum" as const)
: { atLeast: Number(values.zoneRedundancyAtLeast) },
},
roles: [
{
id: values.nodeId,
zone: values.zone,
capacity,
tags: values.tags,
},
],
};
assignNode.mutate(data);
});
@ -214,9 +230,9 @@ const AssignNodeDialog = () => {
value={
field.value
? (field.value as string[]).map((value) => ({
label: value,
value,
}))
label: value,
value,
}))
: null
}
options={tagsList}
@ -228,6 +244,39 @@ const AssignNodeDialog = () => {
/>
)}
/>
<FormControl
form={form}
name="zoneRedundancyType"
title="Zone Redundancy"
render={(field) => (
<Select
name={field.name}
value={String(field.value || "")}
onChange={field.onChange}
>
<option value="atLeast">At Least</option>
<option value="maximum">Maximum</option>
</Select>
)}
/>
{zoneRedundancyType === "atLeast" && (
<FormControl
form={form}
name="zoneRedundancyAtLeast"
title="Minimum Zones"
className="mt-2"
render={(field) => (
<Input
type="number"
name={field.name}
value={String(field.value || "")}
onChange={field.onChange}
/>
)}
/>
)}
</Modal.Body>
<Modal.Actions>
<Button type="button" onClick={assignNodeDialog.close}>

View File

@ -43,7 +43,7 @@ export const useConnectNode = (options?: Partial<UseMutationOptions<ConnectNodeR
export const useAssignNode = (options?: Partial<UseMutationOptions<void, Error, AssignNodeBody>>) => {
return useMutation<void, Error, AssignNodeBody>({
mutationFn: (data) => api.post("/v2/AddClusterLayout", { body: [data] }),
mutationFn: (data) => api.post("/v2/UpdateClusterLayout", { body: { parameters: data.parameters, roles: data.roles } }),
...options,
});
};
@ -51,7 +51,7 @@ export const useAssignNode = (options?: Partial<UseMutationOptions<void, Error,
export const useUnassignNode = (options?: Partial<UseMutationOptions<void, Error, string>>) => {
return useMutation<void, Error, string>({
mutationFn: (nodeId) =>
api.post("/v2/AddClusterLayout", { body: [{ id: nodeId, remove: true }] }),
api.post("/v2/UpdateClusterLayout", { body: { parameters: null, roles: [{ id: nodeId, remove: true }] } }),
...options,
});
};

View File

@ -16,6 +16,8 @@ export const assignNodeSchema = z
capacityUnit: z.enum(capacityUnits),
isGateway: z.boolean(),
tags: z.string().min(1).array(),
zoneRedundancyType: z.enum(["atLeast", "maximum"]),
zoneRedundancyAtLeast: z.coerce.number(),
})
.refine(
(values) => values.isGateway || (values.capacity && values.capacity > 0),
@ -23,6 +25,19 @@ export const assignNodeSchema = z
message: "Capacity required",
path: ["capacity"],
}
)
.refine(
(data) => {
if (data.zoneRedundancyType === "atLeast" && !data.zoneRedundancyAtLeast) {
return false;
}
return true;
},
{
message:
'Zone Redundancy At Least is required when Zone Redundancy Type is "atLeast"',
path: ["zoneRedundancyAtLeast"],
}
);
export type AssignNodeSchema = z.infer<typeof assignNodeSchema>;

View File

@ -32,7 +32,7 @@ export type DataPartition = {
export type Role = {
id: string;
zone: string;
capacity: number;
capacity: number | null;
tags: string[];
};
@ -46,11 +46,22 @@ export type GetClusterLayoutResult = {
stagedRoleChanges: StagedRole[];
};
export type AssignNodeBody = {
export type PartitionNumber = {
atLeast: number;
};
export type LayoutParameters = {
zoneRedundancy: "maximum" | PartitionNumber;
}
export type NodeRoleChange = {
remove: boolean;
id: string;
zone: string;
capacity: number | null;
tags: string[];
}
export type AssignNodeBody = {
parameters: null | LayoutParameters,
roles: Role[] | NodeRoleChange[];
};
export type ApplyLayoutResult = {