Merge branch 'master' into cache-content

pull/2072/head
David Disu 3 years ago committed by GitHub
commit cf90dd727f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      apps/remix-ide/src/app/components/hidden-panel.tsx
  2. 21
      apps/remix-ide/src/app/components/main-panel.tsx
  3. 32
      apps/remix-ide/src/app/components/plugin-manager-component.js
  4. 21
      apps/remix-ide/src/app/components/side-panel.tsx
  5. 31
      apps/remix-ide/src/app/components/vertical-icons.tsx
  6. 61
      apps/remix-ide/src/app/editor/editor.js
  7. 11
      apps/remix-ide/src/app/files/fileManager.ts
  8. 13
      apps/remix-ide/src/app/panels/file-panel.js
  9. 27
      apps/remix-ide/src/app/panels/tab-proxy.js
  10. 32
      apps/remix-ide/src/app/panels/terminal.js
  11. 52
      apps/remix-ide/src/app/tabs/analysis-tab.js
  12. 9
      apps/remix-ide/src/app/tabs/compile-tab.js
  13. 10
      apps/remix-ide/src/app/tabs/debugger-tab.js
  14. 48
      apps/remix-ide/src/app/tabs/settings-tab.tsx
  15. 23
      apps/remix-ide/src/app/tabs/test-tab.js
  16. 11
      apps/remix-ide/src/app/udapp/run-tab.js
  17. 13
      apps/remix-ide/src/app/ui/landing-page/landing-page.js
  18. 4
      apps/remix-ide/src/index.tsx
  19. 57
      apps/remix-ide/src/lib/commands.js
  20. 49
      libs/remix-core-plugin/src/lib/compiler-artefacts.ts
  21. 39
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  22. 1
      libs/remix-ui/helper/src/index.ts
  23. 24
      libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx
  24. 2
      libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx
  25. 1
      libs/remix-ui/panel/src/lib/plugins/panel-plugin.tsx
  26. 5
      libs/remix-ui/panel/src/lib/plugins/panel.css
  27. 1
      libs/remix-ui/terminal/src/lib/commands.ts
  28. 3
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.css
  29. 2
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
  30. 6
      libs/remix-ui/terminal/src/lib/terminalWelcome.tsx
  31. 1
      libs/remix-ui/vertical-icons-panel/src/lib/remix-ui-vertical-icons-panel.css
  32. 11
      libs/remix-ui/workspace/src/lib/actions/index.ts
  33. 6
      libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx
  34. 9
      libs/remix-ui/workspace/src/lib/components/file-explorer.tsx
  35. 1
      libs/remix-ui/workspace/src/lib/contexts/index.ts
  36. 7
      libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx
  37. 2
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  38. 2
      libs/remix-ui/workspace/src/lib/types/index.ts
  39. 6
      libs/remix-ui/workspace/src/lib/utils/index.ts
  40. 14
      package.json

