Fix server file root loading and refresh

This commit is contained in:
npc0-hue
2026-08-24 17:28:54 +08:00
parent d4e3f68032
commit 7e15cb09b4
7 changed files with 77 additions and 22 deletions
+26 -13
View File
@@ -1,5 +1,5 @@
import { ChevronRight, Download, Eye, FileText, Folder, MoonStar, PackageOpen, Pencil, RefreshCw, Save, Search, ShieldCheck, Sparkles, Square, Terminal, Upload, UserRoundMinus, UserRoundPlus, WandSparkles, X } from "lucide-react";
import { type ChangeEvent, type FormEvent, useCallback, useEffect, useMemo, useState } from "react";
import { type ChangeEvent, type FormEvent, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { platformApiClient } from "../api/client";
import type {
@@ -569,12 +569,14 @@ function ServerFilesSection({ instance, session, operations }: ServerFilesSectio
const [panelResult, setPanelResult] = useState<{ status: "pending" | "succeeded" | "failed"; label: string } | null>(null);
const [uploadBusy, setUploadBusy] = useState(false);
const [editor, setEditor] = useState<ServerFileEditorState>({ entry: null, key: "", draft: "", loading: false, saving: false });
const initialRuntimeLoadRef = useRef(false);
const activeDirectory = workspace.status === "ready" ? workspace.data.directories.find((item) => item.key === directoryKey) : undefined;
const canUpload = workspace.status === "ready" && Boolean(activeDirectory) && !uploadBusy;
const entries = list.status === "ready" ? list.data.entries : [];
const loadWorkspace = useCallback(async () => {
initialRuntimeLoadRef.current = false;
setWorkspace({ status: "loading" });
try {
const response = await platformApiClient.getServerFileWorkspace(instance.id);
@@ -603,26 +605,37 @@ function ServerFilesSection({ instance, session, operations }: ServerFilesSectio
void loadWorkspace();
}, [loadWorkspace]);
useEffect(() => {
if (workspace.status !== "ready" || !directoryKey) return;
void loadList();
}, [directoryKey, loadList, workspace.status]);
async function refreshRuntimeList() {
const refreshRuntimeList = useCallback(async (options: { silent?: boolean } = {}) => {
if (!directoryKey) return;
const operationId = operations.begin({ intent: "刷新文件目录", targetKind: "server", targetId: instance.id, requester: session.displayName });
setPanelResult({ status: "pending", label: "正在向 Run 请求实时目录…" });
const operationId = options.silent ? "" : operations.begin({ intent: "刷新文件目录", targetKind: "server", targetId: instance.id, requester: session.displayName });
if (!options.silent) setPanelResult({ status: "pending", label: "正在向 Run 请求实时目录…" });
try {
const response = await platformApiClient.refreshServerFiles(instance.id, { directoryKey, path: relativePath || undefined, query: searchQuery || undefined, recursive, idempotencyKey: serverFileIdempotency("list", instance.id, directoryKey) });
setList({ status: "ready", data: response });
operations.succeed(operationId, `目录刷新任务 ${response.job?.id ?? "已派发"}`, response.job);
if (operationId) operations.succeed(operationId, `目录刷新任务 ${response.job?.id ?? "已派发"}`, response.job);
setPanelResult({ status: "pending", label: response.reason ?? "目录刷新任务已派发,稍后可再次刷新查看实时结果。" });
} catch (error) {
const reason = error instanceof Error ? error.message : "目录刷新失败";
operations.fail(operationId, reason, operationId);
if (operationId) operations.fail(operationId, reason, operationId);
setPanelResult({ status: "failed", label: reason });
}
}
}, [directoryKey, instance.id, operations, relativePath, recursive, searchQuery, session.displayName]);
useEffect(() => {
if (workspace.status !== "ready" || !directoryKey) return;
if (!initialRuntimeLoadRef.current) {
initialRuntimeLoadRef.current = true;
void refreshRuntimeList({ silent: true });
return;
}
void loadList();
}, [directoryKey, loadList, refreshRuntimeList, workspace.status]);
useEffect(() => {
if (workspace.status !== "ready" || !directoryKey || list.status !== "ready" || list.data.state !== "pending") return;
const timer = window.setInterval(() => void loadList(), 2000);
return () => window.clearInterval(timer);
}, [directoryKey, list, loadList, workspace.status]);
async function openEntry(entry: ServerFileEntryResponse) {
if (entry.kind === "directory") {
@@ -781,7 +794,7 @@ function ServerFilesSection({ instance, session, operations }: ServerFilesSectio
<table className="resource-table server-file-table">
<thead><tr><th></th><th></th><th></th><th></th><th></th></tr></thead>
<tbody>
{entries.length === 0 && <tr><td colSpan={5}><span className="provider-id"></span></td></tr>}
{entries.length === 0 && <tr><td colSpan={5}><span className="provider-id">{list.data.state === "pending" ? "正在读取当前目录,Run 返回后会自动更新。" : "当前目录暂无文件。"}</span></td></tr>}
{entries.map((entry) => (
<tr key={serverFileEntryRowKey(entry)} className={entry.kind === "directory" ? "server-file-directory-row" : undefined}>
<td>