Adding useAutoRefresh on agent page.

This commit is contained in:
charlesgauthereau
2025-12-26 11:55:43 +01:00
parent 7f7f8e642f
commit ee285df7b5
7 changed files with 189 additions and 83 deletions
@@ -0,0 +1,79 @@
"use client"
import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card";
import {Server} from "lucide-react";
import {formatDateLastContact} from "@/utils/date-formatting";
import {AgentCardKey} from "@/components/wrappers/dashboard/agent/agent-card-key/agent-card-key";
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
import {DatabaseCard} from "@/components/wrappers/dashboard/projects/project-card/project-database-card";
import {AgentWithDatabases} from "@/db/schema/08_agent";
import {eventUpdate} from "@/types/events";
import {useAutoRefresh} from "@/hooks/use-auto-refresh";
type AgentContentPageProps = {
edgeKey: string;
agent: AgentWithDatabases
}
export const AgentContentPage = ({edgeKey, agent}: AgentContentPageProps) => {
useAutoRefresh({
poll: {
enabled: true,
intervalMs: 5000,
},
sse: {
enabled: true,
url: "/api/events",
eventName: "modification",
shouldRefresh: (data) => {
const update = data as eventUpdate;
return Boolean(update?.update);
},
},
});
return (
<>
<div className="flex flex-col sm:flex-row sm:justify-between gap-6 ">
<Card className="w-full sm:w-auto flex-1">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Databases</CardTitle>
<Server className="h-4 w-4 text-muted-foreground"/>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{agent.databases.length}</div>
<p className="text-xs text-muted-foreground">Databases linked to this agent</p>
</CardContent>
</Card>
<Card className="w-full sm:w-auto flex-1">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Last contact</CardTitle>
<Server className="h-4 w-4 text-muted-foreground"/>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{formatDateLastContact(agent.lastContact)}</div>
<p className="text-xs text-muted-foreground">Last contact with agent</p>
</CardContent>
</Card>
</div>
<Card className="w-full sm:w-auto flex-1 ">
<CardHeader className="font-bold text-xl">
Edge Key
</CardHeader>
<CardContent>
<AgentCardKey
edgeKey={edgeKey}
/>
</CardContent>
</Card>
<CardsWithPagination cardsPerPage={4} numberOfColumns={2} data={agent.databases}
cardItem={DatabaseCard}/>
</>
)
}
+4
View File
@@ -28,3 +28,7 @@ export const agentRelations = relations(agent, ({many}) => ({
export type AgentWith = Agent & {
databases?: Database[] | null;
};
export type AgentWithDatabases = Agent & {
databases: Database[] | [];
};
@@ -0,0 +1,28 @@
"use client";
import {useTheme} from "next-themes";
import {useEffect, useState} from "react";
export function ThemeMetaUpdaterRoot() {
const {resolvedTheme} = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (!mounted || !resolvedTheme) return;
const color = resolvedTheme === "dark" ? "#000000" : "#ffffff";
let tag = document.querySelector<HTMLMetaElement>('meta[name="theme-color"]');
if (!tag) {
tag = document.createElement("meta");
tag.name = "theme-color";
document.head.appendChild(tag);
}
tag.content = color;
}, [mounted, resolvedTheme]);
return null;
}
+71
View File
@@ -0,0 +1,71 @@
"use client";
import {useEffect, useRef} from "react";
import {useRouter} from "next/navigation";
type UseAutoRefreshOptions = {
poll?: {
intervalMs: number;
enabled?: boolean;
};
sse?: {
url: string;
eventName?: string;
enabled?: boolean;
shouldRefresh?: (data: unknown) => boolean;
};
};
export function useAutoRefresh(options: UseAutoRefreshOptions) {
const router = useRouter();
const eventSourceRef = useRef<EventSource | null>(null);
useEffect(() => {
if (!options.poll?.enabled) return;
if (!options.poll.intervalMs) return;
const interval = setInterval(() => {
router.refresh();
}, options.poll.intervalMs);
return () => clearInterval(interval);
}, [options.poll?.enabled, options.poll?.intervalMs, router]);
useEffect(() => {
if (!options.sse?.enabled) return;
if (!options.sse.url) return;
const eventSource = new EventSource(options.sse.url);
eventSourceRef.current = eventSource;
const eventName = options.sse.eventName ?? "message";
eventSource.addEventListener(eventName, (event: MessageEvent) => {
let payload: unknown = event.data;
try {
payload = JSON.parse(event.data);
} catch {
// keep raw payload
}
const shouldRefresh =
options.sse?.shouldRefresh?.(payload) ?? true;
if (shouldRefresh) {
console.log("Received event source", eventSource);
router.refresh();
}
});
return () => {
eventSource.close();
eventSourceRef.current = null;
};
}, [
options.sse?.enabled,
options.sse?.url,
options.sse?.eventName,
router,
]);
}