4.6 KiB
4.6 KiB
AI 操作按钮迁入原生 Cell Toolbar — 设计
- 日期: 2026-07-23
- 状态: 已批准(用户于 2026-07-23 确认)
背景与问题
当前 ✨ 优化 / 🐛 排错 / 🪄 编辑 三个按钮渲染在每个 cell 底部 的 ICellFooter 里,链路为:installOpenCodeEverywhere 替换每个 notebook 的 contentFactory → OpenCodeCellContentFactory.createCellFooter() → OpenCodeCellFooter widget。
问题:按钮位置不符合预期 —— 应出现在每个 cell 右上角、JupyterLab 原生 cell toolbar 的上移/下移按钮(move-cell-up / move-cell-down)旁边。
已确认的决策
| 问题 | 决策 |
|---|---|
| 可见性语义 | 跟随原生 toolbar:只在 active cell 右上角显示(与上移/下移按钮行为严格一致) |
| 底部 footer | 删除,三个按钮全部上移 |
| 点击交互 | 本次不变:🪄 编辑 仍用 window.prompt;结果仍走 Notification;inline prompt box / diff 面板留待后续 |
| 作用范围 | 仅 CodeCell;Markdown 等 cell 不显示 AI 按钮(现状 footer 挂在所有 cell 上,属顺带修正) |
机制(JupyterLab 4.6 真实扩展点,已核实源码)
- 原生 cell toolbar 由内置
@jupyterlab/cell-toolbar-extension提供,toolbar factory 名为'Cell',settings 驱动;默认按钮(含move-cell-up/move-cell-down,rank 均为默认 50)由其 schema 的jupyter.lab.toolbars贡献。 - 第三方扩展通过
IToolbarWidgetRegistry.addFactory<Cell>('Cell', '<itemName>', factory)注册 widget factory;factory 收到具体的Cell实例,toolbar 由 tracker 按 cell model 缓存。 - 自己的
schema/plugin.json顶层加"jupyter.lab.toolbars": { "Cell": [...] }即可把该项贡献进原生 toolbar,无需 DOM 注入或 CSS 定位。 - 原生 toolbar 只渲染在 active cell 内(
activeCellChanged时移动),空间不足时自动隐藏 —— 我们的按钮随它一起获得这些行为。
设计
组件改造
src/components/opencode_cell_footer.ts→ 改造为src/components/opencode_cell_actions.ts:OpenCodeCellActions extends Widget,构造函数直接接收CodeCell(factory 传入),不再在onAfterAttach里靠this.parent instanceof CodeCell解析宿主。model.contentChanged/stateChanged订阅保持,onBeforeDetach摘除。- 渲染逻辑不变:
✨ 优化/🐛 排错(无 error output 时禁用) /🪄 编辑;loading 时全部禁用。 - 错误提示统一走
Notification,widget 内不再渲染 error span(toolbar 空间小)。 - 模块级
setOpenCodeRuntime()运行时注入机制不变。
- 删除
src/components/opencode_cell_factory.ts、src/components/opencode_installer.ts。
注册与配置
src/index.ts:optional增加IToolbarWidgetRegistry(来自@jupyterlab/apputils,已是依赖)。- activate 中:
toolbarRegistry.addFactory('Cell', 'opencode-cell-actions', (cell) => cell instanceof CodeCell ? new OpenCodeCellActions(cell) : new Widget());非 CodeCell 返回空 widget。 - 移除
installOpenCodeEverywhere调用及 import。
schema/plugin.json顶层增加:默认按钮 rank 为 50,我们排 100 → 出现在 delete-cell 右侧,紧邻上移/下移按钮组。"jupyter.lab.toolbars": { "Cell": [{ "name": "opencode-cell-actions", "rank": 100 }] }style/base.css:新增.opencode-cell-actions紧凑按钮样式(适配原生 toolbar 高度)。
上下文提取(不变)
widget attach 后仍用现有 extractCellContextFromCell(沿 cell.parent 链 duck-typing 找 NotebookPanel)。cell 实例改由构造参数传入,比现在更可靠。
测试与文档
src/__tests__/opencode_cell_footer.spec.ts→opencode_cell_actions.spec.ts:构造时直接传 cell,删除Object.defineProperty(footer, 'parent', ...)相关 hack,断言不变(三按钮渲染、禁用态)。design.md第 2 节交互描述更新:悬浮 toolbar → 原生 cell toolbar(仅 active cell 显示)。
兼容性
- 纯前端 UI 搬迁;REST 契约、Python server 端零改动。
cell-toolbar-extension被禁用时,我们的按钮与原生按钮一起消失(行为一致,可接受)。- 移除 contentFactory 覆写后,不再受"已打开的 cell 需 reload 才生效"的限制。
IToolbarWidgetRegistry声明为optional,registry 缺失时插件仍可激活(按钮不显示)。
验证
jlpm test、jlpm lint:check、jlpm build全部通过。- 手动:
jupyter lab打开 notebook,active cell 右上角出现三个按钮,位于 delete 按钮右侧;无错误的 cell 上🐛 排错禁用;切换 active cell 按钮随之移动。