Skip to content
Closed
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 services/web/frontend/extracted-translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@
"cookie_banner_info": "",
"copied": "",
"copy": "",
"copy_path": "",
"copy_project": "",
"copy_response": "",
"copy_sharing_link": "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ function FileTreeItemMenuItems() {
startUploadingDocOrFile,
downloadPath,
selectedFileName,
selectedEntityPath,
canSetRootDocId,
setRootDocId,
} = useFileTreeActionable()
Expand All @@ -48,6 +49,12 @@ function FileTreeItemMenuItems() {
startUploadingDocOrFile()
}, [startUploadingDocOrFile])

const copyPath = useCallback(() => {
if (selectedEntityPath) {
navigator.clipboard?.writeText(selectedEntityPath)
}
}, [selectedEntityPath])

const isDisabledDueToNetworkStall = useIsNetworkStalled()

return (
Expand All @@ -74,6 +81,16 @@ function FileTreeItemMenuItems() {
</OLDropdownItem>
</li>
) : null}
{selectedEntityPath ? (
<li role="none">
<OLDropdownItem
onClick={copyPath}
disabled={isDisabledDueToNetworkStall}
>
{t('copy_path')}
</OLDropdownItem>
</li>
) : null}
{canSetRootDocId ? (
<>
<OLDropdownDivider />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from '../util/sync-mutation'
import { findInTree, findInTreeOrThrow } from '../util/find-in-tree'
import { isNameUniqueInFolder } from '../util/is-name-unique-in-folder'
import { pathInFolder } from '../util/path'
import { isBlockedFilename, isCleanFilename } from '../util/safe-path'

import { useProjectContext } from '../../../shared/context/project-context'
Expand Down Expand Up @@ -68,6 +69,7 @@ const FileTreeActionableContext = createContext<
canCreate: boolean
parentFolderId: string
selectedFileName: string | null | undefined
selectedEntityPath: string | null
isDuplicate: (parentFolderId: string, name: string) => boolean
startRenaming: any
finishRenaming: any
Expand Down Expand Up @@ -406,6 +408,14 @@ export const FileTreeActionableProvider: FC<React.PropsWithChildren> = ({
)
}, [fileTreeData, selectedEntityIds, isRootFolderSelected])

const selectedEntityPath = useMemo(() => {
if (selectedEntityIds.size === 1) {
const [selectedEntityId] = selectedEntityIds
return pathInFolder(fileTreeData, selectedEntityId)
}
return null
}, [fileTreeData, selectedEntityIds])

// return the name of the selected file or doc if there is only one selected
const selectedFileName = useMemo(() => {
if (selectedEntityIds.size === 1) {
Expand Down Expand Up @@ -566,6 +576,7 @@ export const FileTreeActionableProvider: FC<React.PropsWithChildren> = ({
...state,
parentFolderId,
selectedFileName,
selectedEntityPath,
isDuplicate,
startRenaming,
finishRenaming,
Expand Down Expand Up @@ -600,6 +611,7 @@ export const FileTreeActionableProvider: FC<React.PropsWithChildren> = ({
isRootFolderSelected,
parentFolderId,
selectedFileName,
selectedEntityPath,
selectedEntityIds.size,
startCreatingDocOrFile,
startCreatingFile,
Expand Down
1 change: 1 addition & 0 deletions services/web/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@
"cookie_banner_info": "We use cookies to improve your experience on our site, for analytics, and to support marketing, which may involve the sharing of data. You can find out more in our <0>cookie policy</0>.",
"copied": "Copied",
"copy": "Copy",
"copy_path": "Copy path",
"copy_project": "Copy project",
"copy_response": "Copy response",
"copy_sharing_link": "Copy sharing link",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,56 @@ describe('FileTree Context Menu Flow', function () {
cy.findByRole('menu').should('not.exist')
})

it('copies entity path to clipboard when clicking "Copy path"', function () {
const rootFolder = [
{
_id: 'root-folder-id',
name: 'rootFolder',
docs: [{ _id: 'main-doc', name: 'main.tex' }],
folders: [
{
_id: 'sub-folder-id',
name: 'images',
docs: [],
folders: [],
fileRefs: [{ _id: 'img-file', name: 'figure.png', hash: '123' }],
},
],
fileRefs: [],
},
]

cy.window().then(win => {
cy.stub(win.navigator.clipboard, 'writeText').as('writeText')
})

cy.mount(
<EditorProviders
rootFolder={rootFolder as any}
projectId="123abc"
rootDocId="main-doc"
>
<FileTreeRoot
refProviders={{}}
setRefProviderEnabled={cy.stub()}
setStartedFreeTrial={cy.stub()}
onSelect={cy.stub()}
onInit={cy.stub()}
isConnected
/>
</EditorProviders>
)

cy.findByRole('treeitem', { name: 'images' }).click()
cy.findByRole('treeitem', { name: 'figure.png' }).trigger('contextmenu')
cy.findByRole('menu').findByRole('menuitem', { name: 'Copy path' }).click()

cy.get('@writeText').should(
'have.been.calledOnceWithExactly',
'images/figure.png'
)
})

it('shows "set main document" item when appropriate', function () {
const rootFolder = [
{
Expand Down