Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions ui/app/clientLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import FullPageLoader from "@/components/fullPageLoader";
import Header from "@/components/header";
import NotAvailableBanner from "@/components/notAvailableBanner";
import ProgressProvider from "@/components/progressBar";
import Sidebar from "@/components/sidebar";
Expand Down Expand Up @@ -43,8 +44,9 @@ function AppContent({ children }: { children: React.ReactNode }) {
<StoreSyncInitializer />
<SidebarProvider>
<Sidebar />
<div className="dark:bg-card custom-scrollbar content-container my-[0.5rem] mr-[0.5rem] h-[calc(100dvh-1rem)] w-full min-w-xl overflow-auto rounded-md border border-gray-200 bg-white px-10 dark:border-zinc-800">
<main className="custom-scrollbar content-container-inner relative mx-auto flex flex-col overflow-y-hidden p-4">
<div className="dark:bg-card custom-scrollbar content-container h-[100dvh] w-full overflow-auto bg-white md:my-[0.5rem] md:mr-[0.5rem] md:h-[calc(100dvh-1rem)] md:min-w-xl md:rounded-md md:border md:border-gray-200 md:px-10 dark:border-zinc-800 dark:md:border-zinc-800">
<Header />
<main className="custom-scrollbar content-container-inner relative mx-auto flex flex-col overflow-y-hidden p-3 md:p-4">
{isLoading ? <FullPageLoader /> : <FullPage config={bifrostConfig}>{children}</FullPage>}
</main>
</div>
Expand Down
2 changes: 1 addition & 1 deletion ui/app/workspace/config/logging/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import LoggingView from "../views/loggingView";

export default function LoggingPage() {
return (
<div className="mx-auto flex w-full max-w-7xl">
<div className="mx-auto flex w-full max-w-7xl px-3 sm:px-0">
<LoggingView />
</div>
);
Expand Down
12 changes: 6 additions & 6 deletions ui/app/workspace/config/views/loggingView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default function LoggingView() {
<div className="space-y-4">
{/* Enable Logs */}
<div>
<div className="flex items-center justify-between space-x-2 rounded-lg border p-4">
<div className="flex flex-col gap-3 rounded-lg border p-4 sm:flex-row sm:items-center sm:justify-between sm:gap-0 sm:space-x-2">
<div className="space-y-0.5">
<label htmlFor="enable-logging" className="text-sm font-medium">
Enable Logs
Expand Down Expand Up @@ -109,7 +109,7 @@ export default function LoggingView() {
{/* Disable Content Logging - Only show when logging is enabled */}
{localConfig.enable_logging && bifrostConfig?.is_logs_connected && (
<div>
<div className="flex items-center justify-between space-x-2 rounded-lg border p-4">
<div className="flex flex-col gap-3 rounded-lg border p-4 sm:flex-row sm:items-center sm:justify-between sm:gap-0 sm:space-x-2">
<div className="space-y-0.5">
<label htmlFor="disable-content-logging" className="text-sm font-medium">
Disable Content Logging
Expand All @@ -132,7 +132,7 @@ export default function LoggingView() {

{/* Log Retention Days */}
{localConfig.enable_logging && bifrostConfig?.is_logs_connected && (
<div className="flex items-center justify-between space-x-2 rounded-lg border p-4">
<div className="flex flex-col gap-3 rounded-lg border p-4 sm:flex-row sm:items-center sm:justify-between sm:gap-0 sm:space-x-2">
<div className="space-y-0.5">
<Label htmlFor="log-retention-days" className="text-sm font-medium">
Log Retention Days
Expand All @@ -150,12 +150,12 @@ export default function LoggingView() {
const value = parseInt(e.target.value) || 1;
handleConfigChange("log_retention_days", Math.max(1, value));
}}
className="w-24"
className="w-full sm:w-24"
/>
</div>
)}

<div className="flex items-center justify-between space-x-2 rounded-lg border p-4">
<div className="flex flex-col gap-3 rounded-lg border p-4 sm:flex-row sm:items-center sm:justify-between sm:gap-0 sm:space-x-2">
<div className="space-y-0.5">
<label htmlFor="hide-deleted-virtual-keys-in-filters" className="text-sm font-medium">
Do Not Show Deleted VirtualKeys In Filters
Expand Down Expand Up @@ -197,7 +197,7 @@ export default function LoggingView() {
</div>

<div className="flex justify-end pt-2">
<Button onClick={handleSave} disabled={!hasChanges || isLoading || !hasSettingsUpdateAccess}>
<Button onClick={handleSave} disabled={!hasChanges || isLoading || !hasSettingsUpdateAccess} className="w-full sm:w-auto">
{isLoading ? "Saving..." : "Save Changes"}
</Button>
</div>
Expand Down
76 changes: 51 additions & 25 deletions ui/app/workspace/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { LogsFilterSidebar } from "@/components/filters/logsFilterSidebar";
import { Button } from "@/components/ui/button";
import { DateTimePickerWithRange } from "@/components/ui/datePickerWithRange";
import { ScrollArea } from "@/components/ui/scrollArea";
import { Sheet, SheetContent, SheetDescription, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
useGetMCPAvailableFilterDataQuery,
Expand Down Expand Up @@ -35,6 +37,7 @@ import type {
} from "@/lib/types/logs";
import { dateUtils } from "@/lib/types/logs";
import UserRankingsTab from "@enterprise/components/user-rankings/userRankingsTab";
import { Filter } from "lucide-react";
import { parseAsInteger, parseAsString, useQueryStates } from "nuqs";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { type ChartType } from "./components/charts/chartTypeToggle";
Expand Down Expand Up @@ -708,26 +711,47 @@ export default function DashboardPage() {
}, []);

return (
<div id="dashboard-root" className="no-padding-parent no-border-parent bg-background flex h-[calc(100vh_-_16px)] w-full gap-3">
{/* Sidebar Filters */}
<LogsFilterSidebar filters={filters} onFiltersChange={setFilters} />
<div
id="dashboard-root"
className="no-padding-parent no-border-parent bg-background flex h-full min-h-[calc(100dvh_-_5rem)] w-full gap-3 md:h-[calc(100vh_-_16px)] md:min-h-0"
>
{/* Sidebar Filters — hidden on mobile, use date picker + tab-level filters for filtering */}
<div className="hidden md:block">
<LogsFilterSidebar filters={filters} onFiltersChange={setFilters} />
</div>

{/* Main Content */}
<ScrollArea className="bg-card flex min-w-0 flex-1 flex-col gap-4 rounded-l-md">
<ScrollArea
className="bg-card flex min-w-0 flex-1 flex-col gap-4 rounded-md md:rounded-l-md md:rounded-r-none"
viewportClassName="[&>div]:[display:block!important]"
>
{/* Header */}
<div className="flex items-center justify-between p-4">
<div className="flex flex-col gap-3 p-3 md:flex-row md:items-center md:justify-between md:p-4">
<div className="flex items-center gap-2">
<h1 className="text-lg font-semibold">Dashboard</h1>
</div>
<div className="flex items-center gap-2">
<div className="flex flex-wrap items-center gap-2">
{/* Mobile-only filter trigger — opens the sidebar in a Sheet (desktop shows the persistent sidebar) */}
<Sheet>
<SheetTrigger asChild>
<Button variant="outline" size="sm" className="h-7.5 shrink-0 md:hidden" aria-label="Open filters">
<Filter className="size-4" />
</Button>
</SheetTrigger>
<SheetContent side="left" className="w-[85vw] max-w-sm border-r p-0">
<SheetTitle className="sr-only">Filters</SheetTitle>
<SheetDescription className="sr-only">Filter dashboard data by providers, models, status, and metadata.</SheetDescription>
<LogsFilterSidebar filters={filters} onFiltersChange={setFilters} disableCollapse className="w-full rounded-none" />
</SheetContent>
</Sheet>
<ExportPopover
getData={getDashboardData}
onPreloadData={handlePreloadData}
onPdfExport={handlePdfExport}
onPdfExportDone={handlePdfExportDone}
/>
{urlState.tab === "mcp" && mcpFilterData && (
<div className="flex items-center gap-1">
<div className="flex flex-wrap items-center gap-1">
{mcpFilterData.tool_names?.length > 0 && (
<ModelFilterSelect
models={mcpFilterData.tool_names}
Expand Down Expand Up @@ -772,26 +796,28 @@ export default function DashboardPage() {
</div>
</div>

<div className="p-4">
<div className="p-3 md:p-4">
{/* Tabs */}
<Tabs value={urlState.tab} onValueChange={handleTabChange}>
<TabsList className="mb-2">
<TabsTrigger value="overview" data-testid="dashboard-tab-overview">
Overview
</TabsTrigger>
<TabsTrigger value="provider-usage" data-testid="dashboard-tab-provider-usage">
Provider Usage
</TabsTrigger>
<TabsTrigger value="rankings" data-testid="dashboard-tab-rankings">
Model Rankings
</TabsTrigger>
<TabsTrigger value="mcp" data-testid="dashboard-tab-mcp">
MCP usage
</TabsTrigger>
<TabsTrigger value="user-rankings" data-testid="dashboard-tab-user-rankings">
User Rankings
</TabsTrigger>
</TabsList>
<div className="-mx-3 mb-2 overflow-x-auto px-3 [scrollbar-width:none] md:-mx-4 md:px-4 [&::-webkit-scrollbar]:hidden">
<TabsList className="flex max-w-[calc(100vw-26px)] gap-1 overflow-x-auto rounded-sm">
<TabsTrigger value="overview" data-testid="dashboard-tab-overview">
Overview
</TabsTrigger>
<TabsTrigger value="provider-usage" data-testid="dashboard-tab-provider-usage">
Provider Usage
</TabsTrigger>
<TabsTrigger value="rankings" data-testid="dashboard-tab-rankings">
Model Rankings
</TabsTrigger>
<TabsTrigger value="mcp" data-testid="dashboard-tab-mcp">
MCP usage
</TabsTrigger>
<TabsTrigger value="user-rankings" data-testid="dashboard-tab-user-rankings">
User Rankings
</TabsTrigger>
</TabsList>
</div>

{/* Overview Tab */}
<TabsContent value="overview" {...(pdfMode && { forceMount: true })}>
Expand Down
36 changes: 20 additions & 16 deletions ui/app/workspace/logs/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import FullPageLoader from "@/components/fullPageLoader";
import { useColumnConfig } from "@/components/table";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Card, CardContent } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { useWebSocket } from "@/hooks/useWebSocket";
import {
Expand Down Expand Up @@ -835,7 +834,13 @@ export default function LogsPage() {
},
{
title: "User Success Rate",
value: fetchingStats ? <Skeleton className="h-8 w-16" /> : stats ? `${(stats.user_facing_success_rate ?? 0).toFixed(2)}%` : "-",
value: (
<NumberFlow
value={stats?.user_facing_success_rate ?? 0}
format={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }}
suffix="%"
/>
),
icon: <CheckCircle className="size-4" />,
description: "Success rate as perceived by the end user. It includes fallback chains as one request.",
},
Expand Down Expand Up @@ -868,10 +873,7 @@ export default function LogsPage() {
return Object.keys(filterData.metadata_keys).sort();
}, [filterData?.metadata_keys]);

const columns = useMemo(
() => createColumns(handleDelete, hasDeleteAccess, metadataKeys),
[handleDelete, hasDeleteAccess, metadataKeys],
);
const columns = useMemo(() => createColumns(handleDelete, hasDeleteAccess, metadataKeys), [handleDelete, hasDeleteAccess, metadataKeys]);

const columnIds = useMemo(
() => columns.map((col) => ("id" in col && col.id ? col.id : "accessorKey" in col ? String(col.accessorKey) : "")).filter(Boolean),
Expand Down Expand Up @@ -959,18 +961,20 @@ export default function LogsPage() {
);

return (
<div className="dark:bg-card no-padding-parent no-border-parent h-[calc(100vh_-_16px)]">
<div className="dark:bg-card no-padding-parent no-border-parent h-[calc(100dvh_-_16px)]">
{initialLoading ? (
<FullPageLoader />
) : showEmptyState ? (
<EmptyState isSocketConnected={isSocketConnected} error={error} />
) : (
<div className="bg-background flex h-full w-full grow gap-3">
{/* Sidebar Filters */}
<LogsFilterSidebar filters={filters} onFiltersChange={setFilters} />
<div className="bg-background flex h-full w-full grow gap-2 md:gap-3">
{/* Sidebar Filters — hidden on small screens to free up width for the table */}
<div className="hidden h-full md:flex">
<LogsFilterSidebar filters={filters} onFiltersChange={setFilters} />
</div>

{/* Main Content */}
<div className="bg-card flex min-w-0 flex-1 flex-col gap-2 overflow-hidden rounded-l-md p-4 pb-2">
<div className="bg-card flex min-w-0 flex-1 flex-col gap-2 overflow-hidden rounded-md p-2 pb-2 sm:rounded-l-md sm:p-4 sm:pb-2">
<div className="shrink-0">
<LogsHeaderView
filters={filters}
Expand All @@ -985,15 +989,15 @@ export default function LogsPage() {
onResetColumns={resetColumns}
/>
</div>
<div className="grid shrink-0 grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-6">
<div className="grid shrink-0 grid-cols-2 gap-2 sm:gap-3 md:grid-cols-3 md:gap-4 lg:grid-cols-6">
{statCards.map((card) => (
<Card key={card.title} className="py-4 shadow-none">
<Card key={card.title} className="py-3 shadow-none sm:py-4">
<CardContent
className={`flex items-center justify-between px-4 transition-opacity duration-200 ${fetchingStats ? "opacity-50" : "opacity-100"}`}
className={`flex items-center justify-between px-3 transition-opacity duration-200 sm:px-4 ${fetchingStats ? "opacity-50" : "opacity-100"}`}
>
<div className="w-full min-w-0">
<div className="text-muted-foreground flex items-center gap-1 text-xs">
{card.title}
<span className="truncate">{card.title}</span>
{"description" in card && card.description && (
<Tooltip>
<TooltipTrigger asChild>
Expand All @@ -1010,7 +1014,7 @@ export default function LogsPage() {
</Tooltip>
)}
</div>
<div className="truncate font-mono text-xl font-medium sm:text-2xl">{card.value}</div>
<div className="truncate font-mono text-lg font-medium sm:text-xl lg:text-2xl">{card.value}</div>
</div>
</CardContent>
</Card>
Expand Down
Loading
Loading