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
25 changes: 25 additions & 0 deletions platform/src/app/[tenant]/ai-exposure/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Skeleton } from "@/components/ui/skeleton";

export default function AIExposureLoading() {
return (
<div className="space-y-6">
<div className="space-y-2">
<Skeleton className="h-8 w-56" />
<Skeleton className="h-4 w-64" />
</div>

<div className="grid gap-4 md:grid-cols-3">
{Array.from({ length: 3 }).map((_, i) => (
<Skeleton key={i} className="h-28" />
))}
</div>

<div className="space-y-2">
<Skeleton className="h-10 w-full" />
{Array.from({ length: 6 }).map((_, i) => (
<Skeleton key={i} className="h-12 w-full" />
))}
</div>
</div>
);
}
18 changes: 18 additions & 0 deletions platform/src/app/[tenant]/audit-log/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Skeleton } from "@/components/ui/skeleton";

export default function AuditLogLoading() {
return (
<div className="space-y-6">
<div className="space-y-2">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-4 w-64" />
</div>

<div className="space-y-3">
{Array.from({ length: 8 }).map((_, i) => (
<Skeleton key={i} className="h-20 w-full" />
))}
</div>
</div>
);
}
22 changes: 22 additions & 0 deletions platform/src/app/[tenant]/compare/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Skeleton } from "@/components/ui/skeleton";

export default function CompareLoading() {
return (
<div className="space-y-6">
<div className="flex flex-wrap items-start justify-between gap-3">
<div className="space-y-2">
<Skeleton className="h-8 w-40" />
<Skeleton className="h-4 w-56" />
</div>
<Skeleton className="h-8 w-32" />
</div>

<div className="space-y-2">
<Skeleton className="h-10 w-full" />
{Array.from({ length: 6 }).map((_, i) => (
<Skeleton key={i} className="h-12 w-full" />
))}
</div>
</div>
);
}
21 changes: 21 additions & 0 deletions platform/src/app/[tenant]/connect/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";

export default function ConnectLoading() {
return (
<div className="space-y-6">
<Skeleton className="h-8 w-40" />

{Array.from({ length: 3 }).map((_, i) => (
<Card key={i}>
<CardHeader>
<Skeleton className="h-5 w-56" />
</CardHeader>
<CardContent>
<Skeleton className="h-9 w-full" />
</CardContent>
</Card>
))}
</div>
);
}
34 changes: 34 additions & 0 deletions platform/src/app/[tenant]/dashboard/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Skeleton } from "@/components/ui/skeleton";

export default function DashboardLoading() {
return (
<div className="space-y-8">
<div className="flex flex-wrap items-start justify-between gap-3">
<div className="space-y-2">
<Skeleton className="h-8 w-56" />
<Skeleton className="h-4 w-40" />
</div>
<Skeleton className="h-8 w-32" />
</div>

<div className="grid gap-3 grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
{Array.from({ length: 6 }).map((_, i) => (
<Skeleton key={i} className="h-24" />
))}
</div>

<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-28" />
))}
</div>

<Skeleton className="h-72" />

<div className="grid gap-4 lg:grid-cols-2">
<Skeleton className="h-64" />
<Skeleton className="h-64" />
</div>
</div>
);
}
27 changes: 27 additions & 0 deletions platform/src/app/[tenant]/repos/[repoName]/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Skeleton } from "@/components/ui/skeleton";

export default function RepoDetailLoading() {
return (
<div className="space-y-6">
<div className="flex flex-wrap items-start justify-between gap-3">
<div className="space-y-2">
<Skeleton className="h-8 w-64" />
<Skeleton className="h-4 w-48" />
</div>
<Skeleton className="h-8 w-32" />
</div>

<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-24" />
))}
</div>

<div className="grid gap-4 lg:grid-cols-2">
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-56" />
))}
</div>
</div>
);
}
20 changes: 20 additions & 0 deletions platform/src/app/[tenant]/repos/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Skeleton } from "@/components/ui/skeleton";

