diff --git a/platform_web/pages/ServerDetailPage.test.tsx b/platform_web/pages/ServerDetailPage.test.tsx index df2a1e5..b85fa51 100644 --- a/platform_web/pages/ServerDetailPage.test.tsx +++ b/platform_web/pages/ServerDetailPage.test.tsx @@ -35,11 +35,19 @@ describe("ServerDetailPage config write approval", () => { it("keeps the detail header focused on a single shared action row", () => { expect(serverDetailPageSource).not.toContain("Run 心跳"); expect(serverDetailPageSource).not.toContain("已自动附着"); - expect(serverDetailPageSource).toContain('返回列表'); - expect(serverDetailPageSource).toContain('刷新'); - expect(serverDetailPageSource).toContain('打开终端'); - expect(serverDetailPageSource).toContain('启动'); - expect(serverDetailPageSource).toContain('停止'); + const headerSource = serverDetailPageSource.split('
')[1]?.split('
')[0] ?? ""; + expect(headerSource).toContain('返回列表'); + expect(headerSource).not.toContain('刷新'); + expect(headerSource).toContain('打开终端'); + expect(headerSource).toContain('启动'); + expect(headerSource).toContain('停止'); + const actionStripSource = headerSource.split('
')[1]?.split('
')[0] ?? ""; + expect(actionStripSource.indexOf('停止')).toBeLessThan(actionStripSource.indexOf('detailStateText')); + }); + + it("opens the plugin user management page by default when available", () => { + expect(serverDetailPageSource).toContain('page.key === "players"'); + expect(serverDetailPageSource).toContain('setSection(`plugin:${defaultPluginPage.key}`)'); }); it("maps platform diff preview responses into the display diff without losing approval metadata", () => { diff --git a/platform_web/pages/ServerDetailPage.tsx b/platform_web/pages/ServerDetailPage.tsx index 87d2813..f969352 100644 --- a/platform_web/pages/ServerDetailPage.tsx +++ b/platform_web/pages/ServerDetailPage.tsx @@ -52,6 +52,7 @@ export function ServerDetailPage(props: PageComponentProps) { const [confirm, setConfirm] = useState Promise }>(null); const [confirmBusy, setConfirmBusy] = useState(false); const [terminalOpen, setTerminalOpen] = useState(false); + const defaultSectionResolvedRef = useRef(false); const refresh = useCallback(async () => { if (!serverId) { @@ -112,6 +113,7 @@ export function ServerDetailPage(props: PageComponentProps) { const detailFreshness = instance.status === "ready" ? runtimeObservationFreshness(instance.data, runEndpoint) : "unverified"; const detailStateText = instance.status === "ready" && detailFreshness === "fresh" ? stateLabel(instance.data.state) : instance.status === "ready" ? `最后观测:${stateLabel(instance.data.state)}(Run 未验证)` : "未验证"; const detailSections = useMemo(() => serverDetailSectionEntries(readyPlugin), [readyPlugin]); + const defaultPluginPage = readyPlugin?.pages.find((page) => page.key === "players") ?? readyPlugin?.pages[0]; useEffect(() => { if (!params.routeKey || !readyPlugin?.pages.some((page) => page.key === params.routeKey)) return; @@ -123,6 +125,13 @@ export function ServerDetailPage(props: PageComponentProps) { setSection(detailSections[0]?.id ?? "manage"); }, [detailSections, section]); + useEffect(() => { + if (params.routeKey || !defaultPluginPage || defaultSectionResolvedRef.current) return; + defaultSectionResolvedRef.current = true; + if (section !== "manage") return; + setSection(`plugin:${defaultPluginPage.key}`); + }, [defaultPluginPage, params.routeKey, section]); + function requestLifecycle(current: ServerInstanceResponse, action: "start" | "stop") { setConfirm({ title: action === "start" ? "启动服务器" : "停止服务器", @@ -181,11 +190,6 @@ export function ServerDetailPage(props: PageComponentProps) { 返回列表 - - {detailStateText} + {detailStateText}