feat(tasks): 任务输出常驻浮动窗 + 节点卡去竖线 + 手机设置
三件事一起落地(用户 brief),各自独立可验证:
1) 后台任务输出改为常驻浮动窗
- 新增 src/client/FloatingWindow.tsx + .module.css:可复用组件,标题栏(拖拽手柄 +
复制/关闭)、内容区(自滚动,长输出不再跑出视口)、可选底部行、三个拉伸柄
(右/下/右下)。生命周期与 AnchoredPopover 相反:外部点击、失焦、锚点离屏都不关,
只有关闭按钮与 Escape 结束;尺寸只在挂载时量一次(流式输出帧不会挪动读者摆好的窗);
拖拽保持整窗在视口内(放不下才退化到保留 48px 可达);视口变化时夹回。
- 手势复用既有范式:移动走 window 级 pointermove(同 AnchoredPopover),拉伸走
setPointerCapture + createFrameBatcher(同 EditorHost 的面板拉伸)。
- JobOutputPopoverContent → JobOutputWindow;顺带修掉「跟随最新」从不滚动的 bug
(原先滚的是 TerminalBlock 外面那个永不滚动的 div),并清掉随旧弹窗死掉的
.popPre / .jobPopPre 规则。节点/工作流详情与任务窗保持原样。
2) 节点卡统一
- 删除两条左侧竖条(层级条 .cardTop::before、当前会话条 .nodeCurrent::before);
层级改由上段极淡底色承担(7/5/3.5/2.5% → 9/7/5/3.5% 补偿对比度);
当前会话改为 2px accent 描边(「边框加粗高亮」)。
- 圆角 4px → 8px(与浮动窗同一家族);成员/工作流/聚合按用户选择保留类型区分。
- 2px 而非 1.5px:真机 recon 发现 Chromium 在 DPR 1 下把亚像素边框向下取整,
1.5px 的「加粗」完全看不出(实测 borderTopWidth: "1px")。几何不受影响
(border-box + min-height,卡片外框 247×134 与预算逐像素一致)。
3) 手机设置
- 两个新偏好 mobileNoAutoOpen / mobileDefaultTree(默认都开),落到 prefs-shared、
PrefsSchema(volatile 自动)、parsePrefs 校验与设置页新增的「手机」分组。
- 窄屏(沿用 768px 断点)时:新子代理与新后台任务都不再自动激活任务页;
任务页默认树状图(页内切换仍是临时覆盖)。宽屏或开关关掉后行为完全不变。
- 5 条词条 ×20 份词典;外部插件指南的 PrefsSchema 键清单同步。
验证:typecheck / lint ✅;pnpm test 1254 passed / 9 skipped(新增 14 例);
挂载 lane 7/7(真实 DSH 0.1.7-rc.2);3080 真机自测通过(长输出窗口内部滚动
5459px/449px、拖拽 424→304、拉伸 1008×540→918×480、外部点击不关、Escape 关、
卡片 8px/2px/无竖条、窄屏不自动弹出且默认树状图)。
(cherry picked from commit 7d9b428c6c34d28ad2d60c2086496eb533902273)
This commit is contained in:
@@ -879,7 +879,7 @@ ctx.effect(() =>
|
||||
)
|
||||
```
|
||||
|
||||
> ⚠️ **`toggles` 的 key 必须是本插件 `PrefsSchema` 的字段**(`PrefsSchema` 已并入本插件 Loader 行的 `Config`;内置键:`autoOpenSubagent` / `autoOpenJobs` / `agentOpenTools` / `editorExplorer` / `workspaceFence` / `titleBarScheme` / `titleBarPresetId` / `customCss` / `titleBarCompat` / `titleBarStripPx` / `htmlViewerNoSandbox` / `htmlViewerDefaultUnsafe` / `tabsEnabled` / `viewersEnabled` / `pluginSettings`;**已删除**:`agentTerminalTools` / `terminalShell` / `terminalShellArgs` / `terminalFontFamily` / `terminalFontSize` / `bottomPanelAutoTerminal` / `browserNoSandbox` / `browserAllowedLoopback` / 三个按协议分流的旧外链接管键)。**v0.12.0 起设置 seam 已开放**:你自己的设置走 `pluginToggles`(声明式行)或 `render`(自定义面板),值持久化在 `pluginSettings[id]`——不再需要本插件的 schema 字段,也不再被 seam 丢弃。值须 JSON 可序列化(行控件只产出 string/number/boolean;自定义面板自行负责)。
|
||||
> ⚠️ **`toggles` 的 key 必须是本插件 `PrefsSchema` 的字段**(`PrefsSchema` 已并入本插件 Loader 行的 `Config`;内置键:`autoOpenSubagent` / `autoOpenJobs` / `tasksViewMode` / `mobileNoAutoOpen` / `mobileDefaultTree` / `agentOpenTools` / `editorExplorer` / `workspaceFence` / `titleBarScheme` / `titleBarPresetId` / `customCss` / `titleBarCompat` / `titleBarStripPx` / `htmlViewerNoSandbox` / `htmlViewerDefaultUnsafe` / `tabsEnabled` / `viewersEnabled` / `pluginSettings`;**已删除**:`agentTerminalTools` / `terminalShell` / `terminalShellArgs` / `terminalFontFamily` / `terminalFontSize` / `bottomPanelAutoTerminal` / `browserNoSandbox` / `browserAllowedLoopback` / 三个按协议分流的旧外链接管键)。**v0.12.0 起设置 seam 已开放**:你自己的设置走 `pluginToggles`(声明式行)或 `render`(自定义面板),值持久化在 `pluginSettings[id]`——不再需要本插件的 schema 字段,也不再被 seam 丢弃。值须 JSON 可序列化(行控件只产出 string/number/boolean;自定义面板自行负责)。
|
||||
|
||||
### 8.2 宿主设置表单(DSH 0.1.7+:`SettingsForms`)
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
# 任务输出常驻浮动窗 + 节点卡去竖线 + 手机设置
|
||||
|
||||
日期:2026-09-27 分支:`feat/tasks-graph-polish`(承接 PR #680 的打磨线)
|
||||
|
||||
## 背景(用户原话)
|
||||
|
||||
> 1. 后台任务弹窗没有高度限制,输出很长会导致看不到。同时让其变为常驻的全屏弹窗(带关闭/拉伸,建议抽取为全局组件方便后续复用)
|
||||
> 2. 优化节点UI,加上圆角,同时取消左侧装饰条,让整个节点看起来更为统一
|
||||
> 3. 设置中新增手机设置,里面放各种和手机端的适配设置,目前加上这么几项:检测到处于手机状态时,有新的后台任务或Agent任务时不会自动弹出,任务管理的默认状态切换为树状图
|
||||
|
||||
## 用户确认的决策(问答摘要)
|
||||
|
||||
| # | 问题 | 结论 |
|
||||
|---|---|---|
|
||||
| 1 | 弹窗形态 | 可拖拽 + 可拉伸的**常驻浮动窗**(默认约视口 70%×60%,最小 320×240) |
|
||||
| 2 | 复用范围 | 抽成**全局组件**,本轮只把后台任务输出换过去(节点/工作流详情、任务窗保持现状) |
|
||||
| 3 | 常驻边界 | 只靠**关闭按钮 / Escape**;外部点击、失焦、锚点离屏都不关;切会话/关标签、任务结算后都保留 |
|
||||
| 4 | 左侧竖条 | 「就是左侧的竖条,这个去掉」 |
|
||||
| 5 | 层级组色 | 「这个可以留着,只是那个竖线不要了」 |
|
||||
| 6 | 当前会话标记 | 「边框加粗高亮即可」 |
|
||||
| 7 | 圆角 | **8px**,并**保留类型描边**(成员 accent 描边、工作流 accent 描边 + 底色) |
|
||||
| 8 | 手机设置 | **自动检测(沿用 768px 窄屏判定)+ 两个独立开关(默认都开)**,分组放在设置页 |
|
||||
|
||||
## 架构与文件
|
||||
|
||||
```
|
||||
新增
|
||||
src/client/FloatingWindow.tsx 常驻浮动窗(拖拽 + 拉伸 + 关闭,内容区自滚动)
|
||||
src/client/FloatingWindow.module.css 窗框/标题栏/内容区/底部行/三个拉伸柄样式
|
||||
tests/floating-window.spec.tsx 9 例:结构、尺寸与定位、关闭契约、两个手势
|
||||
改写
|
||||
src/client/JobsDrawer.tsx JobOutputPopoverContent → JobOutputWindow
|
||||
src/client/SubagentView.tsx 任务分支改渲染窗口;默认视图加窄屏覆盖
|
||||
src/client/tasks-graph.module.css 卡片:去两条左侧竖条、圆角 8px、当前会话 1.5px 描边
|
||||
src/client/sidebar/use-host-feeds.ts 两个自动弹出 gate 加手机压制
|
||||
src/client/SideCardSection.tsx 新增「手机」分组(两行开关)
|
||||
src/prefs-shared.ts / src/config.ts / src/client/prefs.ts
|
||||
两个新偏好 mobileNoAutoOpen / mobileDefaultTree
|
||||
src/client/locales*.ts(20 份) 5 条手机设置词条
|
||||
```
|
||||
|
||||
## 关键设计
|
||||
|
||||
### 1. 常驻浮动窗(`FloatingWindow.tsx`)
|
||||
|
||||
- **为什么不是复用 `AnchoredPopover`**:那是 popover —— 锚定元素、按内容定尺寸、外部 mousedown / window blur / 锚点离开视口都会关它。被**持续观察**的面(一个跑几分钟的任务输出)需要的恰好相反的生命周期:只有关闭按钮与 Escape 结束它,而且必须能挪开、能拉伸。
|
||||
- **内容区就是高度上限**:`data-window-body` 自己 `overflow: auto`,所以「输出很长看不到」这条被结构性修掉(旧 popover 完全没有高度约束,`.popPre` 那个 160px 滚动井在改用 `TerminalBlock` 之后已成死规则 —— 本轮一并删掉)。
|
||||
- **手势复用既有范式**:移动走 window 级 `pointermove`(同 `AnchoredPopover` 的拖拽,容器捕获会重定向 click、杀掉窗内按钮),拉伸走 `setPointerCapture` + `createFrameBatcher()`(同 `EditorHost` 的面板拉伸;逐事件 setState 是 #315 的拖拽卡顿)。
|
||||
- **几何**:`position: fixed`;尺寸在**挂载时量一次**(之后每条流式输出帧都不会挪动读者摆好的窗);拖拽保证标题栏至少 48px 留在视口内;拉伸夹取到 `minSize` 与视口;window `resize` 时把窗夹回视口。
|
||||
- **常驻**:不注册外部 mousedown / blur / IntersectionObserver;只注册 Escape(捕获阶段)。
|
||||
- **皮肤契约**:令牌全量、8px 圆角与节点卡一致、浮动层保留 `--dsw-shadow-lv3`。
|
||||
|
||||
### 2. 任务输出接入
|
||||
|
||||
- `JobOutputWindow`:标题栏(任务 label + 复制按钮 + 关闭)/内容区(状态行 + `TerminalBlock`,`maxLines: Infinity` 保留「看完整输出」)/底部行(跟随最新 + 两击终止)。
|
||||
- **顺带修掉的 bug**:「跟随最新」原先滚的是包在 `TerminalBlock` 外面的普通 `div`(永不滚动)——现在滚窗口内容区。
|
||||
- 页面侧:`popover.kind === 'job'` 不再走 `AnchoredPopover`;节点/工作流详情仍是 280px 锚定小卡,任务窗不变。
|
||||
- 任务从宿主 roster 消失时窗口关闭(无处再观察);**结算不掉行,窗口继续**。
|
||||
|
||||
### 3. 节点卡(`tasks-graph.module.css`)
|
||||
|
||||
| 变更 | 说明 |
|
||||
|---|---|
|
||||
| 删除 `.cardTop::before` | 层级竖条;层级改由上段极淡底色承担,并把色调从 7/5/3.5/2.5% 抬到 **9/7/5/3.5%** 补偿对比度损失 |
|
||||
| 删除 `.nodeCurrent::before` | 当前会话竖条;`.nodeCurrent` 改为 **2px accent 描边**(「边框加粗高亮」) |
|
||||
| `.node` 圆角 4px → **8px** | 与新的浮动窗同一圆角,卡与窗成为一个家族 |
|
||||
| `.cardTop` 左内边距 10px → 8px | 竖条消失后的回正 |
|
||||
| `.nodeTeam` / `.nodeWorkflow` / `.nodeFold` / `.nodeError` | 按用户选择**保留**类型区分;只继承新圆角 |
|
||||
| 删除 `.popPre` / `.jobPopPre` | 随旧弹窗一起死掉的规则 |
|
||||
|
||||
**几何安全性**:`.node` 是 `box-sizing: border-box` + 布局给的 `min-height`,加粗描边被吸收在盒内,卡片外框尺寸不变 —— `tasks-graph-layout.ts` 的高度/行距预算**不需要改**,`tests/tasks-graph-layout.spec.ts` 保持全绿。
|
||||
|
||||
### 4. 手机设置
|
||||
|
||||
| 键 | 默认 | 语义 |
|
||||
|---|---|---|
|
||||
| `mobileNoAutoOpen` | true | 窄屏时**同时**压制子代理与后台任务两个自动弹出(既有两个开关的值不被改写;宽屏行为不变) |
|
||||
| `mobileDefaultTree` | true | 窄屏时任务页默认树状图(页内切换仍是临时覆盖,优先级最高) |
|
||||
|
||||
- 判定沿用插件既有的 `isNarrowWidth`(768px 断点,与侧边栏手机布局、park 逻辑同源),在**触发时**读视口。
|
||||
- 设置 UI:DSH 设置页「侧边卡片」分区新增「手机」分组(两行 title/desc + 宿主 `Switch`,走既有 `applyPref` 写入)。
|
||||
|
||||
## 实施偏差记录(写给复审)
|
||||
|
||||
1. **窗口尺寸只在挂载时量一次**(`useEffect(..., [])` + 一条 eslint-disable):若跟着 props/内容重算,每条流式输出帧都会把读者拖好的窗口弹回去。视口变化仍会夹取。
|
||||
2. **`aria-label` 用 `<title>` 而不是 `<h1>` 之类**:与既有 `AnchoredPopover`/`Modal` 的可访问名做法一致(`role="dialog"` + 可访问名)。
|
||||
3. **拉伸只给三个柄**(右、下、右下):实际用法是「日志变长 → 往右下长」,两轴各自还可单独拉;八个柄属于没被要求的能力。
|
||||
4. **没有做焦点陷阱**:与插件现有的两个浮层(`AnchoredPopover` / 宿主 `Modal` 之外的弹窗)一致;Escape 是唯一键盘出口。
|
||||
5. **窄屏自动激活的既有两个 spec 显式关掉了手机开关**:它们钉的是「窄屏也激活 + 收回列(park)」这条更早的承诺,而压制行为有自己的新用例;把 harness 的默认值改成「关」会让 spec 脱离真实默认,所以选择在用例里显式声明。
|
||||
6. **`mobileDefaultTree` 只在有 store 时生效**:`SubagentView` 的 prefs 来自 `store` prop,spec harness 里多数用例不传 store(读作 `graph`);视图默认的新用例显式传入 `createSidebarStore()`。
|
||||
7. **当前会话的加粗描边用 2px 而不是 1.5px**:真机自测发现 Chromium 在 device-pixel ratio 1 下**向下取整**亚像素边框宽度 —— 1.5px 的计算值直接是 1px,"加粗"完全看不出来(recon 实测 `borderTopWidth: "1px"`,而 class 与 accent 颜色都在)。改成整数 2px 后在 DPR 1 与 2 上都成立。
|
||||
8. **`.popPre` / `.jobPopPre` 被删除**:旧 `jobs` 弹窗改用 `TerminalBlock` 之后它们就没有消费者了,本轮顺手清掉(与上次「drop the dead rules」同类)。
|
||||
|
||||
## 验证证据(2026-09-27)
|
||||
|
||||
| 项 | 结果 |
|
||||
|---|---|
|
||||
| `pnpm typecheck` / `pnpm lint` | ✅ 0 错误 |
|
||||
| `pnpm test` | ✅ **1254 passed / 9 skipped / 0 failed**(120 文件;新增 14 例:窗口 9 / prefs 1 / 设置分组 1 / 自动激活压制 2 / 视图默认 1) |
|
||||
| 真机挂载 lane | ✅ **7 passed**(真实 DSH 0.1.7-rc.2,scratch profile + 无头渲染 + 全 tab 扫描 + 性能测量;日志 `/tmp/e2e-win.log`) |
|
||||
| 3080 真机自测 | ✅ 见下表(真实工作:长输出后台任务 + 子代理;截图 `/tmp/dsh-selfcheck/10-13-*.png`) |
|
||||
|
||||
### 3080 真机证据(逐项)
|
||||
|
||||
| 项 | 实测 |
|
||||
|---|---|
|
||||
| 卡片去竖条 + 圆角 + 加粗描边 | `radius: 8px`;`::before` 的 `content: none`(层级条与当前会话条都不存在了);当前会话 `borderTopWidth: 2px` + `rgb(65,118,230)`(accent);卡片外框 **247×134** 与布局预算逐像素一致(去掉竖条/加粗描边都不改几何) |
|
||||
| 窗口限高(原始 bug) | 240 行输出的任务:窗口 1008×540 全在 1440×900 视口内,内容区 `scrollHeight 5459 > clientHeight 449` —— **真的在窗内滚动**;滚到底能看到末行 `THE-END` |
|
||||
| 窗口结构 | 标题栏(任务名 + 复制 + 关闭)、内容区、底部行(跟随最新 + 终止)与三个拉伸柄(x / y / both)都在 |
|
||||
| 拖拽与拉伸 | 拖标题栏:(424,352) → (304,352);拖右下角:1008×540 → **918×480** |
|
||||
| 常驻语义 | 外部点击(窗口上方面板区、左侧会话列)后窗口仍在(count 仍为 1);Escape 关闭 |
|
||||
| 手机适配 | 窄屏(700×900)起后台任务 + 子代理后,右侧栏**未被打开**(`data-sidebar-right-panel` 不存在);手动打开任务页 → `tree: 2 / graph: 0`(默认树状图) |
|
||||
|
||||
### 真机自测发现并修掉的两处
|
||||
|
||||
1. **1.5px 的「加粗」边框在 DPR 1 下等于 1px**:Chromium 向下取整亚像素边框宽度,真机上完全看不出加粗(recon 实测 `borderTopWidth: "1px"`,而 class 与 accent 颜色都在)。改成整数 **2px**(DPR 1 与 2 都成立)。
|
||||
2. **拖拽只保证标题栏可达,会把窗口的右下角推出视口**:第一次真机拖拽后窗口底部落到 y=932(视口 900),拉伸柄随之点不到。改为「放得下就整窗留在视口内,放不下才退化成保留 48px 可达」——两个轴都套用,视口变化时同样处理。
|
||||
|
||||
### 未在真机复现 / 已知限制
|
||||
|
||||
- 关掉两个手机开关后的真机行为(真机只验了默认开启的一侧;关闭一侧由单测覆盖,且既有窄屏 park 用例显式关掉该开关后仍然全绿)。
|
||||
- **切会话会关掉窗口**:窗口状态属于该会话的 Tasks 页组件,宿主在切走时卸载该会话视图(实测点击左侧会话列表即窗口消失)。设计文档已列为限制:若要真正跨会话常驻,需要把开启状态提到 `SidebarStore`(本轮范围外)。
|
||||
@@ -116,6 +116,12 @@ client 半(src/client/)
|
||||
| `subagents.live` 新载荷 + `SidebarChildLiveView` | 移植(去掉 `expand`/`stages`) |
|
||||
| 卡片 UI(`subagent-card.tsx` / `subagent-runs.ts` / 树重写 / 5 个词条) | **丢弃** |
|
||||
|
||||
## 后续变更(同日,`2026-09-27-floating-window-mobile-settings.md`)
|
||||
|
||||
本文描述的卡片语言随后被两处调整:**左侧竖条(层级条 + 当前会话条)删除**,层级改由上段极淡底色承担、
|
||||
当前会话改用加粗 accent 描边;**圆角 4px → 8px**。任务输出的锚定浮窗也换成了常驻浮动窗。
|
||||
以新文档为准。
|
||||
|
||||
## 实施偏差记录(写给复审)
|
||||
|
||||
1. **`process-activity.ts` 是裁剪版而不是原样搬运**:本轮「阶段」= 徽标 + 颜色,逐阶段列表没有消费者,留着就是死代码。裁剪后 44 例 → 30 例(阶段相关用例随机制一起删除)。
|
||||
|
||||
Reference in New Issue
Block a user