mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-05 08:07:05 +00:00
fixes ui
This commit is contained in:
parent
5f07635310
commit
2014bcf9d8
2 changed files with 62 additions and 74 deletions
|
|
@ -59,7 +59,7 @@ export const CostBreakdownViewer: React.FC<CostBreakdownViewerProps> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden">
|
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||||
<Accordion>
|
<Accordion>
|
||||||
<AccordionHeader className="p-4 border-b hover:bg-gray-50 transition-colors text-left">
|
<AccordionHeader className="p-4 border-b hover:bg-gray-50 transition-colors text-left">
|
||||||
<div className="flex items-center justify-between w-full">
|
<div className="flex items-center justify-between w-full">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Drawer, Typography, Button, Descriptions, Card, Tag, Tabs, Alert, message, Collapse } from "antd";
|
import { Drawer, Typography, Button, Descriptions, Card, Tag, Tabs, Alert, message } from "antd";
|
||||||
import { CopyOutlined, DownOutlined } from "@ant-design/icons";
|
import { CopyOutlined } from "@ant-design/icons";
|
||||||
|
import { Accordion, AccordionHeader, AccordionBody } from "@tremor/react";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { LogEntry } from "../columns";
|
import { LogEntry } from "../columns";
|
||||||
import { formatNumberWithCommas } from "@/utils/dataUtils";
|
import { formatNumberWithCommas } from "@/utils/dataUtils";
|
||||||
|
|
@ -150,7 +151,7 @@ export function LogDetailsDrawer({
|
||||||
showIcon
|
showIcon
|
||||||
message="Request Failed"
|
message="Request Failed"
|
||||||
description={<ErrorDescription errorInfo={errorInfo} />}
|
description={<ErrorDescription errorInfo={errorInfo} />}
|
||||||
style={{ marginBottom: SPACING_XLARGE }}
|
className="mb-6"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -160,7 +161,7 @@ export function LogDetailsDrawer({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Request Details Section */}
|
{/* Request Details Section */}
|
||||||
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden" style={{ marginBottom: SPACING_XLARGE }}>
|
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||||
<Card title="Request Details" size="small" bordered={false} style={{ marginBottom: 0 }}>
|
<Card title="Request Details" size="small" bordered={false} style={{ marginBottom: 0 }}>
|
||||||
<Descriptions column={2} size="small">
|
<Descriptions column={2} size="small">
|
||||||
<Descriptions.Item label="Model">{logEntry.model}</Descriptions.Item>
|
<Descriptions.Item label="Model">{logEntry.model}</Descriptions.Item>
|
||||||
|
|
@ -191,7 +192,11 @@ export function LogDetailsDrawer({
|
||||||
<CostBreakdownViewer costBreakdown={metadata?.cost_breakdown} totalSpend={logEntry.spend || 0} />
|
<CostBreakdownViewer costBreakdown={metadata?.cost_breakdown} totalSpend={logEntry.spend || 0} />
|
||||||
|
|
||||||
{/* Configuration Info Message - Show when data is missing */}
|
{/* Configuration Info Message - Show when data is missing */}
|
||||||
<ConfigInfoMessage show={missingData} onOpenSettings={onOpenSettings} />
|
{missingData && (
|
||||||
|
<div className="mb-6">
|
||||||
|
<ConfigInfoMessage show={missingData} onOpenSettings={onOpenSettings} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Request/Response JSON - Collapsible */}
|
{/* Request/Response JSON - Collapsible */}
|
||||||
<RequestResponseSection
|
<RequestResponseSection
|
||||||
|
|
@ -239,7 +244,7 @@ function ErrorDescription({ errorInfo }: { errorInfo: any }) {
|
||||||
|
|
||||||
function TagsSection({ tags }: { tags: Record<string, any> }) {
|
function TagsSection({ tags }: { tags: Record<string, any> }) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden p-4" style={{ marginBottom: SPACING_XLARGE }}>
|
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden p-4 mb-6">
|
||||||
<Text strong style={{ display: "block", marginBottom: 8, fontSize: 16 }}>
|
<Text strong style={{ display: "block", marginBottom: 8, fontSize: 16 }}>
|
||||||
Tags
|
Tags
|
||||||
</Text>
|
</Text>
|
||||||
|
|
@ -274,7 +279,7 @@ function MetricsSection({ logEntry, metadata }: { logEntry: LogEntry; metadata:
|
||||||
metadata.additional_usage_values.cache_read_input_tokens > 0);
|
metadata.additional_usage_values.cache_read_input_tokens > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden" style={{ marginBottom: SPACING_XLARGE }}>
|
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||||
<Card title="Metrics" size="small" bordered={false} style={{ marginBottom: 0 }}>
|
<Card title="Metrics" size="small" bordered={false} style={{ marginBottom: 0 }}>
|
||||||
<Descriptions column={2} size="small">
|
<Descriptions column={2} size="small">
|
||||||
<Descriptions.Item label="Tokens">
|
<Descriptions.Item label="Tokens">
|
||||||
|
|
@ -338,7 +343,6 @@ function RequestResponseSection({
|
||||||
getFormattedResponse,
|
getFormattedResponse,
|
||||||
}: RequestResponseSectionProps) {
|
}: RequestResponseSectionProps) {
|
||||||
const [activeTab, setActiveTab] = useState<typeof TAB_REQUEST | typeof TAB_RESPONSE>(TAB_REQUEST);
|
const [activeTab, setActiveTab] = useState<typeof TAB_REQUEST | typeof TAB_RESPONSE>(TAB_REQUEST);
|
||||||
const [isOpen, setIsOpen] = useState<boolean>(true);
|
|
||||||
|
|
||||||
const handleCopy = () => {
|
const handleCopy = () => {
|
||||||
const data = activeTab === TAB_REQUEST ? getRawRequest() : getFormattedResponse();
|
const data = activeTab === TAB_REQUEST ? getRawRequest() : getFormattedResponse();
|
||||||
|
|
@ -347,78 +351,62 @@ function RequestResponseSection({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden" style={{ marginBottom: SPACING_XLARGE }}>
|
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||||
<Collapse
|
<Accordion>
|
||||||
activeKey={isOpen ? ["request-response"] : []}
|
<AccordionHeader className="p-4 border-b hover:bg-gray-50 transition-colors text-left">
|
||||||
onChange={(keys) => setIsOpen(keys.includes("request-response"))}
|
<h3 className="text-lg font-medium text-gray-900">Request & Response</h3>
|
||||||
expandIcon={({ isActive }) => <DownOutlined rotate={isActive ? 180 : 0} />}
|
</AccordionHeader>
|
||||||
bordered={false}
|
<AccordionBody className="px-0">
|
||||||
items={[
|
<Tabs
|
||||||
{
|
activeKey={activeTab}
|
||||||
key: "request-response",
|
onChange={(key) => setActiveTab(key as typeof TAB_REQUEST | typeof TAB_RESPONSE)}
|
||||||
label: <span style={{ fontSize: 16, fontWeight: 500 }}>Request & Response</span>,
|
tabBarExtraContent={
|
||||||
children: (
|
<Button
|
||||||
<Tabs
|
type="text"
|
||||||
activeKey={activeTab}
|
size="small"
|
||||||
onChange={(key) => setActiveTab(key as typeof TAB_REQUEST | typeof TAB_RESPONSE)}
|
icon={<CopyOutlined />}
|
||||||
tabBarExtraContent={
|
onClick={handleCopy}
|
||||||
<Button
|
disabled={activeTab === TAB_RESPONSE && !hasResponse}
|
||||||
type="text"
|
>
|
||||||
size="small"
|
Copy
|
||||||
icon={<CopyOutlined />}
|
</Button>
|
||||||
onClick={handleCopy}
|
}
|
||||||
disabled={activeTab === TAB_RESPONSE && !hasResponse}
|
items={[
|
||||||
>
|
{
|
||||||
Copy
|
key: TAB_REQUEST,
|
||||||
</Button>
|
label: "Request",
|
||||||
}
|
children: (
|
||||||
items={[
|
<div style={{ padding: SPACING_XLARGE }}>
|
||||||
{
|
<JsonViewer data={getRawRequest()} mode="formatted" />
|
||||||
key: TAB_REQUEST,
|
</div>
|
||||||
label: "Request",
|
),
|
||||||
children: (
|
},
|
||||||
<div style={{ paddingTop: SPACING_XLARGE }}>
|
{
|
||||||
<JsonViewer data={getRawRequest()} mode="formatted" />
|
key: TAB_RESPONSE,
|
||||||
|
label: "Response",
|
||||||
|
children: (
|
||||||
|
<div style={{ padding: SPACING_XLARGE }}>
|
||||||
|
{hasResponse ? (
|
||||||
|
<JsonViewer data={getFormattedResponse()} mode="formatted" />
|
||||||
|
) : (
|
||||||
|
<div style={{ textAlign: "center", padding: 20, color: "#999", fontStyle: "italic" }}>
|
||||||
|
Response data not available
|
||||||
</div>
|
</div>
|
||||||
),
|
)}
|
||||||
},
|
</div>
|
||||||
{
|
),
|
||||||
key: TAB_RESPONSE,
|
},
|
||||||
label: "Response",
|
]}
|
||||||
children: (
|
/>
|
||||||
<div style={{ paddingTop: SPACING_XLARGE }}>
|
</AccordionBody>
|
||||||
{hasResponse ? (
|
</Accordion>
|
||||||
<JsonViewer data={getFormattedResponse()} mode="formatted" />
|
|
||||||
) : (
|
|
||||||
<div style={{ textAlign: "center", padding: 20, color: "#999", fontStyle: "italic" }}>
|
|
||||||
Response data not available
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
styles={{
|
|
||||||
header: {
|
|
||||||
padding: "16px",
|
|
||||||
borderBottom: "1px solid #f0f0f0",
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
padding: 0,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MetadataSection({ metadata, onCopy }: { metadata: Record<string, any>; onCopy: (data: string) => void }) {
|
function MetadataSection({ metadata, onCopy }: { metadata: Record<string, any>; onCopy: (data: string) => void }) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden" style={{ marginBottom: SPACING_XLARGE }}>
|
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||||
<Card
|
<Card
|
||||||
title="Metadata"
|
title="Metadata"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue