Skip to content
Merged
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
478 changes: 205 additions & 273 deletions ui/app/workspace/dashboard/page.tsx

Large diffs are not rendered by default.

29 changes: 18 additions & 11 deletions ui/app/workspace/logs/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { LogDetailSheet } from "@/app/workspace/logs/sheets/logDetailsSheet";
import { SessionDetailsSheet } from "@/app/workspace/logs/sheets/sessionDetailsSheet";
import { createColumns } from "@/app/workspace/logs/views/columns";
import { EmptyState } from "@/app/workspace/logs/views/emptyState";
import { LogsSidebar } from "@/app/workspace/logs/views/logsSidebar";
import { LogsDataTable } from "@/app/workspace/logs/views/logsTable";
import { LogsVolumeChart } from "@/app/workspace/logs/views/logsVolumeChart";
import FullPageLoader from "@/components/fullPageLoader";
Expand Down Expand Up @@ -224,12 +225,12 @@ export default function LogsPage() {
missing_cost_only: urlState.missing_cost_only,
metadata_filters: urlState.metadata_filters
? (() => {
try {
return JSON.parse(urlState.metadata_filters);
} catch {
return undefined;
}
})()
try {
return JSON.parse(urlState.metadata_filters);
} catch {
return undefined;
}
})()
: undefined,
}),
// Only re-derive filters when filter-related URL params change (not pagination)
Expand Down Expand Up @@ -294,7 +295,7 @@ export default function LogsPage() {
content_search: newFilters.content_search || "",
start_time: newFilters.start_time ? dateUtils.toUnixTimestamp(new Date(newFilters.start_time)) : undefined,
end_time: newFilters.end_time ? dateUtils.toUnixTimestamp(new Date(newFilters.end_time)) : undefined,
missing_cost_only: newFilters.missing_cost_only ?? filters.missing_cost_only ?? false,
missing_cost_only: newFilters.missing_cost_only ?? false,
metadata_filters: newFilters.metadata_filters ? JSON.stringify(newFilters.metadata_filters) : "",
offset: 0,
});
Expand Down Expand Up @@ -825,7 +826,8 @@ export default function LogsPage() {
title: "Success Rate",
value: fetchingStats ? <Skeleton className="h-8 w-16" /> : stats ? `${stats.success_rate.toFixed(2)}%` : "-",
icon: <CheckCircle className="size-4" />,
description: "Success rate as perceived by the system. Each fallback counts as a separate attempt. Retries on the same request are counted as one attempt.",
description:
"Success rate as perceived by the system. Each fallback counts as a separate attempt. Retries on the same request are counted as one attempt.",
},
{
title: "User Success Rate",
Expand Down Expand Up @@ -910,14 +912,18 @@ export default function LogsPage() {
);

return (
<div className="dark:bg-card h-[calc(100dvh-3.3rem)] max-h-[calc(100dvh-1.5rem)] bg-white">
<div className="dark:bg-card no-padding-parent no-border-parent h-[calc(100vh_-_16px)]">
{initialLoading ? (
<FullPageLoader />
) : showEmptyState ? (
<EmptyState isSocketConnected={isSocketConnected} error={error} />
) : (
<div className="mx-auto flex h-full w-full flex-col">
<div className="flex h-full flex-col gap-2 overflow-hidden">
<div className="bg-background flex h-full w-full grow gap-3">
{/* Sidebar Filters */}
<LogsSidebar filters={filters} onFiltersChange={setFilters} />

{/* 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="grid shrink-0 grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-6">
{statCards.map((card) => (
<Card key={card.title} className="py-4 shadow-none">
Expand Down Expand Up @@ -990,6 +996,7 @@ export default function LogsPage() {
isSocketConnected={isSocketConnected}
fetchLogs={fetchLogs}
fetchStats={fetchStats}
sidebarFilters
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion ui/app/workspace/logs/sheets/logDetailView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ import {
} from "@/lib/constants/logs";
import { LogEntry } from "@/lib/types/logs";
import { Link } from "@tanstack/react-router";
import { Clipboard, Loader2, MoreVertical, Trash2 } from "lucide-react";
import { addMilliseconds, format } from "date-fns";
import { Clipboard, Loader2, MoreVertical, Trash2 } from "lucide-react";
import type { ReactNode } from "react";
import { toast } from "sonner";
import BlockHeader from "../views/blockHeader";
Expand Down
4 changes: 2 additions & 2 deletions ui/app/workspace/logs/views/emptyState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Button } from "@/components/ui/button";
import { CodeEditor } from "@/components/ui/codeEditor";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { getExampleBaseUrl } from "@/lib/utils/port";
import { useCopyToClipboard } from "@/hooks/useCopyToClipboard";
import { getExampleBaseUrl } from "@/lib/utils/port";
import { AlertTriangle, Copy } from "lucide-react";
import { useMemo, useState } from "react";

Expand Down Expand Up @@ -251,7 +251,7 @@ const result = await chain.invoke({ input: "What is LangChain?" });`,
</Alert>
)}

<div className="w-full space-y-6">
<div className="w-full space-y-6 p-4">
<div className="flex flex-row items-center gap-2">
<div>
<h3 className="text-lg font-semibold">Integrate under 60 seconds</h3>
Expand Down
88 changes: 51 additions & 37 deletions ui/app/workspace/logs/views/filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,19 @@ interface LogFiltersProps {
onLiveToggle: (enabled: boolean) => void;
fetchLogs: () => Promise<void>;
fetchStats: () => Promise<void>;
/** When true, hide FilterPopover and DateTimePicker (they live in the sidebar instead) */
hidePopoverFilters?: boolean;
}

export function LogFilters({ filters, onFiltersChange, liveEnabled, onLiveToggle, fetchLogs, fetchStats }: LogFiltersProps) {
export function LogFilters({
filters,
onFiltersChange,
liveEnabled,
onLiveToggle,
fetchLogs,
fetchStats,
hidePopoverFilters,
}: LogFiltersProps) {
const [openMoreActionsPopover, setOpenMoreActionsPopover] = useState(false);
const [localSearch, setLocalSearch] = useState(filters.content_search || "");
const searchTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
Expand Down Expand Up @@ -147,7 +157,7 @@ export function LogFilters({ filters, onFiltersChange, liveEnabled, onLiveToggle
);

return (
<div className="flex items-center justify-between space-x-2">
<div className="flex grow items-center justify-between space-x-2">
<Button variant={"outline"} size="sm" className="h-7.5" onClick={() => onLiveToggle(!liveEnabled)}>
{liveEnabled ? (
<>
Expand All @@ -172,43 +182,47 @@ export function LogFilters({ filters, onFiltersChange, liveEnabled, onLiveToggle
/>
</div>

<DateTimePickerWithRange
triggerTestId="filter-date-range"
dateTime={{
from: startTime,
to: endTime,
}}
onDateTimeUpdate={(p) => {
setStartTime(p.from);
setEndTime(p.to);
onFiltersChange({
...filters,
start_time: p.from?.toISOString(),
end_time: p.to?.toISOString(),
});
}}
preDefinedPeriods={LOG_TIME_PERIODS}
onPredefinedPeriodChange={(periodValue) => {
if (!periodValue) return;
const { from, to } = getRangeForPeriod(periodValue);
setStartTime(from);
setEndTime(to);
onFiltersChange({
...filters,
start_time: from.toISOString(),
end_time: to.toISOString(),
});
}}
/>
<FilterPopover
filters={filters}
onFilterChange={handleFilterChange}
onMetadataFilterChange={handleMetadataFilterChange}
showMissingCost
/>
{!hidePopoverFilters && (
<>
<DateTimePickerWithRange
triggerTestId="filter-date-range"
dateTime={{
from: startTime,
to: endTime,
}}
onDateTimeUpdate={(p) => {
setStartTime(p.from);
setEndTime(p.to);
onFiltersChange({
...filters,
start_time: p.from?.toISOString(),
end_time: p.to?.toISOString(),
});
}}
preDefinedPeriods={LOG_TIME_PERIODS}
onPredefinedPeriodChange={(periodValue) => {
if (!periodValue) return;
const { from, to } = getRangeForPeriod(periodValue);
setStartTime(from);
setEndTime(to);
onFiltersChange({
...filters,
start_time: from.toISOString(),
end_time: to.toISOString(),
});
}}
/>
<FilterPopover
filters={filters}
onFilterChange={handleFilterChange}
onMetadataFilterChange={handleMetadataFilterChange}
showMissingCost
/>
</>
)}
<Popover open={openMoreActionsPopover} onOpenChange={setOpenMoreActionsPopover}>
<PopoverTrigger asChild>
<Button variant="outline" size="sm" className="h-7.5">
<Button variant="outline" size="sm" className="h-7.5 w-7.5">
<MoreVertical className="h-4 w-4" />
</Button>
</PopoverTrigger>
Expand Down
Loading
Loading