Commit 39d47a4a authored by ioedeveloper's avatar ioedeveloper

create new file with plugin call

parent 825db4a6
...@@ -132,7 +132,10 @@ module.exports = class Filepanel extends ViewPlugin { ...@@ -132,7 +132,10 @@ module.exports = class Filepanel extends ViewPlugin {
} }
async createNewFile () { async createNewFile () {
return await this.request.createNewFile() const provider = this.fileManager.currentFileProvider()
const dir = provider.workspace || '/'
this.emit('displayNewFileInput', dir)
} }
async uploadFile (event) { async uploadFile (event) {
......
...@@ -11,9 +11,10 @@ import { customAction } from '@remixproject/plugin-api/lib/file-system/file-pane ...@@ -11,9 +11,10 @@ import { customAction } from '@remixproject/plugin-api/lib/file-system/file-pane
import { contextMenuActions } from './utils' import { contextMenuActions } from './utils'
import './css/file-explorer.css' import './css/file-explorer.css'
import { extractParentFromKey } from '@remix-ui/helper'
export const FileExplorer = (props: FileExplorerProps) => { export const FileExplorer = (props: FileExplorerProps) => {
const { name, focusRoot, contextMenuItems, displayInput, externalUploads, removedContextMenuItems, resetFocus, files } = props const { name, focusRoot, contextMenuItems, externalUploads, removedContextMenuItems, resetFocus, files } = props
const [state, setState] = useState<FileExplorerState>({ const [state, setState] = useState<FileExplorerState>({
focusElement: [{ focusElement: [{
key: '', key: '',
...@@ -62,7 +63,7 @@ export const FileExplorer = (props: FileExplorerProps) => { ...@@ -62,7 +63,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
if (editRef && editRef.current) { if (editRef && editRef.current) {
editRef.current.focus() editRef.current.focus()
} }
}, 150) }, 0)
} }
}, [state.focusEdit.element]) }, [state.focusEdit.element])
...@@ -88,11 +89,12 @@ export const FileExplorer = (props: FileExplorerProps) => { ...@@ -88,11 +89,12 @@ export const FileExplorer = (props: FileExplorerProps) => {
}, [contextMenuItems]) }, [contextMenuItems])
useEffect(() => { useEffect(() => {
if (displayInput) { if (global.fs.focusEdit) {
handleNewFileInput() setState(prevState => {
plugin.resetNewFile() return { ...prevState, focusEdit: { element: global.fs.focusEdit, type: 'file', isNew: true, lastEdit: null } }
})
} }
}, [displayInput]) }, [global.fs.focusEdit])
useEffect(() => { useEffect(() => {
if (externalUploads) { if (externalUploads) {
...@@ -173,14 +175,6 @@ export const FileExplorer = (props: FileExplorerProps) => { ...@@ -173,14 +175,6 @@ export const FileExplorer = (props: FileExplorerProps) => {
return keyPath[keyPath.length - 1] return keyPath[keyPath.length - 1]
} }
const extractParentFromKey = (key: string):string => {
if (!key) return
const keyPath = key.split('/')
keyPath.pop()
return keyPath.join('/')
}
const hasReservedKeyword = (content: string): boolean => { const hasReservedKeyword = (content: string): boolean => {
if (state.reservedKeywords.findIndex(value => content.startsWith(value)) !== -1) return true if (state.reservedKeywords.findIndex(value => content.startsWith(value)) !== -1) return true
else return false else return false
...@@ -196,22 +190,11 @@ export const FileExplorer = (props: FileExplorerProps) => { ...@@ -196,22 +190,11 @@ export const FileExplorer = (props: FileExplorerProps) => {
} }
const createNewFile = async (newFilePath: string) => { const createNewFile = async (newFilePath: string) => {
const fileManager = state.fileManager
try { try {
const newName = await helper.createNonClashingNameAsync(newFilePath, fileManager) global.dispatchCreateNewFile(newFilePath, props.name)
const createFile = await fileManager.writeFile(newName, '') // setState(prevState => {
// return { ...prevState, focusElement: [{ key: newName, type: 'file' }] }
if (!createFile) { // })
return global.toast('Failed to create file ' + newName)
} else {
const path = newName.indexOf(props.name + '/') === 0 ? newName.replace(props.name + '/', '') : newName
await fileManager.open(path)
setState(prevState => {
return { ...prevState, focusElement: [{ key: newName, type: 'file' }] }
})
}
} catch (error) { } catch (error) {
return global.modal('File Creation Failed', typeof error === 'string' ? error : error.message, 'Close', async () => {}) return global.modal('File Creation Failed', typeof error === 'string' ? error : error.message, 'Close', async () => {})
} }
...@@ -536,12 +519,14 @@ export const FileExplorer = (props: FileExplorerProps) => { ...@@ -536,12 +519,14 @@ export const FileExplorer = (props: FileExplorerProps) => {
} }
const label = (file: File) => { const label = (file: File) => {
const isEditable = (state.focusEdit.element === file.path) || (global.fs.focusEdit === file.path)
return ( return (
<div <div
className='remixui_items d-inline-block w-100' className='remixui_items d-inline-block w-100'
ref={state.focusEdit.element === file.path ? editRef : null} ref={ isEditable ? editRef : null}
suppressContentEditableWarning={true} suppressContentEditableWarning={true}
contentEditable={state.focusEdit.element === file.path} contentEditable={isEditable}
onKeyDown={handleEditInput} onKeyDown={handleEditInput}
onBlur={(e) => { onBlur={(e) => {
e.stopPropagation() e.stopPropagation()
......
...@@ -19,3 +19,25 @@ export const checkSpecialChars = (name: string) => { ...@@ -19,3 +19,25 @@ export const checkSpecialChars = (name: string) => {
export const checkSlash = (name: string) => { export const checkSlash = (name: string) => {
return name.match(/\//) != null return name.match(/\//) != null
} }
export const createNonClashingNameAsync = async (name, fileManager, prefix = '') => {
if (!name) name = 'Undefined'
let counter
let ext = 'sol'
const reg = /(.*)\.([^.]+)/g
const split = reg.exec(name)
if (split) {
name = split[1]
ext = split[2]
}
let exist = true
do {
const isDuplicate = await fileManager.exists(name + counter + prefix + '.' + ext)
if (isDuplicate) counter = (counter | 0) + 1
else exist = false
} while (exist)
return name + counter + prefix + '.' + ext
}
import React from 'react' import React from 'react'
import { bufferToHex, keccakFromString } from 'ethereumjs-util' import { bufferToHex, keccakFromString } from 'ethereumjs-util'
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
import { checkSpecialChars, checkSlash, extractParentFromKey, extractNameFromKey } from '@remix-ui/helper' import { checkSpecialChars, checkSlash, extractParentFromKey, extractNameFromKey, createNonClashingNameAsync } from '@remix-ui/helper'
import Gists from 'gists' import Gists from 'gists'
const QueryParams = require('../../../../../../apps/remix-ide/src/lib/query-params') const QueryParams = require('../../../../../../apps/remix-ide/src/lib/query-params')
...@@ -421,7 +421,6 @@ const listenOnEvents = (provider) => { ...@@ -421,7 +421,6 @@ const listenOnEvents = (provider) => {
}) })
provider.event.on('fileRenamed', async (oldPath: string, newPath: string) => { provider.event.on('fileRenamed', async (oldPath: string, newPath: string) => {
console.log('oldPath: ', oldPath, 'newPath: ', newPath)
await executeEvent('fileRenamed', oldPath, newPath) await executeEvent('fileRenamed', oldPath, newPath)
}) })
...@@ -469,9 +468,14 @@ const listenOnEvents = (provider) => { ...@@ -469,9 +468,14 @@ const listenOnEvents = (provider) => {
)) ))
} }
}) })
provider.event.on('fileRenamedError', async () => { provider.event.on('fileRenamedError', async () => {
dispatch(displayNotification('File Renamed Failed', '', 'Ok', 'Cancel')) dispatch(displayNotification('File Renamed Failed', '', 'Ok', 'Cancel'))
}) })
plugin.on('filePanel', 'displayNewFileInput', (path) => {
addInputField('file', path)(dispatch)
})
} }
export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.Dispatch<any>) => { export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.Dispatch<any>) => {
...@@ -750,6 +754,20 @@ export const uploadFile = (target, targetFolder: string) => async (dispatch: Rea ...@@ -750,6 +754,20 @@ export const uploadFile = (target, targetFolder: string) => async (dispatch: Rea
}) })
} }
export const createNewFile = (path: string, rootDir: string) => async (dispatch: React.Dispatch<any>) => {
const fileManager = plugin.fileManager
const newName = await createNonClashingNameAsync(path, fileManager)
const createFile = await fileManager.writeFile(newName, '')
if (!createFile) {
return dispatch(displayPopUp('Failed to create file ' + newName))
} else {
const path = newName.indexOf(rootDir + '/') === 0 ? newName.replace(rootDir + '/', '') : newName
await fileManager.open(path)
}
}
const fileAdded = async (filePath: string) => { const fileAdded = async (filePath: string) => {
await dispatch(fileAddedSuccess(filePath)) await dispatch(fileAddedSuccess(filePath))
if (filePath.includes('_test.sol')) { if (filePath.includes('_test.sol')) {
......
...@@ -15,5 +15,6 @@ export const FileSystemContext = createContext<{ ...@@ -15,5 +15,6 @@ export const FileSystemContext = createContext<{
dispatchRenameWorkspace: (oldName: string, workspaceName: string) => Promise<void>, dispatchRenameWorkspace: (oldName: string, workspaceName: string) => Promise<void>,
dispatchDeleteWorkspace: (workspaceName: string) => Promise<void>, dispatchDeleteWorkspace: (workspaceName: string) => Promise<void>,
dispatchPublishToGist: (path?: string, type?: string) => Promise<void>, dispatchPublishToGist: (path?: string, type?: string) => Promise<void>,
dispatchUploadFile: (target?: SyntheticEvent, targetFolder?: string) => Promise<void> dispatchUploadFile: (target?: SyntheticEvent, targetFolder?: string) => Promise<void>,
dispatchCreateNewFile: (path: string, rootDir: string) => Promise<void>
}>(null) }>(null)
...@@ -5,7 +5,7 @@ import { Toaster } from '@remix-ui/toaster' // eslint-disable-line ...@@ -5,7 +5,7 @@ import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
import { FileSystemContext } from '../contexts' import { FileSystemContext } from '../contexts'
import { browserReducer, browserInitialState } from '../reducers/workspace' import { browserReducer, browserInitialState } from '../reducers/workspace'
import { initWorkspace, fetchDirectory, addInputField, removeInputField, createWorkspace, fetchWorkspaceDirectory, switchToWorkspace, renameWorkspace, deleteWorkspace, clearPopUp, publishToGist, uploadFile } from '../actions/workspace' import { initWorkspace, fetchDirectory, addInputField, removeInputField, createWorkspace, fetchWorkspaceDirectory, switchToWorkspace, renameWorkspace, deleteWorkspace, clearPopUp, publishToGist, uploadFile, createNewFile } from '../actions/workspace'
import { Modal, WorkspaceProps } from '../types' import { Modal, WorkspaceProps } from '../types'
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Workspace } from '../remix-ui-workspace' import { Workspace } from '../remix-ui-workspace'
...@@ -70,6 +70,10 @@ export const FileSystemProvider = (props: WorkspaceProps) => { ...@@ -70,6 +70,10 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
await uploadFile(target, targetFolder)(fsDispatch) await uploadFile(target, targetFolder)(fsDispatch)
} }
const dispatchCreateNewFile = async (path: string, rootDir: string) => {
await createNewFile(path, rootDir)(fsDispatch)
}
useEffect(() => { useEffect(() => {
if (modals.length > 0) { if (modals.length > 0) {
setFocusModal(() => { setFocusModal(() => {
...@@ -154,7 +158,8 @@ export const FileSystemProvider = (props: WorkspaceProps) => { ...@@ -154,7 +158,8 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
dispatchRenameWorkspace, dispatchRenameWorkspace,
dispatchDeleteWorkspace, dispatchDeleteWorkspace,
dispatchPublishToGist, dispatchPublishToGist,
dispatchUploadFile dispatchUploadFile,
dispatchCreateNewFile
} }
return ( return (
<FileSystemContext.Provider value={value}> <FileSystemContext.Provider value={value}>
......
...@@ -32,7 +32,8 @@ export interface BrowserState { ...@@ -32,7 +32,8 @@ export interface BrowserState {
labelCancel: string labelCancel: string
}, },
readonly: boolean, readonly: boolean,
popup: string popup: string,
focusEdit: string
} }
export const browserInitialState: BrowserState = { export const browserInitialState: BrowserState = {
...@@ -63,7 +64,8 @@ export const browserInitialState: BrowserState = { ...@@ -63,7 +64,8 @@ export const browserInitialState: BrowserState = {
labelCancel: '' labelCancel: ''
}, },
readonly: false, readonly: false,
popup: '' popup: '',
focusEdit: ''
} }
export const browserReducer = (state = browserInitialState, action: Action) => { export const browserReducer = (state = browserInitialState, action: Action) => {
...@@ -320,7 +322,8 @@ export const browserReducer = (state = browserInitialState, action: Action) => { ...@@ -320,7 +322,8 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
localhost: { localhost: {
...state.localhost, ...state.localhost,
files: state.mode === 'localhost' ? fetchDirectoryContent(state, payload) : state.localhost.files files: state.mode === 'localhost' ? fetchDirectoryContent(state, payload) : state.localhost.files
} },
focusEdit: payload.path + '/' + 'blank'
} }
} }
...@@ -336,7 +339,8 @@ export const browserReducer = (state = browserInitialState, action: Action) => { ...@@ -336,7 +339,8 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
localhost: { localhost: {
...state.localhost, ...state.localhost,
files: state.mode === 'localhost' ? fetchDirectoryContent(state, payload, payload.path + '/' + 'blank') : state.localhost.files files: state.mode === 'localhost' ? fetchDirectoryContent(state, payload, payload.path + '/' + 'blank') : state.localhost.files
} },
focusEdit: null
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment