feat(ui): migrate budgets, workflows, and guardrails-monitor to path routes (#30236)
* feat(ui): cut budgets, workflows, and guardrails-monitor over to path routes Continues the page-by-page App Router migration (#30185, #30226). All three legacy switch arms passed only accessToken, 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 three up in the migration smoke and sidebar specs automatically. * refactor(ui): colocate budgets, workflows, and guardrails-monitor components budgets and workflow_runs were imported only by the legacy switch, so they move wholesale into their route folders; the budgetItem type hoists into the shared useBudgets hook, which owns the API response shape, so the hooks layer no longer imports from a page folder. GuardrailsMonitor keeps LogViewer, mockData, and MetricCard at the shared src/components home because ToolDetail and ToolPolicies import them; the rest moves. eslint suppressions are re-keyed accordingly. * fix(ui): restore MetricCard test-utils path and merge duplicate import MetricCard.test.tsx got the moved-tree depth rewrite before being moved back to src/components/GuardrailsMonitor, leaving a five-level path that escapes the project root; the suite failed at import. Also merge the two imports from useBudgets in budget_panel.tsx. Both flagged by Greptile.
This commit is contained in:
parent
1828a7c6f0
commit
3ad385a8a4
@ -10,16 +10,18 @@
|
||||
*
|
||||
* Keep this in lockstep with MIGRATED_PAGES in src/utils/migratedPages.ts.
|
||||
* Pending (add as each PR lands): the leaf-pages batch
|
||||
* (budgets, caching, cost-tracking, guardrails, guardrails-monitor, logs,
|
||||
* mcp-servers, memory, policies, prompts, search-tools, skills,
|
||||
* tag-management, tool-policies, transform-request, ui-theme, vector-stores,
|
||||
* workflows).
|
||||
* (caching, cost-tracking, guardrails, logs, mcp-servers, memory,
|
||||
* policies, prompts, search-tools, skills, tag-management, tool-policies,
|
||||
* transform-request, ui-theme, vector-stores).
|
||||
*/
|
||||
export const MIGRATED_E2E_PAGES: Record<string, string> = {
|
||||
api_ref: "api-reference",
|
||||
"llm-playground": "playground",
|
||||
projects: "projects",
|
||||
"access-groups": "access-groups",
|
||||
budgets: "budgets",
|
||||
workflows: "workflows",
|
||||
"guardrails-monitor": "guardrails-monitor",
|
||||
};
|
||||
|
||||
export const MIGRATED_E2E_SEGMENTS: string[] = [...new Set(Object.values(MIGRATED_E2E_PAGES))];
|
||||
|
||||
@ -419,22 +419,22 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/GuardrailsMonitor/EvaluationSettingsModal.tsx": {
|
||||
"src/app/(dashboard)/guardrails-monitor/components/EvaluationSettingsModal.tsx": {
|
||||
"react-hooks/set-state-in-effect": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/GuardrailsMonitor/GuardrailsMonitorView.tsx": {
|
||||
"src/app/(dashboard)/guardrails-monitor/components/GuardrailsMonitorView.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/GuardrailsMonitor/ScoreChart.test.tsx": {
|
||||
"src/app/(dashboard)/guardrails-monitor/components/ScoreChart.test.tsx": {
|
||||
"react/display-name": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/GuardrailsMonitor/ScoreChart.tsx": {
|
||||
"src/app/(dashboard)/guardrails-monitor/components/ScoreChart.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
@ -798,22 +798,22 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/budgets/budget_modal.tsx": {
|
||||
"src/app/(dashboard)/budgets/components/budget_modal.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/budgets/budget_panel.test.tsx": {
|
||||
"src/app/(dashboard)/budgets/components/budget_panel.test.tsx": {
|
||||
"unused-imports/no-unused-imports": {
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"src/components/budgets/budget_panel.tsx": {
|
||||
"src/app/(dashboard)/budgets/components/budget_panel.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/budgets/edit_budget_modal.tsx": {
|
||||
"src/app/(dashboard)/budgets/components/edit_budget_modal.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
@ -2163,7 +2163,7 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/workflow_runs/index.tsx": {
|
||||
"src/app/(dashboard)/workflows/WorkflowRuns.tsx": {
|
||||
"no-restricted-syntax": {
|
||||
"count": 3
|
||||
},
|
||||
|
||||
@ -2,7 +2,7 @@ import React from "react";
|
||||
import { TextInput, Accordion, AccordionHeader, AccordionBody } from "@tremor/react";
|
||||
import { Button as Button2, Modal, Form, InputNumber, Select } from "antd";
|
||||
import { useCreateBudget } from "@/app/(dashboard)/hooks/budgets/useBudgets";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
|
||||
interface BudgetModalProps {
|
||||
isModalVisible: boolean;
|
||||
@ -21,10 +21,10 @@ import {
|
||||
} from "@tremor/react";
|
||||
import React, { useState } from "react";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import DeleteResourceModal from "../common_components/DeleteResourceModal";
|
||||
import TableIconActionButton from "../common_components/IconActionButton/TableIconActionButtons/TableIconActionButton";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
import { useBudgets, useDeleteBudget } from "@/app/(dashboard)/hooks/budgets/useBudgets";
|
||||
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
|
||||
import TableIconActionButton from "@/components/common_components/IconActionButton/TableIconActionButtons/TableIconActionButton";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { useBudgets, useDeleteBudget, budgetItem } from "@/app/(dashboard)/hooks/budgets/useBudgets";
|
||||
import BudgetModal from "./budget_modal";
|
||||
import EditBudgetModal from "./edit_budget_modal";
|
||||
import { CREATE_END_USER_CURL_COMMAND, CHAT_COMPLETIONS_CURL_COMMAND, OPENAI_SDK_PYTHON_CODE } from "./constants";
|
||||
@ -35,14 +35,6 @@ interface BudgetSettingsPageProps {
|
||||
accessToken: string | null;
|
||||
}
|
||||
|
||||
export interface budgetItem {
|
||||
budget_id: string;
|
||||
max_budget: number | null;
|
||||
rpm_limit: number | null;
|
||||
tpm_limit: number | null;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
const BudgetPanel: React.FC<BudgetSettingsPageProps> = ({ accessToken }) => {
|
||||
const [isCreateModelVisible, setIsCreateModelVisible] = useState(false);
|
||||
const [isEditModalVisible, setIsEditModalVisible] = useState(false);
|
||||
@ -2,8 +2,8 @@ import React, { useEffect } from "react";
|
||||
import { TextInput, Accordion, AccordionHeader, AccordionBody } from "@tremor/react";
|
||||
import { Button as Button2, Modal, Form, InputNumber, Select } from "antd";
|
||||
import { useUpdateBudget } from "@/app/(dashboard)/hooks/budgets/useBudgets";
|
||||
import { budgetItem } from "./budget_panel";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
import { budgetItem } from "@/app/(dashboard)/hooks/budgets/useBudgets";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
|
||||
interface EditBudgetModalProps {
|
||||
isModalVisible: boolean;
|
||||
@ -0,0 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import BudgetPanel from "./components/budget_panel";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
|
||||
export default function Budgets() {
|
||||
const { accessToken } = useAuthorized();
|
||||
return <BudgetPanel accessToken={accessToken} />;
|
||||
}
|
||||
@ -4,9 +4,9 @@ import { Button, Col, Row, Spin, Tabs } from "antd";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { getGuardrailsUsageDetail, getGuardrailsUsageLogs } from "@/components/networking";
|
||||
import { EvaluationSettingsModal } from "./EvaluationSettingsModal";
|
||||
import { LogViewer } from "./LogViewer";
|
||||
import { MetricCard } from "./MetricCard";
|
||||
import type { LogEntry } from "./mockData";
|
||||
import { LogViewer } from "@/components/GuardrailsMonitor/LogViewer";
|
||||
import { MetricCard } from "@/components/GuardrailsMonitor/MetricCard";
|
||||
import type { LogEntry } from "@/components/GuardrailsMonitor/mockData";
|
||||
|
||||
interface GuardrailDetailProps {
|
||||
guardrailId: string;
|
||||
@ -4,9 +4,9 @@ import { Button, Card, Col, Row, Spin, Table, Typography } from "antd";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { getGuardrailsUsageOverview } from "@/components/networking";
|
||||
import { type PerformanceRow } from "./mockData";
|
||||
import { type PerformanceRow } from "@/components/GuardrailsMonitor/mockData";
|
||||
import { EvaluationSettingsModal } from "./EvaluationSettingsModal";
|
||||
import { MetricCard } from "./MetricCard";
|
||||
import { MetricCard } from "@/components/GuardrailsMonitor/MetricCard";
|
||||
import { ScoreChart } from "./ScoreChart";
|
||||
|
||||
interface GuardrailsOverviewProps {
|
||||
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { screen } from "@testing-library/react";
|
||||
import { renderWithProviders } from "../../../tests/test-utils";
|
||||
import { renderWithProviders } from "../../../../../tests/test-utils";
|
||||
import { ScoreChart } from "./ScoreChart";
|
||||
|
||||
vi.mock("@tremor/react", async (importOriginal) => {
|
||||
@ -0,0 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import GuardrailsMonitorView from "./components/GuardrailsMonitorView";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
|
||||
export default function GuardrailsMonitor() {
|
||||
const { accessToken } = useAuthorized();
|
||||
return <GuardrailsMonitorView accessToken={accessToken} />;
|
||||
}
|
||||
@ -2,7 +2,14 @@ import { useQuery, useMutation, useQueryClient, UseQueryResult } from "@tanstack
|
||||
import { createQueryKeys } from "../common/queryKeysFactory";
|
||||
import { getBudgetList, budgetCreateCall, budgetUpdateCall, budgetDeleteCall } from "@/components/networking";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
import { budgetItem } from "@/components/budgets/budget_panel";
|
||||
|
||||
export interface budgetItem {
|
||||
budget_id: string;
|
||||
max_budget: number | null;
|
||||
rpm_limit: number | null;
|
||||
tpm_limit: number | null;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export const budgetKeys = createQueryKeys("budgets");
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
import ModelsAndEndpointsView from "@/app/(dashboard)/models-and-endpoints/ModelsAndEndpointsView";
|
||||
import AdminPanel from "@/components/AdminPanel";
|
||||
import AgentsPanel from "@/components/agents";
|
||||
import BudgetPanel from "@/components/budgets/budget_panel";
|
||||
import CacheDashboard from "@/components/cache_dashboard";
|
||||
import ClaudeCodePluginsPanel from "@/components/claude_code_plugins";
|
||||
import { teamListCall as v2TeamListCall } from "@/app/(dashboard)/hooks/teams/useTeams";
|
||||
@ -12,7 +11,6 @@ import useProxySettings from "@/app/(dashboard)/hooks/proxySettings/useProxySett
|
||||
import LoadingScreen from "@/components/common_components/LoadingScreen";
|
||||
import { CostTrackingSettings } from "@/components/CostTrackingSettings";
|
||||
import GeneralSettings from "@/components/general_settings";
|
||||
import GuardrailsMonitorView from "@/components/GuardrailsMonitor/GuardrailsMonitorView";
|
||||
import GuardrailsPanel from "@/components/guardrails";
|
||||
import PoliciesPanel from "@/components/policies";
|
||||
import { Team } from "@/components/key_team_helpers/key_list";
|
||||
@ -37,7 +35,6 @@ import UserDashboard from "@/components/user_dashboard";
|
||||
import VectorStoreManagement from "@/components/vector_store_management";
|
||||
import ToolPoliciesView from "@/components/ToolPoliciesView";
|
||||
import { MemoryView } from "@/components/MemoryView";
|
||||
import WorkflowRuns from "@/components/workflow_runs";
|
||||
import SpendLogsTable from "@/components/view_logs";
|
||||
import ViewUserDashboard from "@/components/view_users";
|
||||
import { useAuth } from "@/contexts/AuthContext";
|
||||
@ -385,8 +382,6 @@ function CreateKeyPageContent() {
|
||||
<AdminPanel proxySettings={proxySettings} />
|
||||
) : page == "logging-and-alerts" ? (
|
||||
<Settings userID={userID} userRole={userRole} accessToken={accessToken} premiumUser={premiumUser} />
|
||||
) : page == "budgets" ? (
|
||||
<BudgetPanel accessToken={accessToken} />
|
||||
) : page == "guardrails" ? (
|
||||
<GuardrailsPanel accessToken={accessToken} userRole={userRole} />
|
||||
) : page == "policies" ? (
|
||||
@ -450,12 +445,8 @@ function CreateKeyPageContent() {
|
||||
<VectorStoreManagement accessToken={accessToken} userRole={userRole} userID={userID} />
|
||||
) : page == "tool-policies" ? (
|
||||
<ToolPoliciesView accessToken={accessToken} userRole={userRole} />
|
||||
) : page == "workflows" ? (
|
||||
<WorkflowRuns accessToken={accessToken} />
|
||||
) : page == "memory" ? (
|
||||
<MemoryView accessToken={accessToken} userID={userID} userRole={userRole} />
|
||||
) : page == "guardrails-monitor" ? (
|
||||
<GuardrailsMonitorView accessToken={accessToken} />
|
||||
) : page == "new_usage" ? (
|
||||
<NewUsagePage teams={(teams as Team[]) ?? []} organizations={(organizations as Organization[]) ?? []} />
|
||||
) : (
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import WorkflowRuns from "./WorkflowRuns";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
|
||||
export default function Workflows() {
|
||||
const { accessToken } = useAuthorized();
|
||||
return <WorkflowRuns accessToken={accessToken} />;
|
||||
}
|
||||
@ -55,6 +55,15 @@ describe("migratedHref / legacyPageHref", () => {
|
||||
expect(MIGRATED_PAGES.projects).toBe("projects");
|
||||
expect(MIGRATED_PAGES["access-groups"]).toBe("access-groups");
|
||||
});
|
||||
|
||||
it("maps the budgets, workflows, and guardrails-monitor sidebar ids to their routes", async () => {
|
||||
vi.doMock("@/components/networking", () => ({ serverRootPath: "/" }));
|
||||
const { MIGRATED_PAGES } = await import("./migratedPages");
|
||||
|
||||
expect(MIGRATED_PAGES.budgets).toBe("budgets");
|
||||
expect(MIGRATED_PAGES.workflows).toBe("workflows");
|
||||
expect(MIGRATED_PAGES["guardrails-monitor"]).toBe("guardrails-monitor");
|
||||
});
|
||||
});
|
||||
|
||||
describe("dev server (NODE_ENV=development)", () => {
|
||||
|
||||
@ -15,6 +15,9 @@ export const MIGRATED_PAGES: Record<string, string> = {
|
||||
"llm-playground": "playground",
|
||||
projects: "projects",
|
||||
"access-groups": "access-groups",
|
||||
budgets: "budgets",
|
||||
workflows: "workflows",
|
||||
"guardrails-monitor": "guardrails-monitor",
|
||||
};
|
||||
|
||||
function uiBase(): string {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user