Resolve Directory

pull/5370/head
ioedeveloper 4 years ago
parent d6c2296f79
commit ff12933190
  1. 8
      apps/remix-ide/src/app/panels/file-panel.js
  2. 340
      libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
  3. 2
      libs/remix-ui/file-explorer/src/lib/types/index.ts
  4. 4
      libs/remix-ui/tree-view/src/types/index.ts

@ -94,20 +94,20 @@ module.exports = class Filepanel extends ViewPlugin {
<div className='pl-2 remixui_treeview' data-id='filePanelFileExplorerTree'>
<FileExplorer
name='browser'
localRegistry={this._components.registry}
registry={this._components.registry}
files={this._deps.fileProviders.browser}
menuItems={['createNewFile', 'publishToGist', canUpload ? 'uploadFile' : '']}
plugin={this}
/>
</div>
<div className='pl-2 filesystemexplorer remixui_treeview'>
<FileExplorer
{/* <FileExplorer
name='localhost'
localRegistry={this._components.registry}
registry={this._components.registry}
files={this._deps.fileProviders.localhost}
menuItems={[]}
plugin={this}
/>
/> */}
</div>
</div>
</div>

@ -5,29 +5,76 @@ import { FileExplorerProps } from './types'
import './css/file-explorer.css'
function extractData (value, tree, key) {
const newValue = {}
let isFile = false
export const FileExplorer = (props: FileExplorerProps) => {
const { files, name, registry } = props
const uploadFile = (target) => {
// 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.
Object.keys(value).filter((x) => {
if (x === '/content') isFile = true
if (x[0] !== '/') return true
}).forEach((x) => { newValue[x] = value[x] })
[...target.files].forEach((file) => {
const files = props.files
return {
path: (tree || {}).path ? tree.path + '/' + key : key,
children: isFile ? undefined
: value instanceof Array ? value.map((item, index) => ({
key: index, value: item
})) : value instanceof Object ? Object.keys(value).map(subkey => ({
key: subkey, value: value[subkey]
})) : undefined
function loadFile () {
const fileReader = new FileReader()
fileReader.onload = async function (event) {
if (helper.checkSpecialChars(file.name)) {
// modalDialogCustom.alert('Special characters are not allowed')
return
}
const success = await files.set(name, event.target.result)
if (!success) {
// modalDialogCustom.alert('Failed to create file ' + name)
} else {
// self.events.trigger('focus', [name])
}
}
fileReader.readAsText(file)
}
const name = files.type + '/' + file.name
files.exists(name, (error, exist) => {
if (error) console.log(error)
if (!exist) {
loadFile()
} else {
// modalDialogCustom.confirm('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() })
}
})
})
}
const publishToGist = () => {
// modalDialogCustom.confirm(
// 'Create a public gist',
// 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.',
// () => { this.toGist() }
// )
}
const createNewFile = (parentFolder = 'browser') => {
// const self = this
// modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => {
// if (!input) input = 'New file'
// helper.createNonClashingName(parentFolder + '/' + input, self.files, async (error, newName) => {
// if (error) return tooltip('Failed to create file ' + newName + ' ' + error)
// const fileManager = self._deps.fileManager
// const createFile = await fileManager.writeFile(newName, '')
// if (!createFile) {
// tooltip('Failed to create file ' + newName)
// } else {
// await fileManager.open(newName)
// if (newName.includes('_test.sol')) {
// self.events.trigger('newTestFileCreated', [newName])
// }
// }
// })
// }, null, true)
}
export const FileExplorer = (props: FileExplorerProps) => {
const [state, setState] = useState({
files: props.files,
focusElement: null,
focusPath: null,
menuItems: [
@ -51,34 +98,184 @@ export const FileExplorer = (props: FileExplorerProps) => {
title: 'Update the current [gist] explorer',
icon: 'fab fa-github'
}
].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action }))
].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })),
files: [],
actions: {
updateGist: () => {},
uploadFile,
publishToGist,
createNewFile
},
fileManager: null
})
useEffect(() => {
if (props.files) {
console.log('props.files.type: ', props.files.type)
props.files.event.register('fileAdded', fileAdded)
}
}, [props.files])
const fileManager = registry.get('filemanager').api
setState(prevState => {
return { ...prevState, fileManager }
})
resolveDirectory(name)
}, [])
const resolveDirectory = (folderPath) => {
const folderIndex = state.files.findIndex(({ path }) => path === folderPath)
const formatSelf = (key, data, li) => {
const isFolder = !!data.children
if (folderIndex === -1) {
files.resolveDirectory(folderPath, (error, fileTree) => {
if (error) console.error(error)
const files = normalize(folderPath, fileTree)
setState(prevState => {
return { ...prevState, files }
})
})
} else {
files.resolveDirectory(folderPath, (error, fileTree) => {
if (error) console.error(error)
const files = state.files
files[folderIndex].child = normalize(folderPath, fileTree)
setState(prevState => {
return { ...prevState, files }
})
})
}
}
const label = (data) => {
return (
<div className='remixui_items'>
<span
title={data.path}
className={'remixui_label ' + (!isFolder ? 'remixui_leaf' : 'folder')}
className={'remixui_label ' + (data.isDirectory ? 'folder' : 'remixui_leaf')}
data-path={data.path}
// onkeydown=${editModeOff}
// onblur=${editModeOff}
>
{key.split('/').pop()}
{ data.path.split('/').pop() }
</span>
</div>
)
}
const normalize = (path, filesList) => {
const prefix = path.split('/')[0]
const files = Object.keys(filesList).map(key => {
const path = prefix + '/' + key
return {
path,
name: extractNameFromKey(path),
isDirectory: filesList[key].isDirectory
}
})
return files
}
const extractNameFromKey = (key) => {
const keyPath = key.split('/')
return keyPath[keyPath.length - 1]
}
const toGist = (id) => {
// const proccedResult = function (error, data) {
// if (error) {
// modalDialogCustom.alert('Failed to manage gist: ' + error)
// console.log('Failed to manage gist: ' + error)
// } else {
// if (data.html_url) {
// modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => {
// window.open(data.html_url, '_blank')
// })
// } else {
// modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t'))
// }
// }
// }
// /**
// * This function is to get the original content of given gist
// * @params id is the gist id to fetch
// */
// async function getOriginalFiles (id) {
// if (!id) {
// return []
// }
// const url = `https://api.github.com/gists/${id}`
// const res = await fetch(url)
// const data = await res.json()
// return data.files || []
// }
// // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer.
// const folder = id ? 'browser/gists/' + id : 'browser/'
// this.packageFiles(this.files, folder, (error, packaged) => {
// if (error) {
// console.log(error)
// modalDialogCustom.alert('Failed to create gist: ' + error.message)
// } else {
// // check for token
// var tokenAccess = this._deps.config.get('settings/gist-access-token')
// if (!tokenAccess) {
// modalDialogCustom.alert(
// 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.'
// )
// } else {
// const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' +
// queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist='
// const gists = new Gists({ token: tokenAccess })
// if (id) {
// const originalFileList = getOriginalFiles(id)
// // Telling the GIST API to remove files
// const updatedFileList = Object.keys(packaged)
// const allItems = Object.keys(originalFileList)
// .filter(fileName => updatedFileList.indexOf(fileName) === -1)
// .reduce((acc, deleteFileName) => ({
// ...acc,
// [deleteFileName]: null
// }), originalFileList)
// // adding new files
// updatedFileList.forEach((file) => {
// const _items = file.split('/')
// const _fileName = _items[_items.length - 1]
// allItems[_fileName] = packaged[file]
// })
// tooltip('Saving gist (' + id + ') ...')
// gists.edit({
// description: description,
// public: true,
// files: allItems,
// id: id
// }, (error, result) => {
// proccedResult(error, result)
// if (!error) {
// for (const key in allItems) {
// if (allItems[key] === null) delete allItems[key]
// }
// }
// })
// } else {
// // id is not existing, need to create a new gist
// tooltip('Creating a new gist ...')
// gists.create({
// description: description,
// public: true,
// files: packaged
// }, (error, result) => {
// proccedResult(error, result)
// })
// }
// }
// }
// })
}
// self._components = {}
// self._components.registry = localRegistry || globalRegistry
// self._deps = {
@ -87,10 +284,6 @@ export const FileExplorer = (props: FileExplorerProps) => {
// fileManager: self._components.registry.get('filemanager').api
// }
// self.events.register('focus', function (path) {
// self._deps.fileManager.open(path)
// })
// self._components.registry.put({ api: self, name: `fileexplorer/${self.files.type}` })
// warn if file changed outside of Remix
@ -128,10 +321,8 @@ export const FileExplorer = (props: FileExplorerProps) => {
// modalDialogCustom.alert(error)
// }
const fileAdded = (filepath) => {
const folderpath = filepath.split('/').slice(0, -1).join('/')
console.log('filePath: ', folderpath)
console.log('folderPath: ', folderpath)
// const fileAdded = (filepath) => {
// const folderpath = filepath.split('/').slice(0, -1).join('/')
// const currentTree = self.treeView.nodeAt(folderpath)
// if (!self.treeView.isExpanded(folderpath)) self.treeView.expand(folderpath)
// if (currentTree) {
@ -148,13 +339,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
// }
// })
// }
}
const extractNameFromKey = (key) => {
const keyPath = key.split('/')
return keyPath[keyPath.length - 1]
}
// }
const renderMenuItems = () => {
let items
@ -181,7 +366,10 @@ export const FileExplorer = (props: FileExplorerProps) => {
<span
id={action}
data-id={'fileExplorerNewFile' + action}
// onclick={({ stopPropagation }) => { stopPropagation(); this[action]() }}
onClick={(e) => {
e.stopPropagation()
state.actions[action]()
}}
className={'newFile ' + icon + ' remixui_newFile'}
title={title}
key={index}
@ -193,57 +381,49 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
return (
<>
<span className='remixui_label' title={props.name} data-path={props.name} style={{ fontWeight: 'bold' }}>{ props.name }</span>
<span className='remixui_label' title={name} data-path={name} style={{ fontWeight: 'bold' }}>{ name }</span>
<span className="remixui_menu">{items}</span>
</>
)
}
const uploadFile = (target) => {
// 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 files = state.files
function loadFile () {
const fileReader = new FileReader()
fileReader.onload = async function (event) {
if (helper.checkSpecialChars(file.name)) {
// modalDialogCustom.alert('Special characters are not allowed')
return
}
const success = await files.set(name, event.target.result)
if (!success) {
// modalDialogCustom.alert('Failed to create file ' + name)
} else {
// self.events.trigger('focus', [name])
}
const renderFiles = (file, index) => {
if (file.isDirectory) {
return (
<TreeViewItem id={`treeViewItem${file.path}`} onClick={() => { resolveDirectory(file.path) }} key={index} label={label(file)}>
{
file.child ? <TreeView id={`treeView${file.path}`} key={index}>{
file.child.map((file, index) => {
return renderFiles(file, index)
})
}
fileReader.readAsText(file)
</TreeView> : <TreeView id={`treeView${file.path}`} key={index} />
}
const name = files.type + '/' + file.name
files.exists(name, (error, exist) => {
if (error) console.log(error)
if (!exist) {
loadFile()
</TreeViewItem>
)
} else {
// modalDialogCustom.confirm('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() })
return (
<TreeViewItem
id={`treeView${file.path}`}
key={index}
label={label(file)}
onClick={() => { state.fileManager.open(file.path) }}
/>
)
}
})
})
}
return (
<div>
<TreeView id='treeView'>
<TreeViewItem id="treeViewItem" label={renderMenuItems()}>
<TreeViewItem id="treeViewItem" label={renderMenuItems()} expand={true}>
<TreeView id='treeViewMenu'>
{
state.files.map((file, index) => {
return renderFiles(file, index)
})
}
</TreeView>
</TreeViewItem>
</TreeView>
</div>

@ -1,7 +1,7 @@
/* eslint-disable-next-line */
export interface FileExplorerProps {
name: string,
localRegistry: any,
registry: any,
files: any,
menuItems?: string[],
plugin: any

@ -1,11 +1,11 @@
export interface TreeViewProps {
children?: React.ReactNode,
id: string
id?: string
}
export interface TreeViewItemProps {
children?: React.ReactNode,
id: string,
id?: string,
label: string | number | React.ReactNode,
expand?: boolean,
onClick?: VoidFunction,

Loading…
Cancel
Save