Scope project refreshes and harden deploy script

This commit is contained in:
kris
2026-04-07 17:20:53 +08:00
parent 1de9ae0492
commit 8fc94f1849
8 changed files with 96 additions and 7 deletions

View File

@@ -1,4 +1,5 @@
import { notFound } from "next/navigation";
import { RealtimeRefresh } from "@/components/app-runtime";
import {
AppShell,
GoalChecklist,
@@ -25,6 +26,7 @@ export default async function GoalsPage({
return (
<AppShell bottomNav={false}>
<RealtimeRefresh projectId={projectId} events={["conversation.updated"]} />
<StatusBar />
<PageNav title="项目目标" backHref={`/conversations/${projectId}`} />
<div className="flex flex-col gap-3 px-[18px] pb-6">

View File

@@ -44,6 +44,7 @@ export default async function ProjectChatPage({
return (
<AppShell bottomNav={false}>
<RealtimeRefresh
projectId={detail.project.id}
events={[
"conversation.updated",
"project.messages.updated",

View File

@@ -1,4 +1,5 @@
import { notFound } from "next/navigation";
import { RealtimeRefresh } from "@/components/app-runtime";
import { AppShell, PageNav, StatusBar } from "@/components/app-ui";
import { requirePageSession } from "@/lib/boss-auth";
import { readState } from "@/lib/boss-data";
@@ -39,6 +40,7 @@ export default async function ThreadStatusPage({
return (
<AppShell bottomNav={false}>
<RealtimeRefresh projectId={projectId} events={["conversation.updated", "project.messages.updated"]} />
<StatusBar />
<PageNav title="线程状态" backHref={`/conversations/${projectId}`} />
<div className="space-y-3 px-[18px] pb-6">

View File

@@ -1,4 +1,5 @@
import { notFound } from "next/navigation";
import { RealtimeRefresh } from "@/components/app-runtime";
import {
AppShell,
PageNav,
@@ -22,6 +23,10 @@ export default async function VersionsPage({
return (
<AppShell bottomNav={false}>
<RealtimeRefresh
projectId={projectId}
events={["conversation.updated", "project.messages.updated", "ota.updated"]}
/>
<StatusBar />
<PageNav title="版本迭代记录" backHref={`/conversations/${projectId}`} />
<div className="flex flex-col gap-3 px-[18px] pb-6">

View File

@@ -253,31 +253,60 @@ export function NativeAppBridge() {
export function RealtimeRefresh({
events,
projectId,
}: {
events: BossEventName[];
projectId?: string;
}) {
const router = useRouter();
useEffect(() => {
const source = new EventSource("/api/v1/events");
const refresh = () => router.refresh();
const listeners = [
const listeners = Array.from(new Set([
"conversation.context_indicator.updated",
"project.context_risk.updated",
...events,
];
]));
const shouldRefresh = (event: Event) => {
if (!projectId || !("data" in event) || typeof event.data !== "string" || !event.data.trim()) {
return true;
}
try {
const payload = JSON.parse(event.data) as { projectId?: string };
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
return true;
}
if (typeof payload.projectId !== "string" || !payload.projectId.trim()) {
return true;
}
return payload.projectId === projectId;
} catch {
return true;
}
};
const listenerMap = new Map<string, (event: Event) => void>();
for (const event of listeners) {
const refresh = (nextEvent: Event) => {
if (!shouldRefresh(nextEvent)) {
return;
}
router.refresh();
};
listenerMap.set(event, refresh);
source.addEventListener(event, refresh);
}
return () => {
for (const event of listeners) {
source.removeEventListener(event, refresh);
const refresh = listenerMap.get(event);
if (refresh) {
source.removeEventListener(event, refresh);
}
}
source.close();
};
}, [events, router]);
}, [events, projectId, router]);
return null;
}