Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .i18n-tracker.lock
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@
"src/domains/model-registry/hooks/use-model-registry-form.tsx": "7209947c2079b41b6b83c9051a5235e2",
"src/domains/image-registry/lib/transform-image-registry-values.ts": "8c26cafe14bf2883c1146e93f64ff9b4",
"src/domains/image-registry/hooks/use-image-registry-form.tsx": "ca7795582e54f820a3fb26492a68c13c",
"src/domains/cluster/hooks/use-cluster-form.tsx": "5d4ca2e20acacb990501aed14cb69d75",
"src/domains/cluster/hooks/use-cluster-form.tsx": "83f339daf54ba7be2b7c07c78808d88e",
"src/foundation/types/resource-types.ts": "6fecb3bc5fdd96313e1745a5defcfd87",
"src/foundation/hooks/use-variables-input.ts": "4e7645dd01994e5fd252bc3e2ad7676f",
"src/foundation/components/VariablesInput.tsx": "24057e155ee2272d6ba949b42639d752",
Expand Down Expand Up @@ -274,16 +274,16 @@
"src/domains/external-endpoint/lib/find-overlapping-model-keys.ts": "c95ecffb5e8e3e0a45983f6e1f5d2ea4",
"src/pages/auth/lib/validate-password-match.ts": "c113f0c5136ce533297e38cc20bf698f",
"src/domains/endpoint/lib/pause-action.ts": "3efa178458d6906c0cc81dad7c41e675",
"src/domains/cluster/components/ClusterUpgradeAction.tsx": "69bbf15ed8d1b0e68a235ada096065e9",
"src/domains/cluster/components/ClusterUpgradeAction.tsx": "12d36c4aa2e5ac304e0a038dfc59087d",
"src/foundation/components/OemFavicon.tsx": "bb7648f90f369cb8a26439963f1966d1",
"src/domains/external-endpoint/lib/get-endpoint-type.ts": "a5fec42612881e3206ee2e19ca3c820f",
"src/domains/endpoint/hooks/use-document-list.ts": "7dc70792a61cc83271e61844abc90ec8",
"src/domains/endpoint/hooks/use-playground-models.ts": "53c557aeb8282c5f4cb5dc1489688505",
"src/domains/endpoint/components/DocumentListEditor.tsx": "397a5b14b2689352e678e44863b4e2f0",
"src/domains/endpoint/components/PlaygroundLayout.tsx": "c4940cfc57dc4696b166ac65f5c769cb",
"src/domains/cluster/components/ClusterUpgradeTip.tsx": "fd41e3d18ecd41c1efda9dc1d06da083",
"src/pages/dashboard/QuickStartDialog.tsx": "b22e8651e26203a5c62ceb9d249f8ef1",
"src/foundation/hooks/use-quick-start.ts": "04189be863e68f0769b650db5a60b985",
"src/pages/dashboard/QuickStartDialog.tsx": "5211801c3c58b8c9755b0bf71a279d30",
"src/foundation/hooks/use-quick-start.ts": "4a8e61679c598598782a5de445a4e987",
"src/foundation/components/ResourceResultList.tsx": "5b87054f8939e64a98ac67e886b68c64",
"src/foundation/hooks/use-refine-field-array.ts": "7dbaa5d3a0ea2c6db1c09da0863f1b74",
"src/domains/external-endpoint/components/TestConnectivityButton.tsx": "c4c97cc62ad41f004d08238c569e0054",
Expand Down Expand Up @@ -374,5 +374,6 @@
"src/foundation/lib/api/model-registries.ts": "63aabfb75c7df819933df76333e6f67b",
"src/foundation/lib/model-registry-visibility.ts": "24550d054dd3e6365f09c526b829302a",
"src/domains/role/lib/format-permission.ts": "9f2b7f7a698e51dc6ba8188a808db44b",
"src/domains/model-catalog/lib/catalog-import.ts": "0722a4c305e6f4066c9f70aed2e61ed0"
"src/domains/model-catalog/lib/catalog-import.ts": "0722a4c305e6f4066c9f70aed2e61ed0",
"src/foundation/lib/api/available-cluster-versions.ts": "db03a13dc9debc8220e03be899b8d96e"
}
27 changes: 23 additions & 4 deletions src/domains/cluster/components/ClusterUpgradeAction.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ const mocks = vi.hoisted(() => ({
availableVersions: [] as string[],
invalidate: vi.fn(),
mutateAsync: vi.fn(),
useCustom: vi.fn(),
}));

