mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
feat(ui): add guardrail jump link in log detail view (#21437)
* feat(ui): add guardrail jump link at top of log detail * fix(ui): align guardrail jump link to the left * fix(ui): move guardrail jump link to trace sidebar * fix(ui): move guardrail pill above event rows in sidebar
This commit is contained in:
parent
93bbc27c53
commit
5a3a0210cb
2 changed files with 45 additions and 9 deletions
|
|
@ -66,9 +66,6 @@ export function LogDetailContent({ logEntry, onOpenSettings, isLoadingDetails =
|
|||
const hasGuardrailData = guardrailEntries.length > 0;
|
||||
const totalMaskedEntities = calculateTotalMaskedEntities(guardrailEntries);
|
||||
const primaryGuardrailLabel = getGuardrailLabel(guardrailEntries);
|
||||
const guardrailPolicyNames = Array.from(
|
||||
new Set(guardrailEntries.map((e: any) => e?.policy_template).filter(Boolean))
|
||||
) as string[];
|
||||
|
||||
// Vector store data
|
||||
const hasVectorStoreData = checkHasVectorStoreData(metadata);
|
||||
|
|
@ -127,7 +124,7 @@ export function LogDetailContent({ logEntry, onOpenSettings, isLoadingDetails =
|
|||
)}
|
||||
{hasGuardrailData && (
|
||||
<Descriptions.Item label="Guardrail">
|
||||
<GuardrailLabel label={primaryGuardrailLabel} maskedCount={totalMaskedEntities} policyNames={guardrailPolicyNames} />
|
||||
<GuardrailLabel label={primaryGuardrailLabel} maskedCount={totalMaskedEntities} />
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
</Descriptions>
|
||||
|
|
@ -225,7 +222,7 @@ function TagsSection({ tags }: { tags: Record<string, any> }) {
|
|||
);
|
||||
}
|
||||
|
||||
function GuardrailLabel({ label, maskedCount, policyNames }: { label: string; maskedCount: number; policyNames: string[] }) {
|
||||
function GuardrailLabel({ label, maskedCount }: { label: string; maskedCount: number }) {
|
||||
const handleClick = () => {
|
||||
const el = document.getElementById("guardrail-section");
|
||||
if (el) el.scrollIntoView({ behavior: "smooth" });
|
||||
|
|
@ -239,9 +236,6 @@ function GuardrailLabel({ label, maskedCount, policyNames }: { label: string; ma
|
|||
{maskedCount} masked
|
||||
</Tag>
|
||||
)}
|
||||
{policyNames.map((name) => (
|
||||
<Tag key={name} color="purple">{name}</Tag>
|
||||
))}
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
|
@ -424,6 +418,42 @@ function RequestResponseSection({
|
|||
);
|
||||
}
|
||||
|
||||
export function GuardrailJumpLink({ guardrailEntries }: { guardrailEntries: any[] }) {
|
||||
const allPassed = guardrailEntries.every((e) => {
|
||||
const status = e?.guardrail_status || e?.status;
|
||||
return status === "pass" || status === "passed" || status === "success";
|
||||
});
|
||||
|
||||
const handleClick = () => {
|
||||
const el = document.getElementById("guardrail-section");
|
||||
if (el) el.scrollIntoView({ behavior: "smooth" });
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ textAlign: "left", marginBottom: 12 }}>
|
||||
<div
|
||||
onClick={handleClick}
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
gap: 6,
|
||||
padding: "4px 12px",
|
||||
borderRadius: 16,
|
||||
cursor: "pointer",
|
||||
fontSize: 13,
|
||||
fontWeight: 500,
|
||||
backgroundColor: allPassed ? "#f0fdf4" : "#fef2f2",
|
||||
color: allPassed ? "#15803d" : "#b91c1c",
|
||||
border: `1px solid ${allPassed ? "#bbf7d0" : "#fecaca"}`,
|
||||
}}
|
||||
>
|
||||
{allPassed ? "\u2713" : "\u2717"} {guardrailEntries.length} guardrail{guardrailEntries.length !== 1 ? "s" : ""} evaluated
|
||||
<span style={{ fontSize: 11, opacity: 0.7 }}>{"\u2193"}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function MetadataSection({ metadata }: { metadata: Record<string, any> }) {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||
|
|
|
|||
|
|
@ -12,10 +12,11 @@ import { MCP_CALL_TYPES } from "../constants";
|
|||
import { getEventDisplayName } from "../utils";
|
||||
import { DrawerHeader } from "./DrawerHeader";
|
||||
import { useKeyboardNavigation } from "./useKeyboardNavigation";
|
||||
import { LogDetailContent } from "./LogDetailContent";
|
||||
import { LogDetailContent, GuardrailJumpLink } from "./LogDetailContent";
|
||||
import { sessionSpendLogsCall } from "../../networking";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getSpendString } from "@/utils/dataUtils";
|
||||
import { normalizeGuardrailEntries } from "./utils";
|
||||
import { DRAWER_WIDTH } from "./constants";
|
||||
import { useLogDetails } from "@/app/(dashboard)/hooks/logDetails/useLogDetails";
|
||||
|
||||
|
|
@ -323,6 +324,11 @@ export function LogDetailsDrawer({
|
|||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
{normalizeGuardrailEntries(metadata?.guardrail_information).length > 0 && (
|
||||
<div className="px-3 pt-2">
|
||||
<GuardrailJumpLink guardrailEntries={normalizeGuardrailEntries(metadata?.guardrail_information)} />
|
||||
</div>
|
||||
)}
|
||||
{isSessionMode ? (
|
||||
<div className="py-1">
|
||||
{/* Child events — vertical tree line with horizontal connectors */}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue