perf: add loading.tsx skeletons for observability detail pages

Add Suspense-boundary loading skeletons for the LLM Calls list page
and the LLM Call detail page. These pages lack internal Suspense
boundaries and make database queries at the server component level,
so Next.js loading.tsx provides instant streaming of the shell while
data fetches resolve. The traces and trace detail pages already have
internal Suspense boundaries and don't need this.
This commit is contained in:
Kevin Turcios 2026-04-11 04:11:26 -05:00
parent f96fba76f3
commit d6cab273bc
2 changed files with 85 additions and 0 deletions

View file

@ -0,0 +1,48 @@
export default function LLMCallDetailLoading() {
return (
<div className="container mx-auto px-4 py-8">
{/* Header */}
<div className="mb-8">
<div className="h-4 w-32 bg-gray-200 dark:bg-gray-700 rounded mb-4 animate-pulse" />
<div className="h-8 w-48 bg-gray-200 dark:bg-gray-700 rounded mb-3 animate-pulse" />
<div className="space-y-2">
<div className="h-6 w-80 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="h-6 w-96 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
</div>
</div>
{/* Summary Cards */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-5 mb-8">
{[1, 2, 3, 4].map(i => (
<div
key={i}
className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 border border-gray-200 dark:border-gray-700"
>
<div className="h-4 w-20 bg-gray-200 dark:bg-gray-700 rounded mb-2 animate-pulse" />
<div className="h-8 w-24 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
</div>
))}
</div>
{/* Metadata */}
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-8 border border-gray-200 dark:border-gray-700">
<div className="h-6 w-28 bg-gray-200 dark:bg-gray-700 rounded mb-4 animate-pulse" />
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{[1, 2, 3, 4, 5, 6].map(i => (
<div key={i}>
<div className="h-4 w-24 bg-gray-200 dark:bg-gray-700 rounded mb-2 animate-pulse" />
<div className="h-5 w-36 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
</div>
))}
</div>
</div>
{/* Prompt skeletons */}
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-8 border border-gray-200 dark:border-gray-700">
<div className="h-6 w-36 bg-gray-200 dark:bg-gray-700 rounded mb-4 animate-pulse" />
<div className="h-48 bg-gray-100 dark:bg-gray-900 rounded animate-pulse" />
</div>
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-8 border border-gray-200 dark:border-gray-700">
<div className="h-6 w-32 bg-gray-200 dark:bg-gray-700 rounded mb-4 animate-pulse" />
<div className="h-48 bg-gray-100 dark:bg-gray-900 rounded animate-pulse" />
</div>
</div>
)
}

View file

@ -0,0 +1,37 @@
export default function LLMCallsLoading() {
return (
<div className="container mx-auto p-6">
<div className="mb-8">
<div className="flex items-center justify-between gap-4 mb-2">
<div className="h-8 w-32 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="flex items-center gap-2 flex-1 max-w-3xl">
<div className="flex-1 h-10 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="w-32 h-10 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="w-32 h-10 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="w-32 h-10 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="w-20 h-10 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
</div>
</div>
<div className="h-4 w-80 bg-gray-200 dark:bg-gray-700 rounded animate-pulse mt-2" />
</div>
<div className="grid grid-cols-1 md:grid-cols-4 gap-5 mb-8">
{[1, 2, 3, 4].map(i => (
<div
key={i}
className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 border border-gray-200 dark:border-gray-700"
>
<div className="h-4 w-24 bg-gray-200 dark:bg-gray-700 rounded mb-2 animate-pulse" />
<div className="h-8 w-16 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
</div>
))}
</div>
<div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-200 dark:border-gray-700">
<div className="p-4 space-y-3">
{[1, 2, 3, 4, 5, 6, 7, 8].map(i => (
<div key={i} className="h-12 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
))}
</div>
</div>
</div>
)
}