@ -1,9 +1,9 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import ReactDOM from 'react-dom' // eslint-disable-line
import { AbstractPanel } from './panel'
import * as packageJson from '../../../../../package.json'
import { RemixPluginPanel } from '@remix-ui/panel'
import { PluginViewWrapper } from '@remix-ui/helper'
const profile = {
name: 'hiddenPanel',
@ -15,6 +15,7 @@ const profile = {
export class HiddenPanel extends AbstractPanel {
el: HTMLElement
dispatch: React.Dispatch<any> = () => {}
constructor () {
super(profile)
this.el = document.createElement('div')
@ -27,11 +28,23 @@ export class HiddenPanel extends AbstractPanel {
this.renderComponent()
}
render () {
return this.el
updateComponent (state: any) {
return <RemixPluginPanel header={<></>} plugins={state.plugins}/>
}
setDispatch (dispatch: React.Dispatch<any>) {
this.dispatch = dispatch
}
render() {
return (
<div className='pluginsContainer'><PluginViewWrapper plugin={this} /></div>
);
}
renderComponent () {
ReactDOM.render(<RemixPluginPanel header={<></>} plugins={this.plugins}/>, this.el)
this.dispatch({
plugins: this.plugins,
})
}
}

@ -1,8 +1,8 @@
import React from 'react' // eslint-disable-line
import { AbstractPanel } from './panel'
import ReactDOM from 'react-dom' // eslint-disable-line
import { RemixPluginPanel } from '@remix-ui/panel'
import packageJson from '../../../../../package.json'
import { PluginViewWrapper } from '@remix-ui/helper'
const profile = {
name: 'mainPanel',
@ -14,6 +14,7 @@ const profile = {
export class MainPanel extends AbstractPanel {
element: HTMLDivElement
dispatch: React.Dispatch<any> = () => {}
constructor (config) {
super(profile)
this.element = document.createElement('div')
@ -22,6 +23,10 @@ export class MainPanel extends AbstractPanel {
// this.config = config
}
setDispatch (dispatch: React.Dispatch<any>) {
this.dispatch = dispatch
}
onActivation () {
this.renderComponent()
}
@ -47,11 +52,17 @@ export class MainPanel extends AbstractPanel {
this.renderComponent()
}
render () {
return this.element
renderComponent () {
this.dispatch({
plugins: this.plugins
})
}
render() {
return <div style={{height: '100%', width: '100%'}} data-id='mainPanelPluginsContainer'><PluginViewWrapper plugin={this} /></div>
}
renderComponent () {
ReactDOM.render(<RemixPluginPanel header={<></>} plugins={this.plugins}/>, this.element)
updateComponent (state: any) {
return <RemixPluginPanel header={<></>} plugins={state.plugins}/>
}
}

@ -1,8 +1,8 @@
import { ViewPlugin } from '@remixproject/engine-web'
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import {RemixUiPluginManager} from '@remix-ui/plugin-manager' // eslint-disable-line
import * as packageJson from '../../../../../package.json'
import { PluginViewWrapper } from '@remix-ui/helper'
const _paq = window._paq = window._paq || []
const profile = {
@ -31,6 +31,7 @@ class PluginManagerComponent extends ViewPlugin {
this.inactivePlugins = []
this.activeProfiles = this.appManager.actives
this._paq = _paq
this.dispatch = null
this.listenOnEvent()
}
@ -40,7 +41,7 @@ class PluginManagerComponent extends ViewPlugin {
* RemixAppManager
* @param {string} name name of Plugin
*/
isActive (name) {
isActive = (name) =>{
return this.appManager.actives.includes(name)
}
@ -49,7 +50,7 @@ class PluginManagerComponent extends ViewPlugin {
* RemixAppManager to enable plugin activation
* @param {string} name name of Plugin
*/
activateP (name) {
activateP = (name) => {
this.appManager.activatePlugin(name)
_paq.push(['trackEvent', 'manager', 'activate', name])
}
@ -60,7 +61,7 @@ class PluginManagerComponent extends ViewPlugin {
* @param {Profile} pluginName
* @returns {void}
*/
async activateAndRegisterLocalPlugin (localPlugin) {
activateAndRegisterLocalPlugin = async (localPlugin) => {
if (localPlugin) {
this.engine.register(localPlugin)
this.appManager.activatePlugin(localPlugin.profile.name)
@ -75,28 +76,33 @@ class PluginManagerComponent extends ViewPlugin {
* of the plugin
* @param {string} name name of Plugin
*/
deactivateP (name) {
deactivateP = (name) => {
this.call('manager', 'deactivatePlugin', name)
_paq.push(['trackEvent', 'manager', 'deactivate', name])
}
onActivation () {
setDispatch (dispatch) {
this.dispatch = dispatch
this.renderComponent()
}
updateComponent(state){
return <RemixUiPluginManager
pluginComponent={state}/>
}
renderComponent () {
ReactDOM.render(
<RemixUiPluginManager
pluginComponent={this}
/>,
this.htmlElement)
if(this.dispatch) this.dispatch({...this, activePlugins: this.activePlugins, inactivePlugins: this.inactivePlugins})
}
render () {
return this.htmlElement
return (
<div id='pluginManager'><PluginViewWrapper plugin={this} /></div>
);
}
getAndFilterPlugins (filter) {
getAndFilterPlugins = (filter) => {
this.filter = typeof filter === 'string' ? filter.toLowerCase() : this.filter
const isFiltered = (profile) => (profile.displayName ? profile.displayName : profile.name).toLowerCase().includes(this.filter)

@ -1,10 +1,10 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import ReactDOM from 'react-dom'
import { AbstractPanel } from './panel'
import { RemixPluginPanel } from '@remix-ui/panel'
import packageJson from '../../../../../package.json'
import RemixUIPanelHeader from 'libs/remix-ui/panel/src/lib/plugins/panel-header'
import { PluginViewWrapper } from '@remix-ui/helper'
// const csjs = require('csjs-inject')
const sidePanel = {
@ -17,6 +17,7 @@ const sidePanel = {
export class SidePanel extends AbstractPanel {
sideelement: any
dispatch: React.Dispatch<any> = () => {}
constructor() {
super(sidePanel)
this.sideelement = document.createElement('section')
@ -78,11 +79,23 @@ export class SidePanel extends AbstractPanel {
this.renderComponent()
}
render() {
return this.sideelement
setDispatch (dispatch: React.Dispatch<any>) {
this.dispatch = dispatch
}
render() {
return (
<section className='panel plugin-manager'> <PluginViewWrapper plugin={this} /></section>
);
}
updateComponent(state: any) {
return <RemixPluginPanel header={<RemixUIPanelHeader plugins={state.plugins}></RemixUIPanelHeader>} plugins={state.plugins} />
}
renderComponent() {
ReactDOM.render(<RemixPluginPanel header={<RemixUIPanelHeader plugins={this.plugins}></RemixUIPanelHeader>} plugins={this.plugins} />, this.sideelement)
this.dispatch({
plugins: this.plugins
})
}
}

@ -1,11 +1,11 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import ReactDOM from 'react-dom'
import packageJson from '../../../../../package.json'
import { Plugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import { IconRecord, RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel'
import { Profile } from '@remixproject/plugin-utils'
import { PluginViewWrapper } from '@remix-ui/helper'
const profile = {
name: 'menuicons',
@ -20,6 +20,7 @@ export class VerticalIcons extends Plugin {
events: EventEmitter
htmlElement: HTMLDivElement
icons: Record<string, IconRecord> = {}
dispatch: React.Dispatch<any> = () => {}
constructor () {
super(profile)
this.events = new EventEmitter()
@ -46,12 +47,15 @@ export class VerticalIcons extends Plugin {
...divived.filter((value) => { return !value.isRequired })
]
ReactDOM.render(
<RemixUiVerticalIconsPanel
verticalIconsPlugin={this}
icons={sorted}
/>,
this.htmlElement)
this.dispatch({
verticalIconsPlugin: this,
icons: sorted
})
}
setDispatch (dispatch: React.Dispatch<any>) {
this.dispatch = dispatch
}
onActivation () {
@ -107,7 +111,16 @@ export class VerticalIcons extends Plugin {
this.events.emit('toggleContent', name)
}
render () {
return this.htmlElement
updateComponent(state: any){
return <RemixUiVerticalIconsPanel
verticalIconsPlugin={state.verticalIconsPlugin}
icons={state.icons}
/>
}
render() {
return (
<div id='icon-panel'><PluginViewWrapper plugin={this} /></div>
);
}
}

@ -1,9 +1,9 @@
'use strict'
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { EditorUI } from '@remix-ui/editor' // eslint-disable-line
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json'
import { PluginViewWrapper } from '@remix-ui/helper'
const EventManager = require('../../lib/events')
@ -61,10 +61,29 @@ class Editor extends Plugin {
// to be implemented by the react component
this.api = {}
this.dispatch = null
this.ref = null
}
setDispatch (dispatch) {
this.dispatch = dispatch
}
updateComponent(state) {
return <EditorUI
editorAPI={state.api}
themeType={state.currentThemeType}
currentFile={state.currentFile}
sourceAnnotationsPerFile={state.sourceAnnotationsPerFile}
markerPerFile={state.markerPerFile}
events={state.events}
plugin={state.plugin}
/>
}
render () {
if (this.el) return this.el
/* if (this.el) return this.el
this.el = document.createElement('div')
this.el.setAttribute('id', 'editorView')
@ -76,22 +95,34 @@ class Editor extends Plugin {
}
}
this.el.gotoLine = (line, column) => this.gotoLine(line, column || 0)
this.el.getCursorPosition = () => this.getCursorPosition()
return this.el
this.el.getCursorPosition = () => this.getCursorPosition() */
return <div ref={(element)=>{
this.ref = element
this.ref.currentContent = () => this.currentContent() // used by e2e test
this.ref.setCurrentContent = (value) => {
if (this.sessions[this.currentFile]) {
this.sessions[this.currentFile].setValue(value)
this._onChange(this.currentFile)
}
}
this.ref.gotoLine = (line, column) => this.gotoLine(line, column || 0)
this.ref.getCursorPosition = () => this.getCursorPosition()
}} id='editorView'>
<PluginViewWrapper plugin={this} />
</div>
}
renderComponent () {
ReactDOM.render(
<EditorUI
editorAPI={this.api}
themeType={this.currentThemeType}
currentFile={this.currentFile}
sourceAnnotationsPerFile={this.sourceAnnotationsPerFile}
markerPerFile={this.markerPerFile}
events={this.events}
plugin={this}
/>
, this.el)
this.dispatch({
api: this.api,
currentThemeType: this.currentThemeType,
currentFile: this.currentFile,
sourceAnnotationsPerFile: this.sourceAnnotationsPerFile,
markerPerFile: this.markerPerFile,
events: this.events,
plugin: this
})
}
triggerEvent (name, params) {

@ -19,7 +19,7 @@ const profile = {
icon: 'assets/img/fileManager.webp',
permission: true,
version: packageJson.version,
methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles'],
methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles'],
kind: 'file-system'
}
const errorMsg = {
@ -704,7 +704,14 @@ class FileManager extends Plugin {
return collectList(path)
}
isRemixDActive() {
async fileList (dirPath) {
const paths: any = await this.readdir(dirPath)
for( const path in paths)
if(paths[path].isDirectory) delete paths[path]
return Object.keys(paths)
}
isRemixDActive () {
return this.appManager.isActive('remixd')
}

@ -2,7 +2,6 @@ import { ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { FileSystemProvider } from '@remix-ui/workspace' // eslint-disable-line
import Registry from '../state/registry'
import { RemixdHandle } from '../plugins/remixd-handle'
@ -58,18 +57,8 @@ module.exports = class Filepanel extends ViewPlugin {
this.currentWorkspaceMetadata = {}
}
onActivation () {
this.renderComponent()
}
render () {
return this.el
}
renderComponent () {
ReactDOM.render(
<FileSystemProvider plugin={this} />
, this.el)
return <div id='fileExplorerView'><FileSystemProvider plugin={this} /></div>
}
/**

@ -1,8 +1,7 @@
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { Plugin } from '@remixproject/engine'
import { TabsUI } from '@remix-ui/tabs'
import { getPathIcon } from '@remix-ui/helper'
import { PluginViewWrapper, getPathIcon } from '@remix-ui/helper'
const EventEmitter = require('events')
const profile = {
@ -11,7 +10,6 @@ const profile = {
kind: 'other'
}
// @todo(#650) Merge this with MainPanel into one plugin
export class TabProxy extends Plugin {
constructor (fileManager, editor) {
super(profile)
@ -23,6 +21,7 @@ export class TabProxy extends Plugin {
this._handlers = {}
this.loadedTabs = []
this.el = document.createElement('div')
this.dispatch = null
}
onActivation () {
@ -286,6 +285,15 @@ export class TabProxy extends Plugin {
this.handlers[type] = fn
}
setDispatch (dispatch) {
this.dispatch = dispatch
this.renderComponent()
}
updateComponent(state) {
return <TabsUI tabs={state.loadedTabs} onSelect={state.onSelect} onClose={state.onClose} onZoomIn={state.onZoomIn} onZoomOut={state.onZoomOut} onReady={state.onReady} />
}
renderComponent () {
const onSelect = (index) => {
if (this.loadedTabs[index]) {
@ -308,12 +316,17 @@ export class TabProxy extends Plugin {
const onReady = (api) => { this.tabsApi = api }
ReactDOM.render(
<TabsUI tabs={this.loadedTabs} onSelect={onSelect} onClose={onClose} onZoomIn={onZoomIn} onZoomOut={onZoomOut} onReady={onReady} />
, this.el)
this.dispatch({
loadedTabs: this.loadedTabs,
onSelect,
onClose,
onZoomIn,
onZoomOut,
onReady
})
}
renderTabsbar () {
return this.el
return <div><PluginViewWrapper plugin={this} /></div>
}
}

@ -1,15 +1,16 @@
/* global Node, requestAnimationFrame */ // eslint-disable-line
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { RemixUiTerminal } from '@remix-ui/terminal' // eslint-disable-line
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json'
import Registry from '../state/registry'
import { PluginViewWrapper } from '@remix-ui/helper'
const vm = require('vm')
const EventManager = require('../../lib/events')
import { CompilerImports } from '@remix-project/core-plugin' // eslint-disable-line
const KONSOLES = []
function register (api) { KONSOLES.push(api) }
@ -79,9 +80,12 @@ class Terminal extends Plugin {
this.call('menuicons', 'select', 'debugger')
this.call('debugger', 'debug', hash)
})
this.dispatch = null
}
onActivation () {
onActivation() {
this.renderComponent()
}
@ -100,19 +104,27 @@ class Terminal extends Plugin {
this.terminalApi.log(message)
}
setDispatch(dispatch) {
this.dispatch = dispatch
}
render () {
return this.element
return <div id='terminal-view' className='panel' data-id='terminalContainer-view'><PluginViewWrapper plugin={this}/></div>
}
updateComponent(state) {
return <RemixUiTerminal
plugin={state.plugin}
onReady={state.onReady}
/>
}
renderComponent () {
const onReady = (api) => { this.terminalApi = api }
ReactDOM.render(
<RemixUiTerminal
plugin={this}
onReady={onReady}
/>,
this.element
)
this.dispatch({
plugin: this,
onReady: onReady
})
}
scroll2bottom () {

@ -1,10 +1,10 @@
import React from 'react' // eslint-disable-line
import { ViewPlugin } from '@remixproject/engine-web'
import ReactDOM from 'react-dom'
import { EventEmitter } from 'events'
import {RemixUiStaticAnalyser} from '@remix-ui/static-analyser' // eslint-disable-line
import * as packageJson from '../../../../../package.json'
import Registry from '../state/registry'
import { PluginViewWrapper } from '@remix-ui/helper'
var EventManager = require('../../lib/events')
@ -35,6 +35,7 @@ class AnalysisTab extends ViewPlugin {
offsetToLineColumnConverter: this.registry.get(
'offsettolinecolumnconverter').api
}
this.dispatch = null
}
async onActivation () {
@ -43,33 +44,40 @@ class AnalysisTab extends ViewPlugin {
await this.call('manager', 'activatePlugin', 'solidity')
}
this.renderComponent()
this.event.register('staticAnaysisWarning', (count) => {
if (count > 0) {
this.emit('statusChanged', { key: count, title: `${count} warning${count === 1 ? '' : 's'}`, type: 'warning' })
} else if (count === 0) {
this.emit('statusChanged', { key: 'succeed', title: 'no warning', type: 'success' })
} else {
// count ==-1 no compilation result
this.emit('statusChanged', { key: 'none' })
}
})
}
setDispatch (dispatch) {
this.dispatch = dispatch
}
render () {
return this.element
return <div id='staticAnalyserView'><PluginViewWrapper plugin={this} /></div>
}
updateComponent(state) {
return <RemixUiStaticAnalyser
registry={state.registry}
analysisModule={state.analysisModule}
event={state.event}
/>
}
renderComponent () {
ReactDOM.render(
<RemixUiStaticAnalyser
registry={this.registry}
analysisModule={this}
event={this.event}
/>,
this.element,
() => {
this.event.register('staticAnaysisWarning', (count) => {
if (count > 0) {
this.emit('statusChanged', { key: count, title: `${count} warning${count === 1 ? '' : 's'}`, type: 'warning' })
} else if (count === 0) {
this.emit('statusChanged', { key: 'succeed', title: 'no warning', type: 'success' })
} else {
// count ==-1 no compilation result
this.emit('statusChanged', { key: 'none' })
}
})
}
)
this.dispatch({
registry: this.registry,
analysisModule: this,
event: this.event
})
}
}

@ -1,6 +1,5 @@
/* global */
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { SolidityCompiler } from '@remix-ui/solidity-compiler' // eslint-disable-line
import { CompileTabLogic } from '@remix-ui/solidity-compiler' // eslint-disable-line
import { CompilerApiMixin } from '@remixproject/solidity-compiler-plugin' // eslint-disable-line
@ -42,9 +41,7 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA
}
renderComponent () {
ReactDOM.render(
<SolidityCompiler api={this}/>
, this.el)
// empty method, is a state update needed?
}
onCurrentFileChanged () {
@ -68,9 +65,7 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA
}
render () {
this.renderComponent()
return this.el
return <div id='compileTabView'><SolidityCompiler api={this}/></div>
}
async compileWithParameters (compilationTargets, settings) {

@ -3,7 +3,6 @@ import { DebuggerApiMixin } from '@remixproject/debugger-plugin' // eslint-disab
import { ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import * as remixBleach from '../../lib/remixBleach'
import { compilationFinishedToastMsg, compilingToastMsg, localCompilationToastMsg, notFoundToastMsg, sourceVerificationNotAvailableToastMsg } from '@remix-ui/helper'
const css = require('./styles/debugger-tab-styles')
@ -51,9 +50,7 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {
this.on('fetchAndCompile', 'sourceVerificationNotAvailable', () => {
this.call('notification', 'toast', sourceVerificationNotAvailableToastMsg())
})
this.renderComponent()
return this.el
return <div className={css.debuggerTabView} id='debugView'><DebuggerUI debuggerAPI={this} /></div>
}
showMessage (title, message) {
@ -68,9 +65,4 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {
}
}
renderComponent () {
ReactDOM.render(
<DebuggerUI debuggerAPI={this} />
, this.el)
}
}

@ -1,9 +1,9 @@
import React from 'react' // eslint-disable-line
import { ViewPlugin } from '@remixproject/engine-web'
import ReactDOM from 'react-dom'
import * as packageJson from '../../../../../package.json'
import { RemixUiSettings } from '@remix-ui/settings' //eslint-disable-line
import Registry from '../state/registry'
import { PluginViewWrapper } from '@remix-ui/helper'
const profile = {
name: 'settings',
@ -20,6 +20,15 @@ const profile = {
}
module.exports = class SettingsTab extends ViewPlugin {
config: any = {}
editor: any
private _deps: {
themeModule: any // eslint-disable-line
}
element: HTMLDivElement
public useMatomoAnalytics: any
dispatch: React.Dispatch<any> = () => {}
constructor (config, editor) {
super(profile)
this.config = config
@ -32,24 +41,31 @@ module.exports = class SettingsTab extends ViewPlugin {
this.useMatomoAnalytics = null
}
onActivation () {
setDispatch (dispatch: React.Dispatch<any>) {
this.dispatch = dispatch
this.renderComponent()
}
render () {
return this.element
render() {
return (
<div id='settingsTab'>
<PluginViewWrapper plugin={this} />
</div>
);
}
updateComponent(state: any){
return <RemixUiSettings
config={state.config}
editor={state.editor}
_deps={state._deps}
useMatomoAnalytics={state.useMatomoAnalytics}
themeModule = {state._deps.themeModule}
/>
}
renderComponent () {
ReactDOM.render(
<RemixUiSettings
config = { this.config }
editor = { this.editor }
_deps = { this._deps }
useMatomoAnalytics = {this.useMatomoAnalytics}
/>,
this.element
)
this.dispatch(this)
}
get (key) {
@ -59,6 +75,8 @@ module.exports = class SettingsTab extends ViewPlugin {
updateMatomoAnalyticsChoice (isChecked) {
this.config.set('settings/matomo-analytics', isChecked)
this.useMatomoAnalytics = isChecked
this.renderComponent()
this.dispatch({
...this
})
}
}
}

@ -1,12 +1,12 @@
/* global */
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { SolidityUnitTesting } from '@remix-ui/solidity-unit-testing' // eslint-disable-line
import { TestTabLogic } from '@remix-ui/solidity-unit-testing' // eslint-disable-line
import { ViewPlugin } from '@remixproject/engine-web'
import helper from '../../lib/helper'
import { canUseWorker, urlFromVersion } from '@remix-project/remix-solidity'
import { PluginViewWrapper } from '@remix-ui/helper'
var { UnitTestRunner, assertLibCode } = require('@remix-project/remix-tests')
@ -34,6 +34,7 @@ module.exports = class TestTab extends ViewPlugin {
this.offsetToLineColumnConverter = offsetToLineColumnConverter
this.allFilesInvolved = ['.deps/remix-tests/remix_tests.sol', '.deps/remix-tests/remix_accounts.sol']
this.element = document.createElement('div')
this.dispatch = null
}
onActivationInternal () {
@ -128,15 +129,25 @@ module.exports = class TestTab extends ViewPlugin {
})
}
setDispatch (dispatch) {
this.dispatch = dispatch
this.renderComponent('tests')
}
render () {
this.onActivationInternal()
this.renderComponent('tests')
return this.element
return <div><PluginViewWrapper plugin={this} /></div>
}
updateComponent(state) {
return <SolidityUnitTesting testTab={state.testTab} helper={state.helper} initialPath={state.testDirPath} />
}
renderComponent (testDirPath) {
ReactDOM.render(
<SolidityUnitTesting testTab={this} helper={helper} initialPath={testDirPath} />
, this.element)
this.dispatch({
testTab: this,
helper: this.helper,
testDirPath: testDirPath
})
}
}

@ -1,5 +1,4 @@
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { RunTabUI } from '@remix-ui/run-tab'
import { ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
@ -40,9 +39,6 @@ export class RunTab extends ViewPlugin {
this.el = document.createElement('div')
}
onActivation () {
this.renderComponent()
}
setupEvents () {
this.blockchain.events.on('newTransaction', (tx, receipt) => {
@ -86,14 +82,9 @@ export class RunTab extends ViewPlugin {
}
render () {
return this.el
return <div><RunTabUI plugin={this} /></div>
}
renderComponent () {
ReactDOM.render(
<RunTabUI plugin={this} />
, this.el)
}
onReady (api) {
this.REACT_API = api

@ -1,6 +1,5 @@
/* global */
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import * as packageJson from '../../../../../../package.json'
import { ViewPlugin } from '@remixproject/engine-web'
import { RemixUiHomeTab } from '@remix-ui/home-tab' // eslint-disable-line
@ -31,15 +30,9 @@ export class LandingPage extends ViewPlugin {
}
render () {
this.renderComponent()
return this.el
return <div id='landingPageHomeContainer' className='remixui_homeContainer justify-content-between bg-light d-flex' data-id='landingPageHomeContainer'><RemixUiHomeTab
plugin={this}
/></div>
}
renderComponent () {
ReactDOM.render(
<RemixUiHomeTab
plugin={this}
/>
, this.el)
}
}

@ -33,9 +33,9 @@ import ('./app').then((AppComponent) => {
const appComponent = new AppComponent.default()
appComponent.run().then(() => {
render(
<React.StrictMode>
<>
<RemixApp app={appComponent} />
</React.StrictMode>,
</>,
document.getElementById('root')
)
})

@ -1,57 +0,0 @@
const allPrograms = [
{ ethers: 'The ethers.js library is a compact and complete JavaScript library for Ethereum.' },
{ remix: 'Ethereum IDE and tools for the web.' },
{ web3: 'The web3.js library is a collection of modules which contain specific functionality for the ethereum ecosystem.' },
{ swarmgw: 'This library can be used to upload/download files to Swarm via https://swarm-gateways.net/.' }
]
const allCommands = [
{ 'remix.execute(filepath)': 'Run the script specified by file path. If filepath is empty, script currently displayed in the editor is executed.' },
{ 'remix.exeCurrent()': 'Run the script currently displayed in the editor.' },
{ 'remix.help()': 'Display this help message.' },
{ 'remix.loadgist(id)': 'Load a gist in the file explorer.' },
{ 'remix.loadurl(url)': 'Load the given url in the file explorer. The url can be of type github, swarm or ipfs.' },
{ 'swarmgw.get(url, cb)': 'Download files from Swarm via https://swarm-gateways.net/' },
{ 'swarmgw.put(content, cb)': 'Upload files to Swarm via https://swarm-gateways.net/' },
{ 'ethers.Contract': 'This API provides a graceful connection to a contract deployed on the blockchain, simplifying calling and querying its functions and handling all the binary protocol and conversion as necessarily.' },
{ 'ethers.HDNode': 'A Hierarchical Deterministic Wallet represents a large tree of private keys which can reliably be reproduced from an initial seed.' },
{ 'ethers.Interface': 'The Interface Object is a meta-class that accepts a Solidity (or compatible) Application Binary Interface (ABI) and populates functions to deal with encoding and decoding the parameters to pass in and results returned.' },
{ 'ethers.providers': 'A Provider abstracts a connection to the Ethereum blockchain, for issuing queries and sending state changing transactions.' },
{ 'ethers.SigningKey': 'The SigningKey interface provides an abstraction around the secp256k1 elliptic curve cryptography library.' },
{ 'ethers.utils': 'The utility functions exposed in both the ethers umbrella package and the ethers-utils.' },
{ 'ethers.utils.AbiCoder': 'Create a new ABI Coder object' },
{ 'ethers.utils.RLP': 'This encoding method is used internally for several aspects of Ethereum, such as encoding transactions and determining contract addresses.' },
{ 'ethers.Wallet': 'A wallet manages a private/public key pair which is used to cryptographically sign transactions and prove ownership on the Ethereum network.' },
{ 'ethers.version': 'Contains the version of the ethers container object.' },
{ 'web3.eth': 'Eth module for interacting with the Ethereum network.' },
{ 'web3.eth.accounts': 'The web3.eth.accounts contains functions to generate Ethereum accounts and sign transactions and data.' },
{ 'web3.eth.abi': 'The web3.eth.abi functions let you de- and encode parameters to ABI (Application Binary Interface) for function calls to the EVM (Ethereum Virtual Machine).' },
{ 'web3.eth.ens': 'The web3.eth.ens functions let you interacting with ENS.' },
{ 'web3.eth.Iban': 'The web3.eth.Iban function lets convert Ethereum addresses from and to IBAN and BBAN.' },
{ 'web3.eth.net': 'Net module for interacting with network properties.' },
{ 'web3.eth.personal': 'Personal module for interacting with the Ethereum accounts.' },
{ 'web3.eth.subscribe': 'The web3.eth.subscribe function lets you subscribe to specific events in the blockchain.' },
{ 'web3.givenProvider': 'When using web3.js in an Ethereum compatible browser, it will set with the current native provider by that browser. Will return the given provider by the (browser) environment, otherwise null.' },
{ 'web3.modules': 'Contains the version of the web3 container object.' },
{ 'web3.providers': 'Contains the current available providers.' },
{ 'web3.shh': 'Shh module for interacting with the whisper protocol' },
{ 'web3.utils': 'This package provides utility functions for Ethereum dapps and other web3.js packages.' },
{ 'web3.version': 'Contains the version of the web3 container object.' },
{ 'web3.eth.clearSubscriptions();': 'Resets subscriptions.' },
{ 'web3.eth.Contract(jsonInterface[, address][, options])': 'The web3.eth.Contract object makes it easy to interact with smart contracts on the ethereum blockchain.' },
{ 'web3.eth.accounts.create([entropy]);': 'The web3.eth.accounts contains functions to generate Ethereum accounts and sign transactions and data.' },
{ 'web3.eth.getAccounts();': 'Retrieve the list of accounts' },
{ 'web3.eth.accounts.privateKeyToAccount(privateKey [, ignoreLength ]);': 'Get the account from the private key' },
{ 'web3.eth.accounts.signTransaction(tx, privateKey [, callback]);': 'Sign Transaction' },
{ 'web3.eth.accounts.recoverTransaction(rawTransaction);': 'Sign Transaction' },
{ 'web3.eth.accounts.hashMessage(message);': 'Hash message' }
]
module.exports = {
allPrograms,
allCommands
}

@ -4,7 +4,7 @@ import { CompilerAbstract } from '@remix-project/remix-solidity'
const profile = {
name: 'compilerArtefacts',
methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult'],
methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName'],
events: [],
version: '0.0.1'
}
@ -72,6 +72,53 @@ export class CompilerArtefacts extends Plugin {
return contractsData
}
async getArtefactsFromFE (path, contractName) {
const dirList = await this.call('fileManager', 'dirList', path)
if(dirList && dirList.length) {
if(dirList.includes(path + '/artifacts')) {
const fileList = await this.call('fileManager', 'fileList', path + '/artifacts')
const artefactsFilePaths = fileList.filter(filePath => {
const filenameArr = filePath.split('/')
const filename = filenameArr[filenameArr.length - 1]
if (filename === `${contractName}.json` || filename === `${contractName}_metadata.json`) return true
})
if (artefactsFilePaths && artefactsFilePaths.length) {
const content = await this.call('fileManager', 'readFile', artefactsFilePaths[1])
const artifacts = JSON.parse(content)
return { abi: artifacts.abi, bytecode: artifacts.data.bytecode.object }
} else {
for (const dirPath of dirList) {
const result = await this.getArtefactsFromFE (dirPath, contractName)
if (result) return result
}
}
} else {
for (const dirPath of dirList) {
const result = await this.getArtefactsFromFE (dirPath, contractName)
if (result) return result
}
}
} else return
}
async getArtefactsByContractName (contractName) {
const contractsDataByFilename = this.getAllContractDatas()
const contractsData = Object.values(contractsDataByFilename)
if (contractsData && contractsData.length) {
const index = contractsData.findIndex((contractsObj) => Object.keys(contractsObj).includes(contractName))
if (index !== -1) return { abi: contractsData[index][contractName].abi, bytecode: contractsData[index][contractName].evm.bytecode.object }
else {
const result = await this.getArtefactsFromFE ('contracts', contractName)
if (result) return result
else throw new Error(`Could not find artifacts for ${contractName}. Compile contract to generate artifacts.`)
}
} else {
const result = await this.getArtefactsFromFE ('contracts', contractName)
if (result) return result
else throw new Error(`Could not find artifacts for ${contractName}. Compile contract to generate artifacts.`)
}
}
getCompilerAbstract (file) {
return this.compilersArtefactsPerFile[file]
}

@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from 'react'
import React, { useContext, useEffect, useRef, useState } from 'react'
import './style/remix-app.css'
import { RemixUIMainPanel } from '@remix-ui/panel'
import MatomoDialog from './components/modals/matomo'
@ -8,6 +8,7 @@ import { AppProvider } from './context/provider'
import AppDialogs from './components/modals/dialogs'
import DialogViewPlugin from './components/modals/dialogViewPlugin'
import { AppContext } from './context/context'
import { RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel'
interface IRemixAppUi {
app: any
@ -17,31 +18,8 @@ const RemixApp = (props: IRemixAppUi) => {
const [appReady, setAppReady] = useState<boolean>(false)
const [hideSidePanel, setHideSidePanel] = useState<boolean>(false)
const sidePanelRef = useRef(null)
const mainPanelRef = useRef(null)
const iconPanelRef = useRef(null)
const hiddenPanelRef = useRef(null)
useEffect(() => {
if (sidePanelRef.current) {
if (props.app.sidePanel) {
sidePanelRef.current.appendChild(props.app.sidePanel.render())
}
}
if (mainPanelRef.current) {
if (props.app.mainview) {
mainPanelRef.current.appendChild(props.app.mainview.render())
}
}
if (iconPanelRef.current) {
if (props.app.menuicons) {
iconPanelRef.current.appendChild(props.app.menuicons.render())
}
}
if (hiddenPanelRef.current) {
if (props.app.hiddenPanel) {
hiddenPanelRef.current.appendChild(props.app.hiddenPanel.render())
}
}
async function activateApp () {
props.app.themeModule.initTheme(() => {
setAppReady(true)
@ -72,13 +50,6 @@ const RemixApp = (props: IRemixAppUi) => {
})
}
const components = {
iconPanel: <div ref={iconPanelRef} id="icon-panel" data-id="remixIdeIconPanel" className="iconpanel bg-light"></div>,
sidePanel: <div ref={sidePanelRef} id="side-panel" data-id="remixIdeSidePanel" className={`sidepanel border-right border-left ${hideSidePanel ? 'd-none' : ''}`}></div>,
mainPanel: <div ref={mainPanelRef} id="main-panel" data-id="remixIdeMainPanel" className='mainpanel'></div>,
hiddenPanel: <div ref={hiddenPanelRef}></div>
}
const value = {
settings: props.app.settings,
showMatamo: props.app.showMatamo,
@ -93,14 +64,14 @@ const RemixApp = (props: IRemixAppUi) => {
<MatomoDialog hide={!appReady}></MatomoDialog>
<div className={`remixIDE ${appReady ? '' : 'd-none'}`} data-id="remixIDE">
{components.iconPanel}
{components.sidePanel}
<div id="icon-panel" data-id="remixIdeIconPanel" className="iconpanel bg-light">{props.app.menuicons.render()}</div>
<div ref={sidePanelRef} id="side-panel" data-id="remixIdeSidePanel" className={`sidepanel border-right border-left ${hideSidePanel ? 'd-none' : ''}`}>{props.app.sidePanel.render()}</div>
<DragBar minWidth={250} refObject={sidePanelRef} hidden={hideSidePanel} setHideStatus={setHideSidePanel}></DragBar>
<div id="main-panel" data-id="remixIdeMainPanel" className='mainpanel'>
<RemixUIMainPanel Context={AppContext}></RemixUIMainPanel>
</div>
</div>
{components.hiddenPanel}
<div>{props.app.hiddenPanel.render()}</div>
<AppDialogs></AppDialogs>
<DialogViewPlugin></DialogViewPlugin>
</AppProvider>

@ -1,2 +1,3 @@
export * from './lib/remix-ui-helper'
export * from './lib/helper-components'
export * from './lib/components/PluginViewWrapper'

@ -0,0 +1,24 @@
import React from "react"
import { useEffect, useState } from "react"
interface IPluginViewWrapperProps {
plugin: any
}
export const PluginViewWrapper = (props: IPluginViewWrapperProps) => {
const [state, setState] = useState<any>(null)
useEffect(() => {
if(props.plugin.setDispatch){
props.plugin.setDispatch(setState)
}
}, [])
return (
<>{state?
<>{props.plugin.updateComponent(state)}</>
:<></>
}</>
)
}

@ -297,7 +297,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
</div>
<div className="row mx-2 mr-4" data-id="landingPageHpSections">
<div className="ml-3">
<div className="mb-5">
<div className="mb-3">
<h4>Featured Plugins</h4>
<div className="d-flex flex-row pt-2">
<ThemeContext.Provider value={ state.themeQuality }>

@ -10,6 +10,7 @@ const RemixUIPanelPlugin = (props: panelPLuginProps, panelRef: any) => {
const localRef = useRef<HTMLDivElement>(null)
const [view, setView] = useState<JSX.Element | HTMLDivElement>()
useEffect(() => {
const ref:any = panelRef || localRef
if (ref.current) {
if (props.pluginRecord.view) {

@ -76,11 +76,6 @@ iframe {
display: block;
}
.pluginsContainer {
height: 100%;
overflow-y: hidden;
}
#editorView {
height: 100%;
width: 100%;

@ -8,7 +8,6 @@ export const allPrograms = [
export const allCommands = [
{ 'remix.execute(filepath)': 'Run the script specified by file path. If filepath is empty, script currently displayed in the editor is executed.' },
{ 'remix.exeCurrent()': 'Run the script currently displayed in the editor.' },
// { 'remix.help()': 'Display this help message.' },
{ 'remix.loadgist(id)': 'Load a gist in the file explorer.' },
// { 'remix.loadurl(url)': 'Load the given url in the file explorer. The url can be of type github, swarm or ipfs.' },

@ -53,6 +53,9 @@ element.style {
.remix_ui_terminal_block > pre {
max-height : 200px;
}
.remix_ui_terminal_welcome {
font-weight: bold;
}
.remix_ui_terminal_cli {
white-space : nowrap;
line-height : 1.7em;

@ -382,7 +382,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const handleAutoComplete = () => (
<div
className='remix_ui_terminal_popup bg-light ml-4 p-2 position-absolute text-left '
style={{ display: (autoCompletState.showSuggestions && autoCompletState.userInput !== '' && (autoCompletState.userInput.length > 2)) && autoCompletState.data._options.length > 0 ? 'block' : 'none' }}
style={{ display: (autoCompletState.showSuggestions && autoCompletState.userInput !== '' && (autoCompletState.userInput.length > 0)) && autoCompletState.data._options.length > 0 ? 'block' : 'none' }}
>
<div>
{autoCompletState.data._options.map((item, index) => {

@ -3,7 +3,7 @@ import React from 'react' // eslint-disable-line
const TerminalWelcomeMessage = ({ packageJson }) => {
return (
<div className="remix_ui_terminal_block px-4 " data-id="block_null">
<div> - Welcome to Remix {packageJson} - </div><br />
<div className="remix_ui_terminal_welcome"> Welcome to Remix {packageJson} </div><br />
<div>You can use this terminal to: </div>
<ul className='ml-0 mr-4'>
<li>Check transactions details and start debugging.</li>
@ -16,12 +16,14 @@ const TerminalWelcomeMessage = ({ packageJson }) => {
<i> - Right click on a JavaScript file in the file explorer and then click \`Run\` </i>
</li>
</ul>
<div>The following libraries are accessible:</div>
<ul className='ml-0 mr-4'>
<li><a target="_blank" href="https://web3js.readthedocs.io/en/1.0/">web3 version 1.5.2</a></li>
<li><a target="_blank" href="https://docs.ethers.io">ethers.js</a> </li>
<li>remix (run remix.help() for more info)</li>
<li>remix</li>
</ul>
<div>Type the library name to see available commands.</div>
</div>
)
}

@ -111,6 +111,7 @@
flex-basis: 510px;
flex-grow: 2;
text-align: center;
margin-top: -6px;
/* border-bottom: 3px solid #3f4455; */
}
.remixui_scrollbar::-webkit-scrollbar { /* Chrome, Safari and other Webkit browsers*/

@ -256,6 +256,17 @@ export const runScript = async (path: string) => {
})
}
export const runScriptWithMocha = async (path: string) => {
const provider = plugin.fileManager.currentFileProvider()
provider.get(path, (error, content: string) => {
if (error) {
return dispatch(displayPopUp(error))
}
if (content) content = content + '\n' + 'mocha.run()'
plugin.call('scriptRunner', 'execute', content)
})
}
export const emitContextMenuEvent = async (cmd: customAction) => {
await plugin.call(cmd.id, cmd.name, cmd)
}

@ -12,7 +12,7 @@ declare global {
const _paq = window._paq = window._paq || [] //eslint-disable-line
export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => {
const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, pushChangesToGist, publishFileToGist, publishFolderToGist, copy, paste, runScript, emit, pageX, pageY, path, type, focus, ...otherProps } = props
const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, pushChangesToGist, publishFileToGist, publishFolderToGist, copy, paste, runScript, runScriptWithMocha, emit, pageX, pageY, path, type, focus, ...otherProps } = props
const contextMenuRef = useRef(null)
useEffect(() => {
contextMenuRef.current.focus()
@ -98,6 +98,10 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) =>
_paq.push(['trackEvent', 'fileExplorer', 'runScript'])
runScript(path)
break
case 'Run with Mocha':
_paq.push(['trackEvent', 'fileExplorer', 'runScriptWithMocha'])
runScriptWithMocha(path)
break
case 'Copy':
copy(path, type)
break

@ -221,6 +221,14 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
}
const runScriptWithMocha = async (path: string) => {
try {
props.dispatchRunScriptWithMocha(path)
} catch (error) {
props.toast('Run script with Mocha failed')
}
}
const emitContextMenuEvent = (cmd: customAction) => {
try {
props.dispatchEmitContextMenuEvent(cmd)
@ -454,6 +462,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
deletePath={deletePath}
renamePath={editModeOn}
runScript={runScript}
runScriptWithMocha={runScriptWithMocha}
copy={handleCopyClick}
paste={handlePasteClick}
emit={emitContextMenuEvent}

@ -25,6 +25,7 @@ export const FileSystemContext = createContext<{
dispatchCopyFile: (src: string, dest: string) => Promise<void>,
dispatchCopyFolder: (src: string, dest: string) => Promise<void>,
dispatchRunScript: (path: string) => Promise<void>,
dispatchRunScriptWithMocha: (path: string) => Promise<void>,
dispatchEmitContextMenuEvent: (cmd: customAction) => Promise<void>,
dispatchHandleClickFile: (path: string, type: 'file' | 'folder' | 'gist') => Promise<void>
dispatchHandleExpandPath: (paths: string[]) => Promise<void>

@ -5,7 +5,7 @@ import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { FileSystemContext } from '../contexts'
import { browserReducer, browserInitialState } from '../reducers/workspace'
import { initWorkspace, fetchDirectory, removeInputField, deleteWorkspace, clearPopUp, publishToGist, createNewFile, setFocusElement, createNewFolder, deletePath, renamePath, copyFile, copyFolder, runScript, emitContextMenuEvent, handleClickFile, handleExpandPath, addInputField, createWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from '../actions'
import { initWorkspace, fetchDirectory, removeInputField, deleteWorkspace, clearPopUp, publishToGist, createNewFile, setFocusElement, createNewFolder, deletePath, renamePath, copyFile, copyFolder, runScript, runScriptWithMocha, emitContextMenuEvent, handleClickFile, handleExpandPath, addInputField, createWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from '../actions'
import { Modal, WorkspaceProps } from '../types'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Workspace } from '../remix-ui-workspace'
@ -103,6 +103,10 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
await runScript(path)
}
const dispatchRunScriptWithMocha = async (path: string) => {
await runScriptWithMocha(path)
}
const dispatchEmitContextMenuEvent = async (cmd: customAction) => {
await emitContextMenuEvent(cmd)
}
@ -212,6 +216,7 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
dispatchCopyFile,
dispatchCopyFolder,
dispatchRunScript,
dispatchRunScriptWithMocha,
dispatchEmitContextMenuEvent,
dispatchHandleClickFile,
dispatchHandleExpandPath

@ -198,6 +198,7 @@ export function Workspace () {
dispatchCopyFolder={global.dispatchCopyFolder}
dispatchPublishToGist={global.dispatchPublishToGist}
dispatchRunScript={global.dispatchRunScript}
dispatchRunScriptWithMocha={global.dispatchRunScriptWithMocha}
dispatchEmitContextMenuEvent={global.dispatchEmitContextMenuEvent}
dispatchHandleClickFile={global.dispatchHandleClickFile}
dispatchSetFocusElement={global.dispatchSetFocusElement}
@ -233,6 +234,7 @@ export function Workspace () {
dispatchCopyFolder={global.dispatchCopyFolder}
dispatchPublishToGist={global.dispatchPublishToGist}
dispatchRunScript={global.dispatchRunScript}
dispatchRunScriptWithMocha={global.dispatchRunScriptWithMocha}
dispatchEmitContextMenuEvent={global.dispatchEmitContextMenuEvent}
dispatchHandleClickFile={global.dispatchHandleClickFile}
dispatchSetFocusElement={global.dispatchSetFocusElement}

@ -78,6 +78,7 @@ export interface FileExplorerProps {
dispatchCopyFile: (src: string, dest: string) => Promise<void>,
dispatchCopyFolder: (src: string, dest: string) => Promise<void>,
dispatchRunScript: (path: string) => Promise<void>,
dispatchRunScriptWithMocha: (path: string) => Promise<void>,
dispatchPublishToGist: (path?: string, type?: string) => Promise<void>,
dispatchEmitContextMenuEvent: (cmd: customAction) => Promise<void>,
dispatchHandleClickFile: (path: string, type: 'file' | 'folder' | 'gist') => Promise<void>,
@ -108,6 +109,7 @@ export interface FileExplorerContextMenuProps {
publishFolderToGist?: (path?: string, type?: string) => void,
publishFileToGist?: (path?: string, type?: string) => void,
runScript?: (path: string) => void,
runScriptWithMocha?: (path: string) => void,
emit?: (cmd: customAction) => void,
pageX: number,
pageY: number,

@ -30,6 +30,12 @@ export const contextMenuActions: MenuItems = [{
extension: ['.js'],
multiselect: false,
label: ''
}, {
id: 'runWithMocha',
name: 'Run with Mocha',
extension: ['.js'],
multiselect: false,
label: ''
}, {
id: 'pushChangesToGist',
name: 'Push changes to gist',

@ -149,13 +149,13 @@
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@monaco-editor/react": "^4.3.1",
"@remixproject/engine": "^0.3.26",
"@remixproject/engine-web": "^0.3.26",
"@remixproject/plugin": "^0.3.26",
"@remixproject/plugin-api": "^0.3.26",
"@remixproject/plugin-utils": "^0.3.26",
"@remixproject/plugin-webview": "^0.3.26",
"@remixproject/plugin-ws": "^0.3.26",
"@remixproject/engine": "^0.3.28",
"@remixproject/engine-web": "^0.3.28",
"@remixproject/plugin": "^0.3.28",
"@remixproject/plugin-api": "^0.3.28",
"@remixproject/plugin-utils": "^0.3.28",
"@remixproject/plugin-webview": "^0.3.28",
"@remixproject/plugin-ws": "^0.3.28",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"axios": ">=0.21.1",

Loading…
Cancel
Save