Skip to content

Commit 03b847a

Browse files
committed
fix(chat): keep the platform default for Alt-clicked chat links
handleExternalLinkClick treated Alt-click as a plain click and diverted it into the desktop browser panel. Alt is a link modifier like Cmd/Ctrl/Shift (Next Link and the sidebar chat links treat it the same), so it now keeps the platform default.
1 parent d6d29f9 commit 03b847a

2 files changed

Lines changed: 59 additions & 4 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import type { MouseEvent } from 'react'
5+
import { beforeEach, describe, expect, it, vi } from 'vitest'
6+
7+
const { mockOpenInBrowserPanel } = vi.hoisted(() => ({ mockOpenInBrowserPanel: vi.fn() }))
8+
vi.mock('@/lib/browser-agent/open-in-panel', () => ({
9+
shouldOpenInBrowserPanel: (href: string | undefined) => Boolean(href),
10+
openInBrowserPanel: mockOpenInBrowserPanel,
11+
}))
12+
13+
import { handleExternalLinkClick } from '@/app/workspace/[workspaceId]/home/components/message-content/components/source-link'
14+
15+
const HREF = 'https://docs.example.com/guide'
16+
17+
function click(modifiers: Partial<MouseEvent<HTMLAnchorElement>> = {}) {
18+
const event = {
19+
metaKey: false,
20+
ctrlKey: false,
21+
shiftKey: false,
22+
altKey: false,
23+
button: 0,
24+
preventDefault: vi.fn(),
25+
...modifiers,
26+
}
27+
handleExternalLinkClick(event as unknown as MouseEvent<HTMLAnchorElement>, HREF)
28+
return event
29+
}
30+
31+
describe('handleExternalLinkClick', () => {
32+
beforeEach(() => {
33+
vi.clearAllMocks()
34+
})
35+
36+
it('diverts a plain primary click into the browser panel', () => {
37+
const event = click()
38+
expect(event.preventDefault).toHaveBeenCalled()
39+
expect(mockOpenInBrowserPanel).toHaveBeenCalledWith(HREF)
40+
})
41+
42+
it.each([
43+
['Cmd', { metaKey: true }],
44+
['Ctrl', { ctrlKey: true }],
45+
['Shift', { shiftKey: true }],
46+
['Alt', { altKey: true }],
47+
['middle button', { button: 1 }],
48+
])('keeps the default behavior for a %s click', (_label, modifiers) => {
49+
const event = click(modifiers)
50+
expect(event.preventDefault).not.toHaveBeenCalled()
51+
expect(mockOpenInBrowserPanel).not.toHaveBeenCalled()
52+
})
53+
})

‎apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/source-link.ts‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ export const PROSE_LINK_CLASS =
2828

2929
/**
3030
* In the desktop app, a plain click diverts into the embedded Sim browser
31-
* panel; modified clicks (Cmd/Ctrl/Shift/middle) keep the default behavior,
32-
* which the shell routes to the system browser. In a web browser this is a
33-
* no-op and the link opens a new tab as usual.
31+
* panel; modified clicks (Cmd/Ctrl/Shift/Alt/middle) keep the platform default,
32+
* whose new-window opens the shell routes to the system browser. In a web
33+
* browser this is a no-op and the link opens a new tab as usual.
3434
*/
3535
export function handleExternalLinkClick(event: MouseEvent<HTMLAnchorElement>, href: string): void {
36-
if (event.metaKey || event.ctrlKey || event.shiftKey || event.button !== 0) return
36+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) {
37+
return
38+
}
3739
if (!shouldOpenInBrowserPanel(href)) return
3840
event.preventDefault()
3941
openInBrowserPanel(href)

0 commit comments

Comments
 (0)