feat(workspace,settings): model menu chip in the composer, compact settings panels
The workspace home's composer takes ONE Model chip (ModelMenu: model list plus Effort) and moves AI Router / Permission / Local-New worktree into the row under it; Settings drops the General-page cost card and export row, PricingSettings and the empty states are compacted for settings panels.
This commit is contained in:
@@ -5,7 +5,9 @@
|
||||
* open, `/` only where slash commands apply), Shift/Alt+Enter newlines, a
|
||||
* pasted image shown as a thumbnail and sent as its saved path, and `ModelPicker` — a tool's own
|
||||
* list from the server, a fixed list (an AI Router's models) when given one,
|
||||
* and Custom…, which is a sentinel, never a model id.
|
||||
* and Custom…, which is a sentinel, never a model id — and `ModelMenu`, the
|
||||
* same list as one chip: aliases up front, pinned versions under More models,
|
||||
* plus the effort slider.
|
||||
*
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
@@ -14,7 +16,13 @@ import { useState } from "react";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import i18n from "i18next";
|
||||
import { ModelPicker, PromptEditor, promptWithImages, type PromptImage } from "../RunSetup";
|
||||
import {
|
||||
ModelMenu,
|
||||
ModelPicker,
|
||||
PromptEditor,
|
||||
promptWithImages,
|
||||
type PromptImage,
|
||||
} from "../RunSetup";
|
||||
import { api } from "../../../lib/api";
|
||||
|
||||
vi.mock("../../../lib/api", async (importOriginal) => {
|
||||
@@ -217,3 +225,24 @@ describe("ModelPicker", () => {
|
||||
expect(screen.queryByText("Sonnet (latest · 5.5)")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("ModelMenu", () => {
|
||||
it("puts the aliases up front, pinned versions under More models, and sets the effort", async () => {
|
||||
const onChange = vi.fn();
|
||||
const onEffort = vi.fn();
|
||||
render(
|
||||
<ModelMenu value="" onChange={onChange} tool="claude" effort="" onEffortChange={onEffort} />
|
||||
);
|
||||
fireEvent.click(screen.getByTitle(i18n.t("run:fields.model")));
|
||||
await screen.findByText("Sonnet (latest · 5.5)");
|
||||
expect(screen.queryByText("Claude Sonnet 5.5")).toBeNull();
|
||||
// Low, Medium, High, … — index 2 is High.
|
||||
fireEvent.change(screen.getByRole("slider", { name: i18n.t("run:fields.effort") }), {
|
||||
target: { value: "2" },
|
||||
});
|
||||
expect(onEffort).toHaveBeenCalledWith("high");
|
||||
fireEvent.click(screen.getByText(i18n.t("run:fields.moreModels")));
|
||||
fireEvent.click(screen.getByText("Claude Sonnet 5.5"));
|
||||
expect(onChange).toHaveBeenCalledWith("claude-sonnet-5-5");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user