Remove AI config approval flow

This commit is contained in:
npc0-hue
2026-09-22 15:33:32 +08:00
parent 20008b4043
commit a8b5d483a3
54 changed files with 364 additions and 875 deletions
@@ -75,10 +75,11 @@ interface ServerManagementTerminalDrawerProps {
open: boolean;
serverId: string;
serverName: string;
jobId?: string;
onClose: () => void;
}
export function ServerManagementTerminalDrawer({ open, serverId, serverName, onClose }: ServerManagementTerminalDrawerProps) {
export function ServerManagementTerminalDrawer({ open, serverId, serverName, jobId, onClose }: ServerManagementTerminalDrawerProps) {
const [command, setCommand] = useState("");
const [pending, setPending] = useState(false);
const [result, setResult] = useState<{ status: "pending" | "succeeded" | "failed"; label: string } | null>(null);
@@ -140,7 +141,7 @@ export function ServerManagementTerminalDrawer({ open, serverId, serverName, onC
followLatestRef.current = true;
setFollowLatest(true);
setLines([terminalSystemLine("info", "正在连接当前受管进程输出。", "SYSTEM", undefined, serverTimeRef.current)]);
}, [open]);
}, [jobId, open]);
useEffect(() => {
if (!open || initialHistoryPendingRef.current || !followLatestRef.current) return undefined;
@@ -153,7 +154,7 @@ export function ServerManagementTerminalDrawer({ open, serverId, serverName, onC
const hydrateCurrentSessionHistory = useCallback((sessionId: string | null | undefined) => {
if (!sessionId) return;
const streamsToHydrate = liveStreamsRef.current.filter((stream) => eventBelongsToLiveSession(stream.logSessionId, sessionId) && stream.latestSeq > 0 && !hydratedLiveStreamKeysRef.current.has(liveHistoryStreamKey(sessionId, stream)));
const streamsToHydrate = liveStreamsRef.current.filter((stream) => (jobId ? stream.id.startsWith(`job.${jobId}.`) : eventBelongsToLiveSession(stream.logSessionId, sessionId)) && stream.latestSeq > 0 && !hydratedLiveStreamKeysRef.current.has(liveHistoryStreamKey(sessionId, stream)));
if (streamsToHydrate.length === 0) return;
const requestId = liveHistoryRequestRef.current + 1;
liveHistoryRequestRef.current = requestId;
@@ -172,12 +173,12 @@ export function ServerManagementTerminalDrawer({ open, serverId, serverName, onC
appendLines([terminalSystemLine("warn", "当前会话历史读取失败,继续等待实时输出。", "SYSTEM", `session-history-failed-${sessionId}`, serverTimeRef.current)]);
lockTerminalFollow();
});
}, [appendLines, lockTerminalFollow]);
}, [appendLines, jobId, lockTerminalFollow]);
useEffect(() => {
if (!open) return undefined;
let ready = false;
const events = platformApiClient.openServerLogEvents(serverId);
const events = platformApiClient.openServerLogEvents(serverId, { jobId });
events.addEventListener("session", (event) => {
const session = parseLogSessionEvent(event);
if (!session) return;
@@ -199,7 +200,7 @@ export function ServerManagementTerminalDrawer({ open, serverId, serverName, onC
});
events.addEventListener("stream", (event) => {
const stream = parseLogStreamEvent(event);
if (!stream || !eventBelongsToLiveSession(stream.logSessionId, liveSessionRef.current)) return;
if (!stream || (jobId ? !stream.id.startsWith(`job.${jobId}.`) : !eventBelongsToLiveSession(stream.logSessionId, liveSessionRef.current))) return;
ready = true;
liveStreamsRef.current = mergeLogStreams(liveStreamsRef.current, stream);
setStreams((current) => ({ status: "ready", data: mergeLogStreams(current.status === "ready" ? current.data : [], stream) }));
@@ -212,7 +213,7 @@ export function ServerManagementTerminalDrawer({ open, serverId, serverName, onC
});
events.addEventListener("log", (event) => {
const payload = parseServerLogEvent(event);
if (!payload || !eventBelongsToLiveSession(payload.logSessionId, liveSessionRef.current)) return;
if (!payload || (jobId ? !payload.streamId.startsWith(`job.${jobId}.`) : !eventBelongsToLiveSession(payload.logSessionId, liveSessionRef.current))) return;
ready = true;
const stream = streamFromServerLogEvent(payload);
liveStreamsRef.current = mergeLogStreams(liveStreamsRef.current, stream);
@@ -223,19 +224,20 @@ export function ServerManagementTerminalDrawer({ open, serverId, serverName, onC
if (!ready) setStreams({ status: "error", reason: "实时日志推送连接失败" });
};
return () => events.close();
}, [appendLines, hydrateCurrentSessionHistory, lockTerminalFollow, open, serverId]);
}, [appendLines, hydrateCurrentSessionHistory, jobId, lockTerminalFollow, open, serverId]);
useEffect(() => {
if (!open || !historyOpen) return;
let cancelled = false;
setHistoryStreams({ status: "loading" });
void platformApiClient.listLogStreams(serverId).then((response) => {
if (!cancelled) setHistoryStreams({ status: "ready", data: [...response.items].sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt)) });
const items = jobId ? response.items.filter((stream) => stream.id.startsWith(`job.${jobId}.`)) : response.items;
if (!cancelled) setHistoryStreams({ status: "ready", data: [...items].sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt)) });
}).catch((error) => {
if (!cancelled) setHistoryStreams({ status: "error", reason: error instanceof Error ? error.message : "历史日志列表加载失败" });
});
return () => { cancelled = true; };
}, [historyOpen, open, serverId]);
}, [historyOpen, jobId, open, serverId]);
async function selectHistoryStream(streamId: string) {
const stream = historyStreams.status === "ready" ? historyStreams.data.find((item) => item.id === streamId) : undefined;
@@ -312,7 +314,7 @@ export function ServerManagementTerminalDrawer({ open, serverId, serverName, onC
<div className="terminal-output-topbar">
<div>
<strong>{serverName}</strong>
<span>{historyOpen ? "历史日志(独立于实时终端)" : `当前受管进程会话${liveSessionId ? " · SSE 实时推送" : " · 等待 Run 输出"}`} · {streams.status === "ready" ? "已连接" : streams.status === "loading" ? "连接日志流" : "日志流异常"} · {followLatest ? "自动置底" : "已解锁滚动"}</span>
<span>{historyOpen ? "历史日志(独立于实时终端)" : jobId ? `AI 写入任务 ${jobId} · ${liveSessionId ? "SSE 实时推送" : "等待 Run 输出"}` : `当前受管进程会话${liveSessionId ? " · SSE 实时推送" : " · 等待 Run 输出"}`} · {streams.status === "ready" ? "已连接" : streams.status === "loading" ? "连接日志流" : "日志流异常"} · {followLatest ? "自动置底" : "已解锁滚动"}</span>
</div>
<div>
<button type="button" className="terminal-output-action" onClick={clearTerminalBuffer}><Trash2 size={14} /><span></span></button>