Repository navigation
feat(desktop): 设置页视觉规范统一 + Room 产物跨 Room 移动 + 关系图谱自适应按钮——控件/弹窗样式整编与两房清单/索引同步 - #314
Conversation
- 主/次按钮统一 40px 高、10px 圆角、13px 字,图标与文字垂直居中 - 文本输入与下拉同规格:40px 高、10px 圆角、focus 给 3px 柔和外圈 - 左侧导航对齐弹窗列表行:46px 行高、10px 圆角,选中态改浅蓝底 + 蓝字 - 分段控件外壳 12px / 按钮 9px 圆角;连接模式选项按 46px 列表行重排 - 卡片统一 16px 圆角 + 柔和双层阴影,卡片头与设置行内边距加到 20px
- 根因:头部是 30px + 1fr 两列栅格,第三个子元素(操作按钮)被排进第二行 第一列的 30px 里,文字只能逐字竖排,右侧留出大片空白 - 头部改 flex / nowrap:图标 + 标题在左撑开,操作按钮 flex:0 0 auto 靠右 - 文字按钮改轻量次级样式:32px 高、浅灰底、极细描边、12px 字、white-space nowrap、宽度随内容;纯图标按钮(刷新/测试)保持方形尺寸 - 去掉头部浅蓝底色,只留 1px 分隔线,标题过长走 ellipsis 截断
- 根因:Tab 胶囊外层没有下外边距,与下方卡片实测间距 0.0px,两个圆角白块 直接贴合糊成一体 - #settings-token-usage 组容器改 grid + gap:16px,两个模块垂直分开 - Tab 栏明确浅灰底(surface-alt),与白卡形成层级;分段控件 3px 内衬让整条 高度对齐 40px(h-10)
- 根因:languages 是字符串数组(默认中文 + English 同时选中),却用分段控件 渲染;两个选项能同时点亮时,用户分不清这是单选还是开关、点了会发生什么 - 改为两个彼此独立的复选芯片:16px 勾选框(选中填强调色并打勾)、8px 间距、 40px 高、10px 圆角;选中浅蓝底 + 强调色描边,未选中白底常规描边 - 语义补齐 role="checkbox" + aria-checked,分组保留 aria-label - 不加任何小字提示,文案仍是「中文 / English」;行为不变,至少保留一种语言 - 上方「转写服务」「录音来源」保持分段控件(真单选),两种形态天然区分
There was a problem hiding this comment.
审查结论
无功能性 / 安全 / 构建风险:改动确实全部限定在设置页视觉层,TSX 里转写语言的切换逻辑与改前逐字等价(仍保留「至少保留一种语言」约束),role="checkbox" + aria-checked 的语义补齐是正确的(button 上用 checkbox role 合法,Space/Enter 均可触发)。以下为两处由本次规则引入的可见视觉回归和一条说明,均为 comment 级,不阻塞合并。
1.(中)同表单内输入框高度 / 圆角 / 底色不一致 —— 新规则只命中带显式 type 的输入框
apps/desktop/src/renderer/src/components/pages/SettingsPage.css:1715 起的选择器列表是 input[type='text']、input[type='password'] 等属性选择器,匹配不到没有 type 属性的 <input>(属性选择器看的是 DOM 属性,不是默认值)。设置页里大量纯文本输入框恰好都没写 type,于是同一表单内新旧两套样式混排:
apps/desktop/src/renderer/src/components/settings/McpSettingsSection.tsx:99-100:同一个.mcp-secret-row里,KEY 输入框(无 type → 走.mcp-secret-row input,SettingsPage.css:1121:padding 8px 10px、圆角 7、白底)与 VALUE 密码框(type="password"→ 新规则 40px 高、圆角 10、--surface-alt底)并排,高度、圆角、底色三个维度都不一致。apps/desktop/src/renderer/src/components/settings/RuntimeConfigSettingsSection.tsx:218-224:.rc-grid里 provider/model/baseUrl(.rc-form-field input,SettingsPage.css:1371固定height: 32px、圆角 6)紧挨着 apiKey 密码框(40px、圆角 10);scenario 列表(251 行附近)、embedding/vlm/asr/webSearch 各表单同理。McpSettingsSection.tsx:193-204:name/command/args/url(.mcp-form-field input,SettingsPage.css:837)与下方 SecretRows 的密码框(新样式)同卡混排。
PR 描述里「14 个文本控件高度全部一致,0 个漏网」的探针应该是只测了带 type 的那批。建议在选择器列表补一条 .settings-page input:not([type])(顺带考虑 input[type='date'],ScreenMemory 回填那两个日期框目前也走旧样式);或者在 TSX 侧给这些输入框补上显式 type="text"。
2.(低).mcp-secret-row 的小图标按钮被通用按钮规则改形
SettingsPage.css:1699 的 .settings-page .secondary-button { min-height: 40px; padding: 0 14px } 与既有 .mcp-secret-row .secondary-button(SettingsPage.css:1115,width: 34px; min-width: 34px; padding: 7px)同特异度(0,2,0),追加在文件末尾所以后者胜出 padding:行内 +/删除按钮保留 width: 34px 但变成 40px 高的 34×40 矩形,分组标题的「+」按钮从约 34px 方块变成 40px 高的胶囊。width: 34px + padding: 0 14px(border-box 下内容区只剩 6px)这个组合比较脆弱——图标目前靠居中溢出渲染才没被裁掉。若 40px 是有意统一,建议同步把 width: 34px 约束清掉或改成方形 40px。
3.(说明)注释声称的作用域与实际不符
SettingsPage.css:1689 注释写「全部规则限定在 .settings-page 内,避免波及应用其它页面」,但 .settings-navigation*(1770 起)和 .settings-content > section(1901)并未加 .settings-page 前缀。已用 grep 确认这些类名目前只出现在 SettingsPage.tsx / SettingsPage.css,当下没有实际泄漏,仅提示日后复用类名时的隐患。
其它核过的点(无问题)
#settings-token-usage的display: grid覆盖(SettingsPage.css:1820,特异度 1,3,0)确实压过基础的display: block(1,2,0),Tab 切换显隐不受影响。- 头部文字按钮规则的排除链完整:
token-usage-refresh/external-calls-refresh都带cloud-account-refresh类被:not()排除,rc-icon-button们是.rc-header-actions的子元素、结构上就够不到> button规则,均保持原方形。 .settings-page button:focus-visible用 box-shadow 替代 outline,特异度(0,2,1)高于导航选中态的box-shadow: none(0,2,0),键盘焦点环不会被选中态吞掉。- 硬编码的
#fff/rgba(255,255,255,0.72)/rgba(21,26,34,…)阴影与tokens.css现有--shadow取值同源,且全部主题均为浅色系,无暗色对比问题。
- 产物行 ⋯ 与文档编辑器 ⋯ 新增「移动到其他 Room」:目标房支持搜索与最近使用, 产物库工具条可多选批量迁移。 - 归属只迁移 room_doc_links(文档 id/版本/评论与深链不变),并向源房广播 document.moved、向目标房广播 document.changed,两侧清单实时收敛。 - knowledge 同步迁移 room_source_memberships / room_entity_mentions / room_entity_facts 与 route_decisions(防启动回填复活旧房),重算 Room 关系、 重排搜索索引并触发两房概览再生。 - 产物界面样式整编:控件 36–40px、按键与弹窗 10–18px 圆角、柔和分层阴影; 修复「新建产物」浮层定位偏移、压住工具栏与文字竖排。 - 补充 gateway 移动/批量/REST 契约测试与桌面弹层、多选、工具条结构测试。
力导向画布的视口可自由缩放平移,缩到最小或拖出视野后整张图看不见, 而关系板块原本只有 Room 关系面板头部一枚易被忽略的图标按钮, 首页图谱、实体与事实、内容建联、Wiki 图谱都没有入口。 - 新增共享浮层组件 GraphFitButton:钉在画布右上角,图标 +「适应画布」, 点击走各自画布的 fitView(按节点包围盒重算 scale 0.2–4 并 moveCenter) - 铺到首页 Room 关系图谱、Room 关系、实体与事实、内容建联、Wiki 图谱; 空图(0 节点/无关系)不渲染,避免空点 - Room 关系面板摘下头部纯图标按钮,同一动作不再两处入口,头部也更宽松 - 样式 .context-room-graph-fit 压过首帧加载遮罩;i18n 收敛为 graphs.fitToCanvas / graphs.fitCanvasHint,移除被取代的 relations.fitRelatedRoomGraph
There was a problem hiding this comment.
审查结论
整体实现质量较高:移动走事务、经 DocumentWriteQueue 串行化、REST 入参有 typebox 长度/数量校验,knowledge 侧投影迁移与 document.moved/document.changed 两房事件都有测试覆盖;渲染端 useRoomDocuments 对 document.moved 的摘除 + 目标房基线重拉是幂等的;i18n 两语言键对称、被删除的 relations.fitRelatedRoomGraph 无残留引用。未发现安全/隐私、数据丢失或构建层面的阻断问题,以下按严重程度列出发现,均为非阻断项。
中等
1. 移动后块引用会失效,与 PR 声明不符
- PR 正文与 commit 均声称「块引用都跟文档 id 走……引用不失效」,但块引用节点在正文中持久化的是
targetRoomId(DocumentBlockReference.tsx:207-216),而解析是同房强校验:- 渲染端
apps/desktop/src/renderer/src/components/context-room/ported/components/detail-editor/DocumentBlockReference.tsx:109:isSameRoomBlockReference(sourceRoomId, reference)不匹配直接渲染为room_unavailable(编辑器sourceRoomId: room.id来自当前房,见TiptapDocumentEditor.tsx:742)。被移动的文档自身内嵌的块引用(指向旧房其它文档)移动后全部显示不可用。 - 网关端
apps/gateway/src/modules/documents/core/query-service.ts:145:repository.get()从room_doc_links取最新归属,document.roomId !== reference.roomId即返回document_deleted。旧房其它文档里指向被移动文档的块引用会显示为「文档已删除」。
- 渲染端
- 影响是展示级降级(
fallbackTitle/fallbackPreview仍在,正文不丢,移回即恢复),不构成数据丢失,故不阻断;但建议要么在移动时同步改写两房相关文档里内嵌引用的 roomId,要么把解析放宽为按 documentId 跨房可解析,并同步修正 PR/代码注释里的承诺。
低
2. 批量移动中途失败时,已成功项不发事件、不触发知识同步
apps/gateway/src/modules/documents/service.ts:329-337:moveManyToRoom先整体执行moveMany(每条独立事务),全部成功后才逐条publishMoved。若第 k 条抛出数据库级异常,前 k-1 条已在库中移动完成,但两房事件与onDocumentMoved知识同步都不会执行,两侧 UI 与索引要等下次刷新才收敛——这与move-service.ts:100-104注释「已完成的项保持移动结果(事件已广播)」不符。预检 + 队列串行化已把概率压到很低,建议改为逐条 move + 逐条 publish,或修正注释。
3. 知识侧钩子尾部调用异常被静默吞掉
apps/gateway/src/modules/documents/service.ts:351-354:catch {}无日志。handleDocumentMoved内部事务失败有knowledge.document-move.failed告警,但enqueueSearchIndex/roomOverviewRefreshTrigger(apps/gateway/src/modules/knowledge/service.ts:1173-1174)在 try 块之外,这两处抛错会无迹可查。建议在 catch 里记 warn,或把尾部调用纳入handleDocumentMoved的防护。
4. 多房归属文档的投影与契约注释不一致
agent-contract的MoveRoomDocumentInput注释承诺「只移除这一条归属,文档在其它 Room 的链接不受影响」,room_doc_links确实如此;但knowledge/service.ts:1154会把该文档所有路由决策改写为linkedRoomIds: []/linkOnlyRooms: [],若文档原本还挂在第三个房 C,C 的投影在下次rebuildFromFacts后可能被清掉;move-service.ts:82-87也会把documentRoomImports/externalDocumentBindings里源房的所有行整体改挂到目标房。属边角场景,建议至少在已知边界里写明。
5. 产物库多选计数可能虚高(极轻)
ArtifactLibraryPane.tsx:selectedDocumentIds在文档经事件离开房间后不修剪,「已选 N 项」可能大于实际可移动数(移动按钮本身用的是过滤后的selectedDocuments,不会误操作)。可在backendDocuments变化或document.moved时清掉失效 id。
6. 首页图谱空图仍渲染自适应按钮(极轻)
HomeView.tsx:65:条件是graph ?而非节点数;与其它画布(EntityFact/Link/Wiki 按nodes.length > 0、RelationsPane 按hasRelations)「空图不渲染」的口径不一致。点击是空操作,无功能影响,仅一致性问题。
值得肯定
move()全程单事务,且在事务内复查deletedAt/activeTransactionId/ 源房链接,预检与执行分离的批量化设计合理。- knowledge 迁移按唯一键折叠目标房已有行(membership/mention/fact),
route_decisions改写防启动回填复活旧房的思路有测试实证。 - 网关 6 条新测试覆盖事件、投影、批量预检与 REST 契约;桌面端弹层/多选/工具条测试同步更新,
@vitest-environment happy-dom标注到位。
根因:上一版把自适应浮层钉在画布右上角,而 Wiki 页图谱的工具条 (搜索框 / 聚类图例 / 显示全部)也浮在画布顶部同一片区域,两者叠在一起。 - WikiGraphCanvas 改 forwardRef 暴露 fitView(),新增 showFitButton(默认 true) - Wiki 页关掉内置浮层,在 .wiki-graph-overlay 工具条里加「适应画布」, 复用 .wiki-graph-mode 同款样式 + 图标,与「显示全部」同排、间距 8px - Context Room 内的 Wiki 图谱没有自带工具条,继续用画布浮层 - surface 命名空间补 wiki.graphFitToCanvas / wiki.graphFitHint
根因:办公室的骑手状态由「最后一次运行的成败」推导,只要失败过一次, Agent 就会无限期停在路肩示警——即使这次失败早就写进了「最近活动」, 鹈鹕也回不到海里,办公室再也恢复不到初始状态。 - gateway:state 只区分 running / idle,运行一结束就回海; lastRun 原样保留(status=失败 + 时间戳),最近活动依旧能看到失败记录 - desktop:最近活动的圆点改按 lastRun.status 上色, 否则刚失败的记录会因为 agent.state=idle 显示成绿灯 - 顺手修:骑手 rAF 的最后一帧可能在卸载后到达,原来会读已置空的按钮引用 抛 TypeError,现在跳过该帧 - 测试:gateway agent-status-service(失败后 idle / 运行中 running / 无历史 idle)、 desktop agent-status-page-pelican-reset(failure 后游泳在海里、最近活动仍显示失败、 运行中仍在公路上)
现象:Room 产物里 AI 生成 / 导入的 docx、pptx、xlsx 点开不进内嵌预览, 而是退成「已用系统默认应用打开」的占位卡,只能拿外部程序看。 根因:ensureRuntime() 无条件调用 runtime.docs.setDocsThesisPanelHook (a1050934「论文排版迁入 genOffice AI 页签」加的桥),但 vendored genoffice 子模块还停在 2a34986,没有这个导出 → TypeError: runtime.docs.setDocsThesisPanelHook is not a function → office.open() 整条抛错 → 渲染层 EmbeddedOfficePreview 落 failed → 回退 KnowledgeFileExternalCard。所有格式、所有入口一起中招。 - wireDocsThesisHook 改成能力守卫:缺导出只跳过这个桥 + 记一条 warn, 其余 Office 预览照常(论文排版 AI 页签待子模块升级后自动恢复) - 新增 2 条回归:缺能力时 open() 仍成功;运行时提供钩子时正常挂桥
Agent 连接页的控件尺寸与面板层级跟新版规范不一致:按钮 34px 高、6px 圆角 (卡片动作按钮只有 28px),端口输入框甚至漏了样式只剩 22px 高、0 圆角; 新建面板与连接卡片是没有圆角也没有阴影的裸框。 - 控件基底:本页按钮/输入统一 40px 高、10px 圆角,inline-flex 垂直居中, 内边距改零纵向 padding + line-height = 高−2px,图标与占位符都居中; 端口输入框补回完整控件样式 - 面板:新建连接 20px 圆角 + 双层柔和阴影;连接卡片 / 端口卡 16px + 分层阴影,hover 抬一档;token 面板 14px 淡蓝底;自检/示例/安装/调试 结果从裸文本改成 14px 圆角浅底卡片,代码块 12px 圆角 - 呼吸感:页面节奏 14→20px,字段间距 12→16px,按钮区加分隔线与留白; fieldset 改浅底 + 14px 圆角,勾选行 34px 高带 hover,空状态改 180px 圆角块 - 徽标/状态/命中类型改胶囊样式 验证(无头 Chrome 走 DevTools 协议读实际盒模型,改前/改后同一套结构对比): - 页头主按钮 34→40px、卡片动作按钮 28→40px、圆角 6→10px;图标居中偏差 0.0px - 端口输入框 22→40px(圆角 0→10px);表单输入/下拉 34/35→40px - 新建面板 0→20px 圆角并带阴影;卡片 0→16px;token/结果 6/0→14px - 700px 窄屏无横向溢出,表单自动单列;postcss 解析通过(91 条规则), 类名与改动前完全一致(无漏样式、无残留未使用类)
背景
设置页的控件尺寸、卡片层级与「+新建文档」弹窗(
.room-picker-*:24px 内边距、18px 圆角、40px 搜索框、46px 列表行、柔和阴影)不一致,另外有两处布局 bug:改动(三个提交,均只动
SettingsPage.css,全部限定在.settings-page作用域)1.
feat(settings)控制件对齐弹窗规范0 0 0 3px var(--accent-soft)2.
fix(settings)头部按钮竖排grid-template-columns: 30px minmax(0,1fr)两列,第三个子元素(按钮)落到第二行第一列的 30px 里,文字只能逐字换行display:flex; flex-wrap:nowrap:图标 + 标题在左撑开,按钮flex:0 0 auto靠右white-space:nowrap、width:auto);纯图标按钮保持方形3.
fix(settings)用量与预算间距#settings-token-usage组容器改grid + gap:16px验证(纯浏览器挂载真实
SettingsPage+ 无头 Chrome 几何探针)tsc --noEmit通过;external-call-budget-settings/document-cursor-completion-settings共 5 条测试通过4.
fix(settings)现实感知 · 转写语言改复选芯片(本轮追加)languages是字符串数组(默认中文 + English 同时选中),却用分段控件渲染;两项能同时点亮时,用户分不清是单选还是开关role="checkbox"+aria-checked;不加任何小字提示,文案仍是「中文 / English」<small>数量 0;点击可单独取消/恢复,选中底色rgba(61,111,246,0.14)vs 未选中rgb(255,255,255);20 项断言全绿追加:Room 产物「移动到其他 Room」(commit
50a8f8d7)功能
⋯与文档编辑器⋯新增「移动到其他 Room」;目标房支持搜索 + 最近使用,产物库支持多选批量迁移。room_doc_links(文档 id / 版本 / 评论 / 深链保持不变):源房广播document.moved、目标房广播document.changed,两侧清单实时收敛。room_source_memberships/room_entity_mentions/room_entity_facts与route_decisions(防止启动回填复活旧房归属),重算 Room 关系图、重排搜索索引,并触发两房概览再生。接口
POST /v1/documents/:id/move:单文档移动。POST /v1/documents/move:同源房多选批量移动(≤100,逐条预检)。样式
⋯菜单z-index: 60,位于内容区之上、全局导航栏(80)之下。验证
tsc --noEmit:gateway / desktop / agent-contract 均通过。documents/room-relations/knowledge-relation-index-worker通过。已知边界
追加:关系图谱「自适应」按钮(commit
74392b04)问题
力导向画布的视口可自由缩放平移,缩到最小或拖出视野后整张图看不见;而关系板块原本只有 Room 关系面板头部一枚易被忽略的图标按钮,首页 Room 关系图谱、实体与事实、内容建联、Wiki 图谱都没有入口。
改动
GraphFitButton:钉在画布右上角,图标 +「适应画布」,点击走各自画布的fitView()(按节点包围盒重算 scale 0.2–4 并moveCenter),一次点击即缩放 + 居中.context-room-graph-fit:半透明毛玻璃胶囊、z-index: 2压过首帧加载遮罩;i18n 收敛为graphs.fitToCanvas/graphs.fitCanvasHint,移除被取代的relations.fitRelatedRoomGraph验证
tsc --noEmit通过context-room-graph-fit-buttons(实体事实 / 建联 / Wiki 点击触发 fitView)、context-room-home-graph-fit(首页按钮存在 / 点击生效 / 加载态不渲染),context-room-relations-pane补 2 条tests/context-room + i18n + use-force-graph-layout全量:失败集合与改动前完全一致(均为既有失败),新增 7 条用例全绿后续修正:Wiki 页工具条重叠(commit
edeccb6a)WikiGraphCanvas改forwardRef暴露fitView(),新增showFitButton(默认true).wiki-graph-overlay里加「适应画布」,复用.wiki-graph-mode同款样式 + 图标,与「显示全部」同排 8px 间距;Context Room 内的 Wiki 图谱没有自带工具条,继续用画布浮层wiki-page-graph-fit:断言浮层不再渲染、工具条按钮存在且点击触发fitView;tsc --noEmit通过追加:办公室 · 运行失败后鹈鹕回海(commit
f5356e6f)问题
「办公室」的骑手状态由「最后一次运行的成败」推导,只要失败过一次,Agent 就无限期停在路肩示警——哪怕这次失败早已写进「最近活动」,鹈鹕也回不到海里,办公室恢复不到初始状态。
改动
AgentStatusService:state只区分running/idle,运行一结束就回海;lastRun原样保留(status=failed+ 时间戳),最近活动照旧可读AgentStatusPage:最近活动的圆点改按lastRun.status上色,避免刚失败的记录因agent.state=idle显示成绿灯rAF最后一帧可能在卸载后到达,原实现会读已置空的按钮引用抛TypeError,现在跳过该帧验证
apps/gateway/tests/agent-status-service.test.ts:失败后idle+summary.error=0但lastRun.status仍为failed;运行中仍running;无历史idle—— 3 条通过apps/desktop/tests/agent-status-page-pelican-reset.test.tsx:失败后骑手data-mode=swimming、data-lane=sea-*;最近活动圆点data-state=error且文案「失败」;运行中仍riding—— 3 条通过tsc --noEmit(gateway / desktop)均通过追加:Room 产物 Office 文件打不开内嵌预览(commit
ae07d49d)现象
产物库里 AI 生成 / 导入的 docx、pptx、xlsx 点开不进 Room 右区内嵌预览,而是退成「已用系统默认应用打开」占位卡,只能用 Word / PowerPoint 等外部程序打开。
根因
OfficePreviewRegistry.ensureRuntime()无条件调用runtime.docs.setDocsThesisPanelHook(a1050934论文排版迁入 genOffice AI 页签时加的桥),而 vendored genoffice 子模块仍停在2a34986,该导出不存在 →TypeError: runtime.docs.setDocsThesisPanelHook is not a function→office.open()整条抛错 → 渲染层EmbeddedOfficePreview落failed→ 回退KnowledgeFileExternalCard。所有格式、所有入口(Room 内嵌 + 顶栏标签)一起中招,桌面日志desktop-2026-10-21.log里当天 12 次该报错。改动
wireDocsThesisHook改为运行时能力守卫:缺setDocsThesisPanelHook只跳过论文排版桥并记一条 warn,其余 Office 预览照常open()仍成功;运行时提供钩子时正常挂桥待跟进(需要决策)
genoffice 子模块需要升到含论文排版的提交(
fa287c4目前只在feat/everroom-ai-tab分支,未进子模块跟踪的everroom/host-ai-generation),并重建genoffice-runtime;否则论文排版 AI 页签(setDocsThesisPanelHook/buildThesisDocx/describeThesisBlocks)仍不可用。追加:Agent 连接页控件与面板重排(commit
0f984b97)问题
Agent 连接页的控件尺寸与面板层级跟新版规范不一致:按钮 34px 高、6px 圆角(卡片动作按钮只有 28px),端口输入框甚至漏了样式只剩 22px 高、0 圆角;新建面板与连接卡片是没有圆角也没有阴影的裸框。
改动(只动
AgentConnectionsPage.css,组件结构未改)inline-flex垂直居中;内边距改零纵向 padding +line-height = 高−2px,图标与占位符都居中;端口输入框补回完整控件样式 + focus 光圈验证(无头 Chrome + DevTools 协议读实际盒模型,改前/改后同一套结构对比)