export default function ReposLoading() {
return (
<div className="space-y-6">
<div className="space-y-2">
<Skeleton className="h-8 w-40" />
<Skeleton className="h-4 w-56" />
</div>

<Skeleton className="h-9 w-full max-w-sm" />

<div className="space-y-2">
{Array.from({ length: 8 }).map((_, i) => (
<Skeleton key={i} className="h-14" />
))}
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";

export default function IntegrationDetailLoading() {
return (
<div className="space-y-6">
<Skeleton className="h-8 w-56" />

<Card>
<CardHeader>
<Skeleton className="h-5 w-40" />
<Skeleton className="mt-1 h-4 w-64" />
</CardHeader>
<CardContent className="space-y-3">
<Skeleton className="h-9 w-full" />
<Skeleton className="h-9 w-full" />
<Skeleton className="h-9 w-2/3" />
</CardContent>
</Card>
</div>
);
}
15 changes: 15 additions & 0 deletions platform/src/app/[tenant]/settings/integrations/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Skeleton } from "@/components/ui/skeleton";

export default function IntegrationsLoading() {
return (
<div className="space-y-6">
<Skeleton className="h-8 w-48" />

<div className="grid gap-4 md:grid-cols-2">
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-32" />
))}
</div>
</div>
);
}
22 changes: 22 additions & 0 deletions platform/src/app/[tenant]/settings/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";

export default function SettingsLoading() {
return (
<div className="space-y-6">
<Skeleton className="h-8 w-40" />

{Array.from({ length: 3 }).map((_, i) => (
<Card key={i}>
<CardHeader>
<Skeleton className="h-5 w-40" />
<Skeleton className="mt-1 h-4 w-64" />
</CardHeader>
<CardContent>
<Skeleton className="h-9 w-full" />
</CardContent>
</Card>
))}
</div>
);
}
25 changes: 25 additions & 0 deletions platform/src/app/[tenant]/team/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";

export default function TeamLoading() {
return (
<div className="space-y-6">
<div className="flex flex-wrap items-start justify-between gap-3">
<Skeleton className="h-8 w-40" />
<Skeleton className="h-9 w-32" />
</div>

<Card>
<CardHeader>
<Skeleton className="h-5 w-32" />
<Skeleton className="mt-1 h-4 w-56" />
</CardHeader>
<CardContent className="space-y-3">
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-16 w-full" />
))}
</CardContent>
</Card>
</div>
);
}
26 changes: 23 additions & 3 deletions platform/src/components/WindowSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
"use client";

import { useTransition } from "react";

import { useRouter, usePathname, useSearchParams } from "next/navigation";

import { Loader2 } from "lucide-react";

import {
Select,
SelectContent,
Expand Down Expand Up @@ -32,23 +36,39 @@ export function WindowSelector({
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const [isPending, startTransition] = useTransition();

if (options.length < 2) return null;

function handleChange(value: string) {
const params = new URLSearchParams(searchParams.toString());
params.set(paramKey, value);
router.replace(`${pathname}?${params.toString()}`, { scroll: false });
// Wrapping the navigation in a transition keeps this page visible with
// isPending=true instead of unmounting to the route's loading.tsx — the
// right feel for a filter (instant feedback on the control itself)
// rather than a full-page flash. Also blocks a second click from firing
// another replace() before the first one resolves.
startTransition(() => {
router.replace(`${pathname}?${params.toString()}`, { scroll: false });
});
}

return (
<div className="flex items-center gap-2">
<span className="text-xs text-muted-foreground">
{t("common.windowSelector.label")}
</span>
<Select value={String(windowDays)} onValueChange={handleChange}>
<Select
value={String(windowDays)}
onValueChange={handleChange}
disabled={isPending}
>
<SelectTrigger className="h-8 w-[112px]">
<SelectValue />
{isPending ? (
<Loader2 className="size-3.5 animate-spin text-muted-foreground" />
) : (
<SelectValue />
)}
</SelectTrigger>
<SelectContent>
{options.map((days) => (
Expand Down
12 changes: 12 additions & 0 deletions platform/src/components/ui/skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { cn } from "@/lib/utils";

function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn("animate-pulse rounded-md bg-muted", className)}
{...props}
/>
);
}

export { Skeleton };
Loading