Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
baas-ide
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
guxukai
baas-ide
Commits
22ea754f
Commit
22ea754f
authored
Feb 22, 2021
by
yann300
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
open-save workspace
parent
f3380cc3
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
354 additions
and
102 deletions
+354
-102
.gitignore
apps/remix-ide/.gitignore
+0
-2
README.txt
apps/remix-ide/contracts/README.txt
+2
-0
app.js
apps/remix-ide/src/app.js
+8
-17
compiler-imports.js
apps/remix-ide/src/app/compiler/compiler-imports.js
+3
-4
editor.js
apps/remix-ide/src/app/editor/editor.js
+0
-1
compiler-metadata.js
apps/remix-ide/src/app/files/compiler-metadata.js
+7
-6
file-explorer.js
apps/remix-ide/src/app/files/file-explorer.js
+2
-2
fileManager.js
apps/remix-ide/src/app/files/fileManager.js
+26
-16
fileProvider.js
apps/remix-ide/src/app/files/fileProvider.js
+35
-1
remixDProvider.js
apps/remix-ide/src/app/files/remixDProvider.js
+8
-14
workspaceFileProvider.js
apps/remix-ide/src/app/files/workspaceFileProvider.js
+41
-0
file-panel.js
apps/remix-ide/src/app/panels/file-panel.js
+166
-5
file-panel-styles.css
apps/remix-ide/src/app/panels/styles/file-panel-styles.css
+3
-0
compile-tab.js
apps/remix-ide/src/app/tabs/compile-tab.js
+1
-0
test-tab.js
apps/remix-ide/src/app/tabs/test-tab.js
+9
-4
testTab.js
apps/remix-ide/src/app/tabs/testTab/testTab.js
+1
-1
config.js
apps/remix-ide/src/config.js
+0
-18
gist-handler.js
apps/remix-ide/src/lib/gist-handler.js
+5
-6
helper.js
apps/remix-ide/src/lib/helper.js
+5
-0
migrateFileSystem.js
apps/remix-ide/src/migrateFileSystem.js
+29
-1
remixAppManager.js
apps/remix-ide/src/remixAppManager.js
+3
-4
No files found.
apps/remix-ide/.gitignore
View file @
22ea754f
...
...
@@ -9,7 +9,6 @@ soljson.js.*
npm-debug.log*
remix
.DS_Store
contracts
TODO
.tern-port
temp_publish_docker
\ No newline at end of file
apps/remix-ide/contracts/README.txt
0 → 100644
View file @
22ea754f
test README
\ No newline at end of file
apps/remix-ide/src/app.js
View file @
22ea754f
...
...
@@ -18,7 +18,7 @@ import { LandingPage } from './app/ui/landing-page/landing-page'
import
{
MainPanel
}
from
'./app/components/main-panel'
import
FetchAndCompile
from
'./app/compiler/compiler-sourceVerifier-fetchAndCompile'
import
migrateFileSystem
from
'./migrateFileSystem'
import
migrateFileSystem
,
{
migrateToWorkspace
}
from
'./migrateFileSystem'
var
isElectron
=
require
(
'is-electron'
)
var
csjs
=
require
(
'csjs-inject'
)
...
...
@@ -28,14 +28,13 @@ var registry = require('./global/registry')
var
loadFileFromParent
=
require
(
'./loadFilesFromParent'
)
var
{
OffsetToLineColumnConverter
}
=
require
(
'./lib/offsetToLineColumnConverter'
)
var
QueryParams
=
require
(
'./lib/query-params'
)
var
GistHandler
=
require
(
'./lib/gist-handler'
)
var
Storage
=
remixLib
.
Storage
var
RemixDProvider
=
require
(
'./app/files/remixDProvider'
)
var
Config
=
require
(
'./config'
)
var
examples
=
require
(
'./app/editor/examples'
)
var
modalDialogCustom
=
require
(
'./app/ui/modal-dialog-custom'
)
var
FileManager
=
require
(
'./app/files/fileManager'
)
var
FileProvider
=
require
(
'./app/files/fileProvider'
)
var
WorkspaceFileProvider
=
require
(
'./app/files/workspaceFileProvider'
)
var
toolTip
=
require
(
'./app/ui/tooltip'
)
var
CompilerMetadata
=
require
(
'./app/files/compiler-metadata'
)
var
CompilerImport
=
require
(
'./app/compiler/compiler-imports'
)
...
...
@@ -145,6 +144,9 @@ class App {
registry
.
put
({
api
:
self
.
_components
.
filesProviders
.
browser
,
name
:
'fileproviders/browser'
})
self
.
_components
.
filesProviders
.
localhost
=
new
RemixDProvider
(
self
.
appManager
)
registry
.
put
({
api
:
self
.
_components
.
filesProviders
.
localhost
,
name
:
'fileproviders/localhost'
})
self
.
_components
.
filesProviders
.
workspace
=
new
WorkspaceFileProvider
()
registry
.
put
({
api
:
self
.
_components
.
filesProviders
.
workspace
,
name
:
'fileproviders/workspace'
})
registry
.
put
({
api
:
self
.
_components
.
filesProviders
,
name
:
'fileproviders'
})
migrateFileSystem
(
self
.
_components
.
filesProviders
.
browser
)
...
...
@@ -438,20 +440,9 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
// get the file list from the parent iframe
loadFileFromParent
(
fileManager
)
// get the file from gist
const
gistHandler
=
new
GistHandler
()
const
loadedFromGist
=
gistHandler
.
loadFromGist
(
params
,
fileManager
)
if
(
!
loadedFromGist
)
{
// insert example contracts if there are no files to show
self
.
_components
.
filesProviders
.
browser
.
resolveDirectory
(
'/'
,
(
error
,
filesList
)
=>
{
if
(
error
)
console
.
error
(
error
)
if
(
Object
.
keys
(
filesList
).
length
===
0
)
{
for
(
const
file
in
examples
)
{
fileManager
.
writeFile
(
examples
[
file
].
name
,
examples
[
file
].
content
)
}
}
})
}
migrateToWorkspace
(
fileManager
)
filePanel
.
initWorkspace
()
if
(
params
.
code
)
{
try
{
...
...
apps/remix-ide/src/app/compiler/compiler-imports.js
View file @
22ea754f
...
...
@@ -77,7 +77,7 @@ module.exports = class CompilerImports extends Plugin {
}
cb
(
null
,
content
,
cleanUrl
,
type
,
url
)
}
catch
(
e
)
{
return
cb
(
'Unable to import url : '
+
e
.
message
)
return
cb
(
new
Error
(
'not found '
+
url
)
)
}
}
...
...
@@ -88,9 +88,9 @@ module.exports = class CompilerImports extends Plugin {
(
error
,
content
,
cleanUrl
,
type
,
url
)
=>
{
if
(
error
)
return
cb
(
error
)
if
(
this
.
fileManager
)
{
const
browser
=
this
.
fileManager
.
fileProviderOf
(
'browser/
'
)
const
workspace
=
this
.
fileManager
.
getProvider
(
'workspace
'
)
const
path
=
targetPath
||
type
+
'/'
+
cleanUrl
if
(
browser
)
browser
.
addExternal
(
path
,
content
,
url
)
if
(
workspace
)
workspace
.
addExternal
(
path
,
content
,
url
)
}
cb
(
null
,
content
)
})
...
...
@@ -123,7 +123,6 @@ module.exports = class CompilerImports extends Plugin {
}
provider
.
exists
(
url
,
(
error
,
exist
)
=>
{
if
(
error
)
return
reject
(
error
)
if
(
!
exist
&&
provider
.
type
===
'localhost'
)
return
reject
(
new
Error
(
`not found
${
url
}
`
))
/*
if the path is absolute and the file does not exist, we can stop here
...
...
apps/remix-ide/src/app/editor/editor.js
View file @
22ea754f
...
...
@@ -355,7 +355,6 @@ class Editor extends Plugin {
- URL prepended with "browser"
- URL not prepended with the file explorer. We assume (as it is in the whole app, that this is a "browser" URL
*/
if
(
!
path
.
startsWith
(
'localhost'
)
&&
!
path
.
startsWith
(
'browser'
))
path
=
`browser/
${
path
}
`
if
(
!
this
.
sessions
[
path
])
{
const
session
=
this
.
_createSession
(
content
,
this
.
_getMode
(
path
))
this
.
sessions
[
path
]
=
session
...
...
apps/remix-ide/src/app/files/compiler-metadata.js
View file @
22ea754f
'use strict'
import
{
Plugin
}
from
'@remixproject/engine'
import
*
as
packageJson
from
'../../../../../package.json'
import
{
joinPath
}
from
'../../lib/helper'
var
CompilerAbstract
=
require
(
'../compiler/compiler-abstract'
)
const
profile
=
{
...
...
@@ -21,11 +22,11 @@ class CompilerMetadata extends Plugin {
}
_JSONFileName
(
path
,
contractName
)
{
return
path
+
'/'
+
this
.
innerPath
+
'/'
+
contractName
+
'.json'
return
joinPath
(
path
,
this
.
innerPath
,
contractName
+
'.json'
)
}
_MetadataFileName
(
path
,
contractName
)
{
return
path
+
'/'
+
this
.
innerPath
+
'/'
+
contractName
+
'_metadata'
+
'.json'
return
joinPath
(
path
,
this
.
innerPath
,
contractName
+
'_metadata.json'
)
}
onActivation
()
{
...
...
@@ -33,9 +34,9 @@ class CompilerMetadata extends Plugin {
this
.
on
(
'solidity'
,
'compilationFinished'
,
(
file
,
source
,
languageVersion
,
data
)
=>
{
if
(
!
self
.
config
.
get
(
'settings/generate-contract-metadata'
))
return
const
compiler
=
new
CompilerAbstract
(
languageVersion
,
data
,
source
)
var
provider
=
self
.
fileManager
.
currentFileProvider
(
)
var
path
=
self
.
fileManager
.
currentPath
(
)
if
(
provider
&&
path
)
{
var
provider
=
self
.
fileManager
.
fileProviderOf
(
source
.
target
)
var
path
=
self
.
fileManager
.
extractPathOf
(
source
.
target
)
if
(
provider
)
{
compiler
.
visitContracts
((
contract
)
=>
{
if
(
contract
.
file
!==
source
.
target
)
return
...
...
@@ -117,7 +118,7 @@ class CompilerMetadata extends Plugin {
path
=
this
.
fileManager
.
currentPath
()
}
if
(
provider
&&
path
)
{
if
(
provider
)
{
this
.
blockchain
.
detectNetwork
((
err
,
{
id
,
name
}
=
{})
=>
{
if
(
err
)
{
console
.
log
(
err
)
...
...
apps/remix-ide/src/app/files/file-explorer.js
View file @
22ea754f
...
...
@@ -506,7 +506,7 @@ fileExplorer.prototype.toGist = function (id) {
}
// 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
/'
const
folder
=
id
?
'
/gists/'
+
id
:
'
/'
this
.
packageFiles
(
this
.
files
,
folder
,
(
error
,
packaged
)
=>
{
if
(
error
)
{
console
.
log
(
error
)
...
...
@@ -596,7 +596,7 @@ fileExplorer.prototype.packageFiles = function (filesProvider, directory, callba
})
}
fileExplorer
.
prototype
.
createNewFile
=
function
(
parentFolder
=
'
browser
'
)
{
fileExplorer
.
prototype
.
createNewFile
=
function
(
parentFolder
=
'
/
'
)
{
const
self
=
this
modalDialogCustom
.
prompt
(
'Create new file'
,
'File Name (e.g Untitled.sol)'
,
'Untitled.sol'
,
(
input
)
=>
{
if
(
!
input
)
input
=
'New file'
...
...
apps/remix-ide/src/app/files/fileManager.js
View file @
22ea754f
...
...
@@ -39,6 +39,7 @@ const createError = (err) => {
class
FileManager
extends
Plugin
{
constructor
(
editor
,
appManager
)
{
super
(
profile
)
this
.
mode
=
'browser'
this
.
openedFiles
=
{}
// list all opened files
this
.
events
=
new
EventEmitter
()
this
.
editor
=
editor
...
...
@@ -48,6 +49,10 @@ class FileManager extends Plugin {
this
.
init
()
}
setMode
(
mode
)
{
this
.
mode
=
mode
}
/**
* Emit error if path doesn't exist
* @param {string} path path of the file/directory
...
...
@@ -265,6 +270,7 @@ class FileManager extends Plugin {
config
:
this
.
_components
.
registry
.
get
(
'config'
).
api
,
browserExplorer
:
this
.
_components
.
registry
.
get
(
'fileproviders/browser'
).
api
,
localhostExplorer
:
this
.
_components
.
registry
.
get
(
'fileproviders/localhost'
).
api
,
workspaceExplorer
:
this
.
_components
.
registry
.
get
(
'fileproviders/workspace'
).
api
,
filesProviders
:
this
.
_components
.
registry
.
get
(
'fileproviders'
).
api
}
this
.
_deps
.
browserExplorer
.
event
.
register
(
'fileChanged'
,
(
path
)
=>
{
this
.
fileChangedEvent
(
path
)
})
...
...
@@ -275,6 +281,11 @@ class FileManager extends Plugin {
this
.
_deps
.
localhostExplorer
.
event
.
register
(
'fileRemoved'
,
(
path
)
=>
{
this
.
fileRemovedEvent
(
path
)
})
this
.
_deps
.
localhostExplorer
.
event
.
register
(
'errored'
,
(
event
)
=>
{
this
.
removeTabsOf
(
this
.
_deps
.
localhostExplorer
)
})
this
.
_deps
.
localhostExplorer
.
event
.
register
(
'closed'
,
(
event
)
=>
{
this
.
removeTabsOf
(
this
.
_deps
.
localhostExplorer
)
})
this
.
_deps
.
workspaceExplorer
.
event
.
register
(
'fileChanged'
,
(
path
)
=>
{
this
.
fileChangedEvent
(
path
)
})
this
.
_deps
.
workspaceExplorer
.
event
.
register
(
'fileRenamed'
,
(
oldName
,
newName
,
isFolder
)
=>
{
this
.
fileRenamedEvent
(
oldName
,
newName
,
isFolder
)
})
this
.
_deps
.
workspaceExplorer
.
event
.
register
(
'fileRemoved'
,
(
path
)
=>
{
this
.
fileRemovedEvent
(
path
)
})
this
.
_deps
.
workspaceExplorer
.
event
.
register
(
'fileAdded'
,
(
path
)
=>
{
this
.
fileAddedEvent
(
path
)
})
this
.
getCurrentFile
=
this
.
file
this
.
getFile
=
this
.
readFile
this
.
getFolder
=
this
.
readdir
...
...
@@ -349,7 +360,7 @@ class FileManager extends Plugin {
extractPathOf
(
file
)
{
var
reg
=
/
(
.*
)(\/)
.*/
var
path
=
reg
.
exec
(
file
)
return
path
?
path
[
1
]
:
null
return
path
?
path
[
1
]
:
'/'
}
getFileContent
(
path
)
{
...
...
@@ -468,19 +479,9 @@ class FileManager extends Plugin {
}
if
(
file
)
return
_openFile
(
file
)
else
{
var
browserProvider
=
this
.
_deps
.
filesProviders
.
browser
browserProvider
.
resolveDirectory
(
'browser'
,
(
error
,
filesProvider
)
=>
{
if
(
error
)
console
.
error
(
error
)
var
fileList
=
Object
.
keys
(
filesProvider
)
if
(
fileList
.
length
)
{
_openFile
(
browserProvider
.
type
+
'/'
+
fileList
[
0
])
}
else
{
// TODO: Only keep `this.emit` (issue#2210)
this
.
emit
(
'noFileSelected'
)
this
.
events
.
emit
(
'noFileSelected'
)
}
})
}
}
getProvider
(
name
)
{
...
...
@@ -488,11 +489,14 @@ class FileManager extends Plugin {
}
fileProviderOf
(
file
)
{
if
(
file
.
indexOf
(
'localhost'
)
===
0
)
{
if
(
file
.
startsWith
(
'localhost'
)
||
this
.
mode
===
'localhost'
)
{
return
this
.
_deps
.
filesProviders
.
localhost
}
if
(
file
.
startsWith
(
'browser'
))
{
return
this
.
_deps
.
filesProviders
.
browser
}
return
this
.
_deps
.
filesProviders
.
workspace
}
// returns the list of directories inside path
dirList
(
path
)
{
...
...
@@ -501,10 +505,8 @@ class FileManager extends Plugin {
return
new
Promise
((
resolve
,
reject
)
=>
{
this
.
readdir
(
path
).
then
((
ls
)
=>
{
const
promises
=
Object
.
keys
(
ls
).
map
((
item
,
index
)
=>
{
const
root
=
(
path
.
indexOf
(
'/'
)
===
-
1
)
?
path
:
path
.
substr
(
0
,
path
.
indexOf
(
'/'
))
const
curPath
=
`
${
root
}
/
${
item
}
`
// adding 'browser' or 'localhost'
if
(
ls
[
item
].
isDirectory
&&
!
dirPaths
.
includes
(
curPath
))
{
dirPaths
.
push
(
curPath
)
if
(
ls
[
item
].
isDirectory
&&
!
dirPaths
.
includes
(
item
))
{
dirPaths
.
push
(
item
)
resolve
(
dirPaths
)
}
return
new
Promise
((
resolve
,
reject
)
=>
{
resolve
()
})
...
...
@@ -579,6 +581,14 @@ class FileManager extends Plugin {
if
(
callback
)
callback
(
error
)
})
}
async
createWorkspace
(
name
)
{
const
workspaceProvider
=
this
.
_deps
.
filesProviders
.
workspace
const
workspacePath
=
'browser/'
+
workspaceProvider
.
workspacesPath
+
'/'
+
name
const
workspaceRootPath
=
'browser/'
+
workspaceProvider
.
workspacesPath
if
(
!
this
.
exists
(
workspaceRootPath
))
await
this
.
mkdir
(
workspaceRootPath
)
if
(
!
this
.
exists
(
workspacePath
))
await
this
.
mkdir
(
workspacePath
)
}
}
module
.
exports
=
FileManager
apps/remix-ide/src/app/files/fileProvider.js
View file @
22ea754f
...
...
@@ -193,6 +193,39 @@ class FileProvider {
})
}
/**
* copy the folder recursively
* @param {string} path is the folder to be copied over
* @param {string} destination is the destination folder
*/
copyFolderToJson
(
path
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
json
=
{}
path
=
this
.
removePrefix
(
path
)
if
(
window
.
remixFileSystem
.
existsSync
(
path
))
{
try
{
const
items
=
window
.
remixFileSystem
.
readdirSync
(
path
)
if
(
items
.
length
!==
0
)
{
items
.
forEach
(
async
(
item
,
index
)
=>
{
const
file
=
{}
const
curPath
=
`
${
path
}${
path
.
endsWith
(
'/'
)
?
''
:
'/'
}${
item
}
`
if
(
window
.
remixFileSystem
.
statSync
(
curPath
).
isDirectory
())
{
file
.
children
=
await
this
.
copyFolderToJson
(
curPath
)
}
else
{
file
.
content
=
window
.
remixFileSystem
.
readFileSync
(
curPath
,
'utf8'
)
}
json
[
curPath
]
=
file
})
}
}
catch
(
e
)
{
console
.
log
(
e
)
return
reject
(
e
)
}
}
return
resolve
(
json
)
})
}
removeFile
(
path
)
{
path
=
this
.
removePrefix
(
path
)
if
(
window
.
remixFileSystem
.
existsSync
(
path
)
&&
!
window
.
remixFileSystem
.
statSync
(
path
).
isDirectory
())
{
...
...
@@ -227,6 +260,8 @@ class FileProvider {
if
(
files
)
{
files
.
forEach
(
element
=>
{
path
=
path
.
replace
(
/^
\/
|
\/
$/g
,
''
)
// remove first and last slash
element
=
element
.
replace
(
/^
\/
|
\/
$/g
,
''
)
// remove first and last slash
const
absPath
=
(
path
===
'/'
?
''
:
path
)
+
'/'
+
element
ret
[
absPath
.
indexOf
(
'/'
)
===
0
?
absPath
.
substr
(
1
,
absPath
.
length
)
:
absPath
]
=
{
isDirectory
:
window
.
remixFileSystem
.
statSync
(
absPath
).
isDirectory
()
}
// ^ ret does not accept path starting with '/'
...
...
@@ -243,7 +278,6 @@ class FileProvider {
}
_normalizePath
(
path
)
{
if
(
path
.
indexOf
(
'/'
)
!==
0
)
path
=
'/'
+
path
return
this
.
type
+
path
}
}
...
...
apps/remix-ide/src/app/files/remixDProvider.js
View file @
22ea754f
...
...
@@ -23,23 +23,23 @@ module.exports = class RemixDProvider {
})
this
.
_appManager
.
on
(
'remixd'
,
'folderAdded'
,
(
path
)
=>
{
this
.
event
.
trigger
(
'folderAdded'
,
[
this
.
addPrefix
(
path
)
])
this
.
event
.
trigger
(
'folderAdded'
,
[
path
])
})
this
.
_appManager
.
on
(
'remixd'
,
'fileAdded'
,
(
path
)
=>
{
this
.
event
.
trigger
(
'fileAdded'
,
[
this
.
addPrefix
(
path
)
])
this
.
event
.
trigger
(
'fileAdded'
,
[
path
])
})
this
.
_appManager
.
on
(
'remixd'
,
'fileChanged'
,
(
path
)
=>
{
this
.
event
.
trigger
(
'fileChanged'
,
[
this
.
addPrefix
(
path
)
])
this
.
event
.
trigger
(
'fileChanged'
,
[
path
])
})
this
.
_appManager
.
on
(
'remixd'
,
'fileRemoved'
,
(
path
)
=>
{
this
.
event
.
trigger
(
'fileRemoved'
,
[
this
.
addPrefix
(
path
)
])
this
.
event
.
trigger
(
'fileRemoved'
,
[
path
])
})
this
.
_appManager
.
on
(
'remixd'
,
'fileRenamed'
,
(
oldPath
,
newPath
)
=>
{
this
.
event
.
trigger
(
'fileRemoved'
,
[
this
.
addPrefix
(
oldPath
),
this
.
addPrefix
(
newPath
)
])
this
.
event
.
trigger
(
'fileRemoved'
,
[
oldPath
,
newPath
])
})
this
.
_appManager
.
on
(
'remixd'
,
'rootFolderChanged'
,
()
=>
{
...
...
@@ -136,7 +136,7 @@ module.exports = class RemixDProvider {
const
unprefixedpath
=
this
.
removePrefix
(
path
)
this
.
_appManager
.
call
(
'remixd'
,
'remove'
,
{
path
:
unprefixedpath
})
.
then
(
result
=>
{
const
path
=
this
.
type
+
'/'
+
unprefixedpath
const
path
=
unprefixedpath
delete
this
.
filesContent
[
path
]
resolve
(
true
)
...
...
@@ -154,8 +154,8 @@ module.exports = class RemixDProvider {
if
(
!
this
.
_isReady
)
return
new
Promise
((
resolve
,
reject
)
=>
reject
(
new
Error
(
'provider not ready'
)))
return
this
.
_appManager
.
call
(
'remixd'
,
'rename'
,
{
oldPath
:
unprefixedoldPath
,
newPath
:
unprefixednewPath
})
.
then
(
result
=>
{
const
newPath
=
this
.
type
+
'/'
+
unprefixednewPath
const
oldPath
=
this
.
type
+
'/'
+
unprefixedoldPath
const
newPath
=
unprefixednewPath
const
oldPath
=
unprefixedoldPath
this
.
filesContent
[
newPath
]
=
this
.
filesContent
[
oldPath
]
delete
this
.
filesContent
[
oldPath
]
...
...
@@ -181,12 +181,6 @@ module.exports = class RemixDProvider {
return
path
}
addPrefix
(
path
)
{
if
(
path
.
indexOf
(
this
.
type
+
'/'
)
===
0
)
return
path
if
(
path
[
0
]
===
'/'
)
return
'localhost'
+
path
return
'localhost/'
+
path
}
resolveDirectory
(
path
,
callback
)
{
var
self
=
this
if
(
path
[
0
]
===
'/'
)
path
=
path
.
substring
(
1
)
...
...
apps/remix-ide/src/app/files/workspaceFileProvider.js
0 → 100644
View file @
22ea754f
'use strict'
const
FileProvider
=
require
(
'./fileProvider'
)
class
WorkspaceFileProvider
extends
FileProvider
{
constructor
()
{
super
(
''
)
this
.
workspacesPath
=
'.workspaces'
}
setWorkspace
(
workspace
)
{
workspace
=
workspace
.
replace
(
/^
\/
|
\/
$/g
,
''
)
// remove first and last slash
this
.
workspace
=
workspace
}
removePrefix
(
path
)
{
path
=
path
.
replace
(
/^
\/
|
\/
$/g
,
''
)
// remove first and last slash
if
(
path
.
startsWith
(
this
.
workspacesPath
+
'/'
+
this
.
workspace
))
return
path
if
(
path
.
startsWith
(
this
.
workspace
))
return
this
.
workspacesPath
+
'/'
+
this
.
workspace
path
=
super
.
removePrefix
(
path
)
const
ret
=
this
.
workspacesPath
+
'/'
+
this
.
workspace
+
'/'
+
(
path
===
'/'
?
''
:
path
)
return
ret
.
replace
(
/^
\/
|
\/
$/g
,
''
)
}
resolveDirectory
(
path
,
callback
)
{
super
.
resolveDirectory
(
path
,
(
error
,
files
)
=>
{
if
(
error
)
return
callback
(
error
)
const
unscoped
=
{}
for
(
const
file
in
files
)
{
unscoped
[
file
.
replace
(
this
.
workspacesPath
+
'/'
+
this
.
workspace
+
'/'
,
''
)]
=
files
[
file
]
}
callback
(
null
,
unscoped
)
})
}
_normalizePath
(
path
)
{
return
path
.
replace
(
this
.
workspacesPath
+
'/'
+
this
.
workspace
+
'/'
,
''
)
}
}
module
.
exports
=
WorkspaceFileProvider
apps/remix-ide/src/app/panels/file-panel.js
View file @
22ea754f
...
...
@@ -7,10 +7,13 @@ import { FileExplorer } from '@remix-ui/file-explorer' // eslint-disable-line
import
'./styles/file-panel-styles.css'
var
yo
=
require
(
'yo-yo'
)
var
EventManager
=
require
(
'../../lib/events'
)
// var FileExplorer = require('../files/file-explorer')
var
{
RemixdHandle
}
=
require
(
'../files/remixd-handle.js'
)
var
{
GitHandle
}
=
require
(
'../files/git-handle.js'
)
var
globalRegistry
=
require
(
'../../global/registry'
)
var
examples
=
require
(
'../editor/examples'
)
var
GistHandler
=
require
(
'../../lib/gist-handler'
)
var
QueryParams
=
require
(
'../../lib/query-params'
)
const
modalDialog
=
require
(
'../ui/modal-dialog-custom'
)
var
canUpload
=
window
.
File
||
window
.
FileReader
||
window
.
FileList
||
window
.
Blob
...
...
@@ -54,13 +57,16 @@ module.exports = class Filepanel extends ViewPlugin {
fileManager
:
this
.
_components
.
registry
.
get
(
'filemanager'
).
api
,
config
:
this
.
_components
.
registry
.
get
(
'config'
).
api
}
this
.
LOCALHOST
=
'<Connect Localhost>'
this
.
hideRemixdExplorer
=
true
this
.
remixdExplorer
=
{
hide
:
()
=>
{
this
.
_deps
.
fileManager
.
setMode
(
'browser'
)
this
.
hideRemixdExplorer
=
true
this
.
renderComponent
()
},
show
:
()
=>
{
this
.
_deps
.
fileManager
.
setMode
(
'localhost'
)
this
.
hideRemixdExplorer
=
false
this
.
renderComponent
()
}
...
...
@@ -93,9 +99,54 @@ module.exports = class Filepanel extends ViewPlugin {
this
.
remixdExplorer
.
hide
()
})
this
.
currentWorkspace
=
null
this
.
renderComponent
()
}
initWorkspace
()
{
const
queryParams
=
new
QueryParams
()
const
params
=
queryParams
.
get
()
// get the file from gist
const
gistHandler
=
new
GistHandler
()
const
loadedFromGist
=
gistHandler
.
loadFromGist
(
params
,
this
.
_deps
.
fileManager
)
if
(
!
loadedFromGist
)
{
// insert example contracts if there are no files to show
this
.
_deps
.
fileProviders
.
browser
.
resolveDirectory
(
'/'
,
async
(
error
,
filesList
)
=>
{
if
(
error
)
console
.
error
(
error
)
if
(
Object
.
keys
(
filesList
).
length
===
0
)
{
const
workspacesPath
=
this
.
_deps
.
fileProviders
.
workspace
.
workspacesPath
for
(
const
file
in
examples
)
{
await
this
.
_deps
.
fileManager
.
writeFile
(
'browser/'
+
workspacesPath
+
'/default_workspace/'
+
examples
[
file
].
name
,
examples
[
file
].
content
)
}
this
.
setWorkspace
(
'default_workspace'
)
}
})
}
else
{
this
.
setWorkspace
(
'gists'
)
}
}
refreshWorkspacesList
()
{
if
(
!
document
.
getElementById
(
'workspacesSelect'
))
return
const
workspacesPath
=
this
.
_deps
.
fileProviders
.
workspace
.
workspacesPath
this
.
_deps
.
fileProviders
.
browser
.
resolveDirectory
(
'/'
+
workspacesPath
,
(
error
,
fileTree
)
=>
{
if
(
error
)
console
.
error
(
error
)
const
items
=
fileTree
items
[
this
.
LOCALHOST
]
=
{
isLocalHost
:
true
}
ReactDOM
.
render
(
(
Object
.
keys
(
items
)
.
filter
((
item
)
=>
fileTree
[
item
].
isDirectory
||
fileTree
[
item
].
isLocalHost
)
.
map
((
folder
)
=>
{
folder
=
folder
.
replace
(
workspacesPath
+
'/'
,
''
)
return
<
option
selected
=
{
this
.
currentWorkspace
===
folder
}
value
=
{
folder
}
>
{
folder
}
<
/option
>
})),
document
.
getElementById
(
'workspacesSelect'
)
)
if
(
!
this
.
currentWorkspace
)
this
.
setWorkspace
(
Object
.
keys
(
fileTree
)[
0
].
replace
(
workspacesPath
+
'/'
,
''
))
})
}
resetFocus
(
value
)
{
this
.
reset
=
value
this
.
renderComponent
()
...
...
@@ -125,6 +176,19 @@ module.exports = class Filepanel extends ViewPlugin {
return
this
.
el
}
setWorkspace
(
name
)
{
this
.
_deps
.
fileManager
.
removeTabsOf
(
this
.
_deps
.
fileProviders
.
workspace
)
this
.
currentWorkspace
=
name
if
(
name
===
this
.
LOCALHOST
)
{
this
.
call
(
'manager'
,
'activatePlugin'
,
'remixd'
)
}
else
{
this
.
_deps
.
fileProviders
.
workspace
.
setWorkspace
(
name
)
this
.
call
(
'manager'
,
'deactivatePlugin'
,
'remixd'
)
}
// TODO remove the opened tabs from the previous workspace
this
.
renderComponent
()
}
/**
*
* @param item { id: string, name: string, type?: string[], path?: string[], extension?: string[], pattern?: string[] }
...
...
@@ -139,24 +203,104 @@ module.exports = class Filepanel extends ViewPlugin {
this
.
renderComponent
()
}
renameWorkspace
()
{
modalDialog
.
prompt
(
'Rename Workspace'
,
'Please choose a name for the workspace'
,
this
.
currentWorkspace
,
async
(
value
)
=>
{
const
workspacesPath
=
this
.
_deps
.
fileProviders
.
workspace
.
workspacesPath
await
this
.
_deps
.
fileManager
.
rename
(
'browser/'
+
workspacesPath
+
'/'
+
this
.
currentWorkspace
,
'browser/workspaces/'
+
value
)
setTimeout
(
async
()
=>
{
this
.
setWorkspace
(
value
)
},
2000
)
})
}
async
createWorkspace
()
{
const
workspace
=
`workspace_
${
Date
.
now
()}
`
modalDialog
.
prompt
(
'New Workspace'
,
'Please choose a name for the workspace'
,
workspace
,
(
value
)
=>
{
const
workspacesPath
=
this
.
_deps
.
fileProviders
.
workspace
.
workspacesPath
this
.
_deps
.
fileProviders
.
browser
.
createDir
(
workspacesPath
+
'/'
+
value
,
async
()
=>
{
this
.
setWorkspace
(
value
)
setTimeout
(
async
()
=>
{
for
(
const
file
in
examples
)
{
await
this
.
_deps
.
fileManager
.
writeFile
(
`
${
examples
[
file
].
name
}
`
,
examples
[
file
].
content
)
}
},
2000
)
})
})
}
deleteCurrentWorkspace
()
{
if
(
!
this
.
currentWorkspace
)
return
modalDialog
.
confirm
(
'Delete Workspace'
,
'Please confirm workspace deletion'
,
()
=>
{
const
workspacesPath
=
this
.
_deps
.
fileProviders
.
workspace
.
workspacesPath
this
.
_deps
.
fileProviders
.
browser
.
remove
(
workspacesPath
+
'/'
+
this
.
currentWorkspace
)
this
.
currentWorkspace
=
null
this
.
renderComponent
()
})
}
renderComponent
()
{
ReactDOM
.
render
(
<
div
className
=
'remixui_container'
>
<
div
className
=
'remixui_fileexplorer'
onClick
=
{()
=>
this
.
resetFocus
(
true
)}
>
<
div
>
<
header
>
<
div
class
=
"mb-2"
>
<
label
className
=
"form-check-label"
htmlFor
=
"workspacesSelect"
>
Workspaces
<
/label
>
<
span
className
=
"remixui_menu"
>
<
span
id
=
'workspaceCreate'
data
-
id
=
'workspaceCreate'
onClick
=
{(
e
)
=>
{
e
.
stopPropagation
()
this
.
createWorkspace
()
}}
className
=
'far fa-plus-square remixui_menuicon'
title
=
'Create a new Workspace'
>
<
/span
>
<
span
hidden
=
{
this
.
currentWorkspace
===
this
.
LOCALHOST
}
id
=
'workspaceRename'
data
-
id
=
'workspaceRename'
onClick
=
{(
e
)
=>
{
e
.
stopPropagation
()
this
.
renameWorkspace
()
}}
className
=
'far fa-edit remixui_menuicon'
title
=
'Rename current Workspace'
>
<
/span
>
<
span
hidden
=
{
this
.
currentWorkspace
===
this
.
LOCALHOST
}
id
=
'workspaceDelete'
data
-
id
=
'workspaceDelete'
onClick
=
{(
e
)
=>
{
e
.
stopPropagation
()
this
.
deleteCurrentWorkspace
()
}}
className
=
'fas fa-trash'
title
=
'Delete current Workspace'
>
<
/span
>
<
/span
>
<
select
id
=
"workspacesSelect"
data
-
id
=
"workspacesSelect"
onChange
=
{(
e
)
=>
this
.
setWorkspace
(
e
.
target
.
value
)}
className
=
"form-control custom-select"
>
<
/select
>
<
/div
>
<
/header
>
<
/div
>
<
div
className
=
'remixui_fileExplorerTree'
>
<
div
>
<
div
className
=
'pl-2 remixui_treeview'
data
-
id
=
'filePanelFileExplorerTree'
>
{
this
.
hideRemixdExplorer
&&
this
.
currentWorkspace
&&
<
FileExplorer
name
=
'browser'
name
=
{
this
.
currentWorkspace
}
registry
=
{
this
.
_components
.
registry
}
filesProvider
=
{
this
.
_deps
.
fileProviders
.
browser
}
filesProvider
=
{
this
.
_deps
.
fileProviders
.
workspace
}
menuItems
=
{[
'createNewFile'
,
'createNewFolder'
,
'publishToGist'
,
canUpload
?
'uploadFile'
:
''
]}
plugin
=
{
this
}
focusRoot
=
{
this
.
reset
}
contextMenuItems
=
{
this
.
registeredMenuItems
}
displayInput
=
{
this
.
displayNewFile
}
externalUploads
=
{
this
.
uploadFileEvent
}
/
>
}
<
/div
>
<
div
className
=
'pl-2 filesystemexplorer remixui_treeview'
>
{
!
this
.
hideRemixdExplorer
&&
...
...
@@ -171,10 +315,27 @@ module.exports = class Filepanel extends ViewPlugin {
/
>
}
<
/div
>
<
div
className
=
'pl-2 remixui_treeview'
>
{
false
&&
<
FileExplorer
name
=
'browser'
registry
=
{
this
.
_components
.
registry
}
filesProvider
=
{
this
.
_deps
.
fileProviders
.
browser
}
menuItems
=
{[
'createNewFile'
,
'createNewFolder'
,
'publishToGist'
,
canUpload
?
'uploadFile'
:
''
]}
plugin
=
{
this
}
focusRoot
=
{
this
.
reset
}
contextMenuItems
=
{
this
.
registeredMenuItems
}
displayInput
=
{
this
.
displayNewFile
}
externalUploads
=
{
this
.
uploadFileEvent
}
/
>
}
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
,
this
.
el
)
setTimeout
(()
=>
{
this
.
refreshWorkspacesList
()
},
500
)
}
}
apps/remix-ide/src/app/panels/styles/file-panel-styles.css
View file @
22ea754f
...
...
@@ -54,3 +54,6 @@
margin-bottom
:
2em
;
word-break
:
break-word
;
}
.remixui_menuicon
{
padding-right
:
10px
;
}
apps/remix-ide/src/app/tabs/compile-tab.js
View file @
22ea754f
...
...
@@ -227,6 +227,7 @@ class CompileTab extends ViewPlugin {
* @param {object} settings {evmVersion, optimize, runs, version, language}
*/
async
compileWithParameters
(
compilationTargets
,
settings
)
{
settings
.
version
=
settings
.
version
||
this
.
compilerContainer
.
data
.
selectedVersion
const
res
=
await
compile
(
compilationTargets
,
settings
)
return
res
}
...
...
apps/remix-ide/src/app/tabs/test-tab.js
View file @
22ea754f
...
...
@@ -35,7 +35,7 @@ module.exports = class TestTab extends ViewPlugin {
this
.
runningTestsNumber
=
0
this
.
readyTestsNumber
=
0
this
.
areTestsRunning
=
false
this
.
defaultPath
=
'
browser/
tests'
this
.
defaultPath
=
'tests'
this
.
offsetToLineColumnConverter
=
offsetToLineColumnConverter
appManager
.
event
.
on
(
'activate'
,
(
name
)
=>
{
...
...
@@ -551,13 +551,18 @@ module.exports = class TestTab extends ViewPlugin {
updateDirList () {
for (var o of this.uiPathList.querySelectorAll('option')) o.remove()
this.uiPathList.appendChild(yo`
<
option
>
browser
<
/option>`
)
if
(
this
.
testTabLogic
.
isRemixDActive
())
this
.
uiPathList
.
appendChild
(
yo
`<option>localhost</option>`
)
if
(
!
this
.
_view
.
el
)
return
this.testTabLogic.dirList('/').then((options) => {
options.forEach((path) => this.uiPathList.appendChild(yo`
<
option
>
$
{
path
}
<
/option>`
)
)
})
/*
It is not possible anymore to see folder from outside of the current workspace
if (this.inputPath.value) {
this.testTabLogic.dirList(this.inputPath.value).then((options) => {
options.forEach((path) => this.uiPathList.appendChild(yo`<option>${path}</option>`))
})
}
*/
}
render
()
{
this
.
onActivationInternal
()
...
...
apps/remix-ide/src/app/tabs/testTab/testTab.js
View file @
22ea754f
...
...
@@ -5,7 +5,7 @@ const remixPath = require('path')
class
TestTabLogic
{
constructor
(
fileManager
)
{
this
.
fileManager
=
fileManager
this
.
currentPath
=
'
browser
/tests'
this
.
currentPath
=
'/tests'
}
setCurrentPath
(
path
)
{
...
...
apps/remix-ide/src/config.js
View file @
22ea754f
...
...
@@ -22,7 +22,6 @@ function Config (storage) {
}
this
.
get
=
function
(
key
)
{
this
.
ensureStorageUpdated
(
key
)
return
this
.
items
[
key
]
}
...
...
@@ -35,23 +34,6 @@ function Config (storage) {
}
}
this
.
ensureStorageUpdated
=
function
(
key
)
{
if
(
key
===
'currentFile'
)
{
if
(
this
.
items
[
key
]
&&
this
.
items
[
key
]
!==
''
&&
this
.
items
[
key
].
indexOf
(
'config/'
)
!==
0
&&
this
.
items
[
key
].
indexOf
(
'browser/'
)
!==
0
&&
this
.
items
[
key
].
indexOf
(
'localhost/'
)
!==
0
&&
this
.
items
[
key
].
indexOf
(
'swarm/'
)
!==
0
&&
this
.
items
[
key
].
indexOf
(
'gist/'
)
!==
0
&&
this
.
items
[
key
].
indexOf
(
'github/'
)
!==
0
&&
this
.
items
[
key
].
indexOf
(
'ipfs/'
)
!==
0
&&
this
.
items
[
key
].
indexOf
(
'http/'
)
!==
0
&&
this
.
items
[
key
].
indexOf
(
'https/'
)
!==
0
)
{
this
.
items
[
key
]
=
'browser/'
+
this
.
items
[
key
]
}
}
}
this
.
getUnpersistedProperty
=
function
(
key
)
{
return
this
.
unpersistedItems
[
key
]
}
...
...
apps/remix-ide/src/lib/gist-handler.js
View file @
22ea754f
...
...
@@ -42,25 +42,24 @@ function GistHandler (_window) {
}
this
.
loadFromGist
=
(
params
,
fileManager
)
=>
{
const
gistProvider
=
fileManager
.
fileProviderOf
(
'browser'
)
const
self
=
this
return
self
.
handleLoad
(
params
,
function
(
gistId
)
{
request
.
get
({
url
:
`https://api.github.com/gists/
${
gistId
}
`
,
json
:
true
},
(
error
,
response
,
data
=
{})
=>
{
},
async
(
error
,
response
,
data
=
{})
=>
{
if
(
error
||
!
data
.
files
)
{
modalDialogCustom
.
alert
(
`Gist load error:
${
error
||
data
.
message
}
`
)
return
}
const
obj
=
{}
Object
.
keys
(
data
.
files
).
forEach
((
element
)
=>
{
obj
[
'/
gists/
'
+
gistId
+
'/'
+
element
]
=
data
.
files
[
element
]
obj
[
'/'
+
gistId
+
'/'
+
element
]
=
data
.
files
[
element
]
})
fileManager
.
setBatchFiles
(
obj
,
'
browser
'
,
true
,
(
errorLoadingFile
)
=>
{
fileManager
.
setBatchFiles
(
obj
,
'
workspace
'
,
true
,
(
errorLoadingFile
)
=>
{
if
(
!
errorLoadingFile
)
{
gistProvider
.
id
=
gistId
gistProvider
.
origGistFiles
=
data
.
files
const
provider
=
fileManager
.
getProvider
(
'workspace'
)
provider
.
lastLoadedGistId
=
gistId
}
})
})
...
...
apps/remix-ide/src/lib/helper.js
View file @
22ea754f
...
...
@@ -79,6 +79,11 @@ module.exports = {
?
'fak fa-vyper-mono'
:
path
.
endsWith
(
'.lex'
)
?
'fak fa-lexon'
:
path
.
endsWith
(
'.contract'
)
?
'fab fa-ethereum'
:
'far fa-file'
},
joinPath
(...
paths
)
{
paths
=
paths
.
filter
((
value
)
=>
value
!==
''
).
map
((
path
)
=>
path
.
replace
(
/^
\/
|
\/
$/g
,
''
))
// remove first and last slash)
if
(
paths
.
length
===
1
)
return
paths
[
0
]
return
paths
.
join
(
'/'
)
}
}
...
...
apps/remix-ide/src/migrateFileSystem.js
View file @
22ea754f
import
{
Storage
}
from
'@remix-project/remix-lib'
import
{
joinPath
}
from
'./lib/helper'
/*
Migrating the files to the BrowserFS storage instead or raw localstorage
...
...
@@ -20,3 +20,31 @@ export default (fileProvider) => {
})
fileStorageBrowserFS
.
set
(
flag
,
'done'
)
}
export
async
function
migrateToWorkspace
(
fileManager
)
{
const
browserProvider
=
fileManager
.
getProvider
(
'browser'
)
const
workspaceProvider
=
fileManager
.
getProvider
(
'workspace'
)
const
flag
=
'status'
const
fileStorageBrowserWorkspace
=
new
Storage
(
'remix_browserWorkspace_migration:'
)
if
(
fileStorageBrowserWorkspace
.
get
(
flag
)
===
'done'
)
return
const
files
=
await
browserProvider
.
copyFolderToJson
(
'/'
)
console
.
log
(
files
)
const
workspaceName
=
'default_workspace'
const
workspacePath
=
joinPath
(
'browser'
,
workspaceProvider
.
workspacesPath
,
workspaceName
)
await
fileManager
.
createWorkspace
(
workspaceName
)
await
populateWorkspace
(
workspacePath
,
files
,
fileManager
)
fileStorageBrowserWorkspace
.
set
(
flag
,
'done'
)
}
const
populateWorkspace
=
async
(
workspace
,
json
,
fileManager
)
=>
{
for
(
const
item
in
json
)
{
const
isFolder
=
json
[
item
].
content
===
undefined
if
(
isFolder
)
{
await
fileManager
.
mkdir
(
joinPath
(
workspace
,
item
))
await
populateWorkspace
(
workspace
,
json
[
item
].
children
,
fileManager
)
}
else
{
await
fileManager
.
writeFile
(
joinPath
(
workspace
,
item
),
json
[
item
].
content
)
}
}
}
apps/remix-ide/src/remixAppManager.js
View file @
22ea754f
...
...
@@ -130,13 +130,12 @@ class PluginLoader {
constructor
()
{
const
queryParams
=
new
QueryParams
()
this
.
donotAutoReload
=
[
'remixd'
]
// that would be a bad practice to force loading some plugins at page load.
this
.
donotAutoReload
=
[
'remixd'
,
'git'
]
// that would be a bad practice to force loading some plugins at page load.
this
.
loaders
=
{}
this
.
loaders
.
localStorage
=
{
set
:
(
plugin
,
actives
)
=>
{
if
(
!
this
.
donotAutoReload
.
includes
(
plugin
.
name
))
{
localStorage
.
setItem
(
'workspace'
,
JSON
.
stringify
(
actives
))
}
const
saved
=
actives
.
filter
((
name
)
=>
!
this
.
donotAutoReload
.
includes
(
name
))
localStorage
.
setItem
(
'workspace'
,
JSON
.
stringify
(
saved
))
},
get
:
()
=>
{
return
JSON
.
parse
(
localStorage
.
getItem
(
'workspace'
))
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment