fix(ui): split semantic cache out of the Redis Type dropdown

Semantic is a caching strategy, not a Redis network topology, so listing it next to Node/Cluster/Sentinel conflated two orthogonal dimensions and confused users. Replace the single Redis Type dropdown with a Cache Type selector (Standard vs Semantic) and a separate Redis Deployment Type selector (Node/Cluster/Sentinel) shown only for standard caching, since redis-semantic connects to a single node only. Also derive redis_type as semantic on read so the selection round-trips on reload.
This commit is contained in:
Devin AI 2026-07-09 14:20:00 +00:00
parent 60729f733e
commit 3b89c594fa
2 changed files with 129 additions and 0 deletions

View file

@ -0,0 +1,67 @@
import { describe, expect, it, vi } from "vitest";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import CacheTypeSelector from "./CacheTypeSelector";
const renderStandard = (overrides: Partial<React.ComponentProps<typeof CacheTypeSelector>> = {}) =>
render(
<CacheTypeSelector
cacheMode="standard"
deploymentType="node"
onCacheModeChange={vi.fn()}
onDeploymentTypeChange={vi.fn()}
{...overrides}
/>,
);
const openSelectFor = (labelText: string) => {
const selector = screen.getByText(labelText).parentElement!.querySelector(".ant-select-selector");
fireEvent.mouseDown(selector as Element);
};
const optionLabels = async (): Promise<string[]> =>
waitFor(() => {
const options = Array.from(document.querySelectorAll(".ant-select-item-option-content"));
expect(options.length).toBeGreaterThan(0);
return options.map((el) => el.textContent ?? "");
});
describe("CacheTypeSelector", () => {
it("should not offer Semantic as a Redis deployment type", async () => {
renderStandard();
openSelectFor("Redis Deployment Type");
expect(await optionLabels()).toEqual(["Node (Single Instance)", "Cluster", "Sentinel"]);
});
it("should offer Semantic only as a Cache Type", async () => {
renderStandard();
openSelectFor("Cache Type");
expect(await optionLabels()).toEqual(["Standard (exact match)", "Semantic (similarity-based)"]);
});
it("should call onCacheModeChange with semantic when the semantic cache type is chosen", async () => {
const onCacheModeChange = vi.fn();
renderStandard({ onCacheModeChange });
openSelectFor("Cache Type");
const semantic = await waitFor(() => {
const match = Array.from(document.querySelectorAll(".ant-select-item-option")).find((el) =>
el.textContent?.includes("Semantic"),
);
expect(match).toBeTruthy();
return match as HTMLElement;
});
fireEvent.click(semantic);
expect(onCacheModeChange).toHaveBeenCalledWith("semantic");
});
it("should hide the deployment type selector when semantic caching is selected", () => {
renderStandard({ cacheMode: "semantic" });
expect(screen.queryByText("Redis Deployment Type")).not.toBeInTheDocument();
});
});

View file

@ -0,0 +1,62 @@
import React from "react";
import { Select } from "antd";
import {
CACHE_MODES,
CACHE_MODE_DESCRIPTIONS,
CACHE_MODE_LABELS,
CacheMode,
REDIS_DEPLOYMENT_DESCRIPTIONS,
REDIS_DEPLOYMENT_LABELS,
REDIS_DEPLOYMENT_TYPES,
RedisDeploymentType,
} from "./cacheSettingsFields";
interface CacheTypeSelectorProps {
cacheMode: CacheMode;
deploymentType: RedisDeploymentType;
onCacheModeChange: (mode: CacheMode) => void;
onDeploymentTypeChange: (type: RedisDeploymentType) => void;
}
const cacheModeOptions = CACHE_MODES.map((mode) => ({ value: mode, label: CACHE_MODE_LABELS[mode] }));
const deploymentTypeOptions = REDIS_DEPLOYMENT_TYPES.map((type) => ({
value: type,
label: REDIS_DEPLOYMENT_LABELS[type],
}));
const CacheTypeSelector: React.FC<CacheTypeSelectorProps> = ({
cacheMode,
deploymentType,
onCacheModeChange,
onDeploymentTypeChange,
}) => {
return (
<div className="space-y-6">
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">Cache Type</label>
<Select<CacheMode>
value={cacheMode}
onChange={(value) => onCacheModeChange(value)}
options={cacheModeOptions}
style={{ width: "100%" }}
/>
<p className="text-xs text-gray-500">{CACHE_MODE_DESCRIPTIONS[cacheMode]}</p>
</div>
{cacheMode === "standard" && (
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">Redis Deployment Type</label>
<Select<RedisDeploymentType>
value={deploymentType}
onChange={(value) => onDeploymentTypeChange(value)}
options={deploymentTypeOptions}
style={{ width: "100%" }}
/>
<p className="text-xs text-gray-500">{REDIS_DEPLOYMENT_DESCRIPTIONS[deploymentType]}</p>
</div>
)}
</div>
);
};
export default CacheTypeSelector;