vi.mock("@refinedev/core", () => ({
useCustom: () => ({
data: { data: { available_versions: mocks.availableVersions } },
isLoading: false,
}),
useCustom: mocks.useCustom,
useInvalidate: () => mocks.invalidate,
useUpdate: () => ({ mutateAsync: mocks.mutateAsync, isLoading: false }),
}));
Expand Down Expand Up @@ -127,6 +125,27 @@ describe("ClusterUpgradeAction", () => {
mocks.availableVersions = [];
mocks.invalidate.mockReset().mockResolvedValue(undefined);
mocks.mutateAsync.mockReset().mockResolvedValue({});
mocks.useCustom.mockImplementation(() => ({
data: { data: { available_versions: mocks.availableVersions } },
isLoading: false,
}));
mocks.useCustom.mockClear();
});

it("requests versions for the cluster type when the dialog opens", async () => {
renderUpgradeAction();

fireEvent.click(
screen.getByRole("button", { name: "clusters.actions.upgrade" }),
);

await screen.findByRole("dialog");
expect(mocks.useCustom).toHaveBeenLastCalledWith(
expect.objectContaining({
url: "/clusters/available_versions?workspace=default&image_registry=registry-a&cluster_type=ssh",
queryOptions: { enabled: true },
}),
);
});

