Commit 6008eeb5 authored by AI-甘富林's avatar AI-甘富林

调整客户端设置页布局并补充运行时路径

parent 97645407
......@@ -354,6 +354,7 @@ export class ProjectWorkspaceExecutorService {
PYTHONUTF8: "1",
PYTHONIOENCODING: "utf-8",
PATH: [
paths.nodeExecutable ? path.dirname(paths.nodeExecutable) : null,
paths.ffmpegExecutable ? path.dirname(paths.ffmpegExecutable) : null,
paths.ffprobeExecutable ? path.dirname(paths.ffprobeExecutable) : null,
path.join(paths.runtimeDir, "python", "Scripts"),
......
......@@ -5065,16 +5065,13 @@ export default function App() {
<div className="page-stack settings-page-stack settings-page-shell">
{showSettingsStatusHint ? <div className={"inline-hint settings-runtime-hint" + (chatLaunchState === "error" ? " error" : "")}>{startupMessage}</div> : null}
<div className="settings-console-grid">
<section className="panel settings-panel settings-panel-modern settings-panel-connection">
<div className="settings-section-card settings-section-card-compact">
<div className="settings-section-headline">
<div>
<section className="panel settings-panel settings-panel-modern settings-panel-basic-config">
<div className="settings-section-card settings-section-card-compact settings-basic-config-card">
<div className="settings-section-headline settings-section-headline-basic">
<span className="settings-section-kicker">基础配置</span>
<h4>客户端绑定</h4>
</div>
<StatusChip tone={workspace?.apiKeyConfigured ? "positive" : "warning"}>{workspace?.apiKeyConfigured ? "已绑定" : "未绑定"}</StatusChip>
</div>
<div className="settings-inline-key-row">
<div className="settings-basic-config-form">
<div className="settings-basic-config-row">
<label className="settings-input-label">
<span className="settings-input-label-text">龙虾密钥</span>
<input
......@@ -5086,19 +5083,11 @@ export default function App() {
</label>
<button className="settings-primary-button settings-inline-save-button" disabled={saving || !hasPendingLobsterKey} onClick={() => void saveConfig({ lobsterKey: lobsterKeyDraft })}>{saving ? ui.saving : "保存"}</button>
</div>
</div>
</section>
<section className="panel settings-panel settings-panel-secondary settings-panel-diagnostics">
<div className="settings-section-card settings-section-card-compact">
<div className="settings-section-headline">
<div>
<span className="settings-section-kicker">诊断与工作区</span>
<h4>工作目录</h4>
</div>
<StatusChip tone={hasPendingWorkspacePathChange ? "warning" : "info"}>{hasPendingWorkspacePathChange ? "待保存" : "已同步"}</StatusChip>
</div>
<div className="workspace-directory-card">
<div className="workspace-directory-panel">
<div className="settings-basic-config-row settings-basic-config-row-directory">
<div className="settings-input-label settings-directory-label">
<span className="settings-input-label-text">工作目录</span>
<div className="workspace-directory-card settings-basic-directory-card">
<div className="workspace-directory-panel settings-basic-directory-panel">
<strong className="workspace-directory-path">{displayedWorkspacePath}</strong>
</div>
{hasPendingWorkspacePathChange ? (
......@@ -5111,11 +5100,14 @@ export default function App() {
</div>
) : null}
</div>
<div className="button-row settings-actions workspace-directory-actions">
</div>
<div className="button-row settings-actions workspace-directory-actions settings-basic-directory-actions">
<button className="settings-primary-button" disabled={saving || !config} onClick={() => void pickWorkspaceDirectory()}>更改目录</button>
<button className="secondary" disabled={saving} onClick={() => void exportDiagnostics()}>{ui.export}</button>
</div>
</div>
</div>
</div>
</section>
<section className="panel settings-panel settings-panel-secondary settings-panel-xhs-feishu">
<div className="settings-section-card settings-section-card-compact">
......
......@@ -4113,14 +4113,18 @@ button.secondary {
min-height: 0;
display: grid;
gap: 10px;
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-template-columns: minmax(0, 1.15fr) minmax(380px, 0.85fr);
grid-template-rows: minmax(236px, 0.58fr) minmax(0, 1.42fr);
grid-template-areas:
"connection diagnostics xhs-feishu"
"models models models";
"basic-config xhs-feishu"
"models models";
overflow: hidden;
}
.settings-panel-basic-config {
grid-area: basic-config;
}
.settings-panel-connection {
grid-area: connection;
}
......@@ -4282,13 +4286,69 @@ button.secondary {
display: grid;
}
.settings-basic-config-card {
grid-template-rows: auto minmax(0, 1fr);
gap: 8px;
}
.settings-section-headline-basic {
align-items: flex-start;
justify-content: flex-start;
}
.settings-basic-config-form {
min-height: 0;
display: grid;
align-content: center;
gap: 10px;
}
.settings-basic-config-row {
min-width: 0;
display: grid;
grid-template-columns: minmax(0, 1fr) max-content;
align-items: end;
gap: 10px;
}
.settings-basic-config-row-directory {
align-items: start;
}
.settings-basic-directory-card {
gap: 6px;
}
.settings-basic-directory-panel {
min-height: 38px;
align-items: center;
}
.settings-basic-directory-actions {
display: grid;
grid-auto-flow: column;
grid-auto-columns: 78px;
align-self: end;
}
.settings-basic-directory-actions button,
.settings-inline-save-button {
min-width: 88px;
padding-inline: 16px;
justify-self: start;
height: 38px;
min-height: 38px;
padding-block: 0;
padding-inline: 8px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 12px;
white-space: nowrap;
}
.settings-inline-save-button {
min-width: 64px;
justify-self: start;
}
.settings-input-label {
min-width: 0;
gap: 5px;
......@@ -4525,6 +4585,20 @@ button.secondary {
grid-template-rows: auto minmax(0, 1fr) auto;
}
.settings-panel-basic-config .settings-section-card {
grid-template-rows: auto minmax(0, 1fr);
}
.settings-panel-basic-config .workspace-directory-card {
gap: 6px;
}
.settings-panel-basic-config .workspace-directory-panel {
min-height: 38px;
height: auto;
align-items: center;
}
.workspace-directory-eyebrow {
font-size: 10px;
letter-spacing: 0.16em;
......@@ -4552,11 +4626,10 @@ button.secondary {
@media (max-width: 1180px) {
.settings-console-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-rows: minmax(164px, auto) minmax(210px, auto) minmax(0, 1fr);
grid-template-columns: minmax(0, 1.1fr) minmax(340px, 0.9fr);
grid-template-rows: minmax(164px, auto) minmax(0, 1fr);
grid-template-areas:
"connection diagnostics"
"xhs-feishu xhs-feishu"
"basic-config xhs-feishu"
"models models";
}
......@@ -4594,8 +4667,7 @@ button.secondary {
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-template-areas:
"connection"
"diagnostics"
"basic-config"
"xhs-feishu"
"models";
overflow: visible;
......@@ -4612,6 +4684,21 @@ button.secondary {
grid-template-columns: minmax(0, 1fr);
}
.settings-basic-config-row {
grid-template-columns: minmax(0, 1fr);
}
.settings-inline-save-button,
.settings-basic-directory-actions {
justify-self: stretch;
}
.settings-basic-directory-actions {
grid-auto-flow: row;
grid-auto-columns: unset;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.settings-field-grid-digital-human {
grid-template-columns: 1fr;
}
......@@ -4653,6 +4740,10 @@ button.secondary {
.workspace-directory-actions button {
width: 100%;
}
.settings-basic-directory-actions {
grid-template-columns: 1fr;
}
}
.composer-attachment-input {
......
......@@ -43,8 +43,10 @@ async function main(): Promise<void> {
assert(existsSync(powerShellPath), "Windows PowerShell was not found for workspace automation smoke.");
const stableRuntimeDir = path.join(tempRoot, "stable-runtime");
const stableNodePath = path.join(stableRuntimeDir, "node", "node.exe");
const stableFfmpegPath = path.join(stableRuntimeDir, "ffmpeg", "bin", "ffmpeg.exe");
const stableFfprobePath = path.join(stableRuntimeDir, "ffmpeg", "bin", "ffprobe.exe");
await writeUtf8(stableNodePath, "stable-node");
await writeUtf8(stableFfmpegPath, "stable-ffmpeg");
await writeUtf8(stableFfprobePath, "stable-ffprobe");
......@@ -89,6 +91,7 @@ async function main(): Promise<void> {
"$payload = @{",
" FFMPEG_BIN = [string]$env:FFMPEG_BIN",
" FFPROBE_BIN = [string]$env:FFPROBE_BIN",
" PATH = [string]$env:PATH",
"} | ConvertTo-Json -Compress",
"Write-Output 'QJC_WORKSPACE_EVENT\t{\"type\":\"started\",\"runId\":\"ffmpeg-runtime-smoke-run\"}'",
"Write-Output ('QJC_WORKSPACE_EVENT\t{\"type\":\"completed\",\"content\":' + (ConvertTo-Json $payload -Compress) + '}')",
......@@ -108,7 +111,7 @@ async function main(): Promise<void> {
resolveBundledPaths() {
return {
runtimeDir: stableRuntimeDir,
nodeExecutable: path.join(stableRuntimeDir, "node", "node.exe"),
nodeExecutable: stableNodePath,
openClawEntry: path.join(stableRuntimeDir, "openclaw", "index.js"),
packagedOpenClawEntry: path.join(stableRuntimeDir, "openclaw", "package", "openclaw.mjs"),
runtimeManifestPath: path.join(stableRuntimeDir, "runtime-manifest.json"),
......@@ -136,13 +139,19 @@ async function main(): Promise<void> {
projectRoot,
prompt: "verify ffmpeg injection"
});
assert("reply" in execution, "Workspace automation did not complete with a reply.");
const injectedPayload = JSON.parse(execution.reply.content || "{}") as {
FFMPEG_BIN?: string;
FFPROBE_BIN?: string;
PATH?: string;
};
assert(injectedPayload.FFMPEG_BIN === stableFfmpegPath, "Workspace automation did not receive the bundled FFMPEG_BIN path.");
assert(injectedPayload.FFPROBE_BIN === stableFfprobePath, "Workspace automation did not receive the bundled FFPROBE_BIN path.");
assert(
(injectedPayload.PATH ?? "").split(path.delimiter).includes(path.dirname(stableNodePath)),
"Workspace automation PATH did not include the bundled runtime/node directory."
);
const summary = {
ok: true,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment