From 6926e40e19df3aa1fe11399616c444b30ec35ac0 Mon Sep 17 00:00:00 2001 From: Diogo Silva Date: Thu, 24 Jan 2019 10:43:52 +0000 Subject: [PATCH] feat: add file operations in preview (#936) ![preview](https://user-images.githubusercontent.com/33324750/51191990-74ec6800-18dd-11e9-877c-2779c2fd56f7.gif) Closes https://github.com/ipfs-shipyard/ipfs-webui/issues/813. --- src/bundles/files.js | 32 +++++++++++++- src/files/FilesPage.js | 63 +++++++++++++++------------ src/files/context-menu/ContextMenu.js | 7 ++- src/files/file-preview/FilePreview.js | 5 ++- src/files/file/File.js | 1 - src/files/files-list/FilesList.js | 16 +++---- 6 files changed, 80 insertions(+), 44 deletions(-) diff --git a/src/bundles/files.js b/src/bundles/files.js index 1a49845e7..253b145db 100644 --- a/src/bundles/files.js +++ b/src/bundles/files.js @@ -44,6 +44,27 @@ const make = (basename, action) => (...args) => async (args2) => { try { data = await action(getIpfs(), ...args, id, args2) dispatch({ type: `FILES_${basename}_FINISHED`, payload: { id, ...data } }) + + // Rename specific logic + if (basename === actions.MOVE) { + const src = args[0][0] + const dst = args[0][1] + + if (src === store.selectFiles().path) { + await store.doUpdateHash(`/files${dst}`) + } + } + + // Delete specific logic + if (basename === actions.DELETE) { + const src = args[0][0] + + let path = src.split('/') + path.pop() + path = path.join('/') + + await store.doUpdateHash(`/files${path}`) + } } catch (error) { dispatch({ type: `FILES_${basename}_FAILED`, payload: { id, error } }) } finally { @@ -67,7 +88,16 @@ const fetchFiles = make(actions.FETCH, async (ipfs, id, { store }) => { fetched: Date.now(), type: 'file', stats: stats, - read: () => ipfs.files.read(path) + read: () => ipfs.files.read(path), + // TODO - This will be refactored in the future + // I'm adding this here to make the file actions work in preview mode + extra: [{ + name: path.split('/').pop(), + path: path, + type: 'file', + size: stats.size, + hash: stats.hash + }] } } diff --git a/src/files/FilesPage.js b/src/files/FilesPage.js index e1c172b41..73dec4bc6 100644 --- a/src/files/FilesPage.js +++ b/src/files/FilesPage.js @@ -11,6 +11,7 @@ import Breadcrumbs from './breadcrumbs/Breadcrumbs' import FilesList from './files-list/FilesList' import FilePreview from './file-preview/FilePreview' import FileInput from './file-input/FileInput' +import ContextMenu from './context-menu/ContextMenu' import Overlay from '../components/overlay/Overlay' import ShareModal from './share-modal/ShareModal' import RenameModal from './rename-modal/RenameModal' @@ -35,7 +36,8 @@ const defaultState = { paths: [], files: 0, folders: 0 - } + }, + isContextMenuOpen: false } class FilesPage extends React.Component { @@ -178,23 +180,23 @@ class FilesPage extends React.Component { this.props.doFilesDelete(paths) } + handleContextMenuClick = (ev) => { + // This is needed to disable the native OS right-click menu + // and deal with the clicking on the ContextMenu options + if (ev !== undefined && typeof ev !== 'string') { + ev.preventDefault() + } + + this.setState(state => ({ isContextMenuOpen: !state.isContextMenuOpen })) + } + render () { const { - ipfsProvider, - files, - writeFilesProgress, - doFilesMove, - doFilesNavigateTo, - doFilesUpdateSorting, - filesSorting: sort, - t + ipfsProvider, files, writeFilesProgress, filesSorting: sort, t, + doFilesMove, doFilesNavigateTo, doFilesUpdateSorting } = this.props - const { - share, - rename, - delete: deleteModal - } = this.state + const { share, rename, delete: deleteModal } = this.state const isCompanion = ipfsProvider === 'window.ipfs' const filesExist = files && files.content && files.content.length @@ -208,17 +210,27 @@ class FilesPage extends React.Component { { files &&
-
- +
+ - { files.type === 'directory' && - - } + :
{/* to render correctly in Firefox */} + this.showShareModal(files.extra)} + onDelete={() => this.showDeleteModal(files.extra)} + onRename={() => this.showRenameModal(files.extra)} + onInspect={() => this.inspect(files.extra)} + onDownload={() => this.download(files.extra)} + hash={files.stats.hash} /> +
}
{ isRoot && isCompanion && } @@ -227,8 +239,8 @@ class FilesPage extends React.Component { { isRoot && !filesExist && } - { files.type === 'directory' ? ( - - ) : ( - - )} + onMove={doFilesMove} /> + : }
} diff --git a/src/files/context-menu/ContextMenu.js b/src/files/context-menu/ContextMenu.js index 10e09e6fa..6aee4eff4 100644 --- a/src/files/context-menu/ContextMenu.js +++ b/src/files/context-menu/ContextMenu.js @@ -25,6 +25,7 @@ class ContextMenu extends React.Component { onInspect: PropTypes.func, onShare: PropTypes.func, hash: PropTypes.string.isRequired, + className: PropTypes.string, t: PropTypes.func.isRequired, tReady: PropTypes.bool.isRequired } @@ -34,6 +35,8 @@ class ContextMenu extends React.Component { top: 0, left: 0, right: 'auto', + translateX: 0, + translateY: 0, className: '' } @@ -47,10 +50,10 @@ class ContextMenu extends React.Component { } render () { - const { t, onRename, onDelete, onDownload, onInspect, onShare, translateX, translateY } = this.props + const { t, onRename, onDelete, onDownload, onInspect, onShare, translateX, translateY, className } = this.props return ( - + default: const cantPreview = ( -
+

{t('cantBePreviewed')} 😢

diff --git a/src/files/file/File.js b/src/files/file/File.js index 38e73028f..d311dc4a1 100644 --- a/src/files/file/File.js +++ b/src/files/file/File.js @@ -147,7 +147,6 @@ class File extends React.Component { translateX={this.state.translateX} translateY={this.state.translateY} isOpen={this.state.isContextMenuOpen} - mousePosition={this.state.mousePosition} onShare={onShare} onDelete={onDelete} onRename={onRename} diff --git a/src/files/files-list/FilesList.js b/src/files/files-list/FilesList.js index 92968fc4b..8f11489e0 100644 --- a/src/files/files-list/FilesList.js +++ b/src/files/files-list/FilesList.js @@ -93,13 +93,12 @@ export class FilesList extends React.Component { unselect={unselectAll} remove={() => this.props.onDelete(this.selectedFiles)} rename={() => this.props.onRename(this.selectedFiles)} - share={this.wrapWithSelected('onShare')} - download={this.wrapWithSelected('onDownload')} - inspect={this.wrapWithSelected('onInspect')} + share={() => this.props.onShare(this.selectedFiles)} + download={() => this.props.onDownload(this.selectedFiles)} + inspect={() => this.props.onInspect(this.selectedFiles)} count={this.state.selected.length} downloadProgress={this.props.downloadProgress} - size={size} - /> + size={size} /> ) } @@ -133,8 +132,7 @@ export class FilesList extends React.Component { key={window.encodeURIComponent(file.name)} setIsDragging={this.isDragging} translucent={this.state.isDragging || (isOver && canDrop)} - {...file} - /> + {...file} /> )) } @@ -156,10 +154,6 @@ export class FilesList extends React.Component { } } - wrapWithSelected = (fn) => async () => { - this.props[fn](this.selectedFiles) - } - keyHandler = (e) => { const { selected, focused } = this.state