refactor(vscode): extract shared diff review UI

This commit is contained in:
marius-kilocode
2026-06-03 13:12:20 +02:00
parent 66f053a38a
commit 52aa8c0ee3
25 changed files with 47 additions and 41 deletions
@@ -23,14 +23,14 @@ const TSX_FILES = [
path.join(ROOT, "webview-ui/agent-manager/NewWorktreeDialog.tsx"),
path.join(ROOT, "webview-ui/agent-manager/sortable-tab.tsx"),
path.join(ROOT, "webview-ui/agent-manager/DiffPanel.tsx"),
path.join(ROOT, "webview-ui/agent-manager/FullScreenDiffView.tsx"),
path.join(ROOT, "webview-ui/agent-manager/MarkdownDiffView.tsx"),
path.join(ROOT, "webview-ui/agent-manager/MarkdownAnnotationLayer.tsx"),
path.join(ROOT, "webview-ui/agent-manager/markdown-comment-ranges.ts"),
path.join(ROOT, "webview-ui/agent-manager/DiffEndMarker.tsx"),
path.join(ROOT, "webview-ui/agent-manager/FileTree.tsx"),
path.join(ROOT, "webview-ui/agent-manager/review-annotations.ts"),
path.join(ROOT, "webview-ui/agent-manager/review-annotation-speech.tsx"),
path.join(ROOT, "webview-ui/diff-viewer/FullScreenDiffView.tsx"),
path.join(ROOT, "webview-ui/diff-viewer/MarkdownDiffView.tsx"),
path.join(ROOT, "webview-ui/diff-viewer/MarkdownAnnotationLayer.tsx"),
path.join(ROOT, "webview-ui/diff-viewer/markdown-comment-ranges.ts"),
path.join(ROOT, "webview-ui/diff-viewer/DiffEndMarker.tsx"),
path.join(ROOT, "webview-ui/diff-viewer/FileTree.tsx"),
path.join(ROOT, "webview-ui/diff-viewer/review-annotations.ts"),
path.join(ROOT, "webview-ui/diff-viewer/review-annotation-speech.tsx"),
path.join(ROOT, "webview-ui/agent-manager/MultiModelSelector.tsx"),
path.join(ROOT, "webview-ui/agent-manager/ApplyDialog.tsx"),
path.join(ROOT, "webview-ui/agent-manager/WorktreeItem.tsx"),
@@ -1,5 +1,5 @@
import { describe, expect, it } from "bun:test"
import { mergeWorktreeDiffs } from "../../webview-ui/agent-manager/diff-state"
import { mergeWorktreeDiffs } from "../../webview-ui/diff-viewer/diff-state"
import {
EAGER_DIFF_REVIEW_LINES,
EXTREME_DIFF_CHANGED_LINES,
@@ -8,7 +8,7 @@ import {
expandableOpenFiles,
initialOpenFiles,
toggleOpenFiles,
} from "../../webview-ui/agent-manager/diff-open-policy"
} from "../../webview-ui/diff-viewer/diff-open-policy"
import type { WorktreeFileDiff } from "../../webview-ui/src/types/messages"
function diff(overrides: Partial<WorktreeFileDiff>): WorktreeFileDiff {
@@ -1,5 +1,5 @@
/**
* Architecture test: FullScreenDiffView CSS co-location.
* Architecture test: FullScreenDiffView CSS imports.
*
* `FullScreenDiffView` and its children (`FileTree`, etc.) rely on classes
* defined in BOTH `agent-manager.css` and `agent-manager-review.css`. The
@@ -22,10 +22,10 @@ import fs from "node:fs"
import path from "node:path"
const ROOT = path.resolve(import.meta.dir, "../..")
const FULL_SCREEN_DIFF_VIEW = path.join(ROOT, "webview-ui/agent-manager/FullScreenDiffView.tsx")
const REQUIRED = ["./agent-manager.css", "./agent-manager-review.css"] as const
const FULL_SCREEN_DIFF_VIEW = path.join(ROOT, "webview-ui/diff-viewer/FullScreenDiffView.tsx")
const REQUIRED = ["../agent-manager/agent-manager.css", "../agent-manager/agent-manager-review.css"] as const
describe("FullScreenDiffView — CSS co-location", () => {
describe("FullScreenDiffView — CSS imports", () => {
it("imports every stylesheet required to render correctly", () => {
const src = fs.readFileSync(FULL_SCREEN_DIFF_VIEW, "utf-8")
const missing = REQUIRED.filter((css) => !src.includes(`import "${css}"`))
@@ -5,7 +5,7 @@ import {
flattenChain,
treeOrder,
type FileTreeNode,
} from "../../webview-ui/agent-manager/file-tree-utils"
} from "../../webview-ui/diff-viewer/file-tree-utils"
import type { WorktreeFileDiff } from "../../webview-ui/src/types/messages"
function diff(file: string, status?: "added" | "deleted" | "modified"): WorktreeFileDiff {
@@ -1,5 +1,5 @@
import { describe, expect, it } from "bun:test"
import { isAnnotationMutation } from "../../webview-ui/agent-manager/markdown-annotation-mutation"
import { isAnnotationMutation } from "../../webview-ui/diff-viewer/markdown-annotation-mutation"
function mutation(target: Node): Pick<MutationRecord, "target"> {
return { target }
@@ -6,8 +6,8 @@ import {
getDirectory,
getFilename,
type ReviewComment,
} from "../../webview-ui/agent-manager/review-comments"
import { markdownCommentBlocks } from "../../webview-ui/agent-manager/markdown-comment-ranges"
} from "../../webview-ui/diff-viewer/review-comments"
import { markdownCommentBlocks } from "../../webview-ui/diff-viewer/markdown-comment-ranges"
import {
buildFileAnnotations,
clearReviewComposer,
@@ -17,7 +17,7 @@ import {
reviewComposerEdit,
reviewDraftSpeechKey,
reviewEditSpeechKey,
} from "../../webview-ui/agent-manager/review-annotations"
} from "../../webview-ui/diff-viewer/review-annotations"
import type { WorktreeFileDiff } from "../../webview-ui/src/types/messages"
function diff(file: string, before: string, after: string): WorktreeFileDiff {
@@ -103,11 +103,11 @@ import { renderTab, renderTerminalLayer, renderNewTabButton } from "./tab-render
import { useTabScroll } from "./tab-scroll"
import { DiffPanel } from "./DiffPanel"
import { createRevertFile } from "./revert-file"
import { FullScreenDiffView } from "./FullScreenDiffView"
import { FullScreenDiffView } from "../diff-viewer/FullScreenDiffView"
import { ApplyDialog } from "./ApplyDialog"
import { groupApplyConflicts } from "./apply-conflicts"
import type { ReviewComment } from "./review-comments"
import { clearReviewComposer, createReviewComposer } from "./review-annotations"
import type { ReviewComment } from "../diff-viewer/review-comments"
import { clearReviewComposer, createReviewComposer } from "../diff-viewer/review-annotations"
import { CurrentTabsMenu, createCurrentTabItems, focusCurrentTab } from "./CurrentTabsMenu"
import { BranchSelect } from "../src/components/shared/BranchSelect"
import { WorktreeItem } from "./WorktreeItem"
@@ -125,7 +125,7 @@ import {
} from "./section-helpers"
import { sectionAwareDetector } from "./section-dnd"
import { ConstrainDragXAxis } from "./constrain-drag-x"
import { mergeWorktreeDiffs } from "./diff-state"
import { mergeWorktreeDiffs } from "../diff-viewer/diff-state"
import { initialMessage, seedInitialVariant } from "./initial-message"
import { createMarkdownRender } from "./review-preferences"
import { createSidebarCollapse } from "./sidebar-collapse"
@@ -4,7 +4,7 @@ import { Button } from "@kilocode/kilo-ui/button"
import { Spinner } from "@kilocode/kilo-ui/spinner"
import type { AgentManagerApplyWorktreeDiffStatus, WorktreeFileDiff } from "../src/types/messages"
import { useLanguage } from "../src/context/language"
import { FileTree } from "./FileTree"
import { FileTree } from "../diff-viewer/FileTree"
import { mapApplyConflictReason, type ApplyConflictRow } from "./apply-conflicts"
interface ApplyDialogProps {
@@ -20,7 +20,13 @@ import { useProvider } from "../src/context/provider"
import { useConfig } from "../src/context/config"
import { canUseSpeechToText, selectedSpeechToTextModel } from "../src/components/speech-to-text/availability"
import { useSpeechToText } from "../src/components/speech-to-text/useSpeechToText"
import { getDirectory, getFilename, lineCount, sanitizeReviewComments, type ReviewComment } from "./review-comments"
import {
getDirectory,
getFilename,
lineCount,
sanitizeReviewComments,
type ReviewComment,
} from "../diff-viewer/review-comments"
import {
buildFileAnnotations,
buildReviewAnnotation,
@@ -34,8 +40,8 @@ import {
type AnnotationMeta,
type ReviewComposer,
type ReviewDraft,
} from "./review-annotations"
import { createReviewAnnotationSpeechRenderer } from "./review-annotation-speech"
} from "../diff-viewer/review-annotations"
import { createReviewAnnotationSpeechRenderer } from "../diff-viewer/review-annotation-speech"
import {
LONG_DIFF_MARKER_FILE_COUNT,
allOpenFiles,
@@ -43,11 +49,11 @@ import {
initialOpenFiles,
isLargeDiffFile,
toggleOpenFiles,
} from "./diff-open-policy"
import { DiffEndMarker } from "./DiffEndMarker"
import { treeOrder } from "./file-tree-utils"
import { isMarkdownFile, MarkdownDiffView } from "./MarkdownDiffView"
import { createDiffRows, diffToken } from "./diff-state"
} from "../diff-viewer/diff-open-policy"
import { DiffEndMarker } from "../diff-viewer/DiffEndMarker"
import { treeOrder } from "../diff-viewer/file-tree-utils"
import { isMarkdownFile, MarkdownDiffView } from "../diff-viewer/MarkdownDiffView"
import { createDiffRows, diffToken } from "../diff-viewer/diff-state"
// --- Data model ---
@@ -11,8 +11,8 @@ import { File } from "@kilocode/kilo-ui/file"
import { Icon } from "@kilocode/kilo-ui/icon"
import { ThemeProvider } from "@kilocode/kilo-ui/theme"
import { Toast } from "@kilocode/kilo-ui/toast"
import { FullScreenDiffView } from "../agent-manager/FullScreenDiffView"
import { mergeWorktreeDiffs } from "../agent-manager/diff-state"
import { FullScreenDiffView } from "./FullScreenDiffView"
import { mergeWorktreeDiffs } from "./diff-state"
import { LanguageProvider, useLanguage } from "../src/context/language"
import { ServerProvider, useServer } from "../src/context/server"
import { ConfigProvider } from "../src/context/config"
@@ -1,9 +1,9 @@
import { type Component, createSignal, createMemo, createEffect, on, onCleanup, For, Show } from "solid-js"
// Styles are co-located with the component so every consumer (sidebar diff viewer,
// agent manager, storybook) picks them up automatically. Do not move these out
// Styles are imported by the component so every consumer (sidebar diff viewer,
// agent manager, storybook) picks them up automatically. Keep these imports here
// see tests/unit/diff-viewer-css-arch.test.ts for the invariant.
import "./agent-manager.css"
import "./agent-manager-review.css"
import "../agent-manager/agent-manager.css"
import "../agent-manager/agent-manager-review.css"
import { Diff } from "@kilocode/kilo-ui/diff"
import { Accordion } from "@kilocode/kilo-ui/accordion"
import { StickyAccordionHeader } from "@kilocode/kilo-ui/sticky-accordion-header"
@@ -16,7 +16,7 @@ import { normalize } from "@kilocode/kilo-ui/session-diff"
import { LanguageProvider, useLanguage } from "../src/context/language"
import { ServerProvider, useServer } from "../src/context/server"
import { getVSCodeAPI, VSCodeProvider } from "../src/context/vscode"
import { isMarkdownFile, MarkdownDiffView } from "../agent-manager/MarkdownDiffView"
import { isMarkdownFile, MarkdownDiffView } from "../diff-viewer/MarkdownDiffView"
type DiffStyle = "unified" | "split"
@@ -6,9 +6,9 @@
import type { Meta, StoryObj } from "storybook-solidjs-vite"
import { StoryProviders } from "./StoryProviders"
import { FileTree } from "../../agent-manager/FileTree"
import { FileTree } from "../../diff-viewer/FileTree"
import { DiffPanel } from "../../agent-manager/DiffPanel"
import { FullScreenDiffView } from "../../agent-manager/FullScreenDiffView"
import { FullScreenDiffView } from "../../diff-viewer/FullScreenDiffView"
import { WorktreeItem } from "../../agent-manager/WorktreeItem"
import { Button } from "@kilocode/kilo-ui/button"
import { IconButton } from "@kilocode/kilo-ui/icon-button"