diff --git a/gui/src/pages/config/sections/ModelsSection.test.tsx b/gui/src/pages/config/sections/ModelsSection.test.tsx new file mode 100644 index 00000000000..10f3aec1e7d --- /dev/null +++ b/gui/src/pages/config/sections/ModelsSection.test.tsx @@ -0,0 +1,116 @@ +import { render, screen } from "@testing-library/react"; +import { Provider } from "react-redux"; +import type { ReactNode } from "react"; +import { describe, expect, it, vi } from "vitest"; +import { createMockStore } from "../../../util/test/mockStore"; +import { ModelsSection } from "./ModelsSection"; + +vi.mock("../../../context/Auth", () => ({ + useAuth: () => ({ + selectedProfile: { + profileType: "local", + }, + }), +})); + +vi.mock("../../../components/mainInput/Lump/useEditBlock", () => ({ + useEditModel: () => vi.fn(), +})); + +vi.mock("../../../components/gui/Shortcut", () => ({ + default: ({ children }: { children: ReactNode }) => <>{children}, +})); + +vi.mock("../../../components/ui", () => ({ + Card: ({ children }: { children: ReactNode }) =>
{children}
, + Divider: () =>
, + Toggle: ({ + children, + title, + subtitle, + }: { + children: ReactNode; + title: string; + subtitle?: string; + }) => ( +
+
{title}
+ {subtitle ?
{subtitle}
: null} + {children} +
+ ), +})); + +vi.mock("../components/ConfigHeader", () => ({ + ConfigHeader: ({ title }: { title: string }) =>
{title}
, +})); + +vi.mock("../components/ModelRoleRow", () => ({ + ModelRoleRow: ({ + role, + description, + setupURL, + }: { + role: string; + description: ReactNode; + setupURL: string; + }) => ( +
+
{description}
+ {`${role} setup`} +
+ ), +})); + +vi.mock("../../../util", async () => { + const actual = + await vi.importActual("../../../util"); + + return { + ...actual, + getMetaKeyLabel: () => "cmd", + isJetBrains: () => false, + }; +}); + +describe("ModelsSection docs links", () => { + function renderComponent() { + const { mockIdeMessenger, ...store } = createMockStore(); + + render( + + + , + ); + + return { store, mockIdeMessenger }; + } + + it("uses current ide-extensions docs routes for learn more and setup links", () => { + renderComponent(); + + const learnMoreLinks = screen.getAllByRole("link", { name: "Learn more" }); + const setupLinks = [ + screen.getByRole("link", { name: "chat setup" }), + screen.getByRole("link", { name: "autocomplete setup" }), + screen.getByRole("link", { name: "edit setup" }), + ]; + + const hrefs = [...learnMoreLinks, ...setupLinks].map((link) => + link.getAttribute("href"), + ); + + expect(hrefs).toEqual([ + "https://docs.continue.dev/ide-extensions/chat/quick-start", + "https://docs.continue.dev/ide-extensions/autocomplete/quick-start", + "https://docs.continue.dev/ide-extensions/edit/quick-start", + "https://docs.continue.dev/ide-extensions/chat/model-setup", + "https://docs.continue.dev/ide-extensions/autocomplete/model-setup", + "https://docs.continue.dev/ide-extensions/edit/model-setup", + ]); + + hrefs.forEach((href) => { + expect(href).not.toContain("/docs/"); + }); + }); +}); diff --git a/gui/src/pages/config/sections/ModelsSection.tsx b/gui/src/pages/config/sections/ModelsSection.tsx index 316f463a88a..1ab9b5758a3 100644 --- a/gui/src/pages/config/sections/ModelsSection.tsx +++ b/gui/src/pages/config/sections/ModelsSection.tsx @@ -14,6 +14,22 @@ import { getMetaKeyLabel, isJetBrains } from "../../../util"; import { ConfigHeader } from "../components/ConfigHeader"; import { ModelRoleRow } from "../components/ModelRoleRow"; +const MODEL_DOCS_URLS = { + chat: { + learnMore: "https://docs.continue.dev/ide-extensions/chat/quick-start", + setup: "https://docs.continue.dev/ide-extensions/chat/model-setup", + }, + autocomplete: { + learnMore: + "https://docs.continue.dev/ide-extensions/autocomplete/quick-start", + setup: "https://docs.continue.dev/ide-extensions/autocomplete/model-setup", + }, + edit: { + learnMore: "https://docs.continue.dev/ide-extensions/edit/quick-start", + setup: "https://docs.continue.dev/ide-extensions/edit/model-setup", + }, +} as const; + export function ModelsSection() { const { selectedProfile } = useAuth(); const dispatch = useAppDispatch(); @@ -83,7 +99,7 @@ export function ModelsSection() { Used in Chat, Plan, Agent mode ( handleRoleUpdate("chat", model)} onConfigure={handleConfigureModel} - setupURL="https://docs.continue.dev/chat/model-setup" + setupURL={MODEL_DOCS_URLS.chat.setup} /> @@ -109,7 +125,7 @@ export function ModelsSection() { Used in inline code completions as you type ( handleRoleUpdate("autocomplete", model)} onConfigure={handleConfigureModel} - setupURL="https://docs.continue.dev/autocomplete/model-setup" + setupURL={MODEL_DOCS_URLS.autocomplete.setup} /> {/* Jetbrains has a model selector inline */} @@ -142,7 +158,7 @@ export function ModelsSection() { Used to transform a selected section of code ( handleRoleUpdate("edit", model)} onConfigure={handleConfigureModel} - setupURL="https://docs.continue.dev/edit/model-setup" + setupURL={MODEL_DOCS_URLS.edit.setup} /> )}