Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qjclaw-dmg
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
AI-甘富林
qjclaw-dmg
Commits
6008eeb5
Commit
6008eeb5
authored
Apr 29, 2026
by
AI-甘富林
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
调整客户端设置页布局并补充运行时路径
parent
97645407
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
151 additions
and
58 deletions
+151
-58
project-workspace-executor.ts
apps/desktop/src/main/services/project-workspace-executor.ts
+1
-0
App.tsx
apps/ui/src/App.tsx
+37
-45
styles.css
apps/ui/src/styles.css
+103
-12
ffmpeg-runtime-smoke.ts
build/scripts/ffmpeg-runtime-smoke.ts
+10
-1
No files found.
apps/desktop/src/main/services/project-workspace-executor.ts
View file @
6008eeb5
...
...
@@ -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"
),
...
...
apps/ui/src/App.tsx
View file @
6008eeb5
...
...
@@ -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">
...
...
apps/ui/src/styles.css
View file @
6008eeb5
...
...
@@ -4113,14 +4113,18 @@ button.secondary {
min-height
:
0
;
display
:
grid
;
gap
:
10px
;
grid-template-columns
:
repeat
(
3
,
minmax
(
0
,
1
fr
)
);
grid-template-columns
:
minmax
(
0
,
1.15
fr
)
minmax
(
380px
,
0.85
fr
);
grid-template-rows
:
minmax
(
236px
,
0.58
fr
)
minmax
(
0
,
1.42
fr
);
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
,
1
fr
);
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
,
1
fr
)
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
,
1
fr
)
auto
;
}
.settings-panel-basic-config
.settings-section-card
{
grid-template-rows
:
auto
minmax
(
0
,
1
fr
);
}
.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
,
1
fr
)
);
grid-template-rows
:
minmax
(
164px
,
auto
)
minmax
(
210px
,
auto
)
minmax
(
0
,
1
fr
);
grid-template-columns
:
minmax
(
0
,
1.1
fr
)
minmax
(
340px
,
0.9
fr
);
grid-template-rows
:
minmax
(
164px
,
auto
)
minmax
(
0
,
1
fr
);
grid-template-areas
:
"connection diagnostics"
"xhs-feishu xhs-feishu"
"basic-config xhs-feishu"
"models models"
;
}
...
...
@@ -4594,8 +4667,7 @@ button.secondary {
grid-template-columns
:
1
fr
;
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
,
1
fr
);
}
.settings-basic-config-row
{
grid-template-columns
:
minmax
(
0
,
1
fr
);
}
.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
,
1
fr
));
}
.settings-field-grid-digital-human
{
grid-template-columns
:
1
fr
;
}
...
...
@@ -4653,6 +4740,10 @@ button.secondary {
.workspace-directory-actions
button
{
width
:
100%
;
}
.settings-basic-directory-actions
{
grid-template-columns
:
1
fr
;
}
}
.composer-attachment-input
{
...
...
build/scripts/ffmpeg-runtime-smoke.ts
View file @
6008eeb5
...
...
@@ -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
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment