diff --git a/src/plugins/driveBrowserPlugin.ts b/src/plugins/driveBrowserPlugin.ts index 2664dbc..0613c03 100644 --- a/src/plugins/driveBrowserPlugin.ts +++ b/src/plugins/driveBrowserPlugin.ts @@ -29,7 +29,9 @@ import { newFolderIcon, fileIcon, notebookIcon, - editIcon + editIcon, + copyIcon, + pasteIcon } from '@jupyterlab/ui-components'; import { PageConfig, PathExt } from '@jupyterlab/coreutils'; import { CommandRegistry } from '@lumino/commands'; @@ -37,7 +39,7 @@ import { Widget } from '@lumino/widgets'; import { driveBrowserIcon, removeIcon } from '../icons'; import { Drive } from '../contents'; -import { setListingLimit } from '../requests'; +import { getContents, setListingLimit } from '../requests'; import { CommandIDs } from '../token'; /** @@ -697,5 +699,85 @@ namespace Private { '#drive-file-browser.jp-SidePanel .jp-DirListing-content .jp-DirListing-item[data-isdir]', rank: 110 }); + + app.commands.addCommand(CommandIDs.copyToFilebrowser, { + isVisible: () => { + // So long as this command only handles one file at time, don't show it + // if multiple files are selected. + return ( + !!tracker.currentWidget && + Array.from(tracker.currentWidget.selectedItems()).length === 1 && + browser.model.path !== 's3:' + ); + }, + isEnabled: () => { + return ( + !!tracker.currentWidget && + tracker.currentWidget?.selectedItems().next()!.value && + tracker.currentWidget?.selectedItems().next()!.value.type !== + 'directory' + ); + }, + execute: async () => { + let currentPath: string = tracker.currentWidget?.selectedItems().next() + .value.path; + Clipboard.copyToSystem(currentPath); + }, + label: 'Copy to Filebrowser', + icon: copyIcon.bindprops({ stylesheet: 'menuItem' }) + }); + + app.contextMenu.addItem({ + command: CommandIDs.copyToFilebrowser, + selector: '#drive-file-browser.jp-SidePanel .jp-DirListing-content', + rank: 10 + }); + + app.commands.addCommand(CommandIDs.pasteToFilebrowser, { + isVisible: () => { + return ( + !!factory.tracker.currentWidget && + factory.tracker.currentWidget!.id === 'filebrowser' + ); + }, + execute: async (args: any) => { + // Get path from clipboard. + let currentPath = await navigator.clipboard.readText(); + // Remove leading drive suffix. + currentPath = currentPath.substring(currentPath.indexOf(':') + 1); + const driveName = currentPath.substring(0, currentPath.indexOf('/')); + // Remove drive name. + currentPath = currentPath.substring(currentPath.indexOf('/') + 1); + const fileName = PathExt.basename(currentPath); + + const filebrowser = factory.tracker.find(fb => fb.id === 'filebrowser'); + + // Save new file. + const toDir = factory.tracker.currentWidget!.model.path; + app.serviceManager.contents.save(PathExt.join(toDir, fileName), { + type: 'file', + format: + PathExt.extname(fileName) === '.txt' || + PathExt.extname(fileName) === '.ipynb' + ? 'text' + : 'base64', + content: ( + await getContents(driveName, { + path: currentPath, + registeredFileTypes: drive.registeredFileTypes + }) + ).response.data.content + }); + await filebrowser?.model.refresh(); + }, + label: 'Paste from Drive', + icon: pasteIcon.bindprops({ stylesheet: 'menuItem' }) + }); + + app.contextMenu.addItem({ + command: CommandIDs.pasteToFilebrowser, + selector: '.jp-FileBrowser-listing', + rank: 10 + }); } } diff --git a/src/token.ts b/src/token.ts index acd8ed5..516d34c 100644 --- a/src/token.ts +++ b/src/token.ts @@ -19,6 +19,8 @@ export namespace CommandIDs { export const copyPath = 'drives:copy-path'; export const excludeDrive = 'drives:exclude-drive'; export const includeDrive = 'drives:include-drive'; + export const copyToFilebrowser = 'drives:copy-to-filebrowser'; + export const pasteToFilebrowser = 'drives:paste-to-filebrowser'; } /**