diff --git a/platform_web/components/ServerDeploymentWorkflow.tsx b/platform_web/components/ServerDeploymentWorkflow.tsx index dcc8ae3..b922000 100644 --- a/platform_web/components/ServerDeploymentWorkflow.tsx +++ b/platform_web/components/ServerDeploymentWorkflow.tsx @@ -1,4 +1,4 @@ -import { CheckCircle2, CircleDashed, Compass, FolderCog, Rocket, ServerCog } from "lucide-react"; +import { CheckCircle2, CircleDashed, Compass, Download, FolderCog, HeartPulse, Rocket, ScanSearch, ServerCog, SlidersHorizontal } from "lucide-react"; import { type ChangeEvent, type FormEvent, useEffect, useMemo, useState } from "react"; import type { GamePluginResponse, RunEndpointResponse, ServerDeploymentResponse } from "../api/types"; @@ -108,6 +108,7 @@ export function ServerDeploymentWorkflow({ open, kind, plugins, endpoints, initi )} ))} + {form.deploymentMode === "guided-install" && } {form.deploymentMode === "existing-server" &&
接管只做预检与绑定不会执行安装命令,也不会把本页的默认游戏参数写进已有服务器。
} {form.deploymentMode === "custom-command" &&
高级启动设置

只有自定义启动器需要这些设置。执行目录留空时,节点以服务器目录执行。

} {kind === "create" && bindingFields.length > 0 &&
运行连接设置

用于插件声明的逻辑连接,不是服务器目录或游戏配置。

{bindingFields.map((field) => )}
} @@ -119,3 +120,19 @@ export function ServerDeploymentWorkflow({ open, kind, plugins, endpoints, initi } function ModeOption({ active, title, copy, onClick }: { active: boolean; title: string; copy: string; onClick: () => void }) { return ; } + +function GuidedInstallPlan({ pluginName, isScum }: { pluginName: string; isScum: boolean }) { + const steps = isScum ? [ + { icon: ScanSearch, title: "预检目录与端口", copy: "确认安装目录可用、节点兼容且端口可绑定。" }, + { icon: Download, title: "下载 SCUM Server", copy: "通过 SteamCMD 安装 App 3792580 到该目录。" }, + { icon: SlidersHorizontal, title: "写入游戏配置", copy: "把本页的名称、端口与人数写入 ServerSettings.ini。" }, + { icon: HeartPulse, title: "启动并健康验证", copy: "检查可执行文件、版本、配置、端口和服务进程。" } + ] : [ + { icon: ScanSearch, title: "预检目录与节点", copy: "确认安装目录、权限、端口与运行节点可用。" }, + { icon: Download, title: "安装游戏服务端", copy: "按插件声明的推荐方案安装到该目录。" }, + { icon: SlidersHorizontal, title: "写入游戏配置", copy: "将本页填写的游戏参数交给受控部署流程。" }, + { icon: HeartPulse, title: "启动并健康验证", copy: "只有启动与插件要求的验证通过才会显示成功。" } + ]; + + return
确认后,{pluginName} 会这样安装“安装目录”就是游戏服务端、数据和配置将落地的位置;它不是命令执行目录,也不会在日志中回显。
{isScum ? "全部 4 步通过才算安装成功" : "节点按插件契约执行"}
    {steps.map(({ icon: Icon, title, copy }, index) =>
  1. {index + 1}. {title}{copy}
  2. )}

不会做:{isScum ? "不会跳过验证就标记成功;失败时不会暴露你的目录、命令或凭据。" : "不会把受保护的路径、命令或凭据回显给浏览器。"}

; +} diff --git a/platform_web/pages/ConsolePages.test.tsx b/platform_web/pages/ConsolePages.test.tsx index 9215677..56d7d76 100644 --- a/platform_web/pages/ConsolePages.test.tsx +++ b/platform_web/pages/ConsolePages.test.tsx @@ -180,6 +180,10 @@ describe("first-party console pages", () => { expect(serverDeploymentWorkflowSource).toContain("执行目录(可选)"); expect(serverDeploymentWorkflowSource).toContain("默认使用服务器目录"); expect(serverDeploymentWorkflowSource).toContain("安装目录{isScum ? \"(必填)\" : \"(可选)\"}"); + expect(serverDeploymentWorkflowSource).toContain("新建并安装执行流程"); + expect(serverDeploymentWorkflowSource).toContain("安装目录”就是游戏服务端、数据和配置将落地的位置"); + expect(serverDeploymentWorkflowSource).toContain("通过 SteamCMD 安装 App 3792580 到该目录"); + expect(serverDeploymentWorkflowSource).toContain("全部 4 步通过才算安装成功"); expect(serverDeploymentWorkflowSource).toContain("已有服务器目录"); expect(serverDeploymentWorkflowSource).toContain("不会重装或覆盖现有游戏配置"); expect(serverDeploymentWorkflowSource).toContain("运行连接设置"); diff --git a/platform_web/theme/base-css.test.js b/platform_web/theme/base-css.test.js index 4afe6bb..14ce563 100644 --- a/platform_web/theme/base-css.test.js +++ b/platform_web/theme/base-css.test.js @@ -172,6 +172,14 @@ describe("platform web shared theme CSS", () => { expect(css).toContain(".deployment-workflow-body.form-grid{align-content:start;align-items:start;grid-auto-rows:min-content}"); }); + it("keeps the guided-install plan compact and responsive inside the deployment workflow", () => { + const css = compact(readThemeCss()); + + expect(css).toContain(".guided-install-plan{display:grid;gap:10px;padding:12px;border:1pxsolidcolor-mix(insrgb,var(--accent)42%,var(--line));border-radius:8px"); + expect(css).toContain(".guided-install-planol{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px"); + expect(css).toContain(".guided-install-planol,.maintenance-node-item"); + }); + it("keeps magical card decoration from becoming square background patches", () => { const css = compact(readThemeCss()); diff --git a/platform_web/theme/base.css b/platform_web/theme/base.css index 728d448..851092f 100644 --- a/platform_web/theme/base.css +++ b/platform_web/theme/base.css @@ -496,6 +496,7 @@ to{transform:translate(-50%,-50%) rotate(calc(var(--construct-drift) + 360deg))} .management-dialog-panel .management-form{grid-template-columns:repeat(2,minmax(0,1fr))} .management-dialog-panel .dialog-form .confirm-actions,.management-dialog-panel .dialog-form .role-selector{grid-column:1/-1} .server-deployment-workflow{display:grid;gap:14px}.deployment-workflow-steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:0;padding:0;list-style:none}.deployment-workflow-steps li{display:flex;align-items:center;gap:6px;min-height:38px;padding:8px;border:1px solid var(--line);border-radius:8px;background:var(--control-surface);color:var(--ink-faint);font-size:12px}.deployment-workflow-steps li>span{display:inline-flex;align-items:center;justify-content:center;color:var(--ink-soft)}.deployment-workflow-steps strong{font-size:12px}.deployment-workflow-step-active{border-color:var(--accent)!important;background:var(--primary-command-surface)!important;color:#fff!important;box-shadow:0 0 16px var(--accent-soft)}.deployment-workflow-step-complete{border-color:color-mix(in srgb,var(--teal) 68%,var(--line));color:var(--ink)!important}.deployment-workflow-body{display:grid;align-content:start;gap:12px;min-height:0}.deployment-workflow-body .form-grid{align-content:start;align-items:start;grid-auto-rows:min-content}.deployment-workflow-body .form-grid>label{align-content:start}.deployment-draft-choice{grid-template-columns:auto minmax(0,1fr);align-items:start;padding:10px 12px;border:1px dashed var(--line-strong);border-radius:8px;background:color-mix(in srgb,var(--surface-solid) 62%,transparent)}.deployment-draft-choice input{width:auto!important;min-height:auto!important;margin-top:3px}.deployment-draft-choice span{display:grid;gap:3px}.deployment-draft-choice small{color:var(--ink-faint);font-weight:600;line-height:1.4}.deployment-mode-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}.deployment-mode-option{display:grid;align-content:start;gap:5px;min-height:130px;padding:14px;border:1px solid var(--line);border-radius:8px;background:var(--control-surface);color:var(--ink-soft);cursor:pointer;text-align:left}.deployment-mode-option strong{color:var(--ink);font-size:14px}.deployment-mode-option span{font-size:12px;line-height:1.45}.deployment-mode-option:hover,.deployment-mode-option:focus-visible,.deployment-mode-option-active{border-color:var(--accent);outline:0;box-shadow:inset 0 1px 0 var(--crystal-rim),0 0 0 2px var(--accent-soft);background:var(--menu-item-active-bg)}.deployment-review{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.deployment-review>div{display:grid;gap:3px;padding:10px;border:1px solid var(--line);border-radius:8px;background:color-mix(in srgb,var(--surface-solid) 64%,transparent)}.deployment-review span{color:var(--ink-faint);font-size:11.5px;font-weight:700}.deployment-review strong{color:var(--ink);font-size:13px;overflow-wrap:anywhere} +.guided-install-plan{display:grid;gap:10px;padding:12px;border:1px solid color-mix(in srgb,var(--accent) 42%,var(--line));border-radius:8px;background:linear-gradient(135deg,color-mix(in srgb,var(--primary-command-surface) 46%,transparent),color-mix(in srgb,var(--surface-solid) 72%,transparent));box-shadow:inset 0 1px 0 var(--crystal-rim)}.guided-install-plan-heading{display:flex;align-items:start;justify-content:space-between;gap:12px}.guided-install-plan-heading>div{display:grid;gap:3px}.guided-install-plan-heading strong,.guided-install-plan li strong,.guided-install-plan p strong{color:var(--ink);font-size:13px}.guided-install-plan-heading span,.guided-install-plan small,.guided-install-plan p{color:var(--ink-soft);font-size:12px;line-height:1.45}.guided-install-plan-heading>small{flex:0 0 auto;padding:3px 6px;border:1px solid var(--line);border-radius:999px;color:var(--accent);font-weight:750}.guided-install-plan ol{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin:0;padding:0;list-style:none}.guided-install-plan li{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:7px;padding:8px;border:1px solid var(--line);border-radius:6px;background:color-mix(in srgb,var(--surface-solid) 62%,transparent)}.guided-install-plan li>span{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border:1px solid color-mix(in srgb,var(--accent) 44%,var(--line));border-radius:50%;color:var(--accent);background:var(--control-surface)}.guided-install-plan li>div{display:grid;gap:2px}.guided-install-plan li small{font-size:11.5px}.guided-install-plan p{margin:0;padding-top:2px} .management-dialog-panel .plugin-detail-panel,.management-dialog-panel .plugin-group{border:0;padding:0;background:0 0;box-shadow:none;clip-path:none} .management-dialog-panel .plugin-group::after,.management-dialog-panel .plugin-group::before{content:none} .plugin-detail-actions{align-items:stretch} @@ -624,7 +625,7 @@ to{transform:translate(-50%,-50%) rotate(calc(var(--construct-drift) + 360deg))} } @media (max-width:760px){.auth-shell{padding:14px;place-items:stretch} .auth-card{align-self:center} -.access-list-row,.deployment-mode-grid,.deployment-review,.deployment-workflow-steps,.maintenance-node-item,.maintenance-triage-grid,.management-form,.profile-background-grid,.profile-palette-grid,.profile-settings-form-row,.profile-settings-grid,.profile-settings-hero,.provider-preset-grid,.runtime-task-stages,.user-management-item,.workflow-hint-grid{grid-template-columns:1fr} +.access-list-row,.deployment-mode-grid,.deployment-review,.deployment-workflow-steps,.guided-install-plan ol,.maintenance-node-item,.maintenance-triage-grid,.management-form,.profile-background-grid,.profile-palette-grid,.profile-settings-form-row,.profile-settings-grid,.profile-settings-hero,.provider-preset-grid,.runtime-task-stages,.user-management-item,.workflow-hint-grid{grid-template-columns:1fr}.guided-install-plan-heading{display:grid} .console-row-actions,.maintenance-actions,.profile-settings-actions,.user-actions{justify-content:flex-start} .app-shell{display:block;grid-template-columns:1fr} .app-sidebar{position:fixed;inset:0 auto 0 0;z-index:60;width:min(82vw,300px);min-width:0;height:100dvh;display:flex;flex-direction:column;gap:12px;align-items:stretch;padding:max(14px,env(safe-area-inset-top)) 12px max(14px,env(safe-area-inset-bottom));border-right:1px solid color-mix(in srgb,var(--line-strong) 74%,transparent);border-bottom:0;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;opacity:0;visibility:hidden;pointer-events:none;transform:translateX(calc(-100% - 18px));transition:transform .2s ease,opacity 160ms ease,visibility .2s step-end}