feat(ui): migrate mcp-servers, search-tools, tag-management, vector-stores, and memory to path routes (#30261)

* feat(ui): cut mcp-servers, search-tools, tag-management, vector-stores, and memory over to path routes

Continues the page-by-page App Router migration. All five legacy switch
arms passed only accessToken/userRole/userID, so each route wrapper is a
thin useAuthorized() + render. MIGRATED_PAGES routes the sidebar and
redirects the legacy ?page= URLs; the e2e fixture picks all five up in
the migration smoke and sidebar specs automatically.

* refactor(ui): colocate MemoryView under the memory route

The legacy switch was its only importer, so the three files move
wholesale into (dashboard)/memory/components. mcp_tools, SearchTools,
tag_management, and vector_store_management stay at src/components for
now: each has importers on other pages (teams, playground, guardrails),
so their colocation needs a shared/page split as a follow-up.
This commit is contained in:
ryan-crabbe-berri 2026-06-11 18:17:06 -07:00 • committed by GitHub
parent 3ad385a8a4
commit 2d576b5695
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 72 additions and 22 deletions

View file

@ -10,9 +10,8 @@
*
* Keep this in lockstep with MIGRATED_PAGES in src/utils/migratedPages.ts.
* Pending (add as each PR lands): the leaf-pages batch
* (caching, cost-tracking, guardrails, logs, mcp-servers, memory,
* policies, prompts, search-tools, skills, tag-management, tool-policies,
* transform-request, ui-theme, vector-stores).
* (caching, cost-tracking, guardrails, logs, policies, prompts, skills,
* tool-policies, transform-request, ui-theme).
*/
export const MIGRATED_E2E_PAGES: Record<string, string> = {
api_ref: "api-reference",
@ -22,6 +21,11 @@ export const MIGRATED_E2E_PAGES: Record<string, string> = {
budgets: "budgets",
workflows: "workflows",
"guardrails-monitor": "guardrails-monitor",
"mcp-servers": "mcp-servers",
"search-tools": "search-tools",
"tag-management": "tag-management",
"vector-stores": "vector-stores",
memory: "memory",
};
export const MIGRATED_E2E_SEGMENTS: string[] = [...new Set(Object.values(MIGRATED_E2E_PAGES))];

View file

@ -444,7 +444,7 @@
"count": 1
}
},
"src/components/MemoryView/MemoryView.tsx": {
"src/app/(dashboard)/memory/components/MemoryView.tsx": {
"react-hooks/set-state-in-effect": {
"count": 1
}

View file

@ -0,0 +1,9 @@
"use client";
import { MCPServers } from "@/components/mcp_tools";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
export default function McpServers() {
const { accessToken, userRole, userId } = useAuthorized();
return <MCPServers accessToken={accessToken} userRole={userRole} userID={userId} />;
}

View file

@ -2,7 +2,7 @@
import React, { useEffect, useState } from "react";
import { Form, Input, Modal, Typography } from "antd";
import type { MemoryRow } from "../networking";
import type { MemoryRow } from "@/components/networking";
const { Text } = Typography;

View file

@ -12,9 +12,9 @@ import {
ReloadOutlined,
SearchOutlined,
} from "@ant-design/icons";
import { MemoryRow, createMemory, deleteMemory, fetchMemoryList, updateMemory } from "../networking";
import { MemoryRow, createMemory, deleteMemory, fetchMemoryList, updateMemory } from "@/components/networking";
import { MemoryEditModal } from "./MemoryEditModal";
import DeleteResourceModal from "../common_components/DeleteResourceModal";
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
const { Text, Paragraph, Title } = Typography;

View file

@ -0,0 +1,9 @@
"use client";
import { MemoryView } from "./components/MemoryView";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
export default function Memory() {
const { accessToken, userRole, userId } = useAuthorized();
return <MemoryView accessToken={accessToken} userID={userId} userRole={userRole} />;
}

View file

@ -14,7 +14,6 @@ import GeneralSettings from "@/components/general_settings";
import GuardrailsPanel from "@/components/guardrails";
import PoliciesPanel from "@/components/policies";
import { Team } from "@/components/key_team_helpers/key_list";
import { MCPServers } from "@/components/mcp_tools";
import ModelHubTable from "@/components/AIHub/ModelHubTable";
import { Organization, proxyBaseUrl, getInProductNudgesCall } from "@/components/networking";
import NewUsagePage from "@/components/UsagePage/components/UsagePageView";
@ -24,17 +23,13 @@ import Organizations, { fetchOrganizations } from "@/components/organizations";
import PassThroughSettings from "@/components/pass_through_settings";
import PromptsPanel from "@/components/prompts";
import PublicModelHub from "@/components/public_model_hub";
import { SearchTools } from "@/components/SearchTools";
import Settings from "@/components/settings";
import { SurveyPrompt, SurveyModal, ClaudeCodePrompt, ClaudeCodeModal } from "@/components/survey";
import TagManagement from "@/components/tag_management";
import TransformRequestPanel from "@/components/transform_request";
import UIThemeSettings from "@/components/ui_theme_settings";
import Usage from "@/components/usage";
import UserDashboard from "@/components/user_dashboard";
import VectorStoreManagement from "@/components/vector_store_management";
import ToolPoliciesView from "@/components/ToolPoliciesView";
import { MemoryView } from "@/components/MemoryView";
import SpendLogsTable from "@/components/view_logs";
import ViewUserDashboard from "@/components/view_users";
import { useAuth } from "@/contexts/AuthContext";
@ -433,20 +428,10 @@ function CreateKeyPageContent() {
accessToken={accessToken}
premiumUser={premiumUser}
/>
) : page == "mcp-servers" ? (
<MCPServers accessToken={accessToken} userRole={userRole} userID={userID} />
) : page == "search-tools" ? (
<SearchTools accessToken={accessToken} userRole={userRole} userID={userID} />
) : page == "tag-management" ? (
<TagManagement accessToken={accessToken} userRole={userRole} userID={userID} />
) : page == "skills" || page == "claude-code-plugins" ? (
<ClaudeCodePluginsPanel accessToken={accessToken} userRole={userRole} />
) : page == "vector-stores" ? (
<VectorStoreManagement accessToken={accessToken} userRole={userRole} userID={userID} />
) : page == "tool-policies" ? (
<ToolPoliciesView accessToken={accessToken} userRole={userRole} />
) : page == "memory" ? (
<MemoryView accessToken={accessToken} userID={userID} userRole={userRole} />
) : page == "new_usage" ? (
<NewUsagePage teams={(teams as Team[]) ?? []} organizations={(organizations as Organization[]) ?? []} />
) : (

View file

@ -0,0 +1,9 @@
"use client";
import { SearchTools } from "@/components/SearchTools";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
export default function SearchToolsPage() {
const { accessToken, userRole, userId } = useAuthorized();
return <SearchTools accessToken={accessToken} userRole={userRole} userID={userId} />;
}

View file

@ -0,0 +1,9 @@
"use client";
import TagManagement from "@/components/tag_management";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
export default function TagManagementPage() {
const { accessToken, userRole, userId } = useAuthorized();
return <TagManagement accessToken={accessToken} userRole={userRole} userID={userId} />;
}

View file

@ -0,0 +1,9 @@
"use client";
import VectorStoreManagement from "@/components/vector_store_management";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
export default function VectorStores() {
const { accessToken, userRole, userId } = useAuthorized();
return <VectorStoreManagement accessToken={accessToken} userRole={userRole} userID={userId} />;
}

View file

@ -64,6 +64,17 @@ describe("migratedHref / legacyPageHref", () => {
expect(MIGRATED_PAGES.workflows).toBe("workflows");
expect(MIGRATED_PAGES["guardrails-monitor"]).toBe("guardrails-monitor");
});
it("maps the mcp-servers, search-tools, tag-management, vector-stores, and memory ids to their routes", async () => {
vi.doMock("@/components/networking", () => ({ serverRootPath: "/" }));
const { MIGRATED_PAGES } = await import("./migratedPages");
expect(MIGRATED_PAGES["mcp-servers"]).toBe("mcp-servers");
expect(MIGRATED_PAGES["search-tools"]).toBe("search-tools");
expect(MIGRATED_PAGES["tag-management"]).toBe("tag-management");
expect(MIGRATED_PAGES["vector-stores"]).toBe("vector-stores");
expect(MIGRATED_PAGES.memory).toBe("memory");
});
});
describe("dev server (NODE_ENV=development)", () => {

View file

@ -18,6 +18,11 @@ export const MIGRATED_PAGES: Record<string, string> = {
budgets: "budgets",
workflows: "workflows",
"guardrails-monitor": "guardrails-monitor",
"mcp-servers": "mcp-servers",
"search-tools": "search-tools",
"tag-management": "tag-management",
"vector-stores": "vector-stores",
memory: "memory",
};
function uiBase(): string {