diff --git a/locales/en.json b/locales/en.json index 44b6924d7..e626ca477 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1411,6 +1411,7 @@ "sessions.fileViewer.openFile": "Open file", "sessions.fileViewer.path": "File path", "sessions.fileViewer.pathCopied": "File path copied", + "sessions.fileViewer.pathCopyFailed": "Failed to copy file path", "sessions.fileViewer.preview.show": "Preview", "sessions.fileViewer.preview.hide": "Hide preview", "sessions.fileViewer.refresh": "Refresh", diff --git a/locales/zh_CN.json b/locales/zh_CN.json index 34f61a95c..a29983c7b 100644 --- a/locales/zh_CN.json +++ b/locales/zh_CN.json @@ -1411,6 +1411,7 @@ "sessions.fileViewer.openFile": "打开文件", "sessions.fileViewer.path": "文件路径", "sessions.fileViewer.pathCopied": "文件路径已复制", + "sessions.fileViewer.pathCopyFailed": "复制文件路径失败", "sessions.fileViewer.preview.show": "预览", "sessions.fileViewer.preview.hide": "退出预览", "sessions.fileViewer.refresh": "刷新", diff --git a/packages/components/src/components/sessions/session-file-content-view.tsx b/packages/components/src/components/sessions/session-file-content-view.tsx index 559b2ad24..8429454b2 100644 --- a/packages/components/src/components/sessions/session-file-content-view.tsx +++ b/packages/components/src/components/sessions/session-file-content-view.tsx @@ -1,5 +1,6 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'; import { + ClipboardCopy, Copy, Eye, EyeClosed, @@ -892,6 +893,17 @@ function SessionFileContentViewImpl({ ); } }, [data, normalizedPath, tRef]); + // SP28: the desktop viewer had no way to get at the path it is showing. + // `MobileFileViewerDrawer` has carried this action since it landed, under the + // same `sessions.fileViewer.copyPath` key. + const handleCopyFilePath = useCallback(async () => { + const copied = await writeTextToClipboard(normalizedPath); + if (copied) { + toast.success(tRef.current('sessions.fileViewer.pathCopied', 'File path copied')); + } else { + toast.error(tRef.current('sessions.fileViewer.pathCopyFailed', 'Failed to copy file path')); + } + }, [normalizedPath, tRef]); const lastCopyMarkdownRequestSeqRef = useRef(copyMarkdownRequestSeq ?? 0); useEffect(() => { if ( @@ -1300,12 +1312,16 @@ function SessionFileContentViewImpl({ isTextFileReady && !showSvgRendered && !showMarkdownRendered && !showHtmlRendered; const showSaveButton = isProviderFileEditable && isTextFileReady; const showRefreshButton = shouldUseProviderFileContent && isTextFileReady; + // The path is knowable for every file the viewer can show, binary previews + // included, so this control has no condition of its own. + const showCopyPathButton = normalizedPath.length > 0; const showViewerTopBar = showPreviewToggle || isMarkdownTextFile || showSearchButton || showSaveButton || - showRefreshButton; + showRefreshButton || + showCopyPathButton; return (
@@ -1409,6 +1425,17 @@ function SessionFileContentViewImpl({