diff --git a/.helloagents/plan/202603252310_connections-tree-search-explorer-polish/.status.json b/.helloagents/plan/202603252310_connections-tree-search-explorer-polish/.status.json new file mode 100644 index 0000000..790941c --- /dev/null +++ b/.helloagents/plan/202603252310_connections-tree-search-explorer-polish/.status.json @@ -0,0 +1 @@ +{"status":"in_progress","completed":1,"failed":0,"pending":3,"total":4,"done":1,"percent":25,"current":"在 ConnectionsView 中实现左侧树搜索和资源管理器式头部布局","updated_at":"2026-03-25 23:10:00"} diff --git a/.helloagents/plan/202603252310_connections-tree-search-explorer-polish/proposal.md b/.helloagents/plan/202603252310_connections-tree-search-explorer-polish/proposal.md new file mode 100644 index 0000000..df95c63 --- /dev/null +++ b/.helloagents/plan/202603252310_connections-tree-search-explorer-polish/proposal.md @@ -0,0 +1,60 @@ +# 变更提案: connections-tree-search-explorer-polish + +## 元信息 +```yaml +类型: 功能增强 +方案类型: implementation +优先级: P1 +状态: 进行中 +状态说明: 已确认补左侧树搜索、节点计数高亮和资源管理器风格头部布局 +创建: 2026-03-25 +``` + +--- + +## 1. 需求 + +### 背景 +连接管理页左侧树已经具备层级浏览和工具栏控制,但仍缺少独立的树内搜索能力,节点计数也偏弱提示;顶部结构离资源管理器式的“标题 + 工具栏 + 搜索条”仍有差距。 + +### 目标 +- 为左侧树增加独立搜索输入。 +- 搜索时仅保留命中节点及其祖先路径,并自动展开命中链路。 +- 强化节点计数的视觉提示。 +- 把左侧树头部整理成更像资源管理器的结构。 + +### 约束条件 +```yaml +范围约束: 优先限制在 ConnectionsView.vue,不改后端接口和 store 结构 +交互约束: 树搜索独立于右侧全局连接搜索,不改变右侧结果筛选逻辑 +展示约束: 仅显示命中节点及祖先路径,不把整棵子树全部保留 +视觉约束: 延续当前黑绿主题与现有双栏管理台风格 +``` + +### 验收标准 +- [ ] 左侧树提供独立搜索框 +- [ ] 搜索时仅显示命中节点及祖先路径,并自动展开命中链路 +- [ ] 节点计数高亮明显强于当前普通状态 +- [ ] 左侧头部布局更接近资源管理器风格 +- [ ] 前端构建通过 + +--- + +## 2. 方案 + +### 技术方案 +在 `ConnectionsView.vue` 中增加独立的 `treeSearchQuery` 和递归树过滤逻辑,对标签树按“自身命中或后代命中”规则裁剪,并在搜索态下强制展开命中链路;同时根据选中态、搜索态和命中态为节点计数生成不同的徽标样式。左侧头部改为资源管理器风格的标题区、工具条与搜索条组合。 + +### 影响范围 +```yaml +涉及模块: + - frontend: ConnectionsView.vue +预计变更文件: 1 +``` + +### 风险评估 +| 风险 | 等级 | 应对 | +|------|------|------| +| 递归筛选后节点引用变化影响现有展开逻辑 | 中 | 搜索态和常规态分开处理,常规态继续复用 expandedTreeNodes,搜索态强制展开命中链路 | +| 左侧树搜索与右侧全局搜索语义混淆 | 低 | 明确区分占位文案和头部层级,让树搜索只作用于标签浏览范围 | +| 高亮过强破坏现有主题一致性 | 低 | 只增强计数徽标与命中行,不重写整套主题变量 | diff --git a/.helloagents/plan/202603252310_connections-tree-search-explorer-polish/tasks.md b/.helloagents/plan/202603252310_connections-tree-search-explorer-polish/tasks.md new file mode 100644 index 0000000..a4b0596 --- /dev/null +++ b/.helloagents/plan/202603252310_connections-tree-search-explorer-polish/tasks.md @@ -0,0 +1,39 @@ +# 任务清单: connections-tree-search-explorer-polish + +```yaml +@feature: connections-tree-search-explorer-polish +@created: 2026-03-25 +@status: in_progress +@mode: R2 +``` + +## 进度概览 + +| 完成 | 失败 | 跳过 | 总数 | +|------|------|------|------| +| 1 | 0 | 0 | 4 | + +--- + +## 任务列表 + +### 1. 方案与范围确认 + +- [√] 1.1 创建左侧树搜索与头部布局增强方案包 | depends_on: [] + +### 2. 交互增强实现 + +- [ ] 2.1 在 `ConnectionsView.vue` 中实现左侧树搜索与命中链路过滤 | depends_on: [1.1] +- [ ] 2.2 重做左侧头部布局并增强节点计数高亮 | depends_on: [2.1] + +### 3. 验证与同步 + +- [ ] 3.1 运行前端构建验证并同步 `.helloagents` 文档与归档记录 | depends_on: [2.2] + +--- + +## 执行日志 + +| 时间 | 任务 | 状态 | 备注 | +|------|------|------|------| +| 2026-03-25 23:10 | 1.1 | 完成 | 创建 implementation 方案包,范围锁定为 ConnectionsView.vue 的左侧树搜索与资源管理器式头部增强 | diff --git a/.helloagents/plan/202603252311_terminal-group-and-broadcast-dedupe/.status.json b/.helloagents/plan/202603252311_terminal-group-and-broadcast-dedupe/.status.json new file mode 100644 index 0000000..0590c01 --- /dev/null +++ b/.helloagents/plan/202603252311_terminal-group-and-broadcast-dedupe/.status.json @@ -0,0 +1 @@ +{"status":"in_progress","completed":4,"failed":1,"pending":0,"total":5,"done":4,"percent":80,"current":"前端改动已完成,验证被现有 ConnectionsView.vue duplicate attribute 错误阻塞","updated_at":"2026-03-25 23:21:00"} diff --git a/.helloagents/plan/202603252311_terminal-group-and-broadcast-dedupe/proposal.md b/.helloagents/plan/202603252311_terminal-group-and-broadcast-dedupe/proposal.md new file mode 100644 index 0000000..e93b7d4 --- /dev/null +++ b/.helloagents/plan/202603252311_terminal-group-and-broadcast-dedupe/proposal.md @@ -0,0 +1,69 @@ +# 变更提案: terminal-group-and-broadcast-dedupe + +## 元信息 +```yaml +类型: 功能增强 +方案类型: implementation +优先级: P1 +状态: 实施中 +状态说明: 代码改动已完成,前端全量构建被现有 ConnectionsView.vue 重复属性错误阻塞 +创建: 2026-03-25 +``` + +--- + +## 1. 需求 + +### 背景 +当前顶部终端标签栏已经有“服务器组头 + 终端子标签”的雏形,但同一服务器新增终端后仍会按全局尾部插入,导致不同服务器之间组关系错乱。另外,`快捷指令` 和 `命令历史` 的“发送到全部会话”仍按终端实例广播,同一服务器有多个终端时会重复执行。 + +### 目标 +- 把服务器组头做成更稳定的胶囊式 tab group,组头固定、子标签更紧凑、激活组整块高亮。 +- 修复多服务器并行使用时的“新增终端乱插组”问题,确保新终端始终插入到所属服务器组尾部。 +- 将 `快捷指令` 与 `命令历史` 的“发送到全部会话”统一改成“每台服务器只执行一次”。 + +### 约束条件 +```yaml +范围约束: 只改前端终端标签栏、session 顺序维护和两处广播入口,不改后端协议 +排序约束: 继续复用 localStorage 中的 sessionOrder,但允许在新增同组终端时做定向插入 +广播约束: 每个 connectionId 最多选择一个已连接 SSH 终端,避免重复执行 +兼容约束: RDP/VNC 不参与组内新增终端,也不参与 SSH 广播去重逻辑 +``` + +### 验收标准 +- [ ] 多台服务器并行打开时,为某台服务器新增终端会稳定插入到该服务器组尾部 +- [ ] 顶部标签栏具备更明显的“胶囊分组”视觉,激活组有整块高亮关系 +- [ ] `快捷指令` 与 `命令历史` 的“发送到全部会话”都按服务器去重,只执行一次 +- [ ] 前端构建通过 + +--- + +## 2. 方案 + +### 技术方案 +在 `sessionActions.ts` 中新增针对 `sessionOrder` 的组内插入逻辑:为某连接创建新终端时,优先把新 `sessionId` 插到同连接最后一个 session 的后面,而不是简单追加到尾部。`TerminalTabBar.vue` 则继续利用连续同 `connectionId` 的会话数组,在组头、子标签和组尾按钮三层上补更强的胶囊边界和激活组高亮。`QuickCommandsView.vue` 与 `CommandHistoryView.vue` 共享一套“按 connectionId 选取代表会话”的广播去重策略,只对每台服务器选择一个已连接 SSH 终端发送指令。 + +### 影响范围 +```yaml +涉及模块: + - frontend: session/actions/sessionActions.ts, TerminalTabBar.vue, QuickCommandsView.vue, CommandHistoryView.vue, locales +预计变更文件: 5-7 +``` + +### 风险评估 +| 风险 | 等级 | 应对 | +|------|------|------| +| sessionOrder 定向插入与拖拽排序持久化冲突 | 中 | 只在“新增同组终端”时做最小插入,不改已有排序语义 | +| 广播去重选错终端,导致发到非激活或异常会话 | 低 | 只从已连接 SSH 会话中选择每个 connectionId 的首个代表 | +| 胶囊分组视觉过重影响移动端 | 低 | 保持结构复用,移动端沿用同逻辑但不额外堆复杂控件 | + +--- + +## 3. 技术决策 + +### terminal-group-and-broadcast-dedupe#D001: 新终端按 connectionId 插回组尾,广播按 connectionId 去重 +**日期**: 2026-03-25 +**状态**: ✅采纳 +**决策**: 会话仍保持独立 `sessionId`,但新增同服务器终端时要把其 `sessionId` 插入到该连接组尾部;批量发送场景统一按 `connectionId` 选择代表会话。 +**理由**: 问题本质是展示顺序和广播粒度,而不是底层 SSH 能力。按连接做最小排序修正和广播去重,能解决“乱加”和“重复执行”两个核心问题,而且改动边界清晰。 +**影响**: 影响 `sessionOrder` 维护逻辑、顶部标签栏分组样式,以及 `快捷指令` / `命令历史` 两个广播入口。 diff --git a/.helloagents/plan/202603252311_terminal-group-and-broadcast-dedupe/tasks.md b/.helloagents/plan/202603252311_terminal-group-and-broadcast-dedupe/tasks.md new file mode 100644 index 0000000..f8e39b6 --- /dev/null +++ b/.helloagents/plan/202603252311_terminal-group-and-broadcast-dedupe/tasks.md @@ -0,0 +1,54 @@ +# 任务清单: terminal-group-and-broadcast-dedupe + +```yaml +@feature: terminal-group-and-broadcast-dedupe +@created: 2026-03-25 +@status: in_progress +@mode: R2 +``` + +## 进度概览 + +| 完成 | 失败 | 跳过 | 总数 | +|------|------|------|------| +| 4 | 1 | 0 | 5 | + +--- + +## 任务列表 + +### 1. 方案与边界确认 + +- [√] 1.1 创建终端分组插入与广播去重方案包 | depends_on: [] + +### 2. 分组与新增终端修复 + +- [√] 2.1 在 `sessionActions.ts` 中实现同服务器新终端插回组尾的顺序维护 | depends_on: [1.1] +- [√] 2.2 调整 `TerminalTabBar.vue` 的胶囊分组样式和激活组高亮 | depends_on: [2.1] + +### 3. 广播去重 + +- [√] 3.1 调整 `QuickCommandsView.vue` 与 `CommandHistoryView.vue`,按服务器去重发送 | depends_on: [2.1] + +### 4. 验证与同步 + +- [X] 4.1 执行前端构建验证并同步 `.helloagents` 文档与归档记录 | depends_on: [2.2, 3.1] + +--- + +## 执行日志 + +| 时间 | 任务 | 状态 | 备注 | +|------|------|------|------| +| 2026-03-25 23:11 | 1.1 | 完成 | 创建 implementation 方案包,并锁定“组尾插入 + 按服务器去重广播”方向 | +| 2026-03-25 23:18 | 2.1 / 2.2 | 完成 | 新增基于 sessionOrder 的组尾插入逻辑,并强化终端组胶囊高亮样式 | +| 2026-03-25 23:20 | 3.1 | 完成 | 快捷指令和命令历史的批量发送已统一改成按 connectionId 去重 | +| 2026-03-25 23:21 | 4.1 | 失败 | `npm --prefix packages/frontend run build` 被现有 `ConnectionsView.vue` duplicate attribute 错误阻塞 | + +--- + +## 执行备注 + +- 本轮以修正会话插入顺序和广播粒度为主,不改后端 SSH 协议。 +- “每台服务器只执行一次”适用于快捷指令和命令历史两个入口。 +- 如果发现空壳 plan 目录,不参与本轮任务状态流转。 diff --git a/packages/frontend/src/components/TerminalTabBar.vue b/packages/frontend/src/components/TerminalTabBar.vue index dcf9b9b..9abf8ab 100644 --- a/packages/frontend/src/components/TerminalTabBar.vue +++ b/packages/frontend/src/components/TerminalTabBar.vue @@ -64,6 +64,14 @@ const showConnectionListPopup = ref(false); // 连接列表弹出状态 const draggableSessions = ref([]); // + Local state for draggable const showTransferProgressModal = ref(false); // 控制传输进度模态框的显示状态 +const activeConnectionId = computed(() => { + if (!props.activeSessionId) { + return null; + } + + return sessionStore.sessions.get(props.activeSessionId)?.connectionId ?? null; +}); + const openConnectionPicker = () => { showConnectionListPopup.value = true; }; @@ -481,13 +489,32 @@ onBeforeUnmount(() => {