mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(site): allow search by label in MultiSelectComboBox (#24421)
Relates to https://linear.app/codercom/issue/CODAGT-103 - Add `keywords={[option.label]}` to `CommandItem` in `MultiSelectCombobox` so cmdk's default filter matches against the visible label text, not just the value (UUID) - Extend `OpenCombobox` story with type-to-filter assertions - Add "search filters by display name" step to `TemplateAllowlist` story > 🤖 --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -31,11 +31,43 @@ export const Default: Story = {};
|
||||
export const OpenCombobox: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByPlaceholderText("Select organization"));
|
||||
const input = canvas.getByPlaceholderText("Select organization");
|
||||
await userEvent.click(input);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(canvas.getByText("My Organization")).toBeInTheDocument(),
|
||||
);
|
||||
// Both options should be visible initially.
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
canvas.getByRole("option", { name: "My Organization" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
canvas.getByRole("option", { name: "My Organization 2" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Type a display name to filter — this verifies cmdk filters
|
||||
// by label rather than by the underlying UUID value.
|
||||
await userEvent.type(input, "My Organization 2");
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
canvas.getByRole("option", { name: "My Organization 2" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
canvas.queryByRole("option", { name: /^My Organization$/ }),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Clear the search and confirm both options reappear.
|
||||
await userEvent.clear(input);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
canvas.getByRole("option", { name: "My Organization" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
canvas.getByRole("option", { name: "My Organization 2" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -642,6 +642,7 @@ export const MultiSelectCombobox: React.FC<MultiSelectComboboxProps> = ({
|
||||
<CommandItem
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
keywords={[option.label]}
|
||||
disabled={option.disable}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -60,6 +60,39 @@ export const TemplateAllowlist: Story = {
|
||||
expect(saveBtn).toBeDisabled();
|
||||
});
|
||||
|
||||
await step("search filters by display name", async () => {
|
||||
const input = canvas.getByPlaceholderText("Select templates...");
|
||||
await userEvent.click(input);
|
||||
|
||||
// Type a partial display name.
|
||||
await userEvent.type(input, "Docker");
|
||||
|
||||
// The matching template should be visible.
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
canvas.getByRole("option", { name: "Docker Development" }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
// A non-matching template should not be visible.
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
canvas.queryByRole("option", { name: "Kubernetes Production" }),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Clear the search and verify the full list returns.
|
||||
await userEvent.clear(input);
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
canvas.getByRole("option", { name: "Kubernetes Production" }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
// Close dropdown by pressing Escape so the next step starts clean.
|
||||
await userEvent.keyboard("{Escape}");
|
||||
});
|
||||
|
||||
await step("select one template and save", async () => {
|
||||
const input = canvas.getByPlaceholderText("Select templates...");
|
||||
await userEvent.click(input);
|
||||
|
||||
Reference in New Issue
Block a user