Skip to content

Commit b3bd6f9

Browse files
committed
feat: 更新版本至 v3.1.3 并添加新功能
新增场景/部署右键上下文菜单,支持快速操作 添加应用优雅退出确认功能,防止状态不一致 优化模板变量表单,根据类型生成对应控件 移除全局右键禁用功能以避免冲突
1 parent 356780e commit b3bd6f9

File tree

3 files changed

+259
-1
lines changed

3 files changed

+259
-1
lines changed
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# 3.43 右键上下文菜单、优雅退出与模板变量表单增强
2+
3+
## 概述
4+
5+
v3.1.3 新增三项功能:场景/部署列表右键上下文菜单、应用优雅退出确认、模板变量类型感知表单控件。同时移除了全局右键禁用功能以避免冲突。
6+
7+
---
8+
9+
## 1. 右键上下文菜单
10+
11+
### 问题
12+
用户需要展开场景详情才能访问常用操作(启动/停止/SSH/删除等),操作路径过长。
13+
14+
### 方案
15+
在场景列表行和自定义部署列表行添加 `oncontextmenu` 事件,弹出浮层菜单。
16+
17+
### 菜单项(根据状态动态显示)
18+
19+
| 场景状态 | 显示菜单项 |
20+
|---------|-----------|
21+
| running | SSH 运维 → 查看输出 → \| → 停止 → \| → 克隆 → 标签 → 发送到 AI → \| → 删除 |
22+
| created/stopped | 启动 → 预览 → \| → 克隆 → 标签 → 发送到 AI → \| → 删除 |
23+
| error/terminated | 启动 → \| → 克隆 → 标签 → 发送到 AI → \| → 删除 |
24+
| starting/stopping/removing | 灰色文字"正在xxx..." |
25+
26+
### 实现细节
27+
28+
**状态管理**(两个组件各自维护):
29+
```javascript
30+
let contextMenu = $state({
31+
show: false, x: 0, y: 0,
32+
caseId: null, caseName: '', caseState: '', caseType: ''
33+
});
34+
```
35+
36+
**打开菜单**
37+
```javascript
38+
function openContextMenu(e, c) {
39+
e.preventDefault();
40+
// 边缘防溢出
41+
const x = Math.min(e.clientX, window.innerWidth - 200);
42+
const y = Math.min(e.clientY, window.innerHeight - 300);
43+
contextMenu = { show: true, x, y, ... };
44+
}
45+
```
46+
47+
**操作分发**
48+
```javascript
49+
// 注意:先执行操作,再关闭菜单
50+
// 因为操作函数通过闭包读取 contextMenu 的值,
51+
// 如果先 close 再执行,contextMenu 已被重置为空
52+
function ctxAction(fn) {
53+
fn();
54+
closeContextMenu();
55+
}
56+
```
57+
58+
**关闭方式**
59+
- 点击背景遮罩层
60+
- 右键背景遮罩层
61+
- 按 Escape 键(通过 onMount 注册 window keydown 监听)
62+
63+
**UI 层级**
64+
- 背景遮罩:`z-[100]``fixed inset-0`
65+
- 菜单面板:`z-[101]`,绝对定位到鼠标位置
66+
67+
### 涉及文件
68+
69+
| 文件 | 改动 |
70+
|------|------|
71+
| `frontend/src/components/Cases/Cases.svelte` | 添加 contextMenu 状态、openContextMenu/closeContextMenu/ctxAction 函数、`<tr>` 添加 oncontextmenu、底部添加菜单 UI |
72+
| `frontend/src/components/CustomDeployment/CustomDeploymentList.svelte` | 同上,适配 CustomDeployment 的数据结构和操作函数 |
73+
74+
---
75+
76+
## 2. 优雅退出确认
77+
78+
### 问题
79+
用户在 terraform apply/destroy 进行中时关闭应用,可能导致云资源状态不一致(如资源已创建但状态未写入本地)。
80+
81+
### 方案
82+
使用 Wails v2 的 `OnBeforeClose` 钩子,在窗口关闭前检查是否有活跃操作,有则弹出原生 OS 确认对话框。
83+
84+
### 活跃操作跟踪
85+
86+
`App` 结构体添加原子计数器:
87+
```go
88+
type App struct {
89+
// ...
90+
activeOps atomic.Int32 // 追踪进行中的异步操作数
91+
}
92+
```
93+
94+
所有异步操作的 goroutine 入口处递增,退出时递减:
95+
```go
96+
go func() {
97+
a.activeOps.Add(1)
98+
defer a.activeOps.Add(-1)
99+
defer func() { /* recover + emitRefresh */ }()
100+
// ... 实际操作
101+
}()
102+
```
103+
104+
### 被跟踪的操作
105+
106+
| 文件 | 函数 | 操作 |
107+
|------|------|------|
108+
| `app_scene.go` | `StartCase` | terraform apply |
109+
| `app_scene.go` | `StopCase` | terraform destroy |
110+
| `app_scene.go` | `RemoveCase` | terraform destroy + 清理 |
111+
| `app_scene.go` | `CreateAndRunCase` | terraform init + apply |
112+
| `app_compose.go` | `ComposeUp` | compose 多服务部署 |
113+
| `app_compose.go` | `ComposeDown` | compose 销毁 |
114+
115+
### 关闭确认对话框
116+
117+
```go
118+
func (a *App) beforeClose(ctx context.Context) bool {
119+
if a.activeOps.Load() > 0 {
120+
result, _ := runtime.MessageDialog(ctx, runtime.MessageDialogOptions{
121+
Type: runtime.QuestionDialog,
122+
Title: "确认退出",
123+
Message: "有正在进行的操作...",
124+
Buttons: []string{"取消", "强制退出"},
125+
DefaultButton: "取消",
126+
CancelButton: "取消",
127+
})
128+
if result != "强制退出" {
129+
return true // 阻止关闭
130+
}
131+
}
132+
return false // 允许关闭
133+
}
134+
```
135+
136+
**注意**:Wails v2 的 `Buttons` 字段用于自定义按钮文本。`DefaultButton``CancelButton` 控制默认焦点和 Escape 键行为。返回 `true` 阻止关闭,`false` 允许关闭。
137+
138+
### 涉及文件
139+
140+
| 文件 | 改动 |
141+
|------|------|
142+
| `app.go` | 添加 `activeOps atomic.Int32` 字段、`HasActiveOperations()` 方法、`beforeClose()` 方法 |
143+
| `main.go` | 添加 `OnBeforeClose: app.beforeClose` 到 Wails 选项 |
144+
| `app_scene.go` | 4 个 goroutine 添加 `activeOps.Add(1)` / `defer activeOps.Add(-1)` |
145+
| `app_compose.go` | 2 个 goroutine 添加计数器 |
146+
| `i18n/zh.go` | 添加 `app_quit_confirm_title``app_quit_confirm_message``app_quit_btn_confirm``app_quit_btn_cancel` |
147+
| `i18n/en.go` | 对应英文翻译 |
148+
149+
---
150+
151+
## 3. 模板变量表单增强
152+
153+
### 问题
154+
所有 Terraform 变量(bool/number/string/sensitive)都使用相同的文本输入框,用户体验差且容易输入错误。
155+
156+
### 方案
157+
根据 `variables.tf` 中的 `type``sensitive` 属性生成对应 UI 控件。
158+
159+
### 控件映射
160+
161+
| 变量类型 | 控件 | 说明 |
162+
|---------|------|------|
163+
| `bool` | 切换开关(toggle) | 自定义 CSS 实现,值为 "true"/"false" 字符串 |
164+
| `number` | `<input type="number">` | 原生数字输入 |
165+
| `string` + `sensitive=true` | `<input type="password">` | 密码遮罩 |
166+
| `string`(默认) | `<input type="text">` | 普通文本 |
167+
168+
### 类型标签
169+
非 string 类型在变量名旁显示灰色小标签(如 `number``bool`),帮助用户识别。
170+
171+
### 后端解析
172+
173+
`app_templates_registry.go``parseVariablesTf()` 中新增 sensitive 检测:
174+
```go
175+
var sensitiveRegex = regexp.MustCompile(`^\s*sensitive\s*=\s*true`)
176+
```
177+
178+
`TemplateVariable` 结构体(`app.go`)新增:
179+
```go
180+
type TemplateVariable struct {
181+
// ...
182+
Sensitive bool `json:"sensitive"`
183+
}
184+
```
185+
186+
### Bool 默认值初始化
187+
188+
加载模板变量时,bool 类型默认值为 `"false"`(如果没有 default),确保切换开关初始状态正确:
189+
```javascript
190+
if (v.type === 'bool' && !variableValues[v.name]) {
191+
variableValues[v.name] = v.defaultValue || 'false';
192+
}
193+
```
194+
195+
### 值序列化
196+
197+
所有变量值始终序列化为字符串(`String(value)`),因为后端使用 `map[string]string` 写入 `terraform.tfvars`。bool/number 值以 `"true"/"false"/"42"` 形式传递,Terraform 可以正确解析。
198+
199+
### 涉及文件
200+
201+
| 文件 | 改动 |
202+
|------|------|
203+
| `app.go` | TemplateVariable 添加 `Sensitive bool` 字段 |
204+
| `app_templates_registry.go` | parseVariablesTf 添加 sensitiveRegex 和解析逻辑 |
205+
| `frontend/src/components/Cases/Cases.svelte` | 变量表单:bool→toggle、number→number input、sensitive→password |
206+
| `frontend/src/components/CustomDeployment/ConfigEditor.svelte` | 必选参数和可选参数两个区域均添加类型感知控件 |
207+
| `frontend/src/components/LocalTemplates/LocalTemplates.svelte` | 只读表格:添加 sensitive 徽章、默认值遮罩 |
208+
209+
### 当前模板变量类型分布
210+
211+
通过扫描所有模板的 variables.tf 统计:
212+
- string: 93 个
213+
- number: 8 个
214+
- bool: 2 个
215+
- list/map: 0 个(暂无,未来可扩展 KV 编辑器)
216+
217+
---
218+
219+
## 4. 移除右键禁用功能
220+
221+
### 问题
222+
全局右键禁用(`window.addEventListener('contextmenu', e.preventDefault()))`与新增的场景右键菜单功能冲突。
223+
224+
### 方案
225+
完全移除右键禁用功能链路:
226+
227+
| 删除位置 | 内容 |
228+
|---------|------|
229+
| `App.svelte` | `rightClickDisabled` 状态变量、`rightClickDisabledSync` 同步变量、`$effect` 同步逻辑、`contextmenu` 全局拦截监听、`GetDisableRightClick` 调用 |
230+
| `Settings.svelte` | `rightClickSaving` 状态、`handleToggleRightClick` 函数、右键菜单开关 UI、`SetDisableRightClick` 导入 |
231+
232+
**注意**:后端 Go 代码(`SetDisableRightClick`/`GetDisableRightClick`/`disableRightClick` 字段/`DisableRightClick` 配置项)保留不动,因为删除会破坏现有配置文件兼容性,且不影响功能。
233+
234+
---
235+
236+
## 注意事项
237+
238+
1. **ctxAction 执行顺序**:必须先执行操作函数再关闭菜单。因为操作函数通过闭包引用 `contextMenu` 状态对象,如果先 close 则所有字段已被重置为空值。
239+
2. **activeOps 使用 atomic.Int32**:不使用 sync.Mutex,因为需要在 `beforeClose`(主线程)和 goroutine 中无锁访问。
240+
3. **Bool 开关实现**:使用 `<button>` + CSS 自定义样式(relative/absolute positioned div),而非原生 `<input type="checkbox">`,保持设计系统一致。
241+
4. **变量值始终为字符串**:前端 `variableValues``map[string]string`,bool 值存为 `"true"/"false"`,number 值存为数字字符串,后端直接写入 tfvars。
242+
5. **TemplateVariable 双定义**`app.go``mod/custom_deployment.go` 各有一个 TemplateVariable 结构体,JSON tag 不同(`defaultValue` vs `default_value`)。Sensitive 字段仅加在 `app.go` 中,因为 CustomDeployment 的变量表单走的是相同的前端解析路径。

frontend/public/changelog.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
{
22
"changelog": [
3+
{
4+
"version": "3.1.3",
5+
"date": "2026-03-14",
6+
"changes": [
7+
"新增:场景右键上下文菜单 — 场景列表行右键弹出快捷菜单,支持启动/停止/SSH/查看输出/预览/克隆/标签/发送到 AI/删除,无需展开详情即可快速操作",
8+
"新增:自定义部署右键上下文菜单 — 自定义部署列表同样支持右键菜单,菜单项根据部署状态动态显示",
9+
"新增:优雅退出确认 — 关闭应用时如果有场景正在 apply/destroy/compose,弹出确认对话框提示用户,支持「取消」和「强制退出」两个按钮",
10+
"新增:模板变量表单增强 — variables.tf 的变量根据类型生成对应控件:bool → 开关切换、number → 数字输入框、sensitive → 密码输入框,并显示类型标签",
11+
"优化:移除右键禁用功能 — 取消全局右键拦截和设置页面的「禁用右键菜单」开关,不再与场景右键功能冲突",
12+
"优化:本地模板参数表 — LocalTemplates 变量详情表格增加 sensitive 标识徽章,敏感变量默认值显示为遮罩",
13+
"修复:exec_command 超时 — 默认超时从 120s 提升到 300s,新增可选 timeout 参数(最大 600s)",
14+
"修复:exec_userdata 超时 — 添加 10 分钟超时保护,防止 session.Run() 永久挂起",
15+
"修复:openclaw-bash userdata 模板 — 修复 bullseye-backports apt 源 404、添加 apt lock 等待循环、设置 DEBIAN_FRONTEND=noninteractive",
16+
"修复:UserdataTemplate 最小内存 — 新增 minMemoryMB 字段,openclaw-bash 设置 4096MB,防止 Agent 选择低配实例导致 OOM"
17+
]
18+
},
319
{
420
"version": "3.1.2",
521
"date": "2026-03-13",

mod/flag.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ var (
88
Domain string
99
Domain2 string
1010
Base64Command string
11-
Version = "v3.1.2"
11+
Version = "v3.1.3"
1212
)

0 commit comments

Comments
 (0)