it("only offers newer versions and selects the highest result", async () => {
Expand Down
22 changes: 8 additions & 14 deletions src/domains/cluster/components/ClusterUpgradeAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
isUpgradeVersion,
} from "@/domains/cluster/lib/upgrade-versions";
import type { Cluster } from "@/domains/cluster/types";
import { buildAvailableClusterVersionsURL } from "@/foundation/lib/api/available-cluster-versions";
import { useTranslation } from "@/foundation/lib/i18n";

type AvailableVersionsResponse = {
Expand Down Expand Up @@ -106,24 +107,17 @@ function UpgradeDialog({
const { mutateAsync, isLoading: isUpdating } = useUpdate<Cluster>();
const [targetVersion, setTargetVersion] = useState<string>("");

const upgradeVersionsUrl = (() => {
const params = new URLSearchParams({
workspace: cluster.metadata.workspace ?? "",
image_registry: cluster.spec.image_registry,
cluster_type: cluster.spec.type,
});
if (cluster.status?.accelerator_type) {
params.set("accelerator_type", cluster.status.accelerator_type);
}
return `/clusters/available_versions?${params.toString()}`;
})();

const upgradeVersionsUrl = buildAvailableClusterVersionsURL(
cluster.spec.type,
cluster.metadata.workspace,
cluster.spec.image_registry,
);
const { data, isLoading: isLoadingVersions } =
useCustom<AvailableVersionsResponse>({
url: upgradeVersionsUrl,
url: upgradeVersionsUrl ?? "",
method: "get",
queryOptions: {
enabled: open,
enabled: open && !!upgradeVersionsUrl,
},
});

Expand Down
129 changes: 124 additions & 5 deletions src/domains/cluster/hooks/use-cluster-form.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ vi.mock("@refinedev/react-hook-form", async () => {
};
});

const { mockUseCustom } = vi.hoisted(() => ({ mockUseCustom: vi.fn() }));
let mockAvailableVersions: string[] = [];

vi.mock("@refinedev/core", () => ({
useSelect: () => ({
query: { data: { data: [] }, isLoading: false },
}),
useCustom: () => ({
data: { data: { available_versions: [] } },
isLoading: false,
}),
useCustom: mockUseCustom,
}));

vi.mock("@/foundation/components/WorkspaceField", () => ({
Expand Down Expand Up @@ -104,6 +104,7 @@ function ClusterConfigurationForm() {
const { form, clusterConfigurationFields } = useClusterForm({
action: "create",
});
formInstance = form;
return (
<FormProvider {...form}>
<form>{clusterConfigurationFields}</form>
Expand Down Expand Up @@ -157,6 +158,12 @@ describe("useClusterForm", () => {
beforeEach(() => {
vi.unstubAllEnvs();
formInstance = null;
mockAvailableVersions = [];
mockUseCustom.mockImplementation(() => ({
data: { data: { available_versions: mockAvailableVersions } },
isLoading: false,
}));
mockUseCustom.mockClear();
});

it("groups type, image registry and version under cluster configuration", () => {
Expand All @@ -170,6 +177,119 @@ describe("useClusterForm", () => {
expect(screen.getByText("common.fields.version")).toBeTruthy();
});

it("does not preselect a version from available_versions", async () => {
mockAvailableVersions = ["v1.1.0", "v1.2.0"];

render(<ClusterConfigurationForm />);

await waitFor(() => {
expect(formInstance?.getValues("spec.version")).toBeFalsy();
});
});

it("waits for an image registry before querying available versions", async () => {
render(<ClusterConfigurationForm />);

expect(mockUseCustom).toHaveBeenLastCalledWith(
expect.objectContaining({
url: "",
queryOptions: { enabled: false },
}),
);

act(() => formInstance?.setValue("spec.image_registry", "registry-a"));

await waitFor(() => {
expect(mockUseCustom).toHaveBeenLastCalledWith(
expect.objectContaining({
url: "/clusters/available_versions?workspace=default&image_registry=registry-a&cluster_type=ssh",
queryOptions: { enabled: true },
}),
);
});
});

it("updates the version query when the cluster type changes", async () => {
render(<CreateForm />);

act(() => formInstance?.setValue("spec.image_registry", "registry-a"));
selectType("clusters.options.kubernetes");

await waitFor(() => {
expect(mockUseCustom).toHaveBeenLastCalledWith(
expect.objectContaining({
url: "/clusters/available_versions?workspace=default&image_registry=registry-a&cluster_type=kubernetes",
queryOptions: { enabled: true },
}),
);
});
});

it("clears a selected version when the registry no longer provides it", async () => {
mockAvailableVersions = ["v1.1.0"];
render(<ClusterConfigurationForm />);

act(() => formInstance?.setValue("spec.image_registry", "registry-a"));
await waitFor(() => {
expect(formInstance?.getValues("spec.version")).toBeFalsy();
});

act(() => {
formInstance?.setValue("spec.version", "v1.1.0");
});
expect(formInstance?.getValues("spec.version")).toBe("v1.1.0");
mockAvailableVersions = ["v1.2.0"];

act(() => formInstance?.setValue("spec.image_registry", "registry-b"));

await waitFor(() => {
expect(formInstance?.getValues("spec.version")).toBeFalsy();
});
});

it("clears a selected version when the cluster type changes", async () => {
mockAvailableVersions = ["v1.1.0"];
render(<CreateForm />);

act(() => formInstance?.setValue("spec.image_registry", "registry-a"));
act(() => formInstance?.setValue("spec.version", "v1.1.0"));
expect(formInstance?.getValues("spec.version")).toBe("v1.1.0");

selectType("clusters.options.kubernetes");

await waitFor(() => {
expect(formInstance?.getValues("spec.version")).toBeFalsy();
});
});

it("clears a selected version when the current source refreshes without it", async () => {
mockAvailableVersions = ["v1.1.0"];
const view = render(<ClusterConfigurationForm />);

act(() => formInstance?.setValue("spec.image_registry", "registry-a"));
act(() => formInstance?.setValue("spec.version", "v1.1.0"));
expect(formInstance?.getValues("spec.version")).toBe("v1.1.0");

mockAvailableVersions = [];
view.rerender(<ClusterConfigurationForm />);

await waitFor(() => {
expect(formInstance?.getValues("spec.version")).toBeFalsy();
});
});

it("does not query versions while workspace is not routable", () => {
mockUseWorkspace.mockReturnValue({ current: "_all_" });
render(<ClusterConfigurationForm />);

expect(mockUseCustom).toHaveBeenLastCalledWith(
expect.objectContaining({
url: "",
queryOptions: { enabled: false },
}),
);
});

describe("edit mode — NodeIPsField props", () => {
it("passes headIpDisabled=true without disabled in edit mode", () => {
nodeIPsFieldProps.mockClear();
Expand Down Expand Up @@ -230,7 +350,6 @@ describe("useClusterForm", () => {
});

it("does not seed router version when switching to kubernetes", async () => {
vi.stubEnv("VITE_DEFAULT_CLUSTER_VERSION", "v1.0.1");
render(<CreateForm />);

selectType("clusters.options.kubernetes");
Expand Down
Loading
Loading