Skip to content

Commit d3fde81

Browse files
committed
feat(chat): enable jump-to-file in regular chat diff accordions (#997)
1 parent 7af1a8a commit d3fde81

2 files changed

Lines changed: 51 additions & 11 deletions

File tree

webview-ui/src/components/chat/ChatRow.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -420,12 +420,13 @@ export const ChatRowContent = ({
420420
return (tool.content ?? tool.diff) as string | undefined
421421
}, [tool])
422422

423-
const onJumpToCreatedFile = useMemo(() => {
424-
if (!tool || tool.tool !== "newFileCreated" || !tool.path) {
423+
const onJumpToFile = useMemo(() => {
424+
const path = tool?.path
425+
if (!tool || !path) {
425426
return undefined
426427
}
427428

428-
return () => vscode.postMessage({ type: "openFile", text: "./" + tool.path })
429+
return () => vscode.postMessage({ type: "openFile", text: path.startsWith("./") ? path : "./" + path })
429430
}, [tool])
430431

431432
const followUpData = useMemo(() => {
@@ -497,7 +498,7 @@ export const ChatRowContent = ({
497498
isLoading={message.partial}
498499
isExpanded={isExpanded}
499500
onToggleExpand={handleToggleExpand}
500-
onJumpToFile={onJumpToCreatedFile}
501+
onJumpToFile={onJumpToFile}
501502
diffStats={tool.diffStats}
502503
/>
503504
</div>
@@ -536,6 +537,7 @@ export const ChatRowContent = ({
536537
isLoading={message.partial}
537538
isExpanded={isExpanded}
538539
onToggleExpand={handleToggleExpand}
540+
onJumpToFile={onJumpToFile}
539541
diffStats={tool.diffStats}
540542
/>
541543
</div>

webview-ui/src/components/chat/__tests__/ChatRow.diff-actions.spec.tsx

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,30 +141,68 @@ describe("ChatRow - inline diff stats and actions", () => {
141141
expect(screen.getByText("-0")).toBeInTheDocument()
142142
})
143143

144-
it("preserves jump-to-file affordance for newFileCreated", () => {
144+
it.each([
145+
["appliedDiff", "@@ -1,1 +1,1 @@\n-old\n+new\n"],
146+
["editedExistingFile", "@@ -1,1 +1,1 @@\n-old\n+new\n"],
147+
["newFileCreated", "+new file"],
148+
["searchAndReplace", "-a\n-b\n+c\n"],
149+
["search_and_replace", "-a\n-b\n+c\n"],
150+
["search_replace", "-a\n-b\n+c\n"],
151+
["edit", "@@ -1,1 +1,1 @@\n-old\n+new\n"],
152+
["edit_file", "@@ -1,1 +1,1 @@\n-old\n+new\n"],
153+
["apply_patch", "@@ -1,1 +1,1 @@\n-old\n+new\n"],
154+
["apply_diff", "@@ -1,1 +1,1 @@\n-old\n+new\n"],
155+
["insertContent", "@@ -1,1 +1,1 @@\n-old\n+new\n"],
156+
])("shows jump-to-file affordance for %s", (tool, diff) => {
145157
const message = createToolAskMessage({
146-
tool: "newFileCreated",
147-
path: "src/new-file.ts",
148-
content: "+new file",
149-
diffStats: { added: 1, removed: 0 },
158+
tool,
159+
path: "src/file.ts",
160+
diff,
161+
lineNumber: 0,
162+
diffStats: { added: 1, removed: 1 },
150163
})
151164

152165
const { container } = renderChatRow(message)
166+
mockPostMessage.mockClear()
153167
const openFileIcon = container.querySelector(".codicon-link-external") as HTMLElement | null
154168

155169
expect(openFileIcon).toBeInTheDocument()
156170
if (!openFileIcon) {
157-
throw new Error("Expected external link icon for newFileCreated")
171+
throw new Error(`Expected external link icon for ${tool}`)
158172
}
159173

160174
fireEvent.click(openFileIcon)
161175

176+
expect(mockPostMessage).toHaveBeenCalledTimes(1)
162177
expect(mockPostMessage).toHaveBeenCalledWith({
163178
type: "openFile",
164-
text: "./src/new-file.ts",
179+
text: "./src/file.ts",
165180
})
166181
})
167182

183+
it("does not show jump-to-file affordance when path is missing", () => {
184+
const message = createToolAskMessage({
185+
tool: "appliedDiff",
186+
diff: "@@ -1,1 +1,1 @@\n-old\n+new\n",
187+
diffStats: { added: 1, removed: 1 },
188+
})
189+
190+
const { container } = renderChatRow(message)
191+
expect(container.querySelector(".codicon-link-external")).not.toBeInTheDocument()
192+
})
193+
194+
it("does not show jump-to-file affordance for non-file tools", () => {
195+
const message = createToolAskMessage({
196+
tool: "executeCommand",
197+
path: "src/file.ts",
198+
command: "echo hello",
199+
content: "hello",
200+
})
201+
202+
const { container } = renderChatRow(message)
203+
expect(container.querySelector(".codicon-link-external")).not.toBeInTheDocument()
204+
})
205+
168206
it("preserves protected and outside-workspace messaging in unified branch", () => {
169207
const outsideWorkspaceMessage = createToolAskMessage({
170208
tool: "searchAndReplace",

0 commit comments

Comments
 (0)