diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/clipboardUtils.ts b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/clipboardUtils.ts deleted file mode 100644 index 6aae95bb72c..00000000000 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/clipboardUtils.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { message } from "antd"; -import { MESSAGE_COPY_SUCCESS } from "./constants"; - -/** - * Copies text to clipboard with fallback for non-secure contexts. - * Shows success/error message to user. - * - * @param text - Text to copy to clipboard - * @param label - Label for the copied content (e.g., "Request", "Metadata") - * @returns Promise - true if copy succeeded, false otherwise - */ -export async function copyToClipboard(text: string, label: string): Promise { - try { - // Try modern clipboard API first - if (navigator.clipboard && window.isSecureContext) { - await navigator.clipboard.writeText(text); - message.success(`${label} ${MESSAGE_COPY_SUCCESS}`); - return true; - } else { - // Fallback for non-secure contexts (like 0.0.0.0) - const textArea = document.createElement("textarea"); - textArea.value = text; - textArea.style.position = "fixed"; - textArea.style.opacity = "0"; - document.body.appendChild(textArea); - textArea.focus(); - textArea.select(); - - const successful = document.execCommand("copy"); - document.body.removeChild(textArea); - - if (!successful) { - throw new Error("execCommand failed"); - } - message.success(`${label} ${MESSAGE_COPY_SUCCESS}`); - return true; - } - } catch (error) { - console.error("Copy failed:", error); - message.error(`Failed to copy ${label}`); - return false; - } -} diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/constants.ts b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/constants.ts index 91f5ff8f118..3186cc27b42 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/constants.ts +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/constants.ts @@ -39,6 +39,4 @@ export const SPACING_LARGE = 12; export const SPACING_XLARGE = 16; export const SPACING_XXLARGE = 24; -// Messages -export const MESSAGE_COPY_SUCCESS = "copied to clipboard"; -export const MESSAGE_REQUEST_ID_COPIED = "Request ID copied to clipboard"; +// Messages (kept for backwards compatibility if needed elsewhere) diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/utils.ts b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/utils.ts new file mode 100644 index 00000000000..61301cf5b54 --- /dev/null +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/utils.ts @@ -0,0 +1,93 @@ +/** + * Utility functions for LogDetailsDrawer component. + * These functions handle data formatting, validation, and guardrail calculations. + */ + +/** + * Formats data for display. If input is a string, attempts to parse as JSON. + * @param input - Data to format (string or object) + * @returns Parsed JSON object or original input + */ +export function formatData(input: any) { + if (typeof input === "string") { + try { + return JSON.parse(input); + } catch { + return input; + } + } + return input; +} + +/** + * Checks if messages array/object contains data. + * @param messages - Messages to check + * @returns True if messages exist and have content + */ +export function checkHasMessages(messages: any): boolean { + if (!messages) return false; + if (Array.isArray(messages)) return messages.length > 0; + if (typeof messages === "object") return Object.keys(messages).length > 0; + return false; +} + +/** + * Checks if response object contains data. + * @param response - Response to check + * @returns True if response exists and has content + */ +export function checkHasResponse(response: any): boolean { + if (!response) return false; + return Object.keys(formatData(response)).length > 0; +} + +/** + * Normalizes guardrail information into an array. + * @param guardrailInfo - Guardrail data (may be array, object, or null) + * @returns Array of guardrail entries + */ +export function normalizeGuardrailEntries(guardrailInfo: any): any[] { + if (Array.isArray(guardrailInfo)) return guardrailInfo; + if (guardrailInfo) return [guardrailInfo]; + return []; +} + +/** + * Calculates total number of masked entities across all guardrail entries. + * @param entries - Array of guardrail entries + * @returns Total count of masked entities + */ +export function calculateTotalMaskedEntities(entries: any[]): number { + return entries.reduce((sum, entry) => { + const maskedCounts = entry?.masked_entity_count; + if (!maskedCounts) return sum; + return ( + sum + + Object.values(maskedCounts).reduce((acc, count) => (typeof count === "number" ? acc + count : acc), 0) + ); + }, 0); +} + +/** + * Gets a display label for guardrail(s). + * @param entries - Array of guardrail entries + * @returns Display string for guardrail label + */ +export function getGuardrailLabel(entries: any[]): string { + if (entries.length === 0) return "-"; + if (entries.length === 1) return entries[0]?.guardrail_name ?? "-"; + return `${entries.length} guardrails`; +} + +/** + * Checks if vector store data exists in metadata. + * @param metadata - Metadata object to check + * @returns True if vector store data exists and is non-empty + */ +export function checkHasVectorStoreData(metadata: Record): boolean { + return ( + metadata.vector_store_request_metadata && + Array.isArray(metadata.vector_store_request_metadata) && + metadata.vector_store_request_metadata.length > 0 + ); +}