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('')[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}