From 52967bebc0276c06878670d15c55b15d2042c661 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 15 Sep 2021 03:54:23 +0100 Subject: [PATCH] Upload file --- .../file-explorer/src/lib/file-explorer.tsx | 63 ++----------------- .../file-explorer/src/lib/types/index.ts | 3 - .../workspace/src/lib/actions/workspace.ts | 49 ++++++++++++++- .../workspace/src/lib/contexts/index.ts | 5 +- .../src/lib/providers/FileSystemProvider.tsx | 11 +++- 5 files changed, 64 insertions(+), 67 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 789bdffa1f..b95b9c5c7e 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -13,13 +13,12 @@ import { contextMenuActions } from './utils' import './css/file-explorer.css' export const FileExplorer = (props: FileExplorerProps) => { - const { name, plugin, focusRoot, contextMenuItems, displayInput, externalUploads, removedContextMenuItems, resetFocus, files } = props + const { name, focusRoot, contextMenuItems, displayInput, externalUploads, removedContextMenuItems, resetFocus, files } = props const [state, setState] = useState({ focusElement: [{ key: '', type: 'folder' }], - fileManager: null, ctrlKey: false, newFileName: '', actions: contextMenuActions, @@ -36,7 +35,6 @@ export const FileExplorer = (props: FileExplorerProps) => { lastEdit: '' }, expandPath: [name], - toasterMsg: '', mouseOverElement: null, showContextMenu: false, reservedKeywords: [name, 'gist-'], @@ -205,7 +203,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const createFile = await fileManager.writeFile(newName, '') if (!createFile) { - return toast('Failed to create file ' + newName) + return global.toast('Failed to create file ' + newName) } else { const path = newName.indexOf(props.name + '/') === 0 ? newName.replace(props.name + '/', '') : newName @@ -239,7 +237,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } const deletePath = async (path: string | string[]) => { - if (global.fs.readonly) return toast('cannot delete file. ' + name + ' is a read only explorer') + if (global.fs.readonly) return global.toast('cannot delete file. ' + name + ' is a read only explorer') if (!Array.isArray(path)) path = [path] global.modal(`Delete ${path.length > 1 ? 'items' : 'item'}`, deleteMessage(path), 'OK', async () => { @@ -251,7 +249,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } catch (e) { const isDir = await state.fileManager.isDirectory(p) - toast(`Failed to remove ${isDir ? 'folder' : 'file'} ${p}.`) + global.toast(`Failed to remove ${isDir ? 'folder' : 'file'} ${p}.`) } } }, 'Cancel', () => {}) @@ -273,55 +271,13 @@ export const FileExplorer = (props: FileExplorerProps) => { } const uploadFile = (target) => { - const filesProvider = fileSystem.provider.provider - // TODO The file explorer is merely a view on the current state of - // the files module. Please ask the user here if they want to overwrite - // a file and then just use `files.add`. The file explorer will - // pick that up via the 'fileAdded' event from the files module. const parentFolder = getFocusedFolder() const expandPath = [...new Set([...state.expandPath, parentFolder])] setState(prevState => { return { ...prevState, expandPath } - }); - - [...target.files].forEach((file) => { - const loadFile = (name: string): void => { - const fileReader = new FileReader() - - fileReader.onload = async function (event) { - if (helper.checkSpecialChars(file.name)) { - global.modal('File Upload Failed', 'Special characters are not allowed', 'Close', async () => {}) - return - } - const success = await filesProvider.set(name, event.target.result) - - if (!success) { - return global.modal('File Upload Failed', 'Failed to create file ' + name, 'Close', async () => {}) - } - const config = registry.get('config').api - const editor = registry.get('editor').api - - if ((config.get('currentFile') === name) && (editor.currentContent() !== event.target.result)) { - editor.setText(event.target.result) - } - } - fileReader.readAsText(file) - } - const name = `${parentFolder}/${file.name}` - - filesProvider.exists(name).then(exist => { - if (!exist) { - loadFile(name) - } else { - global.modal('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, 'OK', () => { - loadFile(name) - }, 'Cancel', () => {}) - } - }).catch(error => { - if (error) console.log(error) - }) }) + global.dispatchUploadFile(target, parentFolder) } const copyFile = (src: string, dest: string) => { @@ -377,12 +333,6 @@ export const FileExplorer = (props: FileExplorerProps) => { plugin.call(cmd.id, cmd.name, cmd) } - const toast = (message: string) => { - setState(prevState => { - return { ...prevState, toasterMsg: message } - }) - } - const handleClickFile = (path: string, type: 'folder' | 'file' | 'gist') => { path = path.indexOf(props.name + '/') === 0 ? path.replace(props.name + '/', '') : path if (!state.ctrlKey) { @@ -564,7 +514,7 @@ export const FileExplorer = (props: FileExplorerProps) => { return { ...prevState, copyElement: [{ key: path, type }] } }) setCanPaste(true) - toast(`Copied to clipboard ${path}`) + global.toast(`Copied to clipboard ${path}`) } const handlePasteClick = (dest: string, destType: string) => { @@ -735,7 +685,6 @@ export const FileExplorer = (props: FileExplorerProps) => { - { state.showContextMenu && 1 ? state.actions.filter(item => item.multiselect) : state.actions.filter(item => !item.multiselect)} diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index 203674d16e..2268e31896 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -5,7 +5,6 @@ export type MenuItems = action[] // eslint-disable-line no-use-before-define export interface FileExplorerProps { name: string, menuItems?: string[], - plugin: any, focusRoot: boolean, contextMenuItems: MenuItems, removedContextMenuItems: MenuItems, @@ -63,7 +62,6 @@ export interface FileExplorerState { key: string type: 'folder' | 'file' | 'gist' }[] - fileManager: any ctrlKey: boolean newFileName: string actions: { @@ -89,7 +87,6 @@ export interface FileExplorerState { lastEdit: string } expandPath: string[] - toasterMsg: string mouseOverElement: string showContextMenu: boolean reservedKeywords: string[] diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index 06095287fd..491b0d8e85 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -254,7 +254,7 @@ const createWorkspaceTemplate = async (workspaceName: string, setDefaults = true provider.lastLoadedGistId = gistId } else { - displayNotification('', errorLoadingFile.message || errorLoadingFile, 'OK', null, () => {}, null) + dispatch(displayNotification('', errorLoadingFile.message || errorLoadingFile, 'OK', null, () => {}, null)) } }) } catch (e) { @@ -697,7 +697,7 @@ export const publishToGist = (path?: string, type?: string) => async (dispatch: } } catch (error) { console.log(error) - displayNotification('Publish to gist Failed', 'Failed to create gist: ' + error.message, 'Close', null, async () => {}) + dispatch(displayNotification('Publish to gist Failed', 'Failed to create gist: ' + error.message, 'Close', null, async () => {})) } } @@ -705,6 +705,51 @@ export const clearPopUp = () => async (dispatch: React.Dispatch) => { dispatch(hidePopUp()) } +export const uploadFile = (target, targetFolder: string) => async (dispatch: React.Dispatch) => { + // TODO The file explorer is merely a view on the current state of + // the files module. Please ask the user here if they want to overwrite + // a file and then just use `files.add`. The file explorer will + // pick that up via the 'fileAdded' event from the files module. + [...target.files].forEach((file) => { + const workspaceProvider = plugin.fileProviders.workspace + const loadFile = (name: string): void => { + const fileReader = new FileReader() + + fileReader.onload = async function (event) { + if (checkSpecialChars(file.name)) { + dispatch(displayNotification('File Upload Failed', 'Special characters are not allowed', 'Close', null, async () => {})) + return + } + const success = await workspaceProvider.set(name, event.target.result) + + if (!success) { + return dispatch(displayNotification('File Upload Failed', 'Failed to create file ' + name, 'Close', null, async () => {})) + } + const config = plugin.registry.get('config').api + const editor = plugin.registry.get('editor').api + + if ((config.get('currentFile') === name) && (editor.currentContent() !== event.target.result)) { + editor.setText(event.target.result) + } + } + fileReader.readAsText(file) + } + const name = `${targetFolder}/${file.name}` + + workspaceProvider.exists(name).then(exist => { + if (!exist) { + loadFile(name) + } else { + dispatch(displayNotification('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, 'OK', null, () => { + loadFile(name) + }, () => {})) + } + }).catch(error => { + if (error) console.log(error) + }) + }) +} + const fileAdded = async (filePath: string) => { await dispatch(fileAddedSuccess(filePath)) if (filePath.includes('_test.sol')) { diff --git a/libs/remix-ui/workspace/src/lib/contexts/index.ts b/libs/remix-ui/workspace/src/lib/contexts/index.ts index 01eda80c88..eed19039c9 100644 --- a/libs/remix-ui/workspace/src/lib/contexts/index.ts +++ b/libs/remix-ui/workspace/src/lib/contexts/index.ts @@ -1,4 +1,4 @@ -import { createContext } from 'react' +import { createContext, SyntheticEvent } from 'react' import { BrowserState } from '../reducers/workspace' export const FileSystemContext = createContext<{ @@ -14,5 +14,6 @@ export const FileSystemContext = createContext<{ dispatchSwitchToWorkspace: (name: string) => Promise, dispatchRenameWorkspace: (oldName: string, workspaceName: string) => Promise, dispatchDeleteWorkspace: (workspaceName: string) => Promise, - dispatchPublishToGist: (path?: string, type?: string) => Promise + dispatchPublishToGist: (path?: string, type?: string) => Promise, + dispatchUploadFile: (target?: SyntheticEvent, targetFolder?: string) => Promise }>(null) diff --git a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx index d3d91b53d6..66d0a3cc82 100644 --- a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx +++ b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx @@ -1,11 +1,11 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars -import React, { useReducer, useState, useEffect } from 'react' +import React, { useReducer, useState, useEffect, SyntheticEvent } from 'react' import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { Toaster } from '@remix-ui/toaster' // eslint-disable-line // eslint-disable-next-line @typescript-eslint/no-unused-vars import { FileSystemContext } from '../contexts' import { browserReducer, browserInitialState } from '../reducers/workspace' -import { initWorkspace, fetchDirectory, addInputField, removeInputField, createWorkspace, fetchWorkspaceDirectory, switchToWorkspace, renameWorkspace, deleteWorkspace, clearPopUp, publishToGist } from '../actions/workspace' +import { initWorkspace, fetchDirectory, addInputField, removeInputField, createWorkspace, fetchWorkspaceDirectory, switchToWorkspace, renameWorkspace, deleteWorkspace, clearPopUp, publishToGist, uploadFile } from '../actions/workspace' import { Modal, WorkspaceProps } from '../types' // eslint-disable-next-line @typescript-eslint/no-unused-vars import { Workspace } from '../remix-ui-workspace' @@ -66,6 +66,10 @@ export const FileSystemProvider = (props: WorkspaceProps) => { await publishToGist(path, type)(fsDispatch) } + const dispatchUploadFile = async (target?: SyntheticEvent, targetFolder?: string) => { + await uploadFile(target, targetFolder)(fsDispatch) + } + useEffect(() => { if (modals.length > 0) { setFocusModal(() => { @@ -149,7 +153,8 @@ export const FileSystemProvider = (props: WorkspaceProps) => { dispatchSwitchToWorkspace, dispatchRenameWorkspace, dispatchDeleteWorkspace, - dispatchPublishToGist + dispatchPublishToGist, + dispatchUploadFile } return (