mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Adding useAutoRefresh on agent page.
This commit is contained in:
@@ -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}/>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
]);
|
||||
}
|
||||
Reference in New Issue
Block a user