feat(ui): mcp_server_cost_display + add_model_tab

- mcp_server_cost_display: @tremor Text \u2192 plain <p>/<span> with
  semantic tokens. Kept the blue summary callout + emerald cost
  values; file added to .eslintrc.json overrides.
- add_model_tab: @tremor Tab/TabGroup/TabList/TabPanel/TabPanels \u2192
  shadcn Tabs/TabsList/TabsTrigger/TabsContent. antd Form is still
  passed through to AddModelForm and AddAutoRouterTab which are
  form-driven; not migrated in this pass.

Gates: TS \u2713 | Build \u2713.

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-04-23 11:15:01 +00:00
parent fab8c8ec8d
commit 56e17427cc
No known key found for this signature in database
3 changed files with 84 additions and 62 deletions

View file

@ -41,6 +41,7 @@
"src/components/mcp_server_management/MCPServerSelector.tsx",
"src/components/mcp_tools/MCPNetworkSettings.tsx",
"src/components/mcp_tools/ByokCredentialModal.tsx",
"src/components/mcp_tools/mcp_server_cost_display.tsx",
"src/components/shared/usage_date_picker.tsx",
"src/components/shared/advanced_date_picker.tsx",
"src/components/activity_metrics.tsx",

View file

@ -1,4 +1,9 @@
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@tremor/react";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@/components/ui/tabs";
import type { FormInstance } from "antd";
import { Form } from "antd";
import type { UploadProps } from "antd/es/upload";
@ -11,7 +16,8 @@ import AddModelForm from "./AddModelForm";
import { handleAddAutoRouterSubmit } from "./handle_add_auto_router_submit";
interface AddModelTabProps {
form: FormInstance; // For the Add Model tab
form: FormInstance;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handleOk: (values?: any) => Promise<void>;
selectedProvider: Providers;
setSelectedProvider: (provider: Providers) => void;
@ -43,14 +49,18 @@ const AddModelTab: React.FC<AddModelTabProps> = ({
accessToken,
userRole,
}) => {
// Create separate form instance for auto router
const [autoRouterForm] = Form.useForm();
const handleAutoRouterOk = () => {
autoRouterForm
.validateFields()
.then((values) => {
handleAddAutoRouterSubmit(values, accessToken, autoRouterForm, handleOk);
handleAddAutoRouterSubmit(
values,
accessToken,
autoRouterForm,
handleOk,
);
})
.catch((error) => {
console.error("Validation failed:", error);
@ -58,40 +68,36 @@ const AddModelTab: React.FC<AddModelTabProps> = ({
};
return (
<>
<TabGroup className="w-full">
<TabList className="mb-4">
<Tab>Add Model</Tab>
<Tab>Add Auto Router</Tab>
</TabList>
<TabPanels>
<TabPanel>
<AddModelForm
form={form}
handleOk={handleOk}
selectedProvider={selectedProvider}
setSelectedProvider={setSelectedProvider}
providerModels={providerModels}
setProviderModelsFn={setProviderModelsFn}
getPlaceholder={getPlaceholder}
uploadProps={uploadProps}
showAdvancedSettings={showAdvancedSettings}
setShowAdvancedSettings={setShowAdvancedSettings}
teams={teams}
credentials={credentials}
/>
</TabPanel>
<TabPanel>
<AddAutoRouterTab
form={autoRouterForm}
handleOk={handleAutoRouterOk}
accessToken={accessToken}
userRole={userRole}
/>
</TabPanel>
</TabPanels>
</TabGroup>
</>
<Tabs defaultValue="add-model" className="w-full">
<TabsList className="mb-4">
<TabsTrigger value="add-model">Add Model</TabsTrigger>
<TabsTrigger value="add-auto-router">Add Auto Router</TabsTrigger>
</TabsList>
<TabsContent value="add-model">
<AddModelForm
form={form}
handleOk={handleOk}
selectedProvider={selectedProvider}
setSelectedProvider={setSelectedProvider}
providerModels={providerModels}
setProviderModelsFn={setProviderModelsFn}
getPlaceholder={getPlaceholder}
uploadProps={uploadProps}
showAdvancedSettings={showAdvancedSettings}
setShowAdvancedSettings={setShowAdvancedSettings}
teams={teams}
credentials={credentials}
/>
</TabsContent>
<TabsContent value="add-auto-router">
<AddAutoRouterTab
form={autoRouterForm}
handleOk={handleAutoRouterOk}
accessToken={accessToken}
userRole={userRole}
/>
</TabsContent>
</Tabs>
);
};

View file

@ -1,26 +1,30 @@
import React from "react";
import { Text } from "@tremor/react";
import { MCPServerCostInfo } from "./types";
interface MCPServerCostDisplayProps {
costConfig?: MCPServerCostInfo | null;
}
const MCPServerCostDisplay: React.FC<MCPServerCostDisplayProps> = ({ costConfig }) => {
const MCPServerCostDisplay: React.FC<MCPServerCostDisplayProps> = ({
costConfig,
}) => {
const hasDefaultCost =
costConfig?.default_cost_per_query !== undefined && costConfig?.default_cost_per_query !== null;
costConfig?.default_cost_per_query !== undefined &&
costConfig?.default_cost_per_query !== null;
const hasToolCosts =
costConfig?.tool_name_to_cost_per_query && Object.keys(costConfig.tool_name_to_cost_per_query).length > 0;
costConfig?.tool_name_to_cost_per_query &&
Object.keys(costConfig.tool_name_to_cost_per_query).length > 0;
const hasCostConfig = hasDefaultCost || hasToolCosts;
if (!hasCostConfig) {
return (
<div className="mt-6 pt-6 border-t border-gray-200">
<div className="mt-6 pt-6 border-t border-border">
<div className="space-y-4">
<div className="p-4 bg-gray-50 border border-gray-200 rounded-lg">
<Text className="text-gray-600">
No cost configuration set for this server. Tool calls will be charged at $0.00 per tool call.
</Text>
<div className="p-4 bg-muted border border-border rounded-lg">
<p className="text-muted-foreground">
No cost configuration set for this server. Tool calls will be
charged at $0.00 per tool call.
</p>
</div>
</div>
</div>
@ -28,28 +32,35 @@ const MCPServerCostDisplay: React.FC<MCPServerCostDisplayProps> = ({ costConfig
}
return (
<div className="mt-6 pt-6 border-t border-gray-200">
<div className="mt-6 pt-6 border-t border-border">
<div className="space-y-4">
{hasDefaultCost &&
costConfig?.default_cost_per_query !== undefined &&
costConfig?.default_cost_per_query !== null && (
<div>
<Text className="font-medium">Default Cost per Query</Text>
<div className="text-green-600 font-mono">${costConfig.default_cost_per_query.toFixed(4)}</div>
<p className="font-medium">Default Cost per Query</p>
<div className="text-emerald-600 dark:text-emerald-400 font-mono">
${costConfig.default_cost_per_query.toFixed(4)}
</div>
</div>
)}
{hasToolCosts && costConfig?.tool_name_to_cost_per_query && (
<div>
<Text className="font-medium">Tool-Specific Costs</Text>
<p className="font-medium">Tool-Specific Costs</p>
<div className="mt-2 space-y-2">
{Object.entries(costConfig.tool_name_to_cost_per_query).map(
([toolName, cost]) =>
cost !== null &&
cost !== undefined && (
<div key={toolName} className="flex justify-between items-center p-3 bg-gray-50 rounded-lg">
<Text className="font-medium">{toolName}</Text>
<Text className="text-green-600 font-mono">${cost.toFixed(4)} per query</Text>
<div
key={toolName}
className="flex justify-between items-center p-3 bg-muted rounded-lg"
>
<span className="font-medium">{toolName}</span>
<span className="text-emerald-600 dark:text-emerald-400 font-mono">
${cost.toFixed(4)} per query
</span>
</div>
),
)}
@ -57,20 +68,24 @@ const MCPServerCostDisplay: React.FC<MCPServerCostDisplayProps> = ({ costConfig
</div>
)}
<div className="mt-4 p-4 bg-blue-50 border border-blue-200 rounded-lg">
<Text className="text-blue-800 font-medium">Cost Summary:</Text>
<div className="mt-4 p-4 bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-900 rounded-lg">
<p className="text-blue-800 dark:text-blue-200 font-medium">
Cost Summary:
</p>
<div className="mt-2 space-y-1">
{hasDefaultCost &&
costConfig?.default_cost_per_query !== undefined &&
costConfig?.default_cost_per_query !== null && (
<Text className="text-blue-700">
• Default cost: ${costConfig.default_cost_per_query.toFixed(4)} per query
</Text>
<p className="text-blue-700 dark:text-blue-300">
• Default cost: $
{costConfig.default_cost_per_query.toFixed(4)} per query
</p>
)}
{hasToolCosts && costConfig?.tool_name_to_cost_per_query && (
<Text className="text-blue-700">
• {Object.keys(costConfig.tool_name_to_cost_per_query).length} tool(s) with custom pricing
</Text>
<p className="text-blue-700 dark:text-blue-300">
• {Object.keys(costConfig.tool_name_to_cost_per_query).length}{" "}
tool(s) with custom pricing
</p>
)}
</div>
</div>