mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-30 17:14:40 +08:00
fix(agent-manager): expand reviewable diffs by default (#10055)
* fix(agent-manager): expand reviewable diffs by default * style(agent-manager): format diff panel
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Open reviewable Agent Manager diffs by default while keeping generated or extreme files collapsed.
|
||||
@@ -1,6 +1,10 @@
|
||||
import { describe, expect, it } from "bun:test"
|
||||
import { mergeWorktreeDiffs } from "../../webview-ui/agent-manager/diff-state"
|
||||
import { initialOpenFiles } from "../../webview-ui/agent-manager/diff-open-policy"
|
||||
import {
|
||||
EXTREME_DIFF_CHANGED_LINES,
|
||||
expandableOpenFiles,
|
||||
initialOpenFiles,
|
||||
} from "../../webview-ui/agent-manager/diff-open-policy"
|
||||
import type { WorktreeFileDiff } from "../../webview-ui/src/types/messages"
|
||||
|
||||
function diff(overrides: Partial<WorktreeFileDiff>): WorktreeFileDiff {
|
||||
@@ -48,15 +52,26 @@ describe("agent manager diff state", () => {
|
||||
expect(result.stale).toEqual(new Set(["src/app.ts"]))
|
||||
})
|
||||
|
||||
it("does not auto-open generated-like files or large diff sets", () => {
|
||||
it("opens reviewable diffs initially", () => {
|
||||
expect(
|
||||
initialOpenFiles([
|
||||
diff({ file: "src/app.ts", generatedLike: false, additions: 3 }),
|
||||
diff({ file: "node_modules/pkg/index.js", generatedLike: true, additions: 3 }),
|
||||
diff({ file: "src/huge.ts", additions: EXTREME_DIFF_CHANGED_LINES + 1 }),
|
||||
]),
|
||||
).toEqual(["src/app.ts"])
|
||||
|
||||
const many = Array.from({ length: 26 }, (_, i) => diff({ file: `src/${i}.ts` }))
|
||||
expect(initialOpenFiles(many)).toEqual([])
|
||||
expect(initialOpenFiles(many)).toHaveLength(26)
|
||||
})
|
||||
|
||||
it("expands only reviewable files from the bulk action", () => {
|
||||
expect(
|
||||
expandableOpenFiles([
|
||||
diff({ file: "src/app.ts", generatedLike: false, additions: 3 }),
|
||||
diff({ file: "src/generated.ts", generatedLike: true, additions: 3 }),
|
||||
diff({ file: "src/huge.ts", additions: EXTREME_DIFF_CHANGED_LINES + 1 }),
|
||||
]),
|
||||
).toEqual(["src/app.ts"])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
type AnnotationLabels,
|
||||
type AnnotationMeta,
|
||||
} from "./review-annotations"
|
||||
import { LONG_DIFF_MARKER_FILE_COUNT, initialOpenFiles, isLargeDiffFile } from "./diff-open-policy"
|
||||
import { LONG_DIFF_MARKER_FILE_COUNT, expandableOpenFiles, initialOpenFiles, isLargeDiffFile } from "./diff-open-policy"
|
||||
import { DiffEndMarker } from "./DiffEndMarker"
|
||||
import { treeOrder } from "./file-tree-utils"
|
||||
import { isMarkdownFile, MarkdownDiffView } from "./MarkdownDiffView"
|
||||
@@ -71,8 +71,8 @@ export const DiffPanel: Component<DiffPanelProps> = (props) => {
|
||||
)
|
||||
const [editing, setEditing] = createSignal<string | null>(null)
|
||||
let nextId = 0
|
||||
// Tracks the session key for which auto-open has already run. When the
|
||||
// key changes (different worktree) we re-expand. Within the same key,
|
||||
// Tracks the session key for which initial open state has already run. When the
|
||||
// key changes (different worktree) we expand reviewable files. Within the same key,
|
||||
// only pruning happens so the user's manual collapse state is preserved.
|
||||
let initializedKey: string | undefined
|
||||
|
||||
@@ -132,9 +132,9 @@ export const DiffPanel: Component<DiffPanelProps> = (props) => {
|
||||
focusRoot()
|
||||
}
|
||||
|
||||
// Unified auto-open effect: tracks both sessionKey and diffs in a single effect
|
||||
// Unified open-state effect: tracks both sessionKey and diffs in a single effect
|
||||
// to eliminate the race condition between the old separate sessionKey-reset and
|
||||
// diffs-watch effects. Uses the session key to decide when auto-expand is needed
|
||||
// diffs-watch effects. Uses the session key to decide when initialization is needed
|
||||
// vs when we just prune stale entries from the open list.
|
||||
createEffect(
|
||||
on(
|
||||
@@ -321,8 +321,7 @@ export const DiffPanel: Component<DiffPanelProps> = (props) => {
|
||||
}
|
||||
|
||||
const handleExpandAll = () => {
|
||||
const allOpen = open().length === props.diffs.length
|
||||
setOpen(allOpen ? [] : props.diffs.map((d) => d.file))
|
||||
setOpen(open().length > 0 ? [] : expandableOpenFiles(props.diffs))
|
||||
}
|
||||
|
||||
const totals = createMemo(() => ({
|
||||
@@ -374,22 +373,14 @@ export const DiffPanel: Component<DiffPanelProps> = (props) => {
|
||||
<div class="am-diff-header-actions">
|
||||
<Show when={props.diffs.length > 0}>
|
||||
<Tooltip
|
||||
value={
|
||||
open().length === props.diffs.length
|
||||
? t("ui.sessionReview.collapseAll")
|
||||
: t("ui.sessionReview.expandAll")
|
||||
}
|
||||
value={open().length > 0 ? t("ui.sessionReview.collapseAll") : t("ui.sessionReview.expandAll")}
|
||||
placement="bottom"
|
||||
>
|
||||
<IconButton
|
||||
icon="chevron-grabber-vertical"
|
||||
size="small"
|
||||
variant="ghost"
|
||||
label={
|
||||
open().length === props.diffs.length
|
||||
? t("ui.sessionReview.collapseAll")
|
||||
: t("ui.sessionReview.expandAll")
|
||||
}
|
||||
label={open().length > 0 ? t("ui.sessionReview.collapseAll") : t("ui.sessionReview.expandAll")}
|
||||
onClick={handleExpandAll}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
type AnnotationLabels,
|
||||
type AnnotationMeta,
|
||||
} from "./review-annotations"
|
||||
import { LONG_DIFF_MARKER_FILE_COUNT, initialOpenFiles, isLargeDiffFile } from "./diff-open-policy"
|
||||
import { LONG_DIFF_MARKER_FILE_COUNT, expandableOpenFiles, initialOpenFiles, isLargeDiffFile } from "./diff-open-policy"
|
||||
import { DiffEndMarker } from "./DiffEndMarker"
|
||||
import { isMarkdownFile, MarkdownDiffView } from "./MarkdownDiffView"
|
||||
|
||||
@@ -84,8 +84,8 @@ export const FullScreenDiffView: Component<FullScreenDiffViewProps> = (props) =>
|
||||
const [treeWidth, setTreeWidth] = createSignal(240)
|
||||
let nextId = 0
|
||||
let draftMeta: AnnotationMeta | null = null
|
||||
// Tracks the session key for which auto-open has already run. When the
|
||||
// key changes (different worktree) we re-expand. Within the same key,
|
||||
// Tracks the session key for which initial open state has already run. When the
|
||||
// key changes (different worktree) we expand reviewable files. Within the same key,
|
||||
// only pruning happens so the user's manual collapse state is preserved.
|
||||
let initializedKey: string | undefined
|
||||
let rootRef: HTMLDivElement | undefined
|
||||
@@ -135,9 +135,9 @@ export const FullScreenDiffView: Component<FullScreenDiffViewProps> = (props) =>
|
||||
focusRoot()
|
||||
}
|
||||
|
||||
// Unified auto-open effect: tracks both sessionKey and diffs in a single effect
|
||||
// Unified open-state effect: tracks both sessionKey and diffs in a single effect
|
||||
// to eliminate the race condition between the old separate sessionKey-reset and
|
||||
// diffs-watch effects. Uses the session key to decide when auto-expand is needed
|
||||
// diffs-watch effects. Uses the session key to decide when initialization is needed
|
||||
// vs when we just prune stale entries from the open list.
|
||||
createEffect(
|
||||
on(
|
||||
@@ -349,8 +349,7 @@ export const FullScreenDiffView: Component<FullScreenDiffViewProps> = (props) =>
|
||||
}
|
||||
|
||||
const handleExpandAll = () => {
|
||||
const allOpen = open().length === props.diffs.length
|
||||
setOpen(allOpen ? [] : props.diffs.map((d) => d.file))
|
||||
setOpen(open().length > 0 ? [] : expandableOpenFiles(props.diffs))
|
||||
}
|
||||
|
||||
const syncActiveFileFromScroll = () => {
|
||||
@@ -456,7 +455,7 @@ export const FullScreenDiffView: Component<FullScreenDiffViewProps> = (props) =>
|
||||
<div class="am-review-toolbar-right">
|
||||
<Button size="small" variant="ghost" onClick={handleExpandAll}>
|
||||
<Icon name="chevron-grabber-vertical" size="small" />
|
||||
{open().length === props.diffs.length ? t("ui.sessionReview.collapseAll") : t("ui.sessionReview.expandAll")}
|
||||
{open().length > 0 ? t("ui.sessionReview.collapseAll") : t("ui.sessionReview.expandAll")}
|
||||
</Button>
|
||||
<Show when={comments().length > 0 && props.canComment !== false}>
|
||||
<TooltipKeybind
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
import type { WorktreeFileDiff } from "../src/types/messages"
|
||||
|
||||
export const LONG_DIFF_MARKER_FILE_COUNT = 50
|
||||
const AUTO_OPEN_FILE_COUNT = 25
|
||||
const AUTO_OPEN_LIMIT = 8
|
||||
const LARGE_FILE_CHANGED_LINES = 400
|
||||
export const EXTREME_DIFF_CHANGED_LINES = 2_000
|
||||
|
||||
export function isLargeDiffFile(diff: WorktreeFileDiff): boolean {
|
||||
return diff.additions + diff.deletions > LARGE_FILE_CHANGED_LINES
|
||||
return diff.additions + diff.deletions > EXTREME_DIFF_CHANGED_LINES
|
||||
}
|
||||
|
||||
export function expandableOpenFiles(diffs: WorktreeFileDiff[]): string[] {
|
||||
return diffs.filter((diff) => !isLargeDiffFile(diff) && diff.generatedLike !== true).map((diff) => diff.file)
|
||||
}
|
||||
|
||||
export function initialOpenFiles(diffs: WorktreeFileDiff[]): string[] {
|
||||
if (diffs.length === 0) return []
|
||||
if (diffs.length > AUTO_OPEN_FILE_COUNT) return []
|
||||
|
||||
const files = diffs
|
||||
.filter((diff) => !isLargeDiffFile(diff) && diff.generatedLike !== true)
|
||||
.slice(0, AUTO_OPEN_LIMIT)
|
||||
.map((diff) => diff.file)
|
||||
return files
|
||||
return expandableOpenFiles(diffs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user