Skip to content

Commit 4567636

Browse files
committed
fix(dashboard): latency work
1 parent f4db65e commit 4567636

File tree

17 files changed

+364
-101
lines changed

17 files changed

+364
-101
lines changed

packages/fern-dashboard/src/app/[orgName]/(homepage)/docs/[docsUrl]/@navbar/default.tsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { isAskAiEnabled } from "@/app/actions/toggleAskAi";
22
import { getCurrentSession } from "@/app/services/auth0/getCurrentSession";
33
import { isFernEmployee } from "@/app/services/auth0/management";
44
import type { Auth0OrgName } from "@/app/services/auth0/types";
5-
import { AskAiEnabledServerSide } from "@/components/ask-ai/AskAiEnabledServerSide";
65
import { DocsSiteNavBarItem } from "@/components/docs-page/DocsSiteNavBarItem";
76
import { DocsSiteNavBarWithOverflow, type NavItem } from "@/components/docs-page/DocsSiteNavBarWithOverflow";
87
import { parseDocsUrlParam } from "@/utils/parseDocsUrlParam";
@@ -45,14 +44,9 @@ export default async function DocsSiteNavbar({
4544
return (
4645
<>
4746
<div className="hidden md:flex">
48-
<DocsSiteNavBarItem title="Overview" href="" />
49-
<DocsSiteNavBarItem title="Web Analytics" href="web-analytics" />
50-
<DocsSiteNavBarItem title="Search" href="search" />
51-
<AskAiEnabledServerSide docsUrl={docsUrl}>
52-
<DocsSiteNavBarItem title="Ask Fern" href="ask-fern" />
53-
</AskAiEnabledServerSide>
54-
<DocsSiteNavBarItem title="Feedback" href="feedback" />
55-
{isEmployee && <DocsSiteNavBarItem title="Settings" href="settings" />}
47+
{navItems.map((item) => (
48+
<DocsSiteNavBarItem key={item.title} title={item.title} href={item.href} />
49+
))}
5650
</div>
5751
<DocsSiteNavBarWithOverflow items={navItems} />
5852
</>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { Skeleton } from "@/components/ui/skeleton";
2+
import { cn } from "@/utils/utils";
3+
4+
const BORDER_STYLES = "mb-4 flex w-full flex-col items-center rounded-2xl p-4";
5+
6+
export default function Loading() {
7+
return (
8+
<div className="flex min-w-0 flex-1 flex-col items-center transition-[flex] duration-500 ease-out">
9+
{/* Page Header Skeleton */}
10+
<div className="mb-4 flex w-full max-w-[1200px] items-center justify-between">
11+
<Skeleton className="h-8 w-32" />
12+
</div>
13+
14+
{/* Main Content Card Skeleton */}
15+
<div className={cn(BORDER_STYLES, "border-gray-0 w-full max-w-[1200px] border")}>
16+
{/* Time Range Selector Skeleton */}
17+
<div className="mb-6 flex w-full items-center justify-between">
18+
<Skeleton className="h-7 w-32" />
19+
<Skeleton className="h-9 w-32" />
20+
</div>
21+
22+
{/* Metrics Cards Skeleton */}
23+
<div className="mb-6 flex w-full gap-6">
24+
{Array.from({ length: 4 }).map((_, i) => (
25+
<div key={i} className="flex flex-1 flex-col items-start">
26+
<Skeleton className="mb-1 h-5 w-20" />
27+
<Skeleton className="h-7 w-16" />
28+
</div>
29+
))}
30+
</div>
31+
32+
{/* Histogram Chart Skeleton */}
33+
<div className="mb-6 w-full overflow-x-auto">
34+
<div className="flex h-[200px] items-end gap-2">
35+
{Array.from({ length: 20 }).map((_, i) => (
36+
<Skeleton
37+
key={i}
38+
className="flex-1"
39+
style={{ height: `${Math.random() * 100 + 50}px` }}
40+
/>
41+
))}
42+
</div>
43+
</div>
44+
45+
{/* Search Bar and Pagination Skeleton */}
46+
<div className="mb-4 flex flex-wrap items-center justify-between gap-2">
47+
<Skeleton className="h-9 w-64" />
48+
<Skeleton className="h-9 w-32" />
49+
</div>
50+
51+
{/* Table Skeleton */}
52+
<div className="flex flex-col gap-2">
53+
{/* Table Header */}
54+
<Skeleton className="h-10 w-full" />
55+
{/* Table Rows */}
56+
{Array.from({ length: 8 }).map((_, i) => (
57+
<Skeleton key={i} className="h-12 w-full" />
58+
))}
59+
</div>
60+
</div>
61+
</div>
62+
);
63+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Skeleton } from "@/components/ui/skeleton";
2+
3+
export default function Loading() {
4+
return (
5+
<div className="border-border border rounded-2xl h-64 w-full p-4">
6+
<Skeleton className=" h-full w-full" />
7+
</div>
8+
);
9+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Skeleton } from "@/components/ui/skeleton";
2+
3+
export default function Loading() {
4+
return (
5+
<div className="flex w-full flex-col gap-4">
6+
<div className="border-border border rounded-2xl h-64 w-full p-4">
7+
<Skeleton className=" h-full w-full" />
8+
</div>
9+
<div className="border-border border rounded-2xl h-64 w-full p-4">
10+
<Skeleton className=" h-full w-full" />
11+
</div>
12+
</div>
13+
);
14+
}

packages/fern-dashboard/src/app/[orgName]/(homepage)/docs/[docsUrl]/page.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export default async function Page(props: {
3636
});
3737
if (!response.ok) {
3838
console.warn("Failed to get docs sites for org: ", JSON.stringify(response.error, null, 2));
39-
4039
notFound();
4140
}
4241
const currentDocsSite = response.docsSites.find((site) => getDocsSiteUrl(site) === docsUrl);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Skeleton } from "@/components/ui/skeleton";
2+
3+
export default function Loading() {
4+
return (
5+
<div className="flex w-full flex-col gap-4">
6+
{/* Date Range and Refresh Button Skeleton */}
7+
<div className="flex items-center gap-2">
8+
<Skeleton className="h-9 w-[180px]" />
9+
<Skeleton className="h-9 w-[100px]" />
10+
</div>
11+
12+
{/* Total Searches Metric Card Skeleton */}
13+
<div className="flex gap-4">
14+
<div className="border-border flex flex-1 flex-col gap-3 rounded-lg border bg-white p-6 dark:bg-transparent">
15+
<Skeleton className="h-5 w-28" />
16+
<Skeleton className="h-9 w-32" />
17+
</div>
18+
</div>
19+
20+
{/* Analytics Tables Skeleton */}
21+
<div className="flex flex-col gap-4">
22+
{/* Top Searches and Searches with No Results */}
23+
<div className="flex flex-col gap-4 lg:flex-row">
24+
<SearchTableSkeleton title="Top searches" />
25+
<SearchTableSkeleton title="Searches with no results" />
26+
</div>
27+
</div>
28+
</div>
29+
);
30+
}
31+
32+
function SearchTableSkeleton({ title }: { title: string }) {
33+
return (
34+
<div className="border-border flex flex-1 flex-col rounded-lg border bg-white dark:bg-transparent">
35+
<div className="border-border flex items-center justify-between border-b px-4 py-3">
36+
<Skeleton className="h-5 w-32">{title}</Skeleton>
37+
</div>
38+
<div className="flex flex-col">
39+
{[...Array(10)].map((_, i) => (
40+
<div key={i} className="border-border flex items-center justify-between border-b px-4 py-3 last:border-b-0">
41+
<Skeleton className="h-4 w-48" />
42+
<Skeleton className="h-4 w-16" />
43+
</div>
44+
))}
45+
</div>
46+
</div>
47+
);
48+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Skeleton } from "@/components/ui/skeleton";
2+
3+
export default function Loading() {
4+
return (
5+
<div className="flex flex-1 flex-col items-center gap-4">
6+
{/* Archive Site Card Skeleton */}
7+
<div className="border-border mx-auto mt-6 flex w-full max-w-[750px] flex-1 flex-col rounded-xl border bg-gray-100 p-4 sm:mt-8 md:mt-10">
8+
<div className="flex flex-col gap-1">
9+
<Skeleton className="h-6 w-32" />
10+
<Skeleton className="h-5 w-full" />
11+
<Skeleton className="h-5 w-3/4" />
12+
</div>
13+
<div className="mt-5 flex justify-center md:justify-end">
14+
<Skeleton className="h-9 w-32" />
15+
</div>
16+
</div>
17+
18+
{/* Ask AI Card Skeleton (might be shown for Fern employees) */}
19+
<div className="border-border mx-auto mt-6 flex w-full max-w-[750px] flex-1 flex-col rounded-xl border bg-gray-100 p-4 sm:mt-8 md:mt-10">
20+
<div className="flex flex-col gap-1">
21+
<Skeleton className="h-6 w-24" />
22+
<Skeleton className="h-5 w-full" />
23+
<Skeleton className="h-5 w-2/3" />
24+
</div>
25+
<div className="mt-5 flex justify-center md:justify-end">
26+
<Skeleton className="h-9 w-32" />
27+
</div>
28+
</div>
29+
30+
{/* Delete Docs Site Card Skeleton */}
31+
<div className="border-border mx-auto mt-6 flex w-full max-w-[750px] flex-1 flex-col rounded-xl border bg-gray-100 p-4 sm:mt-8 md:mt-10">
32+
<div className="flex flex-col gap-1">
33+
<Skeleton className="h-6 w-40" />
34+
<Skeleton className="h-5 w-full" />
35+
</div>
36+
<div className="mt-5 flex justify-center md:justify-end">
37+
<Skeleton className="h-9 w-32" />
38+
</div>
39+
</div>
40+
</div>
41+
);
42+
}

packages/fern-dashboard/src/app/[orgName]/(homepage)/docs/[docsUrl]/settings/page.tsx

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { redirect } from "next/navigation";
2-
2+
import { Suspense } from "react";
3+
import { isAskAiEnabled } from "@/app/actions/toggleAskAi";
34
import { isFernEmployee } from "@/app/services/auth0/management";
45
import type { Auth0OrgName } from "@/app/services/auth0/types";
56
import { getAuthenticatedSessionOrRedirect } from "@/app/services/dal/organization";
6-
import { Settings } from "@/components/settings/Settings";
7+
import { ArchiveSiteButton } from "@/components/settings/ArchiveSiteButton";
8+
import { DeleteDocsSiteButton } from "@/components/settings/DeleteDocsSiteButton";
9+
import { SettingsCard } from "@/components/settings/SettingsCard";
10+
import { ToggleAskAiButton } from "@/components/settings/ToggleAskAiButton";
11+
import { Skeleton } from "@/components/ui/skeleton";
712
import { parseDocsUrlParam } from "@/utils/parseDocsUrlParam";
813
import type { EncodedDocsUrl } from "@/utils/types";
914

@@ -16,11 +21,36 @@ export default async function Page({
1621
const docsUrl = parseDocsUrlParam({ docsUrl: encodedDocsUrl });
1722

1823
const session = await getAuthenticatedSessionOrRedirect(orgName);
19-
2024
const isEmployee = await isFernEmployee(session.user.sub);
2125
if (!isEmployee) {
2226
redirect(`/${orgName}/docs/${docsUrl}`);
2327
}
2428

25-
return <Settings docsUrl={docsUrl} hasFernEmail={isEmployee} orgName={orgName} />;
29+
return (
30+
<div className="flex flex-1 flex-col items-center gap-4">
31+
<SettingsCard
32+
title="Archive site"
33+
description="This will hide the site from the dashboard, but any deployed domains will remain live."
34+
button={<ArchiveSiteButton docsUrl={docsUrl} orgName={orgName} />}
35+
/>
36+
37+
<SettingsCard
38+
title="Ask AI"
39+
description="This will turn on or turn off AI search for this documentation site."
40+
button={
41+
<Suspense fallback={<Skeleton className="h-9 w-32" />}>
42+
<ToggleAskAiButton
43+
docsUrl={docsUrl}
44+
initialAskAiStatus={await isAskAiEnabled({ domain: docsUrl })}
45+
/>
46+
</Suspense>
47+
}
48+
/>
49+
<SettingsCard
50+
title="Delete docs site"
51+
description="This is a destructive action and cannot be reversed."
52+
button={<DeleteDocsSiteButton docsUrl={docsUrl} orgName={orgName} />}
53+
/>
54+
</div>
55+
);
2656
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { Skeleton } from "@/components/ui/skeleton";
2+
3+
export default function Loading() {
4+
return (
5+
<div className="flex w-full flex-col gap-4">
6+
{/* Date Range and Refresh Button Skeleton */}
7+
<div className="flex items-center gap-2">
8+
<Skeleton className="h-9 w-[180px]" />
9+
<Skeleton className="h-9 w-[100px]" />
10+
</div>
11+
12+
{/* Metrics Cards Skeleton */}
13+
<div className="flex gap-4">
14+
<div className="border-border flex flex-1 flex-col gap-3 rounded-lg border bg-white p-6 dark:bg-transparent">
15+
<Skeleton className="h-5 w-16" />
16+
<Skeleton className="h-9 w-32" />
17+
</div>
18+
<div className="border-border flex flex-1 flex-col gap-3 rounded-lg border bg-white p-6 dark:bg-transparent">
19+
<Skeleton className="h-5 w-20" />
20+
<Skeleton className="h-9 w-32" />
21+
</div>
22+
</div>
23+
24+
{/* Chart Skeleton */}
25+
<div className="border-border w-full rounded-lg border">
26+
<div className="flex justify-between p-6 pb-4">
27+
<div className="flex gap-2">
28+
<Skeleton className="h-9 w-24" />
29+
<Skeleton className="h-9 w-24" />
30+
</div>
31+
<Skeleton className="h-9 w-[120px]" />
32+
</div>
33+
<div className="p-6 pr-0">
34+
<Skeleton className="h-[300px] w-full" />
35+
</div>
36+
</div>
37+
38+
{/* Analytics Tables Skeleton */}
39+
<div className="flex flex-col gap-4">
40+
{/* First row: Paths and Countries */}
41+
<div className="flex flex-col gap-4 lg:flex-row">
42+
<TableSkeleton title="Paths" />
43+
<TableSkeleton title="Countries" />
44+
</div>
45+
46+
{/* Second row: Channels and Device Types */}
47+
<div className="flex flex-col gap-4 lg:flex-row">
48+
<TableSkeleton title="Channels" />
49+
<TableSkeleton title="Device Types" />
50+
</div>
51+
52+
{/* Third row: Referring Domains and LLM File Views */}
53+
<div className="flex flex-col gap-4 lg:flex-row">
54+
<TableSkeleton title="Referring Domains" />
55+
<TableSkeleton title="LLM File Views" />
56+
</div>
57+
58+
{/* Fourth row: 404 Pages */}
59+
<div className="flex flex-col gap-4 lg:flex-row">
60+
<TableSkeleton title="404 Pages" fullWidth />
61+
</div>
62+
63+
{/* Fifth row: API Explorer Requests and LLM Bot Traffic */}
64+
<div className="flex flex-col gap-4 lg:flex-row">
65+
<TableSkeleton title="API Explorer Requests" />
66+
<TableSkeleton title="LLM Bot Traffic" />
67+
</div>
68+
</div>
69+
</div>
70+
);
71+
}
72+
73+
function TableSkeleton({ title, fullWidth = false }: { title: string; fullWidth?: boolean }) {
74+
return (
75+
<div className={`border-border flex flex-col rounded-lg border bg-white dark:bg-transparent ${fullWidth ? "w-full" : "flex-1"}`}>
76+
<div className="border-border flex items-center justify-between border-b px-4 py-3">
77+
<Skeleton className="h-5 w-32">{title}</Skeleton>
78+
</div>
79+
<div className="flex flex-col">
80+
{[...Array(5)].map((_, i) => (
81+
<div key={i} className="border-border flex items-center justify-between border-b px-4 py-3 last:border-b-0">
82+
<Skeleton className="h-4 w-40" />
83+
<div className="flex gap-8">
84+
<Skeleton className="h-4 w-16" />
85+
<Skeleton className="h-4 w-16" />
86+
</div>
87+
</div>
88+
))}
89+
</div>
90+
</div>
91+
);
92+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { PageHeader } from "@/components/layout/PageHeader";
2+
import { Skeleton } from "@/components/ui/skeleton";
3+
4+
export default function Loading() {
5+
return (
6+
<div className="flex min-w-0 flex-1 flex-col">
7+
<PageHeader title="Members" subtitle="Manage team members and invitations" />
8+
<Skeleton className="h-12 w-full" />
9+
</div>
10+
);
11+
}

0 commit comments

Comments
 (0)