在 PR #471(file-trace)基础上的演进: - 合并 tab:git tab(id 保留,兼容持久化布局)升级为「文件变动」双视角 tab——Git 视角(原 GitView 全部能力:staged/unstaged/提交/历史/worktree· 子仓库选择/右键菜单/确认弹窗)+ 本轮文件视角(原 file-trace:会话事件 日志实时折叠的模型读写编辑记录,按文件分组、新增类型筛选 chips、相对 时间);file-trace tab 移除(未随任何版本发布)。 - 统一 diff 组件:新 src/client/diff/ 模块(rows.ts 引擎 + DiffRows/ DiffFiles 渲染器 + highlight.ts 语法着色)——git diff 与会话操作 diff 共用一套渲染:mod 改写配对(del-run/add-run 对半标蓝)、行内字符级 高亮(修复了旧实现旧侧失配不高亮的问题,改为行对象身份键)、上下文 hunk 折叠、git hunk 间未输出区间按行号范围生成不可展开折叠、语法着色 色相落位 diff 三色空档、+n −m 统计 chips、行底色 tint;DiffTab 改用 该栈(git diff tab 从此也有高亮)。 - 交互:两视角共用底部可拖拽预览面板(点击文件/提交/操作即预览,不再 直接开 diff tab;面板可刷新、可键盘/拖拽调高、git 目标可一键展开为 独立 diff tab);视角选择与面板高度持久化在 tab.meta;git 行 XY 徽章 按状态字母着色;选中行高亮。 - i18n:fileTrace* 十键重命名为 changes* 前缀,git 键值更新为「文件 变动」,新增 7 键(视角/筛选/面板操作),全部 21 个词典同步。 - 结构:src/client/changes/(ChangesTab/GitLens/SessionLens/DiffPane/ ops)+ src/client/diff/;GitView/DiffView/filetrace/ 删除;git 样式 从 sidebar.module.css 迁至 changes.module.css。 - 测试:builtins 8→7(git tab 承接 badge pin)、diff-rows(unified 转换/mod 配对/间隙折叠/统计)、changes-tab(壳交互 jsdom)、 diff-files-collapse(原 DiffView 折叠行为钉住)、changes-ops(原 filetrace 数据层)、git-view-worktree 迁移至 GitLens;全量 1122 通过。 - 文档:README ×2 功能矩阵合并、external-plugin-guide §4.4 与内置清单 7 tab、mount e2e 菜单标题同步。
60 lines
2.0 KiB
TypeScript
60 lines
2.0 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
import { createElement } from 'react'
|
|
import { createRoot, type Root } from 'react-dom/client'
|
|
import { act } from 'react-dom/test-utils'
|
|
import { DiffFiles } from '../src/client/diff/DiffFiles.tsx'
|
|
|
|
;(globalThis as Record<string, unknown>).IS_REACT_ACT_ENVIRONMENT = true
|
|
|
|
const diff = [
|
|
'diff --git a/src/a.ts b/src/a.ts',
|
|
'--- a/src/a.ts',
|
|
'+++ b/src/a.ts',
|
|
'@@ -1 +1 @@',
|
|
'-old-a',
|
|
'+new-a',
|
|
'diff --git a/tests/b.spec.ts b/tests/b.spec.ts',
|
|
'--- a/tests/b.spec.ts',
|
|
'+++ b/tests/b.spec.ts',
|
|
'@@ -1 +1 @@',
|
|
'-old-b',
|
|
'+new-b',
|
|
'diff --git a/README.md b/README.md',
|
|
'--- a/README.md',
|
|
'+++ b/README.md',
|
|
'@@ -1 +1 @@',
|
|
'-old-doc',
|
|
'+new-doc',
|
|
].join('\n')
|
|
|
|
afterEach(() => { document.body.innerHTML = '' })
|
|
|
|
describe('DiffFiles file folding', () => {
|
|
it('expands source by default while tests and docs stay collapsed', () => {
|
|
const container = document.createElement('div')
|
|
document.body.append(container)
|
|
const root: Root = createRoot(container)
|
|
try {
|
|
act(() => { root.render(createElement(DiffFiles, { diff })) })
|
|
const headers = [...container.querySelectorAll<HTMLButtonElement>('button[aria-expanded]')]
|
|
expect(headers).toHaveLength(3)
|
|
expect(headers.map(header => header.getAttribute('aria-expanded'))).toEqual(['true', 'false', 'false'])
|
|
expect(container.textContent).toContain('new-a')
|
|
expect(container.textContent).not.toContain('new-b')
|
|
expect(container.textContent).not.toContain('new-doc')
|
|
|
|
act(() => { headers[1]!.click() })
|
|
expect(headers[1]!.getAttribute('aria-expanded')).toBe('true')
|
|
expect(container.textContent).toContain('new-b')
|
|
|
|
act(() => { headers[0]!.click() })
|
|
expect(headers[0]!.getAttribute('aria-expanded')).toBe('false')
|
|
expect(container.textContent).not.toContain('new-a')
|
|
} finally {
|
|
act(() => { root.unmount() })
|
|
container.remove()
|
|
}
|
|
})
|
|
})
|