feat(webui): add localized slash commands

Add a session-scoped slash command palette sourced from backend command metadata, and keep welcome-page quick actions localized across all WebUI languages.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Xubin Ren
2026-05-07 00:20:28 +08:00
committed by Xubin Ren
co-authored by Cursor
parent 49c07aa45a
commit ac18a8baad
20 changed files with 1258 additions and 38 deletions
+49 -1
View File
@@ -1,7 +1,24 @@
import { render, screen } from "@testing-library/react";
import { fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { ThreadComposer } from "@/components/thread/ThreadComposer";
import type { SlashCommand } from "@/lib/types";
const COMMANDS: SlashCommand[] = [
{
command: "/stop",
title: "Stop current task",
description: "Cancel the active agent turn.",
icon: "square",
},
{
command: "/history",
title: "Show conversation history",
description: "Print the last N persisted messages.",
icon: "history",
argHint: "[n]",
},
];
describe("ThreadComposer", () => {
it("renders a readonly hero model composer when provided", () => {
@@ -43,4 +60,35 @@ describe("ThreadComposer", () => {
expect(screen.getByRole("button", { name: "Attach image" }).className).toContain("bg-card");
expect(screen.getByRole("button", { name: "Send message" }).className).toContain("bg-foreground");
});
it("opens a slash command palette and inserts the selected command", () => {
const onSend = vi.fn();
render(
<ThreadComposer
onSend={onSend}
placeholder="Type your message..."
slashCommands={COMMANDS}
/>,
);
const input = screen.getByLabelText("Message input");
fireEvent.change(input, { target: { value: "/" } });
expect(screen.getByRole("listbox", { name: "Slash commands" })).toBeInTheDocument();
expect(screen.getByRole("option", { name: /\/stop/i })).toHaveAttribute(
"aria-selected",
"true",
);
fireEvent.keyDown(input, { key: "ArrowDown" });
expect(screen.getByRole("option", { name: /\/history/i })).toHaveAttribute(
"aria-selected",
"true",
);
fireEvent.keyDown(input, { key: "Enter" });
expect(input).toHaveValue("/history ");
expect(onSend).not.toHaveBeenCalled();
expect(screen.queryByRole("listbox", { name: "Slash commands" })).not.toBeInTheDocument();
});
});