File provider actions

pull/5370/head
ioedeveloper 4 years ago
parent f97801de8a
commit ea5118f7b6
  1. 2
      apps/remix-ide/src/app/panels/file-panel.js
  2. 53
      libs/remix-ui/file-explorer/src/lib/actions/fileSystem.ts
  3. 551
      libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
  4. 88
      libs/remix-ui/file-explorer/src/lib/reducers/fileSystem.ts

@ -229,7 +229,7 @@ module.exports = class Filepanel extends ViewPlugin {
/** these are called by the react component, action is already finished whent it's called */ /** these are called by the react component, action is already finished whent it's called */
async setWorkspace (workspace) { async setWorkspace (workspace) {
this._deps.fileManager.closeAllFiles() this._deps.fileManager.removeTabsOf(this._deps.fileProviders.workspace)
if (workspace.isLocalhost) { if (workspace.isLocalhost) {
this.call('manager', 'activatePlugin', 'remixd') this.call('manager', 'activatePlugin', 'remixd')
} else if (await this.call('manager', 'isActive', 'remixd')) { } else if (await this.call('manager', 'isActive', 'remixd')) {

@ -3,10 +3,12 @@ import { File } from '../types'
import { extractNameFromKey, extractParentFromKey } from '../utils' import { extractNameFromKey, extractParentFromKey } from '../utils'
const globalRegistry = require('../../../../../../apps/remix-ide/src/global/registry') const globalRegistry = require('../../../../../../apps/remix-ide/src/global/registry')
const fileProviders = globalRegistry.get('fileproviders').api const initializeProvider = () => {
const browser = fileProviders.browser // eslint-disable-line const fileProviders = globalRegistry.get('fileproviders').api
const workspace = fileProviders.workspace const browser = fileProviders.browser // eslint-disable-line
const localhost = fileProviders.localhost // eslint-disable-line const workspace = fileProviders.workspace
const localhost = fileProviders.localhost // eslint-disable-line
}
export const fetchDirectoryError = (error: any) => { export const fetchDirectoryError = (error: any) => {
return { return {
@ -62,9 +64,9 @@ const normalize = (filesList): File[] => {
return [...folders, ...files] return [...folders, ...files]
} }
const fetchDirectoryContent = async (folderPath: string): Promise<File[]> => { const fetchDirectoryContent = async (provider, folderPath: string): Promise<File[]> => {
return new Promise((resolve) => { return new Promise((resolve) => {
workspace.resolveDirectory(folderPath, (error, fileTree) => { provider.resolveDirectory(folderPath, (error, fileTree) => {
if (error) console.error(error) if (error) console.error(error)
const files = normalize(fileTree) const files = normalize(fileTree)
@ -73,8 +75,43 @@ const fetchDirectoryContent = async (folderPath: string): Promise<File[]> => {
}) })
} }
export const fetchDirectory = (path: string) => (dispatch: React.Dispatch<any>) => { export const fetchDirectory = (provider, path: string) => (dispatch: React.Dispatch<any>) => {
const promise = fetchDirectoryContent(path) initializeProvider()
const promise = fetchDirectoryContent(provider, path)
dispatch(fetchDirectoryRequest(promise))
promise.then((files) => {
dispatch(fetchDirectorySuccess(path, files))
}).catch((error) => {
dispatch(fetchDirectoryError({ error }))
})
return promise
}
export const fetchProviderError = (error: any) => {
return {
type: 'FETCH_PROVIDER_ERROR',
payload: error
}
}
export const fetchProviderRequest = (promise: Promise<any>) => {
return {
type: 'FETCH_PROVIDER_REQUEST',
payload: promise
}
}
export const fetchProviderSuccess = (provider: any) => {
return {
type: 'FETCH_PROVIDER_SUCCESS',
payload: provider
}
}
export const setProvider = () => (dispatch: React.Dispatch<any>) => {
initializeProvider()
const promise = fetchDirectoryContent(provider, path)
dispatch(fetchDirectoryRequest(promise)) dispatch(fetchDirectoryRequest(promise))
promise.then((files) => { promise.then((files) => {

@ -1,4 +1,4 @@
import React, { useEffect, useState, useRef } from 'react' // eslint-disable-line import React, { useEffect, useState, useRef, useReducer } from 'react' // eslint-disable-line
// import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line // import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line
import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line
import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line
@ -7,6 +7,8 @@ import Gists from 'gists'
import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line
import { FileExplorerContextMenu } from './file-explorer-context-menu' // eslint-disable-line import { FileExplorerContextMenu } from './file-explorer-context-menu' // eslint-disable-line
import { FileExplorerProps, File } from './types' import { FileExplorerProps, File } from './types'
import { fileSystemReducer, fileSystemInitialState } from './reducers/fileSystem'
import { fetchDirectory } from './actions/fileSystem'
import * as helper from '../../../../../apps/remix-ide/src/lib/helper' import * as helper from '../../../../../apps/remix-ide/src/lib/helper'
import QueryParams from '../../../../../apps/remix-ide/src/lib/query-params' import QueryParams from '../../../../../apps/remix-ide/src/lib/query-params'
@ -60,6 +62,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
mouseOverElement: null, mouseOverElement: null,
showContextMenu: false showContextMenu: false
}) })
const [fileSystem, dispatch] = useReducer(fileSystemReducer, fileSystemInitialState)
const editRef = useRef(null) const editRef = useRef(null)
useEffect(() => { useEffect(() => {
@ -74,8 +77,8 @@ export const FileExplorer = (props: FileExplorerProps) => {
useEffect(() => { useEffect(() => {
(async () => { (async () => {
await fetchDirectory(filesProvider, name)(dispatch)
const fileManager = registry.get('filemanager').api const fileManager = registry.get('filemanager').api
const files = await fetchDirectoryContent(name)
const actions = [{ const actions = [{
id: 'newFile', id: 'newFile',
name: 'New File', name: 'New File',
@ -121,7 +124,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
}] }]
setState(prevState => { setState(prevState => {
return { ...prevState, fileManager, files, actions, expandPath: [name] } return { ...prevState, fileManager, actions, expandPath: [name] }
}) })
})() })()
}, [name]) }, [name])
@ -134,35 +137,35 @@ export const FileExplorer = (props: FileExplorerProps) => {
} }
}, [state.fileManager]) }, [state.fileManager])
useEffect(() => { // useEffect(() => {
const { expandPath } = state // const { expandPath } = state
const expandFn = async () => { // const expandFn = async () => {
let files = state.files // let files = state.files
for (let i = 0; i < expandPath.length; i++) { // for (let i = 0; i < expandPath.length; i++) {
files = await resolveDirectory(expandPath[i], files) // files = await resolveDirectory(expandPath[i], files)
await setState(prevState => { // await setState(prevState => {
return { ...prevState, files } // return { ...prevState, files }
}) // })
} // }
} // }
if (expandPath && expandPath.length > 0) { // if (expandPath && expandPath.length > 0) {
expandFn() // expandFn()
} // }
}, [state.expandPath]) // }, [state.expandPath])
useEffect(() => { // useEffect(() => {
// unregister event to update state in callback // // unregister event to update state in callback
if (filesProvider.event.registered.fileAdded) filesProvider.event.unregister('fileAdded', fileAdded) // if (filesProvider.event.registered.fileAdded) filesProvider.event.unregister('fileAdded', fileAdded)
if (filesProvider.event.registered.folderAdded) filesProvider.event.unregister('folderAdded', folderAdded) // if (filesProvider.event.registered.folderAdded) filesProvider.event.unregister('folderAdded', folderAdded)
if (filesProvider.event.registered.fileRemoved) filesProvider.event.unregister('fileRemoved', fileRemoved) // if (filesProvider.event.registered.fileRemoved) filesProvider.event.unregister('fileRemoved', fileRemoved)
if (filesProvider.event.registered.fileRenamed) filesProvider.event.unregister('fileRenamed', fileRenamed) // if (filesProvider.event.registered.fileRenamed) filesProvider.event.unregister('fileRenamed', fileRenamed)
filesProvider.event.register('fileAdded', fileAdded) // filesProvider.event.register('fileAdded', fileAdded)
filesProvider.event.register('folderAdded', folderAdded) // filesProvider.event.register('folderAdded', folderAdded)
filesProvider.event.register('fileRemoved', fileRemoved) // filesProvider.event.register('fileRemoved', fileRemoved)
filesProvider.event.register('fileRenamed', fileRenamed) // filesProvider.event.register('fileRenamed', fileRenamed)
}, [state.files]) // }, [state.files])
useEffect(() => { useEffect(() => {
if (focusRoot) { if (focusRoot) {
@ -220,44 +223,44 @@ export const FileExplorer = (props: FileExplorerProps) => {
} }
}, [state.modals]) }, [state.modals])
const resolveDirectory = async (folderPath, dir: File[], isChild = false): Promise<File[]> => { // const resolveDirectory = async (folderPath, dir: File[], isChild = false): Promise<File[]> => {
if (!isChild && (state.focusEdit.element === '/blank') && state.focusEdit.isNew && (dir.findIndex(({ path }) => path === '/blank') === -1)) { // if (!isChild && (state.focusEdit.element === '/blank') && state.focusEdit.isNew && (dir.findIndex(({ path }) => path === '/blank') === -1)) {
dir = state.focusEdit.type === 'file' ? [...dir, { // dir = state.focusEdit.type === 'file' ? [...dir, {
path: state.focusEdit.element, // path: state.focusEdit.element,
name: '', // name: '',
isDirectory: false // isDirectory: false
}] : [{ // }] : [{
path: state.focusEdit.element, // path: state.focusEdit.element,
name: '', // name: '',
isDirectory: true // isDirectory: true
}, ...dir] // }, ...dir]
} // }
dir = await Promise.all(dir.map(async (file) => { // dir = await Promise.all(dir.map(async (file) => {
if (file.path === folderPath) { // if (file.path === folderPath) {
if ((extractParentFromKey(state.focusEdit.element) === folderPath) && state.focusEdit.isNew) { // if ((extractParentFromKey(state.focusEdit.element) === folderPath) && state.focusEdit.isNew) {
file.child = state.focusEdit.type === 'file' ? [...await fetchDirectoryContent(folderPath), { // file.child = state.focusEdit.type === 'file' ? [...await fetchDirectoryContent(folderPath), {
path: state.focusEdit.element, // path: state.focusEdit.element,
name: '', // name: '',
isDirectory: false // isDirectory: false
}] : [{ // }] : [{
path: state.focusEdit.element, // path: state.focusEdit.element,
name: '', // name: '',
isDirectory: true // isDirectory: true
}, ...await fetchDirectoryContent(folderPath)] // }, ...await fetchDirectoryContent(folderPath)]
} else { // } else {
file.child = await fetchDirectoryContent(folderPath) // file.child = await fetchDirectoryContent(folderPath)
} // }
return file // return file
} else if (file.child) { // } else if (file.child) {
file.child = await resolveDirectory(folderPath, file.child, true) // file.child = await resolveDirectory(folderPath, file.child, true)
return file // return file
} else { // } else {
return file // return file
} // }
})) // }))
return dir // return dir
} // }
const fetchDirectoryContent = async (folderPath: string): Promise<File[]> => { const fetchDirectoryContent = async (folderPath: string): Promise<File[]> => {
console.log('folderPath: ', folderPath) console.log('folderPath: ', folderPath)
@ -312,61 +315,61 @@ export const FileExplorer = (props: FileExplorerProps) => {
return keyPath.join('/') return keyPath.join('/')
} }
const createNewFile = (newFilePath: string) => { // const createNewFile = (newFilePath: string) => {
const fileManager = state.fileManager // const fileManager = state.fileManager
try { // try {
helper.createNonClashingName(newFilePath, filesProvider, async (error, newName) => { // helper.createNonClashingName(newFilePath, filesProvider, async (error, newName) => {
if (error) { // if (error) {
modal('Create File Failed', error, { // modal('Create File Failed', error, {
label: 'Close', // label: 'Close',
fn: async () => {} // fn: async () => {}
}, null) // }, null)
} else { // } else {
const createFile = await fileManager.writeFile(newName, '') // const createFile = await fileManager.writeFile(newName, '')
if (!createFile) { // if (!createFile) {
return toast('Failed to create file ' + newName) // return toast('Failed to create file ' + newName)
} else { // } else {
await fileManager.open(newName) // await fileManager.open(newName)
setState(prevState => { // setState(prevState => {
return { ...prevState, focusElement: [{ key: newName, type: 'file' }] } // return { ...prevState, focusElement: [{ key: newName, type: 'file' }] }
}) // })
} // }
} // }
}) // })
} catch (error) { // } catch (error) {
return modal('File Creation Failed', typeof error === 'string' ? error : error.message, { // return modal('File Creation Failed', typeof error === 'string' ? error : error.message, {
label: 'Close', // label: 'Close',
fn: async () => {} // fn: async () => {}
}, null) // }, null)
} // }
} // }
const createNewFolder = async (newFolderPath: string) => { // const createNewFolder = async (newFolderPath: string) => {
const fileManager = state.fileManager // const fileManager = state.fileManager
const dirName = newFolderPath + '/' // const dirName = newFolderPath + '/'
try { // try {
const exists = await fileManager.exists(dirName) // const exists = await fileManager.exists(dirName)
if (exists) { // if (exists) {
return modal('Rename File Failed', `A file or folder ${extractNameFromKey(newFolderPath)} already exists at this location. Please choose a different name.`, { // return modal('Rename File Failed', `A file or folder ${extractNameFromKey(newFolderPath)} already exists at this location. Please choose a different name.`, {
label: 'Close', // label: 'Close',
fn: () => {} // fn: () => {}
}, null) // }, null)
} // }
await fileManager.mkdir(dirName) // await fileManager.mkdir(dirName)
setState(prevState => { // setState(prevState => {
return { ...prevState, focusElement: [{ key: newFolderPath, type: 'folder' }] } // return { ...prevState, focusElement: [{ key: newFolderPath, type: 'folder' }] }
}) // })
} catch (e) { // } catch (e) {
return modal('Folder Creation Failed', typeof e === 'string' ? e : e.message, { // return modal('Folder Creation Failed', typeof e === 'string' ? e : e.message, {
label: 'Close', // label: 'Close',
fn: async () => {} // fn: async () => {}
}, null) // }, null)
} // }
} // }
const deletePath = async (path: string) => { const deletePath = async (path: string) => {
if (filesProvider.isReadOnly(path)) { if (filesProvider.isReadOnly(path)) {
@ -391,72 +394,72 @@ export const FileExplorer = (props: FileExplorerProps) => {
}) })
} }
const renamePath = async (oldPath: string, newPath: string) => { // const renamePath = async (oldPath: string, newPath: string) => {
try { // try {
const fileManager = state.fileManager // const fileManager = state.fileManager
const exists = await fileManager.exists(newPath) // const exists = await fileManager.exists(newPath)
if (exists) { // if (exists) {
modal('Rename File Failed', `A file or folder ${extractNameFromKey(newPath)} already exists at this location. Please choose a different name.`, { // modal('Rename File Failed', `A file or folder ${extractNameFromKey(newPath)} already exists at this location. Please choose a different name.`, {
label: 'Close', // label: 'Close',
fn: () => {} // fn: () => {}
}, null) // }, null)
} else { // } else {
await fileManager.rename(oldPath, newPath) // await fileManager.rename(oldPath, newPath)
} // }
} catch (error) { // } catch (error) {
modal('Rename File Failed', 'Unexpected error while renaming: ' + typeof error === 'string' ? error : error.message, { // modal('Rename File Failed', 'Unexpected error while renaming: ' + typeof error === 'string' ? error : error.message, {
label: 'Close', // label: 'Close',
fn: async () => {} // fn: async () => {}
}, null) // }, null)
} // }
} // }
const removePath = (path: string, files: File[]): File[] => { // const removePath = (path: string, files: File[]): File[] => {
return files.map(file => { // return files.map(file => {
if (file.path === path) { // if (file.path === path) {
return null // return null
} else if (file.child) { // } else if (file.child) {
const childFiles = removePath(path, file.child) // const childFiles = removePath(path, file.child)
file.child = childFiles.filter(file => file) // file.child = childFiles.filter(file => file)
return file // return file
} else { // } else {
return file // return file
} // }
}) // })
} // }
const fileAdded = async (filePath: string) => { // const fileAdded = async (filePath: string) => {
const pathArr = filePath.split('/') // const pathArr = filePath.split('/')
const expandPath = pathArr.map((path, index) => { // const expandPath = pathArr.map((path, index) => {
return [...pathArr.slice(0, index)].join('/') // return [...pathArr.slice(0, index)].join('/')
}).filter(path => path && (path !== props.name)) // }).filter(path => path && (path !== props.name))
const files = await fetchDirectoryContent(props.name) // const files = await fetchDirectoryContent(props.name)
setState(prevState => { // setState(prevState => {
const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] // const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])]
return { ...prevState, files, expandPath: uniquePaths } // return { ...prevState, files, expandPath: uniquePaths }
}) // })
if (filePath.includes('_test.sol')) { // if (filePath.includes('_test.sol')) {
plugin.event.trigger('newTestFileCreated', [filePath]) // plugin.event.trigger('newTestFileCreated', [filePath])
} // }
} // }
const folderAdded = async (folderPath: string) => { // const folderAdded = async (folderPath: string) => {
const pathArr = folderPath.split('/') // const pathArr = folderPath.split('/')
const expandPath = pathArr.map((path, index) => { // const expandPath = pathArr.map((path, index) => {
return [...pathArr.slice(0, index)].join('/') // return [...pathArr.slice(0, index)].join('/')
}).filter(path => path && (path !== props.name)) // }).filter(path => path && (path !== props.name))
const files = await fetchDirectoryContent(props.name) // const files = await fetchDirectoryContent(props.name)
setState(prevState => { // setState(prevState => {
const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] // const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])]
return { ...prevState, files, expandPath: uniquePaths } // return { ...prevState, files, expandPath: uniquePaths }
}) // })
} // }
const fileExternallyChanged = (path: string, file: { content: string }) => { const fileExternallyChanged = (path: string, file: { content: string }) => {
const config = registry.get('config').api const config = registry.get('config').api
@ -476,22 +479,22 @@ export const FileExplorer = (props: FileExplorerProps) => {
} }
} }
const fileRemoved = (filePath) => { // const fileRemoved = (filePath) => {
const files = removePath(filePath, state.files) // const files = removePath(filePath, state.files)
const updatedFiles = files.filter(file => file) // const updatedFiles = files.filter(file => file)
setState(prevState => { // setState(prevState => {
return { ...prevState, files: updatedFiles } // return { ...prevState, files: updatedFiles }
}) // })
} // }
const fileRenamed = async () => { // const fileRenamed = async () => {
const files = await fetchDirectoryContent(props.name) // const files = await fetchDirectoryContent(props.name)
setState(prevState => { // setState(prevState => {
return { ...prevState, files, expandPath: [...prevState.expandPath] } // return { ...prevState, files, expandPath: [...prevState.expandPath] }
}) // })
} // }
// register to event of the file provider // register to event of the file provider
// files.event.register('fileRenamed', fileRenamed) // files.event.register('fileRenamed', fileRenamed)
@ -798,59 +801,59 @@ export const FileExplorer = (props: FileExplorerProps) => {
}) })
} }
const editModeOff = async (content: string) => { // const editModeOff = async (content: string) => {
if (typeof content === 'string') content = content.trim() // if (typeof content === 'string') content = content.trim()
const parentFolder = extractParentFromKey(state.focusEdit.element) // const parentFolder = extractParentFromKey(state.focusEdit.element)
if (!content || (content.trim() === '')) { // if (!content || (content.trim() === '')) {
if (state.focusEdit.isNew) { // if (state.focusEdit.isNew) {
const files = removePath(state.focusEdit.element, state.files) // const files = removePath(state.focusEdit.element, state.files)
const updatedFiles = files.filter(file => file) // const updatedFiles = files.filter(file => file)
setState(prevState => { // setState(prevState => {
return { ...prevState, files: updatedFiles, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } // return { ...prevState, files: updatedFiles, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } }
}) // })
} else { // } else {
editRef.current.textContent = state.focusEdit.lastEdit // editRef.current.textContent = state.focusEdit.lastEdit
setState(prevState => { // setState(prevState => {
return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } // return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } }
}) // })
} // }
} else { // } else {
if (state.focusEdit.lastEdit === content) { // if (state.focusEdit.lastEdit === content) {
editRef.current.textContent = content // editRef.current.textContent = content
return setState(prevState => { // return setState(prevState => {
return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } // return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } }
}) // })
} // }
if (helper.checkSpecialChars(content)) { // if (helper.checkSpecialChars(content)) {
modal('Validation Error', 'Special characters are not allowed', { // modal('Validation Error', 'Special characters are not allowed', {
label: 'OK', // label: 'OK',
fn: () => {} // fn: () => {}
}, null) // }, null)
} else { // } else {
if (state.focusEdit.isNew) { // if (state.focusEdit.isNew) {
state.focusEdit.type === 'file' ? createNewFile(joinPath(parentFolder, content)) : createNewFolder(joinPath(parentFolder, content)) // state.focusEdit.type === 'file' ? createNewFile(joinPath(parentFolder, content)) : createNewFolder(joinPath(parentFolder, content))
const files = removePath(state.focusEdit.element, state.files) // const files = removePath(state.focusEdit.element, state.files)
const updatedFiles = files.filter(file => file) // const updatedFiles = files.filter(file => file)
setState(prevState => { // setState(prevState => {
return { ...prevState, files: updatedFiles } // return { ...prevState, files: updatedFiles }
}) // })
} else { // } else {
const oldPath: string = state.focusEdit.element // const oldPath: string = state.focusEdit.element
const oldName = extractNameFromKey(oldPath) // const oldName = extractNameFromKey(oldPath)
const newPath = oldPath.replace(oldName, content) // const newPath = oldPath.replace(oldName, content)
editRef.current.textContent = extractNameFromKey(oldPath) // editRef.current.textContent = extractNameFromKey(oldPath)
renamePath(oldPath, newPath) // renamePath(oldPath, newPath)
} // }
setState(prevState => { // setState(prevState => {
return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } // return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } }
}) // })
} // }
} // }
} // }
const handleNewFileInput = async (parentFolder?: string) => { const handleNewFileInput = async (parentFolder?: string) => {
if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name
@ -873,12 +876,12 @@ export const FileExplorer = (props: FileExplorerProps) => {
editModeOn(parentFolder + '/blank', 'folder', true) editModeOn(parentFolder + '/blank', 'folder', true)
} }
const handleEditInput = (event) => { // const handleEditInput = (event) => {
if (event.which === 13) { // if (event.which === 13) {
event.preventDefault() // event.preventDefault()
editModeOff(editRef.current.innerText) // editModeOff(editRef.current.innerText)
} // }
} // }
const handleMouseOver = (path: string) => { const handleMouseOver = (path: string) => {
setState(prevState => { setState(prevState => {
@ -899,11 +902,11 @@ export const FileExplorer = (props: FileExplorerProps) => {
ref={state.focusEdit.element === file.path ? editRef : null} ref={state.focusEdit.element === file.path ? editRef : null}
suppressContentEditableWarning={true} suppressContentEditableWarning={true}
contentEditable={state.focusEdit.element === file.path} contentEditable={state.focusEdit.element === file.path}
onKeyDown={handleEditInput} // onKeyDown={handleEditInput}
onBlur={(e) => { // onBlur={(e) => {
e.stopPropagation() // e.stopPropagation()
editModeOff(editRef.current.innerText) // editModeOff(editRef.current.innerText)
}} // }}
> >
<span <span
title={file.path} title={file.path}
@ -1030,7 +1033,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
<div className='pb-2'> <div className='pb-2'>
<TreeView id='treeViewMenu'> <TreeView id='treeViewMenu'>
{ {
state.files.map((file, index) => { fileSystem.files.files.map((file, index) => {
return renderFiles(file, index) return renderFiles(file, index)
}) })
} }
@ -1092,8 +1095,8 @@ async function packageFiles (filesProvider, directory, callback) {
} }
} }
function joinPath (...paths) { // function joinPath (...paths) {
paths = paths.filter((value) => value !== '').map((path) => path.replace(/^\/|\/$/g, '')) // remove first and last slash) // paths = paths.filter((value) => value !== '').map((path) => path.replace(/^\/|\/$/g, '')) // remove first and last slash)
if (paths.length === 1) return paths[0] // if (paths.length === 1) return paths[0]
return paths.join('/') // return paths.join('/')
} // }

@ -4,39 +4,91 @@ interface Action {
payload: Record<string, any>; payload: Record<string, any>;
} }
export const initialState = { export const fileSystemInitialState = {
files: [], files: {
expandPath: [], files: [],
isRequesting: false, expandPath: [],
isSuccessful: false, isRequesting: false,
hasError: null isSuccessful: false,
error: null
},
provider: {
provider: null,
isRequesting: false,
isSuccessful: false,
error: null
}
} }
export const reducer = (state = initialState, action: Action) => { export const fileSystemReducer = (state = fileSystemInitialState, action: Action) => {
switch (action.type) { switch (action.type) {
case 'FETCH_DIRECTORY_REQUEST': { case 'FETCH_DIRECTORY_REQUEST': {
return { return {
...state, ...state,
isRequesting: true, files: {
isSuccessful: false, ...state.files,
hasError: null isRequesting: true,
isSuccessful: false,
error: null
}
} }
} }
case 'FETCH_DIRECTORY_SUCCESS': { case 'FETCH_DIRECTORY_SUCCESS': {
return { return {
files: action.payload.files, ...state,
expandPath: [...action.payload.path], files: {
isRequesting: false, ...state.files,
isSuccessful: true, files: action.payload.files,
hasError: null expandPath: [...state.files.expandPath, action.payload.path],
isRequesting: false,
isSuccessful: true,
error: null
}
} }
} }
case 'FETCH_DIRECTORY_ERROR': { case 'FETCH_DIRECTORY_ERROR': {
return { return {
...state, ...state,
isRequesting: false, files: {
isSuccessful: false, ...state.files,
hasError: action.payload isRequesting: false,
isSuccessful: false,
error: action.payload
}
}
}
case 'FETCH_PROVIDER_REQUEST': {
return {
...state,
provider: {
...state.provider,
isRequesting: true,
isSuccessful: false,
error: null
}
}
}
case 'FETCH_PROVIDER_SUCCESS': {
return {
...state,
provider: {
...state.provider,
provider: action.payload,
isRequesting: false,
isSuccessful: true,
error: null
}
}
}
case 'FETCH_PROVIDER_ERROR': {
return {
...state,
provider: {
...state.provider,
isRequesting: false,
isSuccessful: false,
error: action.payload
}
} }
} }
default: default:

Loading…
Cancel
Save