Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions locales/zh_CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "刷新",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { memo, useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
import {
ClipboardCopy,
Copy,
Eye,
EyeClosed,
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -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 (
<div className={cn('flex h-full min-h-0 flex-col overflow-hidden', className)}>
Expand Down Expand Up @@ -1409,6 +1425,17 @@ function SessionFileContentViewImpl({
<WrapText className="h-3.5 w-3.5" aria-hidden="true" />
</button>
) : null}
{showCopyPathButton ? (
<button
type="button"
onClick={() => void handleCopyFilePath()}
title={t('sessions.fileViewer.copyPath', 'Copy file path')}
aria-label={t('sessions.fileViewer.copyPath', 'Copy file path')}
className="flex h-6 w-6 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
>
<ClipboardCopy className="h-3.5 w-3.5" aria-hidden="true" />
</button>
) : null}
{showSearchButton ? (
<button
type="button"
Expand Down