Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/remix-ide-e2e/src/tests/gist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ module.exports = {
.setValue('*[data-id="modalDialogCustomPromptText"]', testData.invalidGistId)
.modalFooterOKClick()
.waitForElementVisible('*[data-id="modalDialogModalBody"]')
.assert.containsText('*[data-id="modalDialogModalBody"]', 'Gist load error: Not Found')
.assert.containsText('*[data-id="modalDialogModalBody"]', 'Not Found')
.modalFooterOKClick()
},

Expand Down
1 change: 1 addition & 0 deletions apps/remix-ide-e2e/src/tests/solidityImport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = {
.addFile('Untitled2.sol', sources[1]['Untitled2.sol'])
.openFile('Untitled1.sol')
.verifyContracts(['test6', 'test4', 'test5'])
.pause(1000)
},

'Test Failed Import': function (browser: NightwatchBrowser) {
Expand Down
2 changes: 2 additions & 0 deletions apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,14 @@ module.exports = {
.addFile('myTests/simple_storage_test.sol', sources[0]['tests/simple_storage_test.sol'])
.clickLaunchIcon('solidityUnitTesting')
.setValue('*[data-id="uiPathInput"]', 'myTests')
.click('*[data-id="testTabGenerateTestFolder"]')
.clickElementAtPosition('.singleTestLabel', 0)
.scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]')
.waitForElementPresent('*[data-id="testTabSolidityUnitTestsOutputheader"]', 40000)
.waitForElementPresent('*[data-id="testTabSolidityUnitTestsOutput"]')
.clearValue('*[data-id="uiPathInput"]')
.setValue('*[data-id="uiPathInput"]', 'tests')
.click('*[data-id="testTabGenerateTestFolder"]')
},

'Solidity Unittests': function (browser: NightwatchBrowser) {
Expand Down
23 changes: 23 additions & 0 deletions apps/remix-ide-e2e/src/tests/workspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,29 @@ module.exports = {
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.sol"]')
.click('*[data-id="workspacesSelect"] option[value="workspace_name"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
},

'Should rename a workspace': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="workspaceRename"]') // rename workspace_name
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextRename"]')
// eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextRename"]')['value'] = 'workspace_name_renamed' })
.click('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.click('*[data-id="workspacesSelect"] option[value="workspace_name_1"]')
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.sol"]')
.click('*[data-id="workspacesSelect"] option[value="workspace_name_renamed"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]')
},

'Should delete a workspace': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="workspacesSelect"] option[value="workspace_name_1"]')
.click('*[data-id="workspaceDelete"]') // delete workspace_name_1
.waitForElementVisible('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.click('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.waitForElementNotPresent('*[data-id="workspacesSelect"] option[value="workspace_name_1"]')
.end()
},

Expand Down
14 changes: 12 additions & 2 deletions apps/remix-ide/src/app/files/fileManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,8 @@ class FileManager extends Plugin {
if (file.startsWith('browser')) {
return this._deps.filesProviders.browser
}
const provider = this._deps.filesProviders.workspace
if (!provider.isReady()) throw createError({ code: 'ECONNRESET', message: 'No workspace has been opened.' })
return this._deps.filesProviders.workspace
}

