feat(ui): migrate caching, cost-tracking, transform-request, ui-theme, and logs to path routes (#30267)

* feat(ui): cut caching, cost-tracking, transform-request, ui-theme, and logs over to path routes

Completes the simple-leaf portion of the page-by-page App Router
migration. All five legacy switch arms passed only identity props
(accessToken/userRole/userID, plus token/premiumUser for caching and
logs), all of which useAuthorized() provides, 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 caching, cost-tracking, transform-request, and ui-theme components

Each had the legacy switch as its only importer. caching takes its
whole closure (cache_dashboard, cache_health, cache_settings,
response_time_indicator); CostTrackingSettings moves as the
cost-tracking components folder; the transform-request and ui-theme
single-file panels move under their routes. view_logs stays at
src/components: six other pages (guardrails monitor, tool policies,
pass-through, MCP toolsets, usage) import it. Suppressions re-keyed.

* chore: retrigger ci

e2e_ui_testing failed on three specs unrelated to this PR's pages
(team-info tabs, MCP create form) and local_testing_part1 on
test_batch_completions; all pass on the pre-merge commit and none
touch files in this diff.
This commit is contained in:
ryan-crabbe-berri 2026-06-12 15:35:15 -07:00 • committed by GitHub
parent 2893f9b67b
commit 40301820e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 141 additions and 86 deletions

View file

@ -9,8 +9,8 @@
* - navigation specs that assert per-page URLs (tests/navigation/sidebar.spec.ts)
*
* 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, logs, transform-request, ui-theme).
* Pending (add as each PR lands): admin-panel, logging-and-alerts,
* model-hub-table, and usage (#30268).
*/
export const MIGRATED_E2E_PAGES: Record<string, string> = {
api_ref: "api-reference",
@ -30,6 +30,11 @@ export const MIGRATED_E2E_PAGES: Record<string, string> = {
prompts: "prompts",
"tool-policies": "tool-policies",
skills: "skills",
caching: "caching",
"cost-tracking": "cost-tracking",
"transform-request": "transform-request",
"ui-theme": "ui-theme",
logs: "logs",
};
export const MIGRATED_E2E_SEGMENTS: string[] = [...new Set(Object.values(MIGRATED_E2E_PAGES))];

View file

@ -293,77 +293,77 @@
"count": 1
}
},
"src/components/CostTrackingSettings/add_margin_form.tsx": {
"src/app/(dashboard)/cost-tracking/components/add_margin_form.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/add_provider_form.tsx": {
"src/app/(dashboard)/cost-tracking/components/add_provider_form.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/cost_tracking_settings.tsx": {
"src/app/(dashboard)/cost-tracking/components/cost_tracking_settings.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/how_it_works.tsx": {
"src/app/(dashboard)/cost-tracking/components/how_it_works.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.test.tsx": {
"src/app/(dashboard)/cost-tracking/components/pricing_calculator/multi_cost_results.test.tsx": {
"unused-imports/no-unused-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx": {
"src/app/(dashboard)/cost-tracking/components/pricing_calculator/multi_cost_results.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/pricing_calculator/multi_export_dropdown.test.tsx": {
"src/app/(dashboard)/cost-tracking/components/pricing_calculator/multi_export_dropdown.test.tsx": {
"unused-imports/no-unused-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/pricing_calculator/multi_export_dropdown.tsx": {
"src/app/(dashboard)/cost-tracking/components/pricing_calculator/multi_export_dropdown.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/pricing_calculator/use_multi_cost_estimate.ts": {
"src/app/(dashboard)/cost-tracking/components/pricing_calculator/use_multi_cost_estimate.ts": {
"no-restricted-syntax": {
"count": 1
}
},
"src/components/CostTrackingSettings/provider_discount_table.test.tsx": {
"src/app/(dashboard)/cost-tracking/components/provider_discount_table.test.tsx": {
"unused-imports/no-unused-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/provider_discount_table.tsx": {
"src/app/(dashboard)/cost-tracking/components/provider_discount_table.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/provider_display_helpers.test.ts": {
"src/app/(dashboard)/cost-tracking/components/provider_display_helpers.test.ts": {
"unused-imports/no-unused-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/provider_margin_table.tsx": {
"src/app/(dashboard)/cost-tracking/components/provider_margin_table.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/CostTrackingSettings/use_discount_config.ts": {
"src/app/(dashboard)/cost-tracking/components/use_discount_config.ts": {
"no-restricted-syntax": {
"count": 2
}
},
"src/components/CostTrackingSettings/use_margin_config.ts": {
"src/app/(dashboard)/cost-tracking/components/use_margin_config.ts": {
"no-restricted-syntax": {
"count": 2
}
@ -826,7 +826,7 @@
"count": 1
}
},
"src/components/cache_dashboard.tsx": {
"src/app/(dashboard)/caching/components/cache_dashboard.tsx": {
"no-restricted-imports": {
"count": 1
},
@ -837,22 +837,22 @@
"count": 2
}
},
"src/components/cache_health.tsx": {
"src/app/(dashboard)/caching/components/cache_health.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/cache_settings/CacheFieldRenderer.tsx": {
"src/app/(dashboard)/caching/components/cache_settings/CacheFieldRenderer.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/cache_settings/RedisTypeSelector.tsx": {
"src/app/(dashboard)/caching/components/cache_settings/RedisTypeSelector.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/cache_settings/index.tsx": {
"src/app/(dashboard)/caching/components/cache_settings/index.tsx": {
"no-restricted-imports": {
"count": 1
},
@ -1993,12 +1993,12 @@
"count": 1
}
},
"src/components/transform_request.tsx": {
"src/app/(dashboard)/transform-request/TransformRequestPanel.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/ui_theme_settings.tsx": {
"src/app/(dashboard)/ui-theme/UIThemeSettings.tsx": {
"no-restricted-imports": {
"count": 1
},

View file

@ -16,11 +16,11 @@ import {
Text,
} from "@tremor/react";
import React, { useEffect, useState } from "react";
import NotificationsManager from "./molecules/notifications_manager";
import UsageDatePicker from "./shared/usage_date_picker";
import NotificationsManager from "@/components/molecules/notifications_manager";
import UsageDatePicker from "@/components/shared/usage_date_picker";
import { RefreshIcon } from "@heroicons/react/outline";
import { adminGlobalCacheActivity, cachingHealthCheckCall } from "./networking";
import { adminGlobalCacheActivity, cachingHealthCheckCall } from "@/components/networking";
// Import the new component
import { CacheHealthTab } from "./cache_health";

View file

@ -5,7 +5,7 @@ import { NumberInput, TextInput } from "@tremor/react";
import { Select } from "antd";
import React, { useEffect, useState } from "react";
import { fetchAvailableModels, ModelGroup } from "@/components/llm_calls/fetch_models";
import NumericalInput from "../shared/numerical_input";
import NumericalInput from "@/components/shared/numerical_input";
interface CacheFieldRendererProps {
field: any;

View file

@ -1,7 +1,7 @@
import React, { useState, useEffect, useCallback } from "react";
import { Button, Accordion, AccordionHeader, AccordionBody } from "@tremor/react";
import { getCacheSettingsCall, testCacheConnectionCall, updateCacheSettingsCall } from "../networking";
import NotificationsManager from "../molecules/notifications_manager";
import { getCacheSettingsCall, testCacheConnectionCall, updateCacheSettingsCall } from "@/components/networking";
import NotificationsManager from "@/components/molecules/notifications_manager";
import RedisTypeSelector from "./RedisTypeSelector";
import CacheFieldRenderer from "./CacheFieldRenderer";
import { gatherFormValues, groupFieldsByCategory } from "./cacheSettingsUtils";

View file

@ -0,0 +1,17 @@
"use client";
import CacheDashboard from "./components/cache_dashboard";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
export default function Caching() {
const { accessToken, userRole, userId, token, premiumUser } = useAuthorized();
return (
<CacheDashboard
userID={userId}
userRole={userRole}
token={token}
accessToken={accessToken}
premiumUser={premiumUser}
/>
);
}

View file

@ -2,11 +2,11 @@ import React from "react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../tests/test-utils";
import { renderWithProviders } from "../../../../../tests/test-utils";
import AddMarginForm from "./add_margin_form";
import { MarginConfig } from "./types";
vi.mock("../provider_info_helpers", () => ({
vi.mock("@/components/provider_info_helpers", () => ({
Providers: {
OpenAI: "OpenAI",
Anthropic: "Anthropic",

View file

@ -2,7 +2,7 @@ import React from "react";
import { TextInput, Button } from "@tremor/react";
import { Select as AntdSelect, Form, Tooltip, Radio } from "antd";
import { InfoCircleOutlined } from "@ant-design/icons";
import { Providers, provider_map, providerLogoMap } from "../provider_info_helpers";
import { Providers, provider_map, providerLogoMap } from "@/components/provider_info_helpers";
import { MarginConfig } from "./types";
import { handleImageError } from "./provider_display_helpers";

View file

@ -2,11 +2,11 @@ import React from "react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../tests/test-utils";
import { renderWithProviders } from "../../../../../tests/test-utils";
import AddProviderForm from "./add_provider_form";
import { DiscountConfig } from "./types";
vi.mock("../provider_info_helpers", () => ({
vi.mock("@/components/provider_info_helpers", () => ({
Providers: {
OpenAI: "OpenAI",
Anthropic: "Anthropic",

View file

@ -2,7 +2,7 @@ import React from "react";
import { TextInput, Button } from "@tremor/react";
import { Select as AntdSelect, Form, Tooltip } from "antd";
import { InfoCircleOutlined } from "@ant-design/icons";
import { Providers, provider_map, providerLogoMap } from "../provider_info_helpers";
import { Providers, provider_map, providerLogoMap } from "@/components/provider_info_helpers";
import { DiscountConfig } from "./types";
import { handleImageError } from "./provider_display_helpers";

View file

@ -2,7 +2,7 @@ import React from "react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../tests/test-utils";
import { renderWithProviders } from "../../../../../tests/test-utils";
import CostTrackingSettings from "./cost_tracking_settings";
// Mock sub-hooks so we can control their state without network calls
@ -37,7 +37,7 @@ vi.mock("@/components/llm_calls/fetch_models", () => ({
fetchAvailableModels: vi.fn().mockResolvedValue([]),
}));
vi.mock("../HelpLink", () => ({
vi.mock("@/components/HelpLink", () => ({
DocsMenu: () => null,
}));
@ -45,7 +45,7 @@ vi.mock("./how_it_works", () => ({
default: () => <div data-testid="how-it-works">How It Works</div>,
}));
vi.mock("../provider_info_helpers", () => ({
vi.mock("@/components/provider_info_helpers", () => ({
Providers: { OpenAI: "OpenAI" },
provider_map: { OpenAI: "openai" },
providerLogoMap: {},

View file

@ -20,7 +20,7 @@ import ProviderMarginTable from "./provider_margin_table";
import AddMarginForm from "./add_margin_form";
import PricingCalculator from "./pricing_calculator/index";
import { ExclamationCircleOutlined } from "@ant-design/icons";
import { DocsMenu } from "../HelpLink";
import { DocsMenu } from "@/components/HelpLink";
import HowItWorks from "./how_it_works";
import { useDiscountConfig } from "./use_discount_config";
import { useMarginConfig } from "./use_margin_config";

View file

@ -2,7 +2,7 @@ import React from "react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../tests/test-utils";
import { renderWithProviders } from "../../../../../tests/test-utils";
import HowItWorks from "./how_it_works";
vi.mock("@/app/(dashboard)/api-reference/components/CodeBlock", () => ({

View file

@ -2,7 +2,7 @@ import React from "react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../../tests/test-utils";
import { renderWithProviders } from "../../../../../../tests/test-utils";
import PricingCalculator from "./index";
import type { ModelEntry } from "./types";
import type { MultiModelResult } from "./types";

View file

@ -2,7 +2,7 @@ import React from "react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../../tests/test-utils";
import { renderWithProviders } from "../../../../../../tests/test-utils";
import MultiCostResults from "./multi_cost_results";
import type { MultiModelResult } from "./types";
import type { CostEstimateResponse } from "../types";

View file

@ -2,7 +2,7 @@ import React from "react";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../../tests/test-utils";
import { renderWithProviders } from "../../../../../../tests/test-utils";
import MultiExportDropdown from "./multi_export_dropdown";
import type { MultiModelResult } from "./types";

View file

@ -2,7 +2,7 @@ import React from "react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../tests/test-utils";
import { renderWithProviders } from "../../../../../tests/test-utils";
import ProviderDiscountTable from "./provider_discount_table";
vi.mock("@heroicons/react/outline", () => ({

View file

@ -1,7 +1,7 @@
import React, { useState } from "react";
import { TextInput, Icon, Text } from "@tremor/react";
import { TrashIcon, PencilAltIcon, CheckIcon, XIcon } from "@heroicons/react/outline";
import { SimpleTable } from "../common_components/simple_table";
import { SimpleTable } from "@/components/common_components/simple_table";
import { DiscountConfig } from "./types";
import { getProviderDisplayInfo, handleImageError } from "./provider_display_helpers";

View file

@ -1,7 +1,7 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { getProviderDisplayInfo, getProviderBackendValue, handleImageError } from "./provider_display_helpers";
vi.mock("../provider_info_helpers", () => ({
vi.mock("@/components/provider_info_helpers", () => ({
Providers: {
OpenAI: "OpenAI",
Anthropic: "Anthropic",

View file

@ -1,4 +1,4 @@
import { Providers, provider_map, providerLogoMap } from "../provider_info_helpers";
import { Providers, provider_map, providerLogoMap } from "@/components/provider_info_helpers";
export interface ProviderDisplayInfo {
displayName: string;

View file

@ -2,7 +2,7 @@ import React from "react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../tests/test-utils";
import { renderWithProviders } from "../../../../../tests/test-utils";
import ProviderMarginTable from "./provider_margin_table";
vi.mock("@heroicons/react/outline", () => ({

View file

@ -1,7 +1,7 @@
import React, { useState } from "react";
import { TextInput, Icon, Text } from "@tremor/react";
import { TrashIcon, PencilAltIcon, CheckIcon, XIcon } from "@heroicons/react/outline";
import { SimpleTable } from "../common_components/simple_table";
import { SimpleTable } from "@/components/common_components/simple_table";
import { MarginConfig } from "./types";
import { getProviderDisplayInfo, handleImageError } from "./provider_display_helpers";

View file

@ -18,7 +18,7 @@ vi.mock("./provider_display_helpers", () => ({
}),
}));
vi.mock("../provider_info_helpers", () => ({
vi.mock("@/components/provider_info_helpers", () => ({
Providers: {
OpenAI: "OpenAI",
Anthropic: "Anthropic",

View file

@ -1,9 +1,9 @@
import { useState, useCallback } from "react";
import { getProxyBaseUrl, getGlobalLitellmHeaderName } from "@/components/networking";
import NotificationsManager from "../molecules/notifications_manager";
import NotificationsManager from "@/components/molecules/notifications_manager";
import { DiscountConfig } from "./types";
import { getProviderBackendValue } from "./provider_display_helpers";
import { Providers } from "../provider_info_helpers";
import { Providers } from "@/components/provider_info_helpers";
export interface UseDiscountConfigProps {
accessToken: string | null;

View file

@ -18,7 +18,7 @@ vi.mock("./provider_display_helpers", () => ({
}),
}));
vi.mock("../provider_info_helpers", () => ({
vi.mock("@/components/provider_info_helpers", () => ({
Providers: {
OpenAI: "OpenAI",
Anthropic: "Anthropic",

View file

@ -1,9 +1,9 @@
import { useState, useCallback } from "react";
import { getProxyBaseUrl, getGlobalLitellmHeaderName } from "@/components/networking";
import NotificationsManager from "../molecules/notifications_manager";
import NotificationsManager from "@/components/molecules/notifications_manager";
import { MarginConfig } from "./types";
import { getProviderBackendValue } from "./provider_display_helpers";
import { Providers } from "../provider_info_helpers";
import { Providers } from "@/components/provider_info_helpers";
export interface UseMarginConfigProps {
accessToken: string | null;

View file

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

View file

@ -0,0 +1,17 @@
"use client";
import SpendLogsTable from "@/components/view_logs";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
export default function Logs() {
const { accessToken, userRole, userId, token, premiumUser } = useAuthorized();
return (
<SpendLogsTable
userID={userId}
userRole={userRole}
token={token}
accessToken={accessToken}
premiumUser={premiumUser}
/>
);
}

View file

@ -3,12 +3,10 @@
import ModelsAndEndpointsView from "@/app/(dashboard)/models-and-endpoints/ModelsAndEndpointsView";
import AdminPanel from "@/components/AdminPanel";
import AgentsPanel from "@/components/agents";
import CacheDashboard from "@/components/cache_dashboard";
import { teamListCall as v2TeamListCall } from "@/app/(dashboard)/hooks/teams/useTeams";
import { useUISettings } from "@/app/(dashboard)/hooks/uiSettings/useUISettings";
import useProxySettings from "@/app/(dashboard)/hooks/proxySettings/useProxySettings";
import LoadingScreen from "@/components/common_components/LoadingScreen";
import { CostTrackingSettings } from "@/components/CostTrackingSettings";
import GeneralSettings from "@/components/general_settings";
import { Team } from "@/components/key_team_helpers/key_list";
import ModelHubTable from "@/components/AIHub/ModelHubTable";
@ -21,11 +19,8 @@ import PassThroughSettings from "@/components/pass_through_settings";
import PublicModelHub from "@/components/public_model_hub";
import Settings from "@/components/settings";
import { SurveyPrompt, SurveyModal, ClaudeCodePrompt, ClaudeCodeModal } from "@/components/survey";
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 SpendLogsTable from "@/components/view_logs";
import ViewUserDashboard from "@/components/view_users";
import { useAuth } from "@/contexts/AuthContext";
import {
@ -374,14 +369,8 @@ function CreateKeyPageContent() {
<Settings userID={userID} userRole={userRole} accessToken={accessToken} premiumUser={premiumUser} />
) : page == "agents" ? (
<AgentsPanel accessToken={accessToken} userRole={userRole} teams={teams} />
) : page == "transform-request" ? (
<TransformRequestPanel accessToken={accessToken} />
) : page == "router-settings" ? (
<GeneralSettings userID={userID} userRole={userRole} accessToken={accessToken} modelData={modelData} />
) : page == "ui-theme" ? (
<UIThemeSettings userID={userID} userRole={userRole} accessToken={accessToken} />
) : page == "cost-tracking" ? (
<CostTrackingSettings userID={userID} userRole={userRole} accessToken={accessToken} />
) : page == "model-hub-table" ? (
isAdminRole(userRole) ? (
<ModelHubTable
@ -393,14 +382,6 @@ function CreateKeyPageContent() {
) : (
<PublicModelHub accessToken={accessToken} isEmbedded={true} />
)
) : page == "caching" ? (
<CacheDashboard
userID={userID}
userRole={userRole}
token={token}
accessToken={accessToken}
premiumUser={premiumUser}
/>
) : page == "pass-through-settings" ? (
<PassThroughSettings
userID={userID}
@ -409,14 +390,6 @@ function CreateKeyPageContent() {
modelData={modelData}
premiumUser={premiumUser}
/>
) : page == "logs" ? (
<SpendLogsTable
userID={userID}
userRole={userRole}
token={token}
accessToken={accessToken}
premiumUser={premiumUser}
/>
) : page == "new_usage" ? (
<NewUsagePage teams={(teams as Team[]) ?? []} organizations={(organizations as Organization[]) ?? []} />
) : (

View file

@ -2,8 +2,8 @@ import React, { useState } from "react";
import { Button } from "antd";
import { CopyOutlined } from "@ant-design/icons";
import { Title } from "@tremor/react";
import { transformRequestCall } from "./networking";
import NotificationsManager from "./molecules/notifications_manager";
import { transformRequestCall } from "@/components/networking";
import NotificationsManager from "@/components/molecules/notifications_manager";
interface TransformRequestPanelProps {
accessToken: string | null;
}

View file

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

View file

@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react";
import { Card, Title, Text, TextInput, Button } from "@tremor/react";
import { useTheme } from "@/contexts/ThemeContext";
import { getProxyBaseUrl, getGlobalLitellmHeaderName } from "@/components/networking";
import NotificationsManager from "./molecules/notifications_manager";
import NotificationsManager from "@/components/molecules/notifications_manager";
interface UIThemeSettingsProps {
userID: string | null;

View file

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

View file

@ -88,6 +88,17 @@ describe("migratedHref / legacyPageHref", () => {
// Old bookmarks used ?page=claude-code-plugins for the same panel.
expect(MIGRATED_PAGES["claude-code-plugins"]).toBe("skills");
});
it("maps the caching, cost-tracking, transform-request, ui-theme, and logs ids to their routes", async () => {
vi.doMock("@/components/networking", () => ({ serverRootPath: "/" }));
const { MIGRATED_PAGES } = await import("./migratedPages");
expect(MIGRATED_PAGES.caching).toBe("caching");
expect(MIGRATED_PAGES["cost-tracking"]).toBe("cost-tracking");
expect(MIGRATED_PAGES["transform-request"]).toBe("transform-request");
expect(MIGRATED_PAGES["ui-theme"]).toBe("ui-theme");
expect(MIGRATED_PAGES.logs).toBe("logs");
});
});
describe("dev server (NODE_ENV=development)", () => {

View file

@ -30,6 +30,11 @@ export const MIGRATED_PAGES: Record<string, string> = {
skills: "skills",
// Legacy alias: the old switch matched ?page=claude-code-plugins for the same panel.
"claude-code-plugins": "skills",
caching: "caching",
"cost-tracking": "cost-tracking",
"transform-request": "transform-request",
"ui-theme": "ui-theme",
logs: "logs",
};
function uiBase(): string {