diff --git a/ui/litellm-dashboard/.eslintrc.json b/ui/litellm-dashboard/.eslintrc.json index 47a25bf9748..4e09cbacd0a 100644 --- a/ui/litellm-dashboard/.eslintrc.json +++ b/ui/litellm-dashboard/.eslintrc.json @@ -95,6 +95,11 @@ "src/components/Navbar/UserDropdown/UserDropdown.tsx", "src/components/playground/chat_ui/ChatMessageBubble.tsx", "src/components/view_logs/AuditLogDrawer/AuditLogDrawer.tsx", + "src/components/view_logs/columns.tsx", + "src/components/view_logs/GuardrailViewer/GuardrailViewer.tsx", + "src/components/view_logs/LogDetailsDrawer/RealtimePrettyView.tsx", + "src/components/view_logs/LogDetailsDrawer/LogDetailContent.tsx", + "src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx", "src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx", "src/components/permissions/VectorStorePermissions.tsx", "src/components/permissions/AgentPermissions.tsx", diff --git a/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.tsx b/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.tsx index a9ce90a73f0..0026570444b 100644 --- a/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/CostBreakdownViewer.tsx @@ -1,6 +1,11 @@ import React from "react"; -import { Collapse } from "antd"; import { formatNumberWithCommas } from "@/utils/dataUtils"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; export interface CostBreakdown { input_cost?: number; @@ -91,179 +96,175 @@ export const CostBreakdownViewer: React.FC = ({ const totalCost = isCached ? 0 : (costBreakdown?.total_cost ?? totalSpend); return ( -
- -

Cost Breakdown

-
- Total: - - {formatCost(totalSpend)} - {isCached && " (Cached)"} - -
-
- ), - children: ( -
- {/* Step 1: Base Token Costs */} -
- {(() => { - const hasCacheBreakdown = - costBreakdown?.cache_read_cost !== undefined || - costBreakdown?.cache_creation_cost !== undefined; - if (hasCacheBreakdown) { - // Separate line items: Input / Cache Read / Cache Write - const rawCost = isCached ? 0 : (inputCost ?? 0) - (costBreakdown?.cache_read_cost ?? 0) - (costBreakdown?.cache_creation_cost ?? 0); - return ( - <> -
- Input Cost: - - {formatCost(rawCost)} - {rawInputTokens !== undefined && rawInputTokens !== null && ( - ({rawInputTokens.toLocaleString()} tokens) - )} - -
- {(costBreakdown?.cache_read_cost ?? 0) > 0 && ( -
- Cache Read Cost: - - {formatCost(isCached ? 0 : costBreakdown?.cache_read_cost)} - {(cacheReadTokens ?? 0) > 0 && ( - ({(cacheReadTokens ?? 0).toLocaleString()} tokens) - )} - -
- )} - {(costBreakdown?.cache_creation_cost ?? 0) > 0 && ( -
- Cache Write Cost: - - {formatCost(isCached ? 0 : costBreakdown?.cache_creation_cost)} - {(cacheCreationTokens ?? 0) > 0 && ( - ({(cacheCreationTokens ?? 0).toLocaleString()} tokens) - )} - -
- )} - - ); - } - return ( -
- Input Cost: - - {formatCost(inputCost)} - {promptTokens !== undefined && ( - - ({promptTokens.toLocaleString()} prompt tokens) - - )} - -
- ); - })()} -
- Output Cost: - - {formatCost(outputCost)} - {completionTokens !== undefined && ( - - ({completionTokens.toLocaleString()} completion tokens) - - )} - -
- {costBreakdown?.tool_usage_cost !== undefined && costBreakdown.tool_usage_cost > 0 && ( -
- Tool Usage Cost: - {formatCost(costBreakdown.tool_usage_cost)} -
- )} - {costBreakdown?.additional_costs && - Object.entries(costBreakdown.additional_costs) - .filter(([, value]) => value != null && value !== 0) - .map(([key, value]) => ( -
- {key}: - {formatCost(value)} -
- ))} -
- - {/* Subtotal / Original Cost - hide when cached since it would be $0 */} - {!isCached && ( -
-
- Original LLM Cost: - {formatCost(originalCost)} -
-
- )} - - {/* Step 2: Adjustments (Discount & Margin) */} - {(hasDiscount || hasMargin) && ( -
- {/* Discounts */} - {hasDiscount && ( -
- {costBreakdown.discount_percent !== undefined && costBreakdown.discount_percent !== 0 && ( -
- Discount ({formatPercent(costBreakdown.discount_percent)}): - -{formatCost(costBreakdown.discount_amount)} -
- )} - {costBreakdown.discount_amount !== undefined && costBreakdown.discount_percent === undefined && ( -
- Discount Amount: - -{formatCost(costBreakdown.discount_amount)} -
- )} -
- )} - - {/* Margins */} - {hasMargin && ( -
- {costBreakdown.margin_percent !== undefined && costBreakdown.margin_percent !== 0 && ( -
- Margin ({formatPercent(costBreakdown.margin_percent)}): - +{formatCost((costBreakdown.margin_total_amount || 0) - (costBreakdown.margin_fixed_amount || 0))} -
- )} - {costBreakdown.margin_fixed_amount !== undefined && costBreakdown.margin_fixed_amount !== 0 && ( -
- Margin: - +{formatCost(costBreakdown.margin_fixed_amount)} -
- )} -
- )} -
- )} - - {/* Final Summary */} -
-
- Final Calculated Cost: - - {formatCost(totalCost)} +
+ + + +
+

Cost Breakdown

+
+ Total: + + {formatCost(totalSpend)} {isCached && " (Cached)"}
-
- ), - }, - ]} - /> + + +
+ {/* Step 1: Base Token Costs */} +
+ {(() => { + const hasCacheBreakdown = + costBreakdown?.cache_read_cost !== undefined || + costBreakdown?.cache_creation_cost !== undefined; + if (hasCacheBreakdown) { + // Separate line items: Input / Cache Read / Cache Write + const rawCost = isCached ? 0 : (inputCost ?? 0) - (costBreakdown?.cache_read_cost ?? 0) - (costBreakdown?.cache_creation_cost ?? 0); + return ( + <> +
+ Input Cost: + + {formatCost(rawCost)} + {rawInputTokens !== undefined && rawInputTokens !== null && ( + ({rawInputTokens.toLocaleString()} tokens) + )} + +
+ {(costBreakdown?.cache_read_cost ?? 0) > 0 && ( +
+ Cache Read Cost: + + {formatCost(isCached ? 0 : costBreakdown?.cache_read_cost)} + {(cacheReadTokens ?? 0) > 0 && ( + ({(cacheReadTokens ?? 0).toLocaleString()} tokens) + )} + +
+ )} + {(costBreakdown?.cache_creation_cost ?? 0) > 0 && ( +
+ Cache Write Cost: + + {formatCost(isCached ? 0 : costBreakdown?.cache_creation_cost)} + {(cacheCreationTokens ?? 0) > 0 && ( + ({(cacheCreationTokens ?? 0).toLocaleString()} tokens) + )} + +
+ )} + + ); + } + return ( +
+ Input Cost: + + {formatCost(inputCost)} + {promptTokens !== undefined && ( + + ({promptTokens.toLocaleString()} prompt tokens) + + )} + +
+ ); + })()} +
+ Output Cost: + + {formatCost(outputCost)} + {completionTokens !== undefined && ( + + ({completionTokens.toLocaleString()} completion tokens) + + )} + +
+ {costBreakdown?.tool_usage_cost !== undefined && costBreakdown.tool_usage_cost > 0 && ( +
+ Tool Usage Cost: + {formatCost(costBreakdown.tool_usage_cost)} +
+ )} + {costBreakdown?.additional_costs && + Object.entries(costBreakdown.additional_costs) + .filter(([, value]) => value != null && value !== 0) + .map(([key, value]) => ( +
+ {key}: + {formatCost(value)} +
+ ))} +
+ + {/* Subtotal / Original Cost - hide when cached since it would be $0 */} + {!isCached && ( +
+
+ Original LLM Cost: + {formatCost(originalCost)} +
+
+ )} + + {/* Step 2: Adjustments (Discount & Margin) */} + {(hasDiscount || hasMargin) && ( +
+ {/* Discounts */} + {hasDiscount && ( +
+ {costBreakdown.discount_percent !== undefined && costBreakdown.discount_percent !== 0 && ( +
+ Discount ({formatPercent(costBreakdown.discount_percent)}): + -{formatCost(costBreakdown.discount_amount)} +
+ )} + {costBreakdown.discount_amount !== undefined && costBreakdown.discount_percent === undefined && ( +
+ Discount Amount: + -{formatCost(costBreakdown.discount_amount)} +
+ )} +
+ )} + + {/* Margins */} + {hasMargin && ( +
+ {costBreakdown.margin_percent !== undefined && costBreakdown.margin_percent !== 0 && ( +
+ Margin ({formatPercent(costBreakdown.margin_percent)}): + +{formatCost((costBreakdown.margin_total_amount || 0) - (costBreakdown.margin_fixed_amount || 0))} +
+ )} + {costBreakdown.margin_fixed_amount !== undefined && costBreakdown.margin_fixed_amount !== 0 && ( +
+ Margin: + +{formatCost(costBreakdown.margin_fixed_amount)} +
+ )} +
+ )} +
+ )} + + {/* Final Summary */} +
+
+ Final Calculated Cost: + + {formatCost(totalCost)} + {isCached && " (Cached)"} + +
+
+
+
+ +
); }; diff --git a/ui/litellm-dashboard/src/components/view_logs/GuardrailViewer/GuardrailViewer.tsx b/ui/litellm-dashboard/src/components/view_logs/GuardrailViewer/GuardrailViewer.tsx index 5608e3677fa..0bf3e614f43 100644 --- a/ui/litellm-dashboard/src/components/view_logs/GuardrailViewer/GuardrailViewer.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/GuardrailViewer/GuardrailViewer.tsx @@ -1,5 +1,10 @@ import React, { useState, useMemo } from "react"; -import { Tooltip } from "antd"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import PresidioDetectedEntities from "./PresidioDetectedEntities"; import BedrockGuardrailDetails, { BedrockGuardrailResponse, @@ -249,11 +254,11 @@ const MatchDetailsTable = ({ matchDetails }: { matchDetails: MatchDetail[] }) => return (
-
Match Details ({matchDetails.length})
+
Match Details ({matchDetails.length})
- + @@ -262,7 +267,7 @@ const MatchDetailsTable = ({ matchDetails }: { matchDetails: MatchDetail[] }) => {matchDetails.map((match, idx) => ( - + - @@ -297,7 +302,7 @@ const GenericGuardrailResponse = ({ response }: { response: any }) => {
setShowRaw(!showRaw)} >
@@ -306,8 +311,8 @@ const GenericGuardrailResponse = ({ response }: { response: any }) => {
{showRaw && ( -
-
+          
+
               {JSON.stringify(response, null, 2)}
             
@@ -407,7 +412,7 @@ const RequestLifecycle = ({ entries }: { entries: GuardrailInformation[] }) => { return (
-

+

Request Lifecycle

@@ -427,7 +432,7 @@ const RequestLifecycle = ({ entries }: { entries: GuardrailInformation[] }) => { )}
{idx < timeline.length - 1 && ( -
+
)}
@@ -436,7 +441,7 @@ const RequestLifecycle = ({ entries }: { entries: GuardrailInformation[] }) => {
{item.label} @@ -452,7 +457,7 @@ const RequestLifecycle = ({ entries }: { entries: GuardrailInformation[] }) => { {item.status} )} - + T+{item.offsetMs}ms
@@ -495,10 +500,10 @@ const EvaluationCard = ({ entry }: { entry: GuardrailInformation }) => { : null; return ( -
+
{/* Collapsed header row */}
setExpanded(!expanded)} > {/* Status icon */} @@ -508,7 +513,7 @@ const EvaluationCard = ({ entry }: { entry: GuardrailInformation }) => { {/* Name + badges */}
- {displayName} + {displayName} {modeStr} @@ -533,25 +538,30 @@ const EvaluationCard = ({ entry }: { entry: GuardrailInformation }) => { )} {entry.confidence_score != null && ( - + {(entry.confidence_score * 100).toFixed(0)}% conf )} {riskScore != null && success && ( - - - Risk {riskScore}/10 - - + + + + + Risk {riskScore}/10 + + + {`Risk score: ${riskScore}/10`} + + )}
{/* Right side: duration + method + chevron */}
- {durationStr} + {durationStr} {entry.detection_method && ( - + {entry.detection_method.split(",")[0].trim()} )} @@ -561,33 +571,33 @@ const EvaluationCard = ({ entry }: { entry: GuardrailInformation }) => { {/* Expanded details */} {expanded && ( -
+
{/* Classification details for llm-judge */} {entry.classification && ( -
-
Classification
+
+
Classification
{entry.classification.category && (
- Category: + Category: {entry.classification.category}
)} {entry.classification.article_reference && (
- Reference: + Reference: {entry.classification.article_reference}
)} {entry.classification.confidence != null && (
- Confidence: + Confidence: {(entry.classification.confidence * 100).toFixed(0)}%
)} {entry.classification.reason && (
- Reason: + Reason: {entry.classification.reason}
)} @@ -602,7 +612,7 @@ const EvaluationCard = ({ entry }: { entry: GuardrailInformation }) => { {/* Masked entity summary */} {totalMasked > 0 && (
-
Masked Entities
+
Masked Entities
{Object.entries(entry.masked_entity_count || {}).map(([entityType, count]) => ( @@ -677,20 +687,20 @@ const GuardrailViewer = ({ data, accessToken, logEntry }: GuardrailViewerProps) }; return ( -
+
{/* ── Header ─────────────────────────────────────────────── */} -
+
-

+

Guardrails & Policy Compliance

- + {guardrailEntries.length} guardrail{guardrailEntries.length !== 1 ? "s" : ""} evaluated - | + |
-
+
Total: {totalOverheadMs}ms overhead
+
+ +
+ +
+
+ +
+ {hasResponse || hasError ? ( + + ) : ( +
+ Response data not available +
+ )} +
+
+ + )} +
+ + +
); } @@ -515,68 +555,68 @@ export function GuardrailJumpLink({ guardrailEntries }: { guardrailEntries: any[ }; return ( -
+
{allPassed ? "\u2713" : "\u2717"} {guardrailEntries.length} guardrail{guardrailEntries.length !== 1 ? "s" : ""} evaluated - {"\u2193"} + {"\u2193"}
); } function MetadataSection({ metadata }: { metadata: Record }) { + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(JSON.stringify(metadata, null, 2)); + } catch { + /* noop */ + } + }; + return ( -
- Metadata, - children: ( -
-
- -
-
+      
+        
+          
+            

Metadata

+
+ +
+
+
+ +
- ), - }, - ]} - /> +
+                {JSON.stringify(metadata, null, 2)}
+              
+
+ + +
); } diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx index 5495102e77f..4e0854f8056 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx @@ -1,5 +1,6 @@ import { useEffect, useMemo, useState } from "react"; -import { Button, Drawer } from "antd"; +import { Button } from "@/components/ui/button"; +import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet"; import { Check as CheckOutlined, Copy as CopyOutlined, ChevronLeft as LeftOutlined, ChevronRight as RightOutlined } from "lucide-react"; import { Bot, Sparkles, Wrench } from "lucide-react"; import { LogEntry } from "../columns"; @@ -239,39 +240,34 @@ export function LogDetailsDrawer({ if (!currentLog || !enrichedLog) return null; return ( - -
+ { if (!o) onClose(); }}> + + Log Details +
{!isSidebarCollapsed ? ( ) : ( )} {!isSidebarCollapsed && (
- +
+
); } diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/RealtimePrettyView.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/RealtimePrettyView.tsx index 1365fdcf0be..46133f05303 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/RealtimePrettyView.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/RealtimePrettyView.tsx @@ -5,11 +5,32 @@ */ import { useState } from 'react'; -import { Typography, Tag, Tooltip } from 'antd'; +import { Badge } from "@/components/ui/badge"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { Volume2 as SoundOutlined, MessageSquare as MessageOutlined, Settings as SettingOutlined, Mic as AudioOutlined, ChevronDown as DownOutlined, ChevronUp as UpOutlined } from "lucide-react"; import { SectionHeader } from './SectionHeader'; -const { Text } = Typography; +/** Mimics antd `Typography.Text`'s `type="secondary"` mutted-gray style. */ +function SecondaryText({ + children, + className = "", + style, +}: { + children: React.ReactNode; + className?: string; + style?: React.CSSProperties; +}) { + return ( + + {children} + + ); +} interface RealtimeEvent { type: string; @@ -170,30 +191,27 @@ function SessionCard({ session, turnCount }: { session: RealtimeSession; turnCou
- Session + Session
- + {session.model} - + {turnCount > 0 && ( - + {turnCount} {turnCount === 1 ? 'turn' : 'turns'} - + )} {session.voice && ( - - {session.voice} - + + {session.voice} + )} {session.modalities && (
{session.modalities.map((m) => ( - - {m === 'audio' ? : } {m} - + + {m === 'audio' ? : } {m} + ))}
)} @@ -248,8 +266,7 @@ function SessionCard({ session, turnCount }: { session: RealtimeSession; turnCou {session.instructions && (
- Instructions - +
- {response.status || 'unknown'} - + {usage && ( - + {usage.input_tokens ?? 0} in / {usage.output_tokens ?? 0} out tokens - + )} {response.conversation_id && ( - - - conv: {response.conversation_id.slice(0, 12)}... - - + + + + + conv: {response.conversation_id.slice(0, 12)}... + + + {response.conversation_id} + + )}
@@ -427,8 +449,7 @@ function OutputMessage({ output }: { output: RealtimeOutputItem }) { return (
- {output.role?.toUpperCase() || 'ASSISTANT'} - + {contents.map((c, cIdx) => { const text = c.transcript || c.text; if (!text) return null; @@ -507,12 +528,11 @@ function TokenBreakdown({ return (
- {label} Token Breakdown - +
{ if (typeof value === 'number') { return ( - + {formatTokenLabel(key)}: {value.toLocaleString()} - + ); } return null; @@ -546,10 +566,10 @@ function ConfigRow({ if (value === undefined || value === null) return null; return (
- + {label} - -
+ +
{String(value)}
diff --git a/ui/litellm-dashboard/src/components/view_logs/columns.tsx b/ui/litellm-dashboard/src/components/view_logs/columns.tsx index 44d8ddb6bcc..1b4cf7186e5 100644 --- a/ui/litellm-dashboard/src/components/view_logs/columns.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/columns.tsx @@ -1,8 +1,13 @@ import { getSpendString } from "@/utils/dataUtils"; import type { ColumnDef } from "@tanstack/react-table"; -// eslint-disable-next-line litellm-ui/no-banned-ui-imports -import { Badge, Button } from "@tremor/react"; -import { Tooltip } from "antd"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import React, { useState } from "react"; import { getProviderLogoAndName } from "../provider_info_helpers"; import { TableHeaderSortDropdown } from "../common_components/TableHeaderSortDropdown/TableHeaderSortDropdown"; @@ -76,6 +81,26 @@ export type LogEntry = { onSessionClick?: (sessionId: string) => void; }; +/** Small wrapper that renders a shadcn Tooltip with its own provider so it drops + * in where antd's `` used to go without needing a root-level + * provider in every call site. */ +const HoverTooltip = ({ + content, + children, + asChild = true, +}: { + content: React.ReactNode; + children: React.ReactNode; + asChild?: boolean; +}) => ( + + + {children} + {content} + + +); + const SortableHeader = ({ label, field, @@ -162,9 +187,9 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] sessionMcpCount > 0 && `${sessionMcpCount} MCP`, ].filter(Boolean); return ( - + {sessionTypeBadge} - + ); }, }, @@ -193,16 +218,16 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] const value = String(info.getValue() || ""); const onSessionClick = info.row.original.onSessionClick; return ( - + - + ); }, }, @@ -211,9 +236,9 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] header: "Request ID", accessorKey: "request_id", cell: (info: any) => ( - + {String(info.getValue() || "")} - + ), }, { @@ -236,9 +261,9 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] return (
- + {getSpendString(info.getValue() || 0)} - + {mcpCount > 0 && mcpSpend > 0 && ( incl. {getSpendString(mcpSpend)} from {mcpCount} MCP @@ -266,9 +291,9 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] if (ms == null) return -; const seconds = (ms / 1000).toFixed(2); return ( - + {seconds} - + ); }, }, @@ -285,9 +310,9 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] if (ttftMs <= 0) return -; const ttftSeconds = (ttftMs / 1000).toFixed(2); return ( - + {ttftSeconds} - + ); }, }, @@ -295,9 +320,9 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] header: "Team Name", accessorKey: "metadata.user_api_key_team_alias", cell: (info: any) => ( - + {String(info.getValue() || "-")} - + ), }, { @@ -308,14 +333,14 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] const onKeyHashClick = info.row.original.onKeyHashClick; return ( - + onKeyHashClick?.(value)} > {value} - + ); }, }, @@ -323,9 +348,9 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] header: "Key Name", accessorKey: "metadata.user_api_key_alias", cell: (info: any) => ( - + {String(info.getValue() || "-")} - + ), }, { @@ -348,9 +373,9 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] }} /> )} - + {modelName} - +
); }, @@ -373,7 +398,7 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] return ( {String(row.total_tokens || "0")} - + ({String(row.prompt_tokens || "0")}+{String(row.completion_tokens || "0")}) @@ -384,18 +409,18 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] header: "Internal User", accessorKey: "user", cell: (info: any) => ( - + {String(info.getValue() || "-")} - + ), }, { header: "End User", accessorKey: "end_user", cell: (info: any) => ( - + {String(info.getValue() || "-")} - + ), }, @@ -412,8 +437,8 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[] return (
- {tagEntries.map(([key, value]) => ( @@ -423,11 +448,11 @@ export const createColumns = (sortProps?: LogsSortProps): ColumnDef[]
} > - + {firstTag[0]}: {String(firstTag[1])} {remainingTags.length > 0 && ` +${remainingTags.length}`} -
+
); }, @@ -464,12 +489,12 @@ export const RequestResponsePanel = ({ request, response }: { request: any; resp return (
-
-
+
+

Request

-
-
+
+

Response

{isExpanded && ( -
{jsonString}
+
{jsonString}
)}
); @@ -556,7 +581,7 @@ export type AuditLogEntry = { const getActionBadge = (action: string) => { return ( - + {action} ); @@ -647,13 +672,11 @@ export const auditLogColumns: ColumnDef[] = [
{changedBy}
{apiKey && ( // Only show API key if it exists - +
- {" "} - {/* Apply max-width and truncate */} {apiKey}
-
+ )}
); @@ -680,11 +703,11 @@ export const auditLogColumns: ColumnDef[] = [ }; return ( - + {String(objectId)} - + ); }; return ;
Type Method Action
{match.type} @@ -278,7 +283,7 @@ const MatchDetailsTable = ({ matchDetails }: { matchDetails: MatchDetail[] }) => {match.action_taken ?? "-"} + {match.category ? `[${match.category}] ` : ""} {match.snippet ?? "-"}