diff --git a/src/renderer/src/components/link-actions/LinkActionPopover.test.tsx b/src/renderer/src/components/link-actions/LinkActionPopover.test.tsx
index 39b1f283a6a..475c05fdbc7 100644
--- a/src/renderer/src/components/link-actions/LinkActionPopover.test.tsx
+++ b/src/renderer/src/components/link-actions/LinkActionPopover.test.tsx
@@ -254,13 +254,13 @@ describe('LinkActionPopover', () => {
await waitFor(() => expect(mocks.writeClipboardText).toHaveBeenCalledTimes(2))
})
- it('does not offer copy link for non-URL destinations', () => {
+ it('does not offer copy actions for non-copyable destinations', () => {
vi.stubGlobal('navigator', { userAgent: 'Macintosh' })
const request: LinkActionRequest = {
anchorX: 100,
anchorY: 200,
destination: '/tmp/example.ts',
- kind: 'file',
+ kind: 'workspace',
primary: { label: 'Open file', run: vi.fn() },
restoreFocus: vi.fn()
}
@@ -268,6 +268,31 @@ describe('LinkActionPopover', () => {
render()
expect(screen.queryByRole('button', { name: 'Copy link' })).toBeNull()
+ expect(screen.queryByRole('button', { name: 'Copy file path' })).toBeNull()
+ })
+
+ it('copies the resolved file path without closing the popover', async () => {
+ vi.stubGlobal('navigator', { userAgent: 'Macintosh' })
+ Object.assign(window, { api: { ui: { writeClipboardText: mocks.writeClipboardText } } })
+ mocks.writeClipboardText.mockResolvedValue(undefined)
+ const onClose = vi.fn()
+ const request: LinkActionRequest = {
+ anchorX: 100,
+ anchorY: 200,
+ destination: 'file:///repo/src/main.ts',
+ copyValue: '/repo/src/main.ts',
+ kind: 'file',
+ primary: { label: 'Open file', run: vi.fn() },
+ restoreFocus: vi.fn()
+ }
+
+ render()
+ fireEvent.click(screen.getByRole('button', { name: 'Copy file path' }))
+
+ await waitFor(() => expect(mocks.writeClipboardText).toHaveBeenCalledWith('/repo/src/main.ts'))
+ await waitFor(() => expect(screen.getByRole('button', { name: 'Copied' })).toBeTruthy())
+ expect(mocks.toastSuccess).toHaveBeenCalledWith('Copied file path')
+ expect(onClose).not.toHaveBeenCalled()
})
it('opens the terminal link setting from the compact settings button', () => {
diff --git a/src/renderer/src/components/link-actions/LinkActionPopover.tsx b/src/renderer/src/components/link-actions/LinkActionPopover.tsx
index 29338b208f9..8b787c56e4b 100644
--- a/src/renderer/src/components/link-actions/LinkActionPopover.tsx
+++ b/src/renderer/src/components/link-actions/LinkActionPopover.tsx
@@ -61,7 +61,11 @@ export function LinkActionPopover({
}: LinkActionPopoverProps): React.JSX.Element {
const openSettingsPage = useAppStore((state) => state.openSettingsPage)
const openSettingsTarget = useAppStore((state) => state.openSettingsTarget)
- const copyableDestination = request?.kind === 'url' ? request.destination : ''
+ const isFilePath = request?.kind === 'file'
+ const canCopyDestination = isFilePath || request?.kind === 'url'
+ const copyableDestination = canCopyDestination
+ ? (request?.copyValue ?? request?.destination ?? '')
+ : ''
const { copyText, status: copyStatus } = useClipboardTextCopyFeedback(copyableDestination)
const copyInFlightRef = useRef(false)
const contentRef = useRef(null)
@@ -103,7 +107,28 @@ export function LinkActionPopover({
const copyLabel =
copyStatus === 'copied'
? translate('auto.components.terminal.pane.TerminalLinkActionPopover.copied', 'Copied')
- : translate('auto.components.terminal.pane.TerminalLinkActionPopover.copyLink', 'Copy link')
+ : isFilePath
+ ? translate(
+ 'auto.components.terminal.pane.TerminalLinkActionPopover.copyFilePath',
+ 'Copy file path'
+ )
+ : translate('auto.components.terminal.pane.TerminalLinkActionPopover.copyLink', 'Copy link')
+
+ const copiedMessage = isFilePath
+ ? translate(
+ 'auto.components.terminal.pane.TerminalLinkActionPopover.copiedFilePath',
+ 'Copied file path'
+ )
+ : translate('auto.components.terminal.pane.TerminalLinkActionPopover.copiedLink', 'Copied link')
+ const copyFailedMessage = isFilePath
+ ? translate(
+ 'auto.components.terminal.pane.TerminalLinkActionPopover.copyFilePathFailed',
+ 'Failed to copy file path'
+ )
+ : translate(
+ 'auto.components.terminal.pane.TerminalLinkActionPopover.copyLinkFailed',
+ 'Failed to copy link'
+ )
const copyDestination = async (): Promise => {
if (copyInFlightRef.current) {
@@ -112,20 +137,10 @@ export function LinkActionPopover({
copyInFlightRef.current = true
try {
if (await copyText()) {
- toast.success(
- translate(
- 'auto.components.terminal.pane.TerminalLinkActionPopover.copiedLink',
- 'Copied link'
- )
- )
+ toast.success(copiedMessage)
return
}
- toast.error(
- translate(
- 'auto.components.terminal.pane.TerminalLinkActionPopover.copyLinkFailed',
- 'Failed to copy link'
- )
- )
+ toast.error(copyFailedMessage)
} finally {
copyInFlightRef.current = false
}
@@ -170,7 +185,7 @@ export function LinkActionPopover({
>
{request.destination}
- {request.kind === 'url' ? (
+ {canCopyDestination ? (