mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
98 lines
4.8 KiB
TypeScript
98 lines
4.8 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import Link from "next/link";
|
||
|
|
import { HoverCard, HoverCardTrigger, HoverCardContent } from "@/components/ui/hover-card";
|
||
|
|
import { AlertTriangleIcon } from "lucide-react";
|
||
|
|
import { useDomain } from "@/hooks/useDomain";
|
||
|
|
import { getConnections } from "@/actions";
|
||
|
|
import { useState } from "react";
|
||
|
|
import { useEffect } from "react";
|
||
|
|
import { isServiceError } from "@/lib/utils";
|
||
|
|
import { SyncStatusMetadataSchema } from "@/lib/syncStatusMetadataSchema";
|
||
|
|
|
||
|
|
interface Warning {
|
||
|
|
connectionId?: number;
|
||
|
|
connectionName?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export const WarningNavIndicator = () => {
|
||
|
|
const domain = useDomain();
|
||
|
|
const [warnings, setWarnings] = useState<Warning[]>([]);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
const fetchWarnings = async () => {
|
||
|
|
const connections = await getConnections(domain);
|
||
|
|
const warnings: Warning[] = [];
|
||
|
|
if (!isServiceError(connections)) {
|
||
|
|
for (const connection of connections) {
|
||
|
|
const parseResult = SyncStatusMetadataSchema.safeParse(connection.syncStatusMetadata);
|
||
|
|
if (parseResult.success && parseResult.data.notFound) {
|
||
|
|
const { notFound } = parseResult.data;
|
||
|
|
if (notFound.users.length > 0 || notFound.orgs.length > 0 || notFound.repos.length > 0) {
|
||
|
|
warnings.push({ connectionId: connection.id, connectionName: connection.name });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
setWarnings(prevWarnings => {
|
||
|
|
// Only update if the warnings have actually changed
|
||
|
|
const warningsChanged = prevWarnings.length !== warnings.length ||
|
||
|
|
prevWarnings.some((warning, idx) =>
|
||
|
|
warning.connectionId !== warnings[idx]?.connectionId ||
|
||
|
|
warning.connectionName !== warnings[idx]?.connectionName
|
||
|
|
);
|
||
|
|
return warningsChanged ? warnings : prevWarnings;
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
fetchWarnings();
|
||
|
|
const intervalId = setInterval(fetchWarnings, 1000);
|
||
|
|
return () => clearInterval(intervalId);
|
||
|
|
}, [domain]);
|
||
|
|
|
||
|
|
if (warnings.length === 0) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Link href={`/${domain}/connections`}>
|
||
|
|
<HoverCard>
|
||
|
|
<HoverCardTrigger asChild>
|
||
|
|
<div className="flex items-center gap-2 px-3 py-1.5 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-700 rounded-full text-yellow-700 dark:text-yellow-400 text-xs font-medium hover:bg-yellow-100 dark:hover:bg-yellow-900/30 transition-colors cursor-pointer">
|
||
|
|
<AlertTriangleIcon className="h-4 w-4" />
|
||
|
|
<span>{warnings.length}</span>
|
||
|
|
</div>
|
||
|
|
</HoverCardTrigger>
|
||
|
|
<HoverCardContent className="w-80 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
||
|
|
<div className="flex flex-col gap-4 p-5">
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<div className="h-2 w-2 rounded-full bg-yellow-500"></div>
|
||
|
|
<h3 className="text-sm font-medium text-yellow-700 dark:text-yellow-400">Missing References</h3>
|
||
|
|
</div>
|
||
|
|
<p className="text-sm text-yellow-600/90 dark:text-yellow-300/90 leading-relaxed">
|
||
|
|
The following connections have references that could not be found:
|
||
|
|
</p>
|
||
|
|
<div className="flex flex-col gap-2 pl-4">
|
||
|
|
{warnings.slice(0, 10).map(warning => (
|
||
|
|
<Link key={warning.connectionName} href={`/${domain}/connections/${warning.connectionId}`}>
|
||
|
|
<div className="flex items-center gap-2 px-3 py-2 bg-yellow-50 dark:bg-yellow-900/20
|
||
|
|
rounded-md text-sm text-yellow-700 dark:text-yellow-300
|
||
|
|
border border-yellow-200/50 dark:border-yellow-800/50
|
||
|
|
hover:bg-yellow-100 dark:hover:bg-yellow-900/30 transition-colors">
|
||
|
|
<span className="font-medium">{warning.connectionName}</span>
|
||
|
|
</div>
|
||
|
|
</Link>
|
||
|
|
))}
|
||
|
|
{warnings.length > 10 && (
|
||
|
|
<div className="text-sm text-yellow-600/90 dark:text-yellow-300/90 pl-3 pt-1">
|
||
|
|
And {warnings.length - 10} more...
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</HoverCardContent>
|
||
|
|
</HoverCard>
|
||
|
|
</Link>
|
||
|
|
);
|
||
|
|
};
|