Expand Down Expand Up @@ -579,7 +581,11 @@ class FileManager extends Plugin {

async.each(Object.keys(filesSet), (file, callback) => {
if (override) {
self._deps.filesProviders[fileProvider].set(file, filesSet[file].content)
try {
self._deps.filesProviders[fileProvider].set(file, filesSet[file].content)
} catch (e) {
return callback(e.message || e)
}
self.syncEditor(fileProvider + file)
return callback()
}
Expand All @@ -591,7 +597,11 @@ class FileManager extends Plugin {
} else if (helper.checkSpecialChars(name)) {
modalDialogCustom.alert('Special characters are not allowed')
} else {
self._deps.filesProviders[fileProvider].set(name, filesSet[file].content)
try {
self._deps.filesProviders[fileProvider].set(name, filesSet[file].content)
} catch (e) {
return callback(e.message || e)
}
self.syncEditor(fileProvider + name)
}
callback()
Expand Down
12 changes: 12 additions & 0 deletions apps/remix-ide/src/app/files/workspaceFileProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,28 @@ class WorkspaceFileProvider extends FileProvider {
constructor () {
super('')
this.workspacesPath = '.workspaces'
this.workspace = null
}

setWorkspace (workspace) {
workspace = workspace.replace(/^\/|\/$/g, '') // remove first and last slash
this.workspace = workspace
}

getWorkspace () {
return this.workspace
}

isReady () {
return this.workspace !== null
}

clearWorkspace () {
this.workspace = null
}

removePrefix (path) {
if (!this.workspace) throw new Error('No workspace has been opened.')
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
Expand All @@ -27,6 +37,7 @@ class WorkspaceFileProvider extends FileProvider {
}

resolveDirectory (path, callback) {
if (!this.workspace) throw new Error('No workspace has been opened.')
super.resolveDirectory(path, (error, files) => {
if (error) return callback(error)
const unscoped = {}
Expand All @@ -38,6 +49,7 @@ class WorkspaceFileProvider extends FileProvider {
}

_normalizePath (path) {
if (!this.workspace) throw new Error('No workspace has been opened.')
return path.replace(this.workspacesPath + '/' + this.workspace + '/', '')
}
}
Expand Down
17 changes: 15 additions & 2 deletions apps/remix-ide/src/app/panels/file-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { Workspace } from '@remix-ui/workspace' // eslint-disable-line
import * as ethutil from 'ethereumjs-util'
import { checkSpecialChars, checkSlash } from '../../lib/helper'
var EventManager = require('../../lib/events')
var { RemixdHandle } = require('../files/remixd-handle.js')
var { GitHandle } = require('../files/git-handle.js')
Expand Down Expand Up @@ -74,6 +75,7 @@ module.exports = class Filepanel extends ViewPlugin {
ReactDOM.render(
<Workspace
createWorkspace={this.createWorkspace.bind(this)}
renameWorkspace={this.renameWorkspace.bind(this)}
setWorkspace={this.setWorkspace.bind(this)}
workspaceRenamed={this.workspaceRenamed.bind(this)}
workspaceDeleted={this.workspaceDeleted.bind(this)}
Expand Down Expand Up @@ -165,8 +167,8 @@ module.exports = class Filepanel extends ViewPlugin {
return await this.request.createNewFile()
}

async uploadFile () {
return await this.request.uploadFile()
async uploadFile (event) {
return await this.request.uploadFile(event)
}

async processCreateWorkspace (name) {
Expand All @@ -186,6 +188,8 @@ module.exports = class Filepanel extends ViewPlugin {
}

async createWorkspace (workspaceName) {
if (!workspaceName) throw new Error('name cannot be empty')
if (checkSpecialChars(workspaceName) || checkSlash(workspaceName)) throw new Error('special characters are not allowed')
if (await this.workspaceExists(workspaceName)) throw new Error('workspace already exists')
const browserProvider = this._deps.fileProviders.browser
const workspacesPath = this._deps.fileProviders.workspace.workspacesPath
Expand All @@ -199,6 +203,15 @@ module.exports = class Filepanel extends ViewPlugin {
}
}

async renameWorkspace (oldName, workspaceName) {
if (!workspaceName) throw new Error('name cannot be empty')
if (checkSpecialChars(workspaceName) || checkSlash(workspaceName)) throw new Error('special characters are not allowed')
if (await this.workspaceExists(workspaceName)) throw new Error('workspace already exists')
const browserProvider = this._deps.fileProviders.browser
const workspacesPath = this._deps.fileProviders.workspace.workspacesPath
browserProvider.rename('browser/' + workspacesPath + '/' + oldName, 'browser/' + workspacesPath + '/' + workspaceName, true)
}

/** these are called by the react component, action is already finished whent it's called */
async setWorkspace (workspace) {
this._deps.fileManager.removeTabsOf(this._deps.fileProviders.workspace)
Expand Down
3 changes: 3 additions & 0 deletions apps/remix-ide/src/app/tabs/styles/test-tab-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,8 @@ var css = csjs`
.labelOnBtn {
border: hidden;
}
.inputFolder {
width: 80%;
}
`
module.exports = css
17 changes: 14 additions & 3 deletions apps/remix-ide/src/app/tabs/test-tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -573,18 +573,29 @@ module.exports = class TestTab extends ViewPlugin {
this.inputPath = yo`<input
placeholder=${this.defaultPath}
list="utPathList"
class="custom-select"
class="${css.inputFolder} custom-select"
id="utPath"
data-id="uiPathInput"
name="utPath"
style="background-image: var(--primary);"
onkeydown=${(e) => { if (e.keyCode === 191) this.updateDirList() }}
onchange=${(e) => this.updateCurrentPath(e)}/>`

const createTestFolder = yo`<button
class="btn border ml-2"
data-id="testTabGenerateTestFolder"
title="Create a test folder"
onclick=${(e) => { this.testTabLogic.generateTestFolder(this.inputPath.value) }}>
Create
</button>`

const availablePaths = yo`
<div>
${this.inputPath}
${this.uiPathList}
<div class="d-flex p-2">
${this.inputPath}
${createTestFolder}
${this.uiPathList}
</div>
</div>
`
this.updateDirList()
Expand Down
7 changes: 5 additions & 2 deletions apps/remix-ide/src/app/tabs/testTab/testTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ class TestTabLogic {
setCurrentPath (path) {
if (path.indexOf('/') === 0) return
this.currentPath = path
}

generateTestFolder (path) {
const fileProvider = this.fileManager.fileProviderOf(path.split('/')[0])
fileProvider.exists(path, (e, res) => { if (!res) fileProvider.createDir(path) })
}
Expand Down Expand Up @@ -44,9 +47,9 @@ class TestTabLogic {
const provider = this.fileManager.fileProviderOf(this.currentPath)
if (!provider) return cb(null, [])
const tests = []
let files
let files = []
try {
files = await this.fileManager.readdir(this.currentPath)
if (await this.fileManager.exists(this.currentPath)) files = await this.fileManager.readdir(this.currentPath)
} catch (e) {
cb(e.message)
}
Expand Down
13 changes: 9 additions & 4 deletions apps/remix-ide/src/app/ui/landing-page/landing-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,17 +240,22 @@ export class LandingPage extends ViewPlugin {
<div>e.g ${examples.map((url) => { return yo`<div class="p-1"><a>${url}</a></div>` })}</div>
</div>`

modalDialogCustom.prompt(`Import from ${service}`, msg, null, (target) => {
const title = `Import from ${service}`
modalDialogCustom.prompt(title, msg, null, (target) => {
if (target !== '') {
compilerImport.import(
target,
(loadingMsg) => { tooltip(loadingMsg) },
(error, content, cleanUrl, type, url) => {
if (error) {
modalDialogCustom.alert(error)
modalDialogCustom.alert(title, error.message || error)
} else {
fileProviders.browser.addExternal(type + '/' + cleanUrl, content, url)
this.verticalIcons.select('fileExplorers')
try {
fileProviders.workspace.addExternal(type + '/' + cleanUrl, content, url)
this.verticalIcons.select('fileExplorers')
} catch (e) {
modalDialogCustom.alert(title, e.message)
}
}
}
)
Expand Down
2 changes: 1 addition & 1 deletion apps/remix-ide/src/app/ui/modal-dialog-custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var css = require('./styles/modal-dialog-custom-styles')
module.exports = {
alert: function (title, text) {
if (text) return modal(title, yo`<div>${text}</div>`, null, { label: null })
return modal('', yo`<div>${title}</div>`, null, { label: null })
return modal('Alert', yo`<div>${title}</div>`, null, { label: null })
},
prompt: function (title, text, inputValue, ok, cancel, focus) {
return prompt(title, text, false, inputValue, ok, cancel, focus)
Expand Down
6 changes: 4 additions & 2 deletions apps/remix-ide/src/lib/gist-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function GistHandler (_window) {
if (gistId) {
cb(gistId)
} else {
modalDialogCustom.alert('Error while loading gist. Please provide a valid Gist ID or URL.')
modalDialogCustom.alert('Gist load error', 'Error while loading gist. Please provide a valid Gist ID or URL.')
}
}
})
Expand Down Expand Up @@ -49,7 +49,7 @@ function GistHandler (_window) {
json: true
}, async (error, response, data = {}) => {
if (error || !data.files) {
modalDialogCustom.alert(`Gist load error: ${error || data.message}`)
modalDialogCustom.alert('Gist load error', error || data.message)
return
}
const obj = {}
Expand All @@ -60,6 +60,8 @@ function GistHandler (_window) {
if (!errorLoadingFile) {
const provider = fileManager.getProvider('workspace')
provider.lastLoadedGistId = gistId
} else {
modalDialogCustom.alert('Gist load error', errorLoadingFile.message || errorLoadingFile)
}
})
})
Expand Down
3 changes: 3 additions & 0 deletions apps/remix-ide/src/lib/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ module.exports = {
checkSpecialChars (name) {
return name.match(/[:*?"<>\\'|]/) != null
},
checkSlash (name) {
return name.match(/\//) != null
},
isHexadecimal (value) {
return /^[0-9a-fA-F]+$/.test(value) && (value.length % 2 === 0)
},
Expand Down
13 changes: 8 additions & 5 deletions apps/remix-ide/src/migrateFileSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,20 @@ export async function migrateToWorkspace (fileManager, filePanel) {
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 filePanel.createWorkspace(workspaceName)
filePanel.getWorkspaces() // refresh list
await populateWorkspace(workspacePath, files, browserProvider)
if (Object.keys(files).length > 0) {
const workspaceName = 'default_workspace'
const workspacePath = joinPath('browser', workspaceProvider.workspacesPath, workspaceName)
await filePanel.processCreateWorkspace(workspaceName)
filePanel.getWorkspaces() // refresh list
await populateWorkspace(workspacePath, files, browserProvider)
}
fileStorageBrowserWorkspace.set(flag, 'done')
}

const populateWorkspace = async (workspace, json, browserProvider) => {
for (const item in json) {
const isFolder = json[item].content === undefined
if (isFolder && item === '/.workspaces') continue // we don't want to replicate this one.
if (isFolder) {
browserProvider.createDir(joinPath(workspace, item))
await populateWorkspace(workspace, json[item].children, browserProvider)
Expand Down
4 changes: 2 additions & 2 deletions libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
},
{
action: 'publishToGist',
title: 'Publish all [browser] explorer files to a github gist',
title: 'Publish all the current workspace files (only root) to a github gist',
icon: 'fab fa-github'
},
{
action: 'uploadFile',
title: 'Load a local file into Remix\'s browser folder',
title: 'Load a local file into current workspace',
icon: 'fa fa-upload'
},
{
Expand Down
Loading