diff --git a/apps/remix-ide-e2e/nightwatch.ts b/apps/remix-ide-e2e/nightwatch.ts
index 2bc20e8274..d8a111a617 100644
--- a/apps/remix-ide-e2e/nightwatch.ts
+++ b/apps/remix-ide-e2e/nightwatch.ts
@@ -68,7 +68,13 @@ module.exports = {
desiredCapabilities: {
browserName: 'firefox',
javascriptEnabled: true,
- acceptSslCerts: true
+ acceptSslCerts: true,
+ 'moz:firefoxOptions': {
+ args: [
+ '-width=2560',
+ '-height=1440'
+ ]
+ }
}
},
@@ -78,7 +84,11 @@ module.exports = {
javascriptEnabled: true,
acceptSslCerts: true,
'moz:firefoxOptions': {
- args: ['-headless']
+ args: [
+ '-headless',
+ '-width=2560',
+ '-height=1440'
+ ]
}
}
}
diff --git a/apps/remix-ide-e2e/src/commands/modalFooterCancelClick.ts b/apps/remix-ide-e2e/src/commands/modalFooterCancelClick.ts
index e3f90e0c1b..c6505f8450 100644
--- a/apps/remix-ide-e2e/src/commands/modalFooterCancelClick.ts
+++ b/apps/remix-ide-e2e/src/commands/modalFooterCancelClick.ts
@@ -1,14 +1,15 @@
import { NightwatchBrowser } from 'nightwatch'
import EventEmitter from 'events'
-class ModalFooterOKClick extends EventEmitter {
- command (this: NightwatchBrowser): NightwatchBrowser {
- this.api.waitForElementVisible('#modal-footer-cancel').perform((client, done) => {
- this.api.execute(function () {
- const elem = document.querySelector('#modal-footer-cancel') as HTMLElement
+class ModalFooterCancelClick extends EventEmitter {
+ command (this: NightwatchBrowser, id?: string): NightwatchBrowser {
+ const clientId = id ? `*[data-id="${id}-modal-footer-cancel-react"]` : '#modal-footer-cancel'
+ this.api.waitForElementVisible(clientId).perform((client, done) => {
+ this.api.execute(function (clientId) {
+ const elem = document.querySelector(clientId) as HTMLElement
elem.click()
- }, [], () => {
+ }, [clientId], () => {
done()
this.emit('complete')
})
@@ -17,4 +18,4 @@ class ModalFooterOKClick extends EventEmitter {
}
}
-module.exports = ModalFooterOKClick
+module.exports = ModalFooterCancelClick
diff --git a/apps/remix-ide-e2e/src/commands/modalFooterOKClick.ts b/apps/remix-ide-e2e/src/commands/modalFooterOKClick.ts
index bea13a01b2..2e656f287c 100644
--- a/apps/remix-ide-e2e/src/commands/modalFooterOKClick.ts
+++ b/apps/remix-ide-e2e/src/commands/modalFooterOKClick.ts
@@ -2,13 +2,14 @@ import { NightwatchBrowser } from 'nightwatch'
import EventEmitter from 'events'
class ModalFooterOKClick extends EventEmitter {
- command (this: NightwatchBrowser): NightwatchBrowser {
- this.api.waitForElementVisible('#modal-footer-ok').perform((client, done) => {
- this.api.execute(function () {
- const elem = document.querySelector('#modal-footer-ok') as HTMLElement
+ command (this: NightwatchBrowser, id?: string): NightwatchBrowser {
+ const clientId = id ? `*[data-id="${id}-modal-footer-ok-react"]` : '#modal-footer-ok'
+ this.api.waitForElementVisible(clientId).perform((client, done) => {
+ this.api.execute(function (clientId) {
+ const elem = document.querySelector(clientId) as HTMLElement
elem.click()
- }, [], () => {
+ }, [clientId], () => {
done()
this.emit('complete')
})
diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts
index a5926bd028..e934ae2f7b 100644
--- a/apps/remix-ide-e2e/src/helpers/init.ts
+++ b/apps/remix-ide-e2e/src/helpers/init.ts
@@ -9,6 +9,7 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url
.switchBrowserTab(0)
.waitForElementVisible('[id="remixTourSkipbtn"]')
.click('[id="remixTourSkipbtn"]')
+ .maximizeWindow()
.fullscreenWindow(() => {
if (preloadPlugins) {
initModules(browser, () => {
diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts
index 3216ff4b39..8759cd2448 100644
--- a/apps/remix-ide-e2e/src/tests/gist.test.ts
+++ b/apps/remix-ide-e2e/src/tests/gist.test.ts
@@ -76,29 +76,34 @@ module.exports = {
.waitForElementVisible('button[data-id="landingPageImportFromGistButton"]')
.pause(1000)
.scrollAndClick('button[data-id="landingPageImportFromGistButton"]')
- .waitForElementVisible('*[data-id="modalDialogModalTitle"]')
- .assert.containsText('*[data-id="modalDialogModalTitle"]', 'Load a Gist')
- .waitForElementVisible('*[data-id="modalDialogModalBody"]')
- .assert.containsText('*[data-id="modalDialogModalBody"]', 'Enter the ID of the Gist or URL you would like to load.')
- .waitForElementVisible('*[data-id="modalDialogCustomPromptText"]')
- .modalFooterCancelClick()
+ .waitForElementVisible('*[data-id="gisthandlerModalDialogModalTitle-react"]')
+ .assert.containsText('*[data-id="gisthandlerModalDialogModalTitle-react"]', 'Load a Gist')
+ .waitForElementVisible('*[data-id="gisthandlerModalDialogModalBody-react"]')
+ .assert.containsText('*[data-id="gisthandlerModalDialogModalBody-react"]', 'Enter the ID of the Gist or URL you would like to load.')
+ .waitForElementVisible('*[data-id="modalDialogCustomPromp"]')
+ .modalFooterCancelClick('gisthandler')
},
'Display Error Message For Invalid Gist ID': function (browser: NightwatchBrowser) {
browser
+ .pause(1000)
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('filePanel')
.scrollAndClick('*[data-id="landingPageImportFromGistButton"]')
- .waitForElementVisible('*[data-id="modalDialogCustomPromptText"]')
- .setValue('*[data-id="modalDialogCustomPromptText"]', testData.invalidGistId)
- .modalFooterOKClick()
- .waitForElementVisible('*[data-id="modalDialogModalBody"]')
- .assert.containsText('*[data-id="modalDialogModalBody"]', 'Not Found')
- .modalFooterOKClick()
+ .waitForElementVisible('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]')
+ .execute(() => {
+ (document.querySelector('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]') as any).focus()
+ }, [], () => {})
+ .setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.invalidGistId)
+ .modalFooterOKClick('gisthandler')
+ .waitForElementVisible('*[data-id="gisthandlerModalDialogModalBody-react"]')
+ .assert.containsText('*[data-id="gisthandlerModalDialogModalBody-react"]', 'Not Found')
+ .modalFooterOKClick('gisthandler')
},
'Display Error Message For Missing Gist Token When Publishing': function (browser: NightwatchBrowser) {
browser
+ .pause(1000)
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('settings')
.waitForElementVisible('[data-id="settingsTabRemoveGistToken"]')
@@ -129,9 +134,12 @@ module.exports = {
.click('[data-id="settingsTabSaveGistToken"]')
.clickLaunchIcon('filePanel')
.scrollAndClick('*[data-id="landingPageImportFromGistButton"]')
- .waitForElementVisible('*[data-id="modalDialogCustomPromptText"]')
- .setValue('*[data-id="modalDialogCustomPromptText"]', testData.validGistId)
- .modalFooterOKClick()
+ .waitForElementVisible('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]')
+ .execute(() => {
+ (document.querySelector('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]') as any).focus()
+ }, [], () => {})
+ .setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.validGistId)
+ .modalFooterOKClick('gisthandler')
.openFile(`gist-${testData.validGistId}/README.txt`)
.waitForElementVisible(`div[title='default_workspace/gist-${testData.validGistId}/README.txt']`)
.assert.containsText(`div[title='default_workspace/gist-${testData.validGistId}/README.txt'] > span`, 'README.txt')
diff --git a/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts b/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts
index 036d9ceae9..bbf57ca3db 100644
--- a/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts
+++ b/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts
@@ -31,8 +31,6 @@ module.exports = {
'Display Error Message For Invalid GitHub URL Modal': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
- .clickLaunchIcon('settings')
- .clickLaunchIcon('filePanel')
.scrollAndClick('*[data-id="landingPageImportFromGitHubButton"]')
.waitForElementVisible('input[data-id="homeTabModalDialogCustomPromptText"]')
.execute(() => {
@@ -48,8 +46,6 @@ module.exports = {
'Import From Github For Valid URL': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
- .clickLaunchIcon('settings')
- .clickLaunchIcon('filePanel')
.scrollAndClick('*[data-id="landingPageImportFromGitHubButton"]')
.waitForElementVisible('*[data-id="homeTabModalDialogCustomPromptText"]')
.clearValue('*[data-id="homeTabModalDialogCustomPromptText"]')
diff --git a/apps/remix-ide-e2e/src/tests/remixd.test.ts b/apps/remix-ide-e2e/src/tests/remixd.test.ts
index 38f66665c0..0781733b99 100644
--- a/apps/remix-ide-e2e/src/tests/remixd.test.ts
+++ b/apps/remix-ide-e2e/src/tests/remixd.test.ts
@@ -125,9 +125,9 @@ function startRemixd (browser: NightwatchBrowser) {
.clickLaunchIcon('filePanel')
.clickLaunchIcon('pluginManager')
.scrollAndClick('#pluginManager *[data-id="pluginManagerComponentActivateButtonremixd"]')
- .waitForElementVisible('#modal-footer-ok', 2000)
+ .waitForElementVisible('*[data-id="remixdConnect-modal-footer-ok-react"]', 2000)
.pause(2000)
- .click('#modal-footer-ok')
+ .click('*[data-id="remixdConnect-modal-footer-ok-react"]')
// .click('*[data-id="workspacesModalDialog-modal-footer-ok-react"]')
}
diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts
index 373139fbf4..1ddb10aa10 100644
--- a/apps/remix-ide-e2e/src/types/index.d.ts
+++ b/apps/remix-ide-e2e/src/types/index.d.ts
@@ -18,7 +18,7 @@ declare module 'nightwatch' {
goToVMTraceStep(step: number, incr?: number): NightwatchBrowser,
checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser,
addAtAddressInstance(address: string, isValidFormat: boolean, isValidChecksum: boolean): NightwatchBrowser,
- modalFooterOKClick(): NightwatchBrowser,
+ modalFooterOKClick(id?: string): NightwatchBrowser,
clickInstance(index: number): NightwatchBrowser,
journalLastChildIncludes(val: string): NightwatchBrowser,
executeScript(script: string): NightwatchBrowser,
@@ -32,7 +32,7 @@ declare module 'nightwatch' {
scrollToLine(line: number): NightwatchBrowser,
waitForElementContainsText(id: string, value: string, timeout?: number): NightwatchBrowser,
getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser,
- modalFooterCancelClick(): NightwatchBrowser,
+ modalFooterCancelClick(id?: string): NightwatchBrowser,
selectContract(contractName: string): NightwatchBrowser,
createContract(inputParams: string): NightwatchBrowser,
getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser,
diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js
index 0698c90ee5..338af4bbec 100644
--- a/apps/remix-ide/src/app.js
+++ b/apps/remix-ide/src/app.js
@@ -2,7 +2,6 @@
import { RunTab, makeUdapp } from './app/udapp'
import { RemixEngine } from './remixEngine'
import { RemixAppManager } from './remixAppManager'
-import { MainView } from './app/panels/main-view'
import { ThemeModule } from './app/tabs/theme-module'
import { NetworkModule } from './app/tabs/network-module'
import { Web3ProviderModule } from './app/tabs/web3-provider'
@@ -11,15 +10,16 @@ import { HiddenPanel } from './app/components/hidden-panel'
import { VerticalIcons } from './app/components/vertical-icons'
import { LandingPage } from './app/ui/landing-page/landing-page'
import { MainPanel } from './app/components/main-panel'
-import { FramingService } from './framingService'
import { WalkthroughService } from './walkthroughService'
-import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, EditorContextListener } from '@remix-project/core-plugin'
+import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, EditorContextListener, GistHandler } from '@remix-project/core-plugin'
import migrateFileSystem from './migrateFileSystem'
import Registry from './app/state/registry'
import { ConfigPlugin } from './app/plugins/config'
+import { Layout } from './app/panels/layout'
+import { ModalPlugin } from './app/plugins/modal'
const isElectron = require('is-electron')
@@ -49,6 +49,7 @@ const TestTab = require('./app/tabs/test-tab')
const FilePanel = require('./app/panels/file-panel')
const Editor = require('./app/editor/editor')
const Terminal = require('./app/panels/terminal')
+const { TabProxy } = require('./app/panels/tab-proxy.js')
class AppComponent {
constructor () {
@@ -66,13 +67,27 @@ class AppComponent {
// load file system
self._components.filesProviders = {}
self._components.filesProviders.browser = new FileProvider('browser')
- Registry.getInstance().put({ api: self._components.filesProviders.browser, name: 'fileproviders/browser' })
- self._components.filesProviders.localhost = new RemixDProvider(self.appManager)
- Registry.getInstance().put({ api: self._components.filesProviders.localhost, name: 'fileproviders/localhost' })
+ Registry.getInstance().put({
+ api: self._components.filesProviders.browser,
+ name: 'fileproviders/browser'
+ })
+ self._components.filesProviders.localhost = new RemixDProvider(
+ self.appManager
+ )
+ Registry.getInstance().put({
+ api: self._components.filesProviders.localhost,
+ name: 'fileproviders/localhost'
+ })
self._components.filesProviders.workspace = new WorkspaceFileProvider()
- Registry.getInstance().put({ api: self._components.filesProviders.workspace, name: 'fileproviders/workspace' })
+ Registry.getInstance().put({
+ api: self._components.filesProviders.workspace,
+ name: 'fileproviders/workspace'
+ })
- Registry.getInstance().put({ api: self._components.filesProviders, name: 'fileproviders' })
+ Registry.getInstance().put({
+ api: self._components.filesProviders,
+ name: 'fileproviders'
+ })
migrateFileSystem(self._components.filesProviders.browser)
}
@@ -82,6 +97,7 @@ class AppComponent {
// APP_MANAGER
const appManager = self.appManager
const pluginLoader = self.appManager.pluginLoader
+ self.panels = {}
self.workspace = pluginLoader.get()
self.engine = new RemixEngine()
self.engine.register(appManager)
@@ -91,8 +107,15 @@ class AppComponent {
'remix-beta.ethereum.org': 25,
'remix.ethereum.org': 23
}
- self.showMatamo = (matomoDomains[window.location.hostname] && !Registry.getInstance().get('config').api.exists('settings/matomo-analytics'))
- self.walkthroughService = new WalkthroughService(appManager, self.showMatamo)
+ self.showMatamo =
+ matomoDomains[window.location.hostname] &&
+ !Registry.getInstance()
+ .get('config')
+ .api.exists('settings/matomo-analytics')
+ self.walkthroughService = new WalkthroughService(
+ appManager,
+ self.showMatamo
+ )
const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080']
// workaround for Electron support
@@ -104,6 +127,8 @@ class AppComponent {
}
// SERVICES
+ // ----------------- gist service ---------------------------------
+ self.gistHandler = new GistHandler()
// ----------------- theme service ---------------------------------
self.themeModule = new ThemeModule()
Registry.getInstance().put({ api: self.themeModule, name: 'themeModule' })
@@ -111,7 +136,9 @@ class AppComponent {
// ----------------- editor service ----------------------------
const editor = new Editor() // wrapper around ace editor
Registry.getInstance().put({ api: editor, name: 'editor' })
- editor.event.register('requiringToSaveCurrentfile', () => fileManager.saveCurrentFile())
+ editor.event.register('requiringToSaveCurrentfile', () =>
+ fileManager.saveCurrentFile()
+ )
// ----------------- fileManager service ----------------------------
const fileManager = new FileManager(editor, appManager)
@@ -128,7 +155,10 @@ class AppComponent {
const compilerMetadataGenerator = new CompilerMetadata()
// ----------------- compilation result service (can keep track of compilation results) ----------------------------
const compilersArtefacts = new CompilerArtefacts() // store all the compilation results (key represent a compiler name)
- Registry.getInstance().put({ api: compilersArtefacts, name: 'compilersartefacts' })
+ Registry.getInstance().put({
+ api: compilersArtefacts,
+ name: 'compilersartefacts'
+ })
// service which fetch contract artifacts from sourve-verify, put artifacts in remix and compile it
const fetchAndCompile = new FetchAndCompile()
@@ -139,28 +169,37 @@ class AppComponent {
const hardhatProvider = new HardhatProvider(blockchain)
// ----------------- convert offset to line/column service -----------
const offsetToLineColumnConverter = new OffsetToLineColumnConverter()
- Registry.getInstance().put({ api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter' })
+ Registry.getInstance().put({
+ api: offsetToLineColumnConverter,
+ name: 'offsettolinecolumnconverter'
+ })
// -------------------Terminal----------------------------------------
- makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl))
+ makeUdapp(blockchain, compilersArtefacts, domEl => terminal.logHtml(domEl))
const terminal = new Terminal(
{ appManager, blockchain },
{
- getPosition: (event) => {
+ getPosition: event => {
const limitUp = 36
const limitDown = 20
const height = window.innerHeight
- let newpos = (event.pageY < limitUp) ? limitUp : event.pageY
- newpos = (newpos < height - limitDown) ? newpos : height - limitDown
+ let newpos = event.pageY < limitUp ? limitUp : event.pageY
+ newpos = newpos < height - limitDown ? newpos : height - limitDown
return height - newpos
}
}
)
const contextualListener = new EditorContextListener()
+ self.modal = new ModalPlugin()
+
const configPlugin = new ConfigPlugin()
+ self.layout = new Layout()
self.engine.register([
+ self.layout,
+ self.modal,
+ self.gistHandler,
configPlugin,
blockchain,
contentImport,
@@ -182,22 +221,27 @@ class AppComponent {
// LAYOUT & SYSTEM VIEWS
const appPanel = new MainPanel()
- self.mainview = new MainView(contextualListener, editor, appPanel, fileManager, appManager, terminal)
Registry.getInstance().put({ api: self.mainview, name: 'mainview' })
-
- self.engine.register([
- appPanel,
- self.mainview.tabProxy
- ])
+ const tabProxy = new TabProxy(fileManager, editor)
+ self.engine.register([appPanel, tabProxy])
// those views depend on app_manager
self.menuicons = new VerticalIcons(appManager)
self.sidePanel = new SidePanel(appManager, self.menuicons)
self.hiddenPanel = new HiddenPanel()
- const pluginManagerComponent = new PluginManagerComponent(appManager, self.engine)
+ const pluginManagerComponent = new PluginManagerComponent(
+ appManager,
+ self.engine
+ )
const filePanel = new FilePanel(appManager)
- const landingPage = new LandingPage(appManager, self.menuicons, fileManager, filePanel, contentImport)
+ const landingPage = new LandingPage(
+ appManager,
+ self.menuicons,
+ fileManager,
+ filePanel,
+ contentImport
+ )
self.settings = new SettingsTab(
Registry.getInstance().get('config').api,
editor,
@@ -215,7 +259,10 @@ class AppComponent {
])
// CONTENT VIEWS & DEFAULT PLUGINS
- const compileTab = new CompileTab(Registry.getInstance().get('config').api, Registry.getInstance().get('filemanager').api)
+ const compileTab = new CompileTab(
+ Registry.getInstance().get('config').api,
+ Registry.getInstance().get('filemanager').api
+ )
const run = new RunTab(
blockchain,
Registry.getInstance().get('config').api,
@@ -224,7 +271,6 @@ class AppComponent {
filePanel,
Registry.getInstance().get('compilersartefacts').api,
networkModule,
- self.mainview,
Registry.getInstance().get('fileproviders/browser').api
)
const analysis = new AnalysisTab()
@@ -249,6 +295,13 @@ class AppComponent {
filePanel.hardhatHandle,
filePanel.slitherHandle
])
+
+ self.layout.panels = {
+ tabs: { plugin: tabProxy, active: true },
+ editor: { plugin: editor, active: true },
+ main: { plugin: appPanel, active: false },
+ terminal: { plugin: terminal, active: true, minimized: false }
+ }
}
async activate () {
@@ -263,61 +316,70 @@ class AppComponent {
try {
self.engine.register(await self.appManager.registeredPlugins())
} catch (e) {
- console.log('couldn\'t register iframe plugins', e.message)
+ console.log("couldn't register iframe plugins", e.message)
}
-
+ await self.appManager.activatePlugin(['layout'])
+ await self.appManager.activatePlugin(['modal'])
await self.appManager.activatePlugin(['editor'])
await self.appManager.activatePlugin(['theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter'])
await self.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])
await self.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await self.appManager.activatePlugin(['home'])
await self.appManager.activatePlugin(['settings', 'config'])
- await self.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport'])
+ await self.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler'])
await self.appManager.activatePlugin(['settings'])
await self.appManager.activatePlugin(['walkthrough'])
- self.appManager.on('filePanel', 'workspaceInitializationCompleted', async () => {
- await self.appManager.registerContextMenuItems()
- })
+ self.appManager.on(
+ 'filePanel',
+ 'workspaceInitializationCompleted',
+ async () => {
+ await self.appManager.registerContextMenuItems()
+ }
+ )
await self.appManager.activatePlugin(['filePanel'])
// Set workspace after initial activation
self.appManager.on('editor', 'editorMounted', () => {
if (Array.isArray(self.workspace)) {
- self.appManager.activatePlugin(self.workspace).then(async () => {
- try {
- if (params.deactivate) {
- await self.appManager.deactivatePlugin(params.deactivate.split(','))
+ self.appManager
+ .activatePlugin(self.workspace)
+ .then(async () => {
+ try {
+ if (params.deactivate) {
+ await self.appManager.deactivatePlugin(
+ params.deactivate.split(',')
+ )
+ }
+ } catch (e) {
+ console.log(e)
+ }
+ if (params.code) {
+ // if code is given in url we focus on solidity plugin
+ self.menuicons.select('solidity')
+ } else {
+ // If plugins are loaded from the URL params, we focus on the last one.
+ if (
+ self.appManager.pluginLoader.current === 'queryParams' &&
+ self.workspace.length > 0
+ ) { self.menuicons.select(self.workspace[self.workspace.length - 1]) }
}
- } catch (e) {
- console.log(e)
- }
- if (params.code) {
- // if code is given in url we focus on solidity plugin
- self.menuicons.select('solidity')
- } else {
- // If plugins are loaded from the URL params, we focus on the last one.
- if (self.appManager.pluginLoader.current === 'queryParams' && self.workspace.length > 0) self.menuicons.select(self.workspace[self.workspace.length - 1])
- }
-
- if (params.call) {
- const callDetails = params.call.split('//')
- if (callDetails.length > 1) {
- toolTip(`initiating ${callDetails[0]} ...`)
- // @todo(remove the timeout when activatePlugin is on 0.3.0)
- self.appManager.call(...callDetails).catch(console.error)
+
+ if (params.call) {
+ const callDetails = params.call.split('//')
+ if (callDetails.length > 1) {
+ toolTip(`initiating ${callDetails[0]} ...`)
+ // @todo(remove the timeout when activatePlugin is on 0.3.0)
+ self.appManager.call(...callDetails).catch(console.error)
+ }
}
- }
- }).catch(console.error)
+ })
+ .catch(console.error)
}
})
// activate solidity plugin
self.appManager.activatePlugin(['solidity', 'udapp'])
// Load and start the service who manager layout and frame
- const framingService = new FramingService(self.sidePanel, self.menuicons, self.mainview, null)
-
- if (params.embed) framingService.embed()
- framingService.start(params)
}
}
diff --git a/apps/remix-ide/src/app/components/hidden-panel.js b/apps/remix-ide/src/app/components/hidden-panel.js
deleted file mode 100644
index 77f67c6f4c..0000000000
--- a/apps/remix-ide/src/app/components/hidden-panel.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { AbstractPanel } from './panel'
-import * as packageJson from '../../../../../package.json'
-const csjs = require('csjs-inject')
-const yo = require('yo-yo')
-
-const css = csjs`
- .pluginsContainer {
- display: none;
- }
-`
-
-const profile = {
- name: 'hiddenPanel',
- displayName: 'Hidden Panel',
- description: '',
- version: packageJson.version,
- methods: ['addView', 'removeView']
-}
-
-export class HiddenPanel extends AbstractPanel {
- constructor () {
- super(profile)
- }
-
- render () {
- return yo`
-
- ${this.view}
-
`
- }
-}
diff --git a/apps/remix-ide/src/app/components/hidden-panel.tsx b/apps/remix-ide/src/app/components/hidden-panel.tsx
new file mode 100644
index 0000000000..bfdff5a11a
--- /dev/null
+++ b/apps/remix-ide/src/app/components/hidden-panel.tsx
@@ -0,0 +1,37 @@
+// 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'
+
+const profile = {
+ name: 'hiddenPanel',
+ displayName: 'Hidden Panel',
+ description: '',
+ version: packageJson.version,
+ methods: ['addView', 'removeView']
+}
+
+export class HiddenPanel extends AbstractPanel {
+ el: HTMLElement
+ constructor () {
+ super(profile)
+ this.el = document.createElement('div')
+ this.el.setAttribute('class', 'pluginsContainer')
+ }
+
+ addView (profile: any, view: any): void {
+ super.removeView(profile)
+ super.addView(profile, view)
+ this.renderComponent()
+ }
+
+ render () {
+ return this.el
+ }
+
+ renderComponent () {
+ ReactDOM.render(>} plugins={this.plugins}/>, this.el)
+ }
+}
diff --git a/apps/remix-ide/src/app/components/main-panel.js b/apps/remix-ide/src/app/components/main-panel.js
deleted file mode 100644
index 66e6a50245..0000000000
--- a/apps/remix-ide/src/app/components/main-panel.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { AbstractPanel } from './panel'
-import * as packageJson from '../../../../../package.json'
-const yo = require('yo-yo')
-const csjs = require('csjs-inject')
-
-const css = csjs`
- .pluginsContainer {
- height: 100%;
- display: flex;
- overflow-y: hidden;
- }
-`
-
-const profile = {
- name: 'mainPanel',
- displayName: 'Main Panel',
- description: '',
- version: packageJson.version,
- methods: ['addView', 'removeView']
-}
-
-export class MainPanel extends AbstractPanel {
- constructor () {
- super(profile)
- }
-
- focus (name) {
- this.emit('focusChanged', name)
- super.focus(name)
- }
-
- render () {
- return yo`
-
- ${this.view}
-
`
- }
-}
diff --git a/apps/remix-ide/src/app/components/main-panel.tsx b/apps/remix-ide/src/app/components/main-panel.tsx
new file mode 100644
index 0000000000..b9d180f194
--- /dev/null
+++ b/apps/remix-ide/src/app/components/main-panel.tsx
@@ -0,0 +1,57 @@
+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'
+
+const profile = {
+ name: 'mainPanel',
+ displayName: 'Main Panel',
+ description: '',
+ version: packageJson.version,
+ methods: ['addView', 'removeView', 'showContent']
+}
+
+export class MainPanel extends AbstractPanel {
+ element: HTMLDivElement
+ constructor (config) {
+ super(profile)
+ this.element = document.createElement('div')
+ this.element.setAttribute('data-id', 'mainPanelPluginsContainer')
+ this.element.setAttribute('style', 'height: 100%; width: 100%;')
+ // this.config = config
+ }
+
+ onActivation () {
+ this.renderComponent()
+ }
+
+ focus (name) {
+ this.emit('focusChanged', name)
+ super.focus(name)
+ this.renderComponent()
+ }
+
+ addView (profile, view) {
+ super.addView(profile, view)
+ this.renderComponent()
+ }
+
+ removeView (profile) {
+ super.removeView(profile)
+ this.renderComponent()
+ }
+
+ async showContent (name) {
+ super.showContent(name)
+ this.renderComponent()
+ }
+
+ render () {
+ return this.element
+ }
+
+ renderComponent () {
+ ReactDOM.render(>} plugins={this.plugins}/>, this.element)
+ }
+}
diff --git a/apps/remix-ide/src/app/components/panel.js b/apps/remix-ide/src/app/components/panel.js
deleted file mode 100644
index 08d9abf20f..0000000000
--- a/apps/remix-ide/src/app/components/panel.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import { EventEmitter } from 'events'
-import { HostPlugin } from '@remixproject/engine-web'
-const csjs = require('csjs-inject')
-const yo = require('yo-yo')
-
-const css = csjs`
- .plugins {
- height: 100%;
- }
- .plugItIn {
- display : none;
- height : 100%;
- }
- .plugItIn > div {
- overflow-y : auto;
- overflow-x : hidden;
- height : 100%;
- width : 100%;
- }
- .plugItIn.active {
- display : block;
- }
- .pluginsContainer {
- height : 100%;
- overflow-y : hidden;
- }
-`
-
-/** Abstract class used for hosting the view of a plugin */
-export class AbstractPanel extends HostPlugin {
- constructor (profile) {
- super(profile)
- this.events = new EventEmitter()
- this.contents = {}
- this.active = undefined
-
- // View where the plugin HTMLElement leaves
- this.view = yo`
`
- }
-
- /**
- * Add the plugin to the panel
- * @param {String} name the name of the plugin
- * @param {HTMLElement} content the HTMLContent of the plugin
- */
- add (view, name) {
- if (this.contents[name]) throw new Error(`Plugin ${name} already rendered`)
- view.style.height = '100%'
- view.style.width = '100%'
- view.style.border = '0'
-
- const isIframe = view.tagName === 'IFRAME'
- view.style.display = isIframe ? 'none' : 'block'
- const loading = isIframe ? yo`
-
- ` : ''
- this.contents[name] = yo`${view}${loading}
`
-
- if (view.tagName === 'IFRAME') {
- view.addEventListener('load', () => {
- if (this.contents[name].contains(loading)) {
- this.contents[name].removeChild(loading)
- }
- view.style.display = 'block'
- })
- }
- this.contents[name].style.display = 'none'
- this.view.appendChild(this.contents[name])
- }
-
- addView (profile, view) {
- this.add(view, profile.name)
- }
-
- removeView (profile) {
- this.remove(profile.name)
- }
-
- /**
- * Remove a plugin from the panel
- * @param {String} name The name of the plugin to remove
- */
- remove (name) {
- const el = this.contents[name]
- delete this.contents[name]
- if (el) el.parentElement.removeChild(el)
- if (name === this.active) this.active = undefined
- }
-
- /**
- * Display the content of this specific plugin
- * @param {String} name The name of the plugin to display the content
- */
- showContent (name) {
- if (!this.contents[name]) throw new Error(`Plugin ${name} is not yet activated`)
- // hiding the current view and display the `moduleName`
- if (this.active) {
- this.contents[this.active].style.display = 'none'
- }
- this.contents[name].style.display = 'flex'
- this.active = name
- }
-
- focus (name) {
- this.showContent(name)
- }
-}
diff --git a/apps/remix-ide/src/app/components/panel.ts b/apps/remix-ide/src/app/components/panel.ts
new file mode 100644
index 0000000000..a5747188af
--- /dev/null
+++ b/apps/remix-ide/src/app/components/panel.ts
@@ -0,0 +1,63 @@
+import React from 'react' // eslint-disable-line
+import { EventEmitter } from 'events'
+import { HostPlugin } from '@remixproject/engine-web' // eslint-disable-line
+import { PluginRecord } from 'libs/remix-ui/panel/src/lib/types'
+const EventManager = require('../../lib/events')
+
+export class AbstractPanel extends HostPlugin {
+ events: EventEmitter
+ event: any
+ public plugins: Record = {}
+ constructor (profile) {
+ super(profile)
+ this.events = new EventEmitter()
+ this.event = new EventManager()
+ }
+
+ currentFocus (): string {
+ return Object.values(this.plugins).find(plugin => {
+ return plugin.active
+ }).profile.name
+ }
+
+ addView (profile, view) {
+ if (this.plugins[profile.name]) throw new Error(`Plugin ${profile.name} already rendered`)
+ this.plugins[profile.name] = {
+ profile: profile,
+ view: view,
+ active: false,
+ class: 'plugItIn active'
+ }
+ }
+
+ removeView (profile) {
+ this.emit('pluginDisabled', profile.name)
+ this.call('menuicons', 'unlinkContent', profile)
+ this.remove(profile.name)
+ }
+
+ /**
+ * Remove a plugin from the panel
+ * @param {String} name The name of the plugin to remove
+ */
+ remove (name) {
+ delete this.plugins[name]
+ }
+
+ /**
+ * Display the content of this specific plugin
+ * @param {String} name The name of the plugin to display the content
+ */
+ showContent (name) {
+ if (!this.plugins[name]) throw new Error(`Plugin ${name} is not yet activated`)
+
+ Object.values(this.plugins).forEach(plugin => {
+ plugin.active = false
+ })
+ this.plugins[name].active = true
+ }
+
+ focus (name) {
+ this.showContent(name)
+ }
+}
diff --git a/apps/remix-ide/src/app/components/side-panel.js b/apps/remix-ide/src/app/components/side-panel.js
deleted file mode 100644
index 0cc09d84d4..0000000000
--- a/apps/remix-ide/src/app/components/side-panel.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import { AbstractPanel } from './panel'
-import * as packageJson from '../../../../../package.json'
-const csjs = require('csjs-inject')
-const yo = require('yo-yo')
-
-const css = csjs`
- .panel {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- flex: auto;
- }
- .swapitTitle {
- margin: 0;
- text-transform: uppercase;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- .swapitTitle i{
- padding-left: 6px;
- font-size: 14px;
- }
- .swapitHeader {
- display: flex;
- align-items: center;
- padding: 16px 24px 15px;
- justify-content: space-between;
- }
- .icons i {
- height: 80%;
- cursor: pointer;
- }
- .pluginsContainer {
- height: 100%;
- overflow-y: auto;
- }
- .titleInfo {
- padding-left: 10px;
- }
- .versionBadge {
- background-color: var(--light);
- padding: 0 7px;
- font-weight: bolder;
- margin-left: 5px;
- text-transform: lowercase;
- cursor: default;
- }
-`
-
-const sidePanel = {
- name: 'sidePanel',
- displayName: 'Side Panel',
- description: '',
- version: packageJson.version,
- methods: ['addView', 'removeView']
-}
-
-// TODO merge with vertical-icons.js
-export class SidePanel extends AbstractPanel {
- constructor (appManager, verticalIcons) {
- super(sidePanel)
- this.appManager = appManager
- this.header = yo``
- this.renderHeader()
- this.verticalIcons = verticalIcons
-
- // Toggle content
- verticalIcons.events.on('toggleContent', (name) => {
- if (!this.contents[name]) return
- if (this.active === name) {
- // TODO: Only keep `this.emit` (issue#2210)
- this.emit('toggle', name)
- this.events.emit('toggle', name)
- return
- }
- this.showContent(name)
- // TODO: Only keep `this.emit` (issue#2210)
- this.emit('showing', name)
- this.events.emit('showing', name)
- })
- // Force opening
- verticalIcons.events.on('showContent', (name) => {
- if (!this.contents[name]) return
- this.showContent(name)
- // TODO: Only keep `this.emit` (issue#2210)
- this.emit('showing', name)
- this.events.emit('showing', name)
- })
- }
-
- focus (name) {
- this.emit('focusChanged', name)
- super.focus(name)
- }
-
- removeView (profile) {
- super.removeView(profile)
- this.emit('pluginDisabled', profile.name)
- this.verticalIcons.unlinkContent(profile)
- }
-
- addView (profile, view) {
- super.addView(profile, view)
- this.verticalIcons.linkContent(profile)
- }
-
- /**
- * Display content and update the header
- * @param {String} name The name of the plugin to display
- */
- async showContent (name) {
- super.showContent(name)
- this.renderHeader()
- this.emit('focusChanged', name)
- }
-
- /** The header of the side panel */
- async renderHeader () {
- let name = ' - '
- let docLink = ''
- let versionWarning
- if (this.active) {
- const profile = await this.appManager.getProfile(this.active)
- name = profile.displayName ? profile.displayName : profile.name
- docLink = profile.documentation ? yo` ` : ''
- if (profile.version && profile.version.match(/\b(\w*alpha\w*)\b/g)) {
- versionWarning = yo`alpha `
- }
- // Beta
- if (profile.version && profile.version.match(/\b(\w*beta\w*)\b/g)) {
- versionWarning = yo`beta `
- }
- }
-
- const header = yo`
-
- `
- yo.update(this.header, header)
- }
-
- render () {
- return yo`
-
- ${this.header}
-
- ${this.view}
-
- `
- }
-}
diff --git a/apps/remix-ide/src/app/components/side-panel.tsx b/apps/remix-ide/src/app/components/side-panel.tsx
new file mode 100644
index 0000000000..8b64d64e45
--- /dev/null
+++ b/apps/remix-ide/src/app/components/side-panel.tsx
@@ -0,0 +1,95 @@
+// 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 { RemixAppManager } from '../../remixAppManager'
+import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel'
+import RemixUIPanelHeader from 'libs/remix-ui/panel/src/lib/plugins/panel-header'
+// const csjs = require('csjs-inject')
+
+const sidePanel = {
+ name: 'sidePanel',
+ displayName: 'Side Panel',
+ description: '',
+ version: packageJson.version,
+ methods: ['addView', 'removeView']
+}
+
+// TODO merge with vertical-icons.js
+export class SidePanel extends AbstractPanel {
+ appManager: RemixAppManager
+ sideelement: any
+ verticalIcons: VerticalIcons;
+ constructor (appManager: RemixAppManager, verticalIcons: VerticalIcons) {
+ super(sidePanel)
+ this.appManager = appManager
+ this.sideelement = document.createElement('section')
+ this.sideelement.setAttribute('class', 'panel plugin-manager')
+ this.verticalIcons = verticalIcons
+
+ // Toggle content
+ verticalIcons.events.on('toggleContent', (name) => {
+ if (!this.plugins[name]) return
+ if (this.plugins[name].active) {
+ // TODO: Only keep `this.emit` (issue#2210)
+ this.emit('toggle', name)
+ this.events.emit('toggle', name)
+ return
+ }
+ this.showContent(name)
+ // TODO: Only keep `this.emit` (issue#2210)
+ this.emit('showing', name)
+ this.events.emit('showing', name)
+ })
+ // Force opening
+ verticalIcons.events.on('showContent', (name) => {
+ if (!this.plugins[name]) return
+ this.showContent(name)
+ // TODO: Only keep `this.emit` (issue#2210)
+ this.emit('showing', name)
+ this.events.emit('showing', name)
+ })
+ }
+
+ onActivation () {
+ this.renderComponent()
+ }
+
+ focus (name) {
+ this.emit('focusChanged', name)
+ super.focus(name)
+ }
+
+ removeView (profile) {
+ super.removeView(profile)
+ this.emit('pluginDisabled', profile.name)
+ this.call('menuicons', 'unlinkContent', profile)
+ this.renderComponent()
+ }
+
+ addView (profile, view) {
+ super.addView(profile, view)
+ this.verticalIcons.linkContent(profile)
+ this.renderComponent()
+ }
+
+ /**
+ * Display content and update the header
+ * @param {String} name The name of the plugin to display
+ */
+ async showContent (name) {
+ super.showContent(name)
+ this.emit('focusChanged', name)
+ this.renderComponent()
+ }
+
+ render () {
+ return this.sideelement
+ }
+
+ renderComponent () {
+ ReactDOM.render(} plugins={this.plugins}/>, this.sideelement)
+ }
+}
diff --git a/apps/remix-ide/src/app/components/vertical-icons.js b/apps/remix-ide/src/app/components/vertical-icons.js
index cd86b1d796..69f6132939 100644
--- a/apps/remix-ide/src/app/components/vertical-icons.js
+++ b/apps/remix-ide/src/app/components/vertical-icons.js
@@ -15,7 +15,7 @@ const profile = {
displayName: 'Vertical Icons',
description: '',
version: packageJson.version,
- methods: ['select']
+ methods: ['select', 'unlinkContent']
}
// TODO merge with side-panel.js. VerticalIcons should not be a plugin
diff --git a/apps/remix-ide/src/app/files/fileManager.js b/apps/remix-ide/src/app/files/fileManager.ts
similarity index 94%
rename from apps/remix-ide/src/app/files/fileManager.js
rename to apps/remix-ide/src/app/files/fileManager.ts
index c526f36600..14aa2d424c 100644
--- a/apps/remix-ide/src/app/files/fileManager.js
+++ b/apps/remix-ide/src/app/files/fileManager.ts
@@ -5,9 +5,9 @@ import async from 'async'
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json'
import Registry from '../state/registry'
-const EventEmitter = require('events')
+import { EventEmitter } from 'events'
+import { RemixAppManager } from '../../../../../libs/remix-ui/plugin-manager/src/types'
const toaster = require('../ui/tooltip')
-const modalDialogCustom = require('../ui/modal-dialog-custom')
const helper = require('../../lib/helper.js')
/*
@@ -22,7 +22,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'],
+ 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'],
kind: 'file-system'
}
const errorMsg = {
@@ -37,6 +37,18 @@ const createError = (err) => {
}
class FileManager extends Plugin {
+ mode: string
+ openedFiles: any
+ events: EventEmitter
+ editor: any
+ _components: any
+ appManager: RemixAppManager
+ _deps: any
+ getCurrentFile: () => any
+ getFile: (path: any) => Promise
+ getFolder: (path: any) => Promise
+ setFile: (path: any, data: any) => Promise
+ switchFile: (path: any) => Promise
constructor (editor, appManager) {
super(profile)
this.mode = 'browser'
@@ -70,7 +82,7 @@ class FileManager extends Plugin {
* @param {string} path path of the file/directory
* @param {string} message message to display if path doesn't exist.
*/
- async _handleExists (path, message) {
+ async _handleExists (path: string, message?:string) {
const exists = await this.exists(path)
if (!exists) {
@@ -96,7 +108,7 @@ class FileManager extends Plugin {
* @param {string} path path of the file/directory
* @param {string} message message to display if path is not a directory.
*/
- async _handleIsDir (path, message) {
+ async _handleIsDir (path: string, message?: string) {
const isDir = await this.isDirectory(path)
if (!isDir) {
@@ -305,13 +317,19 @@ class FileManager extends Plugin {
if (isFile) {
if (newPathExists) {
- modalDialogCustom.alert('File already exists.')
+ this.call('modal', 'alert', {
+ id: 'fileManagerAlert',
+ message: 'File already exists'
+ })
return
}
return provider.rename(oldPath, newPath, false)
} else {
if (newPathExists) {
- modalDialogCustom.alert('Folder already exists.')
+ this.call('modal', 'alert', {
+ id: 'fileManagerAlert',
+ message: 'Directory already exists'
+ })
return
}
return provider.rename(oldPath, newPath, true)
@@ -612,7 +630,7 @@ class FileManager extends Plugin {
this.events.emit('noFileSelected')
}
- async openFile (file) {
+ async openFile (file?: string) {
if (!file) {
this.emit('noFileSelected')
this.events.emit('noFileSelected')
@@ -639,7 +657,7 @@ class FileManager extends Plugin {
// TODO: Only keep `this.emit` (issue#2210)
this.emit('currentFileChanged', file)
this.events.emit('currentFileChanged', file)
- resolve()
+ resolve(true)
}
})
})
@@ -698,7 +716,7 @@ class FileManager extends Plugin {
dirPaths.push(item)
resolve(dirPaths)
}
- return new Promise((resolve, reject) => { resolve() })
+ return new Promise((resolve, reject) => { resolve(true) })
})
Promise.all(promises).then(() => { resolve(dirPaths) })
})
@@ -760,9 +778,15 @@ class FileManager extends Plugin {
helper.createNonClashingName(file, self._deps.filesProviders[fileProvider],
(error, name) => {
if (error) {
- modalDialogCustom.alert('Unexpected error loading the file ' + error)
+ this.call('modal', 'alert', {
+ id: 'fileManagerAlert',
+ message: 'Unexpected error loading file ' + file + ': ' + error
+ })
} else if (helper.checkSpecialChars(name)) {
- modalDialogCustom.alert('Special characters are not allowed')
+ this.call('modal', 'alert', {
+ id: 'fileManagerAlert',
+ message: 'Special characters are not allowed in file names.'
+ })
} else {
try {
self._deps.filesProviders[fileProvider].set(name, filesSet[file].content)
diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js
index 142ff4296e..47e40a2f5f 100644
--- a/apps/remix-ide/src/app/panels/file-panel.js
+++ b/apps/remix-ide/src/app/panels/file-panel.js
@@ -5,7 +5,7 @@ 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'
-const { RemixdHandle } = require('../files/remixd-handle.js')
+import { RemixdHandle } from '../plugins/remixd-handle'
const { GitHandle } = require('../files/git-handle.js')
const { HardhatHandle } = require('../files/hardhat-handle.js')
const { SlitherHandle } = require('../files/slither-handle.js')
diff --git a/apps/remix-ide/src/app/panels/layout.ts b/apps/remix-ide/src/app/panels/layout.ts
new file mode 100644
index 0000000000..451c2aefe7
--- /dev/null
+++ b/apps/remix-ide/src/app/panels/layout.ts
@@ -0,0 +1,94 @@
+import { Plugin } from '@remixproject/engine'
+import { Profile } from '@remixproject/plugin-utils'
+import { EventEmitter } from 'events'
+import QueryParams from '../../lib/query-params'
+
+const profile: Profile = {
+ name: 'layout',
+ description: 'layout',
+ methods: ['minimize']
+}
+
+interface panelState {
+ active: boolean
+ plugin: Plugin
+ minimized: boolean
+}
+interface panels {
+ tabs: panelState
+ editor: panelState
+ main: panelState
+ terminal: panelState
+}
+
+export class Layout extends Plugin {
+ event: any
+ panels: panels
+ constructor () {
+ super(profile)
+ this.event = new EventEmitter()
+ }
+
+ async onActivation (): Promise {
+ this.on('fileManager', 'currentFileChanged', () => {
+ this.panels.editor.active = true
+ this.panels.main.active = false
+ this.event.emit('change', null)
+ })
+ this.on('tabs', 'openFile', () => {
+ this.panels.editor.active = true
+ this.panels.main.active = false
+ this.event.emit('change', null)
+ })
+ this.on('tabs', 'switchApp', (name: string) => {
+ this.call('mainPanel', 'showContent', name)
+ this.panels.editor.active = false
+ this.panels.main.active = true
+ this.event.emit('change', null)
+ })
+ this.on('tabs', 'closeApp', (name: string) => {
+ this.panels.editor.active = true
+ this.panels.main.active = false
+ this.event.emit('change', null)
+ })
+ this.on('tabs', 'tabCountChanged', async count => {
+ if (!count) await this.call('manager', 'activatePlugin', 'home')
+ })
+ this.on('manager', 'activate', (profile: Profile) => {
+ switch (profile.name) {
+ case 'filePanel':
+ this.call('menuicons', 'select', 'filePanel')
+ break
+ }
+ })
+ document.addEventListener('keypress', e => {
+ if (e.shiftKey && e.ctrlKey) {
+ if (e.code === 'KeyF') {
+ // Ctrl+Shift+F
+ this.call('menuicons', 'select', 'filePanel')
+ } else if (e.code === 'KeyA') {
+ // Ctrl+Shift+A
+ this.call('menuicons', 'select', 'pluginManager')
+ } else if (e.code === 'KeyS') {
+ // Ctrl+Shift+S
+ this.call('menuicons', 'select', 'settings')
+ }
+ e.preventDefault()
+ }
+ })
+ const queryParams = new QueryParams()
+ const params = queryParams.get()
+ if (params.minimizeterminal || params.embed) {
+ this.panels.terminal.minimized = true
+ this.event.emit('change', null)
+ }
+ if (params.minimizesidepanel || params.embed) {
+ this.event.emit('minimizesidepanel')
+ }
+ }
+
+ minimize (name: string, minimized:boolean): void {
+ this.panels[name].minimized = minimized
+ this.event.emit('change', null)
+ }
+}
diff --git a/apps/remix-ide/src/app/panels/main-view.js b/apps/remix-ide/src/app/panels/main-view.js
deleted file mode 100644
index bf3a07a35b..0000000000
--- a/apps/remix-ide/src/app/panels/main-view.js
+++ /dev/null
@@ -1,204 +0,0 @@
-import Registry from '../state/registry'
-
-var yo = require('yo-yo')
-var EventManager = require('../../lib/events')
-
-var { TabProxy } = require('./tab-proxy.js')
-
-var csjs = require('csjs-inject')
-
-var css = csjs`
- .mainview {
- display : flex;
- flex-direction : column;
- height : 100%;
- width : 100%;
- }
-`
-
-// @todo(#650) Extract this into two classes: MainPanel (TabsProxy + Iframe/Editor) & BottomPanel (Terminal)
-export class MainView {
- constructor (contextualListener, editor, mainPanel, fileManager, appManager, terminal) {
- var self = this
- self.event = new EventManager()
- self._view = {}
- self._components = {}
- self._components.registry = Registry.getInstance()
- self.contextualListener = contextualListener
- self.editor = editor
- self.fileManager = fileManager
- self.mainPanel = mainPanel
- self.txListener = Registry.getInstance().get('txlistener').api
- self._components.terminal = terminal
- this.appManager = appManager
- this.init()
- }
-
- showApp (name) {
- this.fileManager.unselectCurrentFile()
- this.mainPanel.showContent(name)
- this._view.editor.style.display = 'none'
- this._view.mainPanel.style.display = 'block'
- }
-
- getAppPanel () {
- return this.mainPanel
- }
-
- init () {
- var self = this
- self._deps = {
- config: self._components.registry.get('config').api,
- fileManager: self._components.registry.get('filemanager').api
- }
-
- self.tabProxy = new TabProxy(self.fileManager, self.editor)
- /*
- We listen here on event from the tab component to display / hide the editor and mainpanel
- depending on the content that should be displayed
- */
- self.fileManager.events.on('currentFileChanged', (file) => {
- // we check upstream for "fileChanged"
- self._view.editor.style.display = 'block'
- self._view.mainPanel.style.display = 'none'
- })
- self.tabProxy.event.on('openFile', (file) => {
- self._view.editor.style.display = 'block'
- self._view.mainPanel.style.display = 'none'
- })
- self.tabProxy.event.on('closeFile', (file) => {
- })
- self.tabProxy.event.on('switchApp', self.showApp.bind(self))
- self.tabProxy.event.on('closeApp', (name) => {
- self._view.editor.style.display = 'block'
- self._view.mainPanel.style.display = 'none'
- })
- self.tabProxy.event.on('tabCountChanged', (count) => {
- if (!count) this.editor.displayEmptyReadOnlySession()
- })
- self.data = {
- _layout: {
- top: {
- offset: self._terminalTopOffset(),
- show: true
- }
- }
- }
-
- self._components.terminal.event.register('resize', delta => self._adjustLayout('top', delta))
- if (self.txListener) {
- self._components.terminal.event.register('listenOnNetWork', (listenOnNetWork) => {
- self.txListener.setListenOnNetwork(listenOnNetWork)
- })
- }
- }
-
- _terminalTopOffset () {
- return this._deps.config.get('terminal-top-offset') || 150
- }
-
- _adjustLayout (direction, delta) {
- var limitUp = 0
- var limitDown = 32
- var containerHeight = window.innerHeight - limitUp // - menu bar containerHeight
- var self = this
- var layout = self.data._layout[direction]
- if (layout) {
- if (delta === undefined) {
- layout.show = !layout.show
- if (layout.show) delta = layout.offset
- else delta = 0
- } else {
- layout.show = true
- self._deps.config.set(`terminal-${direction}-offset`, delta)
- layout.offset = delta
- }
- }
- var tmp = delta - limitDown
- delta = tmp > 0 ? tmp : 0
- if (direction === 'top') {
- var mainPanelHeight = containerHeight - delta
- mainPanelHeight = mainPanelHeight < 0 ? 0 : mainPanelHeight
- self._view.editor.style.height = `${mainPanelHeight}px`
- self._view.mainPanel.style.height = `${mainPanelHeight}px`
- self._view.terminal.style.height = `${delta}px` // - menu bar height
- self.editor.resize((document.querySelector('#editorWrap') || {}).checked)
- self._components.terminal.scroll2bottom()
- }
- }
-
- minimizeTerminal () {
- this._adjustLayout('top')
- }
-
- showTerminal (offset) {
- this._adjustLayout('top', offset || this._terminalTopOffset())
- }
-
- getTerminal () {
- return this._components.terminal
- }
-
- getEditor () {
- var self = this
- return self.editor
- }
-
- refresh () {
- var self = this
- self._view.tabs.onmouseenter()
- }
-
- log (data = {}) {
- var self = this
- var command = self._components.terminal.commands[data.type]
- if (typeof command === 'function') command(data.value)
- }
-
- logMessage (msg) {
- var self = this
- self.log({ type: 'log', value: msg })
- }
-
- logHtmlMessage (msg) {
- var self = this
- self.log({ type: 'html', value: msg })
- }
-
- render () {
- var self = this
- if (self._view.mainview) return self._view.mainview
- self._view.editor = self.editor.render()
- self._view.editor.style.display = 'none'
- self._view.mainPanel = self.mainPanel.render()
- self._view.terminal = self._components.terminal.render()
-
- self._view.mainview = yo`
-
- ${self.tabProxy.renderTabsbar()}
- ${self._view.editor}
- ${self._view.mainPanel}
-
- ${self._view.terminal}
-
- `
-
- // INIT
- self._adjustLayout('top', self.data._layout.top.offset)
-
- document.addEventListener('keydown', (e) => {
- if (e.altKey && e.keyCode === 84) self.tabProxy.switchNextTab() // alt + t
- })
-
- return self._view.mainview
- }
-
- registerCommand (name, command, opts) {
- var self = this
- return self._components.terminal.registerCommand(name, command, opts)
- }
-
- updateTerminalFilter (filter) {
- this._components.terminal.updateJournal(filter)
- }
-}
diff --git a/apps/remix-ide/src/app/panels/tab-proxy.js b/apps/remix-ide/src/app/panels/tab-proxy.js
index 5b65254830..267b54d853 100644
--- a/apps/remix-ide/src/app/panels/tab-proxy.js
+++ b/apps/remix-ide/src/app/panels/tab-proxy.js
@@ -22,6 +22,7 @@ export class TabProxy extends Plugin {
this._view = {}
this._handlers = {}
this.loadedTabs = []
+ this.el = document.createElement('div')
}
onActivation () {
@@ -72,10 +73,12 @@ export class TabProxy extends Plugin {
this.addTab(workspacePath, '', () => {
this.fileManager.open(file)
this.event.emit('openFile', file)
+ this.emit('openFile', file)
},
() => {
this.fileManager.closeFile(file)
this.event.emit('closeFile', file)
+ this.emit('closeFile', file)
})
this.tabsApi.activateTab(workspacePath)
} else {
@@ -88,10 +91,12 @@ export class TabProxy extends Plugin {
this.addTab(path, '', () => {
this.fileManager.open(file)
this.event.emit('openFile', file)
+ this.emit('openFile', file)
},
() => {
this.fileManager.closeFile(file)
this.event.emit('closeFile', file)
+ this.emit('closeFile', file)
})
this.tabsApi.activateTab(path)
}
@@ -132,9 +137,9 @@ export class TabProxy extends Plugin {
this.addTab(
name,
displayName,
- () => this.event.emit('switchApp', name),
+ () => this.emit('switchApp', name),
() => {
- this.event.emit('closeApp', name)
+ this.emit('closeApp', name)
this.call('manager', 'deactivatePlugin', name)
},
icon
@@ -149,7 +154,7 @@ export class TabProxy extends Plugin {
}
focus (name) {
- this.event.emit('switchApp', name)
+ this.emit('switchApp', name)
this.tabsApi.activateTab(name)
}
@@ -199,6 +204,7 @@ export class TabProxy extends Plugin {
() => {
this.fileManager.closeFile(newName)
this.event.emit('closeFile', newName)
+ this.emit('closeFile', newName)
})
this.removeTab(oldName)
}
@@ -285,7 +291,7 @@ export class TabProxy extends Plugin {
if (this.loadedTabs[index]) {
const name = this.loadedTabs[index].name
if (this._handlers[name]) this._handlers[name].switchTo()
- this.event.emit('tabCountChanged', this.loadedTabs.length)
+ this.emit('tabCountChanged', this.loadedTabs.length)
}
}
@@ -293,7 +299,7 @@ export class TabProxy extends Plugin {
if (this.loadedTabs[index]) {
const name = this.loadedTabs[index].name
if (this._handlers[name]) this._handlers[name].close()
- this.event.emit('tabCountChanged', this.loadedTabs.length)
+ this.emit('tabCountChanged', this.loadedTabs.length)
}
}
@@ -308,8 +314,6 @@ export class TabProxy extends Plugin {
}
renderTabsbar () {
- this.el = document.createElement('div')
- this.renderComponent()
return this.el
}
}
diff --git a/apps/remix-ide/src/app/panels/terminal.js b/apps/remix-ide/src/app/panels/terminal.js
index 4837f24203..6309327cb6 100644
--- a/apps/remix-ide/src/app/panels/terminal.js
+++ b/apps/remix-ide/src/app/panels/terminal.js
@@ -13,8 +13,6 @@ const AutoCompletePopup = require('../ui/auto-complete-popup')
import { CompilerImports } from '@remix-project/core-plugin' // eslint-disable-line
-const GistHandler = require('../../lib/gist-handler')
-
const KONSOLES = []
function register (api) { KONSOLES.push(api) }
@@ -22,7 +20,7 @@ function register (api) { KONSOLES.push(api) }
const profile = {
displayName: 'Terminal',
name: 'terminal',
- methods: ['log'],
+ methods: ['log', 'logHtml'],
events: [],
description: ' - ',
version: packageJson.version
@@ -32,7 +30,6 @@ class Terminal extends Plugin {
constructor (opts, api) {
super(profile)
this.fileImport = new CompilerImports()
- this.gistHandler = new GistHandler()
this.event = new EventManager()
this.globalRegistry = Registry.getInstance()
this.element = document.createElement('div')
diff --git a/apps/remix-ide/src/app/plugins/modal.tsx b/apps/remix-ide/src/app/plugins/modal.tsx
new file mode 100644
index 0000000000..f69cfda0d4
--- /dev/null
+++ b/apps/remix-ide/src/app/plugins/modal.tsx
@@ -0,0 +1,44 @@
+import { Plugin } from '@remixproject/engine'
+import { LibraryProfile, MethodApi, StatusEvents } from '@remixproject/plugin-utils'
+import { AppModal } from '@remix-ui/app'
+import { AlertModal } from 'libs/remix-ui/app/src/lib/remix-app/interface'
+import { dispatchModalInterface } from 'libs/remix-ui/app/src/lib/remix-app/context/context'
+
+interface IModalApi {
+ events: StatusEvents,
+ methods: {
+ modal: (args: AppModal) => void
+ alert: (args: AlertModal) => void
+ toast: (message: string) => void
+ }
+}
+
+const profile:LibraryProfile = {
+ name: 'modal',
+ displayName: 'Modal',
+ description: 'Modal',
+ methods: ['modal', 'alert', 'toast']
+}
+
+export class ModalPlugin extends Plugin implements MethodApi {
+ dispatcher: dispatchModalInterface
+ constructor () {
+ super(profile)
+ }
+
+ setDispatcher (dispatcher: dispatchModalInterface) {
+ this.dispatcher = dispatcher
+ }
+
+ async modal (args: AppModal) {
+ this.dispatcher.modal(args)
+ }
+
+ async alert (args: AlertModal) {
+ this.dispatcher.alert(args)
+ }
+
+ async toast (message: string) {
+ this.dispatcher.toast(message)
+ }
+}
diff --git a/apps/remix-ide/src/app/files/remixd-handle.js b/apps/remix-ide/src/app/plugins/remixd-handle.tsx
similarity index 56%
rename from apps/remix-ide/src/app/files/remixd-handle.js
rename to apps/remix-ide/src/app/plugins/remixd-handle.tsx
index be6997574d..3b6d27c815 100644
--- a/apps/remix-ide/src/app/files/remixd-handle.js
+++ b/apps/remix-ide/src/app/plugins/remixd-handle.tsx
@@ -1,24 +1,13 @@
+/* eslint-disable no-unused-vars */
+import React, { useRef, useState, useEffect } from 'react' // eslint-disable-line
import isElectron from 'is-electron'
import { WebsocketPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
import { version as remixdVersion } from '../../../../../libs/remixd/package.json'
-var yo = require('yo-yo')
-var modalDialog = require('../ui/modaldialog')
-var modalDialogCustom = require('../ui/modal-dialog-custom')
-var copyToClipboard = require('../ui/copy-to-clipboard')
+import { PluginManager } from '@remixproject/engine'
+import { AppModal, AlertModal } from '@remix-ui/app'
+import { CopyToClipboard } from '@remix-ui/clipboard'
-var csjs = require('csjs-inject')
-
-var css = csjs`
- .dialog {
- display: flex;
- flex-direction: column;
- }
- .dialogParagraph {
- margin-bottom: 2em;
- word-break: break-word;
- }
-`
const LOCALHOST = ' - connect to localhost - '
const profile = {
@@ -32,29 +21,37 @@ const profile = {
version: packageJson.version
}
+enum State {
+ ok,
+ cancel,
+ new
+}
+
export class RemixdHandle extends WebsocketPlugin {
+ localhostProvider: any
+ appManager: PluginManager
+ state: State
constructor (localhostProvider, appManager) {
super(profile)
this.localhostProvider = localhostProvider
this.appManager = appManager
}
- deactivate () {
+ async deactivate () {
if (super.socket) super.deactivate()
// this.appManager.deactivatePlugin('git') // plugin call doesn't work.. see issue https://github.com/ethereum/remix-plugin/issues/342
- if (this.appManager.actives.includes('hardhat')) this.appManager.deactivatePlugin('hardhat')
- if (this.appManager.actives.includes('slither')) this.appManager.deactivatePlugin('slither')
+ if (this.appManager.isActive('hardhat')) this.appManager.deactivatePlugin('hardhat')
+ if (this.appManager.isActive('slither')) this.appManager.deactivatePlugin('slither')
this.localhostProvider.close((error) => {
if (error) console.log(error)
})
}
- activate () {
- this.connectToLocalhost()
+ async activate () {
+ await this.connectToLocalhost()
}
async canceled () {
- // await this.appManager.deactivatePlugin('git') // plugin call doesn't work.. see issue https://github.com/ethereum/remix-plugin/issues/342
await this.appManager.deactivatePlugin('remixd')
}
@@ -65,23 +62,25 @@ export class RemixdHandle extends WebsocketPlugin {
* @param {String} txHash - hash of the transaction
*/
async connectToLocalhost () {
- const connection = (error) => {
+ const connection = (error?:any) => {
if (error) {
console.log(error)
- modalDialogCustom.alert(
- 'Cannot connect to the remixd daemon. ' +
- 'Please make sure you have the remixd running in the background.'
- )
+ const alert:AlertModal = {
+ id: 'connectionAlert',
+ message: 'Cannot connect to the remixd daemon. Please make sure you have the remixd running in the background.'
+ }
+ this.call('modal', 'alert', alert)
this.canceled()
} else {
const intervalId = setInterval(() => {
if (!this.socket || (this.socket && this.socket.readyState === 3)) { // 3 means connection closed
clearInterval(intervalId)
console.log(error)
- modalDialogCustom.alert(
- 'Connection to remixd terminated. ' +
- 'Please make sure remixd is still running in the background.'
- )
+ const alert:AlertModal = {
+ id: 'connectionAlert',
+ message: 'Connection to remixd terminated.Please make sure remixd is still running in the background.'
+ }
+ this.call('modal', 'alert', alert)
this.canceled()
}
}, 3000)
@@ -96,34 +95,38 @@ export class RemixdHandle extends WebsocketPlugin {
this.deactivate()
} else if (!isElectron()) {
// warn the user only if he/she is in the browser context
- modalDialog(
- 'Connect to localhost',
- remixdDialog(),
- {
- label: 'Connect',
- fn: () => {
- try {
- this.localhostProvider.preInit()
- super.activate()
- setTimeout(() => {
- if (!this.socket || (this.socket && this.socket.readyState === 3)) { // 3 means connection closed
- connection(new Error('Connection with daemon failed.'))
- } else {
- connection()
- }
- }, 3000)
- } catch (error) {
- connection(error)
- }
+ this.state = State.new
+ const mod:AppModal = {
+ id: 'remixdConnect',
+ title: 'Connect to localhost',
+ message: remixdDialog(),
+ okFn: () => {
+ this.state = State.ok
+ try {
+ this.localhostProvider.preInit()
+ super.activate()
+ setTimeout(() => {
+ if (!this.socket || (this.socket && this.socket.readyState === 3)) { // 3 means connection closed
+ connection(new Error('Connection with daemon failed.'))
+ } else {
+ connection()
+ }
+ }, 3000)
+ } catch (error) {
+ connection(error)
}
},
- {
- label: 'Cancel',
- fn: () => {
- this.canceled()
- }
+ cancelFn: async () => {
+ this.state = State.cancel
+ await this.canceled()
+ },
+ okLabel: 'Connect',
+ cancelLabel: 'Cancel',
+ hideFn: async () => {
+ if (this.state === State.new) await this.canceled()
}
- )
+ }
+ await this.call('modal', 'modal', mod)
} else {
try {
super.activate()
@@ -137,31 +140,31 @@ export class RemixdHandle extends WebsocketPlugin {
function remixdDialog () {
const commandText = 'remixd -s -u '
- return yo`
-
-
- Access your local file system from Remix IDE using
Remixd NPM package .
+ return (<>
+
+
+ Access your local file system from Remix IDE using
Remixd NPM package .
Remixd needs to be running in the background to load the files in localhost workspace. For more info, please check the
Remixd tutorial .
-
+
If you are just looking for the remixd command, here it is:
- ${commandText}
- ${copyToClipboard(() => commandText)}
+ ${commandText}
+
-
+
When connected, a session will be started between
${window.location.origin} and your local file system at
ws://127.0.0.1:65520 .
- The shared folder will be in the "File Explorers" workspace named "localhost".
+ The shared folder will be in the "File Explorers" workspace named "localhost".
Read more about other
Remixd ports usage
-
+
This feature is still in Alpha. We recommend to keep a backup of the shared folder.
-
- `
+ >)
}
diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js
index b966287690..48f5484979 100644
--- a/apps/remix-ide/src/app/udapp/run-tab.js
+++ b/apps/remix-ide/src/app/udapp/run-tab.js
@@ -34,14 +34,14 @@ const profile = {
}
export class RunTab extends ViewPlugin {
- constructor (blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, mainView, fileProvider) {
+ constructor (blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, fileProvider) {
super(profile)
this.event = new EventManager()
this.config = config
this.blockchain = blockchain
this.fileManager = fileManager
this.editor = editor
- this.logCallback = (msg) => { mainView.getTerminal().logHtml(yo`
${msg} `) }
+ this.logCallback = (msg) => { this.call('terminal', 'logHtml', yo`
${msg} `) }
this.filePanel = filePanel
this.compilersArtefacts = compilersArtefacts
this.networkModule = networkModule
diff --git a/apps/remix-ide/src/app/ui/landing-page/landing-page.js b/apps/remix-ide/src/app/ui/landing-page/landing-page.js
index a100c4ea4e..b05271dc96 100644
--- a/apps/remix-ide/src/app/ui/landing-page/landing-page.js
+++ b/apps/remix-ide/src/app/ui/landing-page/landing-page.js
@@ -5,8 +5,6 @@ import * as packageJson from '../../../../../../package.json'
import { ViewPlugin } from '@remixproject/engine-web'
import { RemixUiHomeTab } from '@remix-ui/home-tab' // eslint-disable-line
-const GistHandler = require('../../../lib/gist-handler')
-
const profile = {
name: 'home',
displayName: 'Home',
@@ -26,7 +24,6 @@ export class LandingPage extends ViewPlugin {
this.contentImport = contentImport
this.appManager = appManager
this.verticalIcons = verticalIcons
- this.gistHandler = new GistHandler()
this.el = document.createElement('div')
this.el.setAttribute('id', 'landingPageHomeContainer')
this.el.setAttribute('class', 'remixui_homeContainer justify-content-between bg-light d-flex')
diff --git a/apps/remix-ide/src/framingService.js b/apps/remix-ide/src/framingService.js
deleted file mode 100644
index ed029b7a65..0000000000
--- a/apps/remix-ide/src/framingService.js
+++ /dev/null
@@ -1,34 +0,0 @@
-export class FramingService {
- constructor (sidePanel, verticalIcons, mainView, resizeFeature) {
- this.sidePanel = sidePanel
- this.verticalIcons = verticalIcons
- this.mainPanel = mainView.getAppPanel()
- this.mainView = mainView
- this.resizeFeature = resizeFeature
- }
-
- start (params) {
- this.verticalIcons.select('filePanel')
-
- document.addEventListener('keypress', (e) => {
- if (e.shiftKey && e.ctrlKey) {
- if (e.code === 'KeyF') { // Ctrl+Shift+F
- this.verticalIcons.select('filePanel')
- } else if (e.code === 'KeyA') { // Ctrl+Shift+A
- this.verticalIcons.select('pluginManager')
- } else if (e.code === 'KeyS') { // Ctrl+Shift+S
- this.verticalIcons.select('settings')
- }
- e.preventDefault()
- }
- })
-
- if (params.minimizeterminal) this.mainView.minimizeTerminal()
- if (params.minimizesidepanel) this.resizeFeature.hidePanel()
- }
-
- embed () {
- this.mainView.minimizeTerminal()
- this.resizeFeature.hidePanel()
- }
-}
diff --git a/apps/remix-ide/src/lib/cmdInterpreterAPI.js b/apps/remix-ide/src/lib/cmdInterpreterAPI.js
index 530846873d..82ae4636fe 100644
--- a/apps/remix-ide/src/lib/cmdInterpreterAPI.js
+++ b/apps/remix-ide/src/lib/cmdInterpreterAPI.js
@@ -6,7 +6,6 @@ var async = require('async')
var EventManager = require('../lib/events')
var toolTip = require('../app/ui/tooltip')
-var GistHandler = require('./gist-handler')
class CmdInterpreterAPI {
constructor (terminal, blockchain) {
@@ -17,7 +16,6 @@ class CmdInterpreterAPI {
self._components.registry = Registry.getInstance()
self._components.terminal = terminal
self._components.fileImport = new CompilerImports()
- self._components.gistHandler = new GistHandler()
self._deps = {
fileManager: self._components.registry.get('filemanager').api,
editor: self._components.registry.get('editor').api,
@@ -35,8 +33,7 @@ class CmdInterpreterAPI {
log () { arguments[0] != null ? this._components.terminal.commands.html(arguments[0]) : this._components.terminal.commands.html(arguments[1]) }
loadgist (id, cb) {
- const self = this
- self._components.gistHandler.loadFromGist({ gist: id }, this._deps.fileManager)
+ this._components.terminal.call('gistHandler', 'load', id)
if (cb) cb()
}
diff --git a/apps/remix-ide/src/lib/gist-handler.js b/apps/remix-ide/src/lib/gist-handler.js
deleted file mode 100644
index da881e1103..0000000000
--- a/apps/remix-ide/src/lib/gist-handler.js
+++ /dev/null
@@ -1,74 +0,0 @@
-'use strict'
-var modalDialogCustom = require('../app/ui/modal-dialog-custom')
-var request = require('request')
-
-// Allowing window to be overriden for testing
-function GistHandler (_window) {
- if (_window !== undefined) {
- modalDialogCustom = _window
- }
-
- this.handleLoad = function (params, cb) {
- if (!cb) cb = () => {}
- var loadingFromGist = false
- var gistId
- if (params.gist === '') {
- loadingFromGist = true
- modalDialogCustom.prompt('Load a Gist', 'Enter the ID of the Gist or URL you would like to load.', null, (target) => {
- if (target !== '') {
- gistId = getGistId(target)
- if (gistId) {
- cb(gistId)
- } else {
- modalDialogCustom.alert('Gist load error', 'Error while loading gist. Please provide a valid Gist ID or URL.')
- }
- }
- })
- return loadingFromGist
- } else {
- gistId = params.gist
- loadingFromGist = !!gistId
- }
- if (loadingFromGist) {
- cb(gistId)
- }
- return loadingFromGist
- }
-
- function getGistId (str) {
- var idr = /[0-9A-Fa-f]{8,}/
- var match = idr.exec(str)
- return match ? match[0] : null
- }
-
- this.loadFromGist = (params, fileManager) => {
- const self = this
- return self.handleLoad(params, function (gistId) {
- request.get({
- url: `https://api.github.com/gists/${gistId}`,
- json: true
- }, 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) => {
- const path = element.replace(/\.\.\./g, '/')
-
- obj['/' + 'gist-' + gistId + '/' + path] = data.files[element]
- })
- fileManager.setBatchFiles(obj, 'workspace', true, (errorLoadingFile) => {
- if (!errorLoadingFile) {
- const provider = fileManager.getProvider('workspace')
- provider.lastLoadedGistId = gistId
- } else {
- modalDialogCustom.alert('Gist load error', errorLoadingFile.message || errorLoadingFile)
- }
- })
- })
- })
- }
-}
-
-module.exports = GistHandler
diff --git a/apps/remix-ide/src/lib/panels-resize.js b/apps/remix-ide/src/lib/panels-resize.js
deleted file mode 100644
index 157535a869..0000000000
--- a/apps/remix-ide/src/lib/panels-resize.js
+++ /dev/null
@@ -1,88 +0,0 @@
-const yo = require('yo-yo')
-const csjs = require('csjs-inject')
-
-const css = csjs`
- .dragbar {
- width : 2px;
- height : 100%;
- cursor : col-resize;
- z-index : 999;
- }
- .ghostbar {
- width : 3px;
- background-color : var(--primary);
- opacity : 0.5;
- position : absolute;
- cursor : col-resize;
- z-index : 9999;
- top : 0;
- bottom : 0;
- }
-`
-
-export default class PanelsResize {
- constructor (panel) {
- this.panel = panel
- const string = panel.style.minWidth
- this.minWidth = string.length > 2 ? parseInt(string.substring(0, string.length - 2)) : 0
- }
-
- render () {
- this.ghostbar = yo`
`
-
- const mousedown = (event) => {
- event.preventDefault()
- if (event.which === 1) {
- moveGhostbar(event)
- document.body.appendChild(this.ghostbar)
- document.addEventListener('mousemove', moveGhostbar)
- document.addEventListener('mouseup', removeGhostbar)
- document.addEventListener('keydown', cancelGhostbar)
- }
- }
-
- const cancelGhostbar = (event) => {
- if (event.keyCode === 27) {
- document.body.removeChild(this.ghostbar)
- document.removeEventListener('mousemove', moveGhostbar)
- document.removeEventListener('mouseup', removeGhostbar)
- document.removeEventListener('keydown', cancelGhostbar)
- }
- }
-
- const moveGhostbar = (event) => {
- this.ghostbar.style.left = event.x + 'px'
- }
-
- const removeGhostbar = (event) => {
- document.body.removeChild(this.ghostbar)
- document.removeEventListener('mousemove', moveGhostbar)
- document.removeEventListener('mouseup', removeGhostbar)
- document.removeEventListener('keydown', cancelGhostbar)
- this.setPosition(event)
- }
-
- return yo`
`
- }
-
- calculatePanelWidth (event) {
- return event.x - this.panel.offsetLeft
- }
-
- setPosition (event) {
- const panelWidth = this.calculatePanelWidth(event)
- // close the panel if the width is less than a minWidth
- if (panelWidth > this.minWidth - 10 || this.panel.style.display === 'none') {
- this.panel.style.width = panelWidth + 'px'
- this.showPanel()
- } else this.hidePanel()
- }
-
- hidePanel () {
- this.panel.style.display = 'none'
- }
-
- showPanel () {
- this.panel.style.display = 'flex'
- }
-}
diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js
index 32afcaec9a..5f5fa2f8eb 100644
--- a/apps/remix-ide/src/remixAppManager.js
+++ b/apps/remix-ide/src/remixAppManager.js
@@ -1,20 +1,20 @@
/* global localStorage, fetch */
import { PluginManager } from '@remixproject/engine'
-import { IframePlugin } from '@remixproject/engine-web'
import { EventEmitter } from 'events'
import QueryParams from './lib/query-params'
import { PermissionHandler } from './app/ui/persmission-handler'
+import { IframePlugin } from '@remixproject/engine-web'
const _paq = window._paq = window._paq || []
const requiredModules = [ // services + layout views + system views
'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme',
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons',
- 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic']
+ 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic', 'gistHandler', 'layout', 'modal']
const dependentModules = ['git', 'hardhat', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd)
export function isNative (name) {
- const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting']
+ const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'modal']
return nativePlugins.includes(name) || requiredModules.includes(name)
}
@@ -78,6 +78,7 @@ export class RemixAppManager extends PluginManager {
onPluginActivated (plugin) {
this.pluginLoader.set(plugin, this.actives)
this.event.emit('activate', plugin)
+ this.emit('activate', plugin)
if (!requiredModules.includes(plugin.name)) _paq.push(['trackEvent', 'pluginManager', 'activate', plugin.name])
}
@@ -131,6 +132,7 @@ export class RemixAppManager extends PluginManager {
}
return plugins.map(plugin => {
return new IframePlugin(plugin)
+ // return new IframeReactPlugin(plugin)
})
}
diff --git a/apps/remix-ide/test/compiler-test.js b/apps/remix-ide/test/compiler-test.js
deleted file mode 100644
index 5af70fd14f..0000000000
--- a/apps/remix-ide/test/compiler-test.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict'
-
-var test = require('tape')
-
-var Compiler = require('@remix-project/remix-solidity').Compiler
-
-test('compiler.compile smoke', function (t) {
- t.plan(1)
-
- var noop = function () {}
- var fakeImport = function (url, cb) { cb('Not implemented') }
- var compiler = new Compiler(fakeImport)
- compiler.compileJSON = noop
- compiler.compile({ 'test': '' }, 'test')
- t.ok(compiler)
-})
diff --git a/apps/remix-ide/test/gist-handler-test.js b/apps/remix-ide/test/gist-handler-test.js
deleted file mode 100644
index 07eaad830c..0000000000
--- a/apps/remix-ide/test/gist-handler-test.js
+++ /dev/null
@@ -1,52 +0,0 @@
-'use strict'
-var modalDialogCustom
-if (typeof window !== 'undefined') {
- modalDialogCustom = require('../app/ui/modal-dialog-custom')
-}
-// ^ this class can be load in a non browser context when running node unit testing.
-// should not load UI in that case
-
-// Allowing window to be overriden for testing
-function GistHandler (_window) {
- if (_window !== undefined) {
- modalDialogCustom = _window
- }
-
- this.handleLoad = function (params, cb) {
- if (!cb) cb = () => {}
- var loadingFromGist = false
- var gistId
- if (params['gist'] === '') {
- loadingFromGist = true
- modalDialogCustom.prompt(
- 'Load a Gist',
- 'Enter the URL or ID of the Gist you would like to load.',
- null,
- target => {
- if (target !== '') {
- gistId = getGistId(target)
- if (gistId) {
- cb(gistId)
- }
- }
- }
- )
- return loadingFromGist
- } else {
- gistId = params['gist']
- loadingFromGist = !!gistId
- }
- if (loadingFromGist) {
- cb(gistId)
- }
- return loadingFromGist
- }
-
- function getGistId (str) {
- var idr = /[0-9A-Fa-f]{8,}/
- var match = idr.exec(str)
- return match ? match[0] : null
- }
-}
-
-module.exports = GistHandler
diff --git a/apps/remix-ide/test/index.js b/apps/remix-ide/test/index.js
deleted file mode 100644
index 84d8a5c68f..0000000000
--- a/apps/remix-ide/test/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-'use strict'
-
-require('./compiler-test')
-require('./gist-handler-test')
-require('./query-params-test')
diff --git a/apps/remix-ide/test/query-params-test.js b/apps/remix-ide/test/query-params-test.js
deleted file mode 100644
index c9062f6da0..0000000000
--- a/apps/remix-ide/test/query-params-test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-'use strict'
-
-var test = require('tape')
-
-var QueryParams = require('../src/lib/query-params')
-
-test('queryParams.get', function (t) {
- t.plan(2)
-
- var fakeWindow = {location: {hash: '#wat=sup&foo=bar', search: ''}}
- var params = new QueryParams(fakeWindow).get()
- t.equal(params.wat, 'sup')
- t.equal(params.foo, 'bar')
-})
-
-test('queryParams.update', function (t) {
- t.plan(1)
-
- var fakeWindow = {location: {hash: '#wat=sup', search: ''}}
- var qp = new QueryParams(fakeWindow)
- qp.update({foo: 'bar'})
- t.equal(fakeWindow.location.hash, '#wat=sup&foo=bar')
-})
diff --git a/apps/remix-ide/tsconfig.json b/apps/remix-ide/tsconfig.json
index b3e2e7d0ca..04d219a926 100644
--- a/apps/remix-ide/tsconfig.json
+++ b/apps/remix-ide/tsconfig.json
@@ -4,9 +4,11 @@
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
+ "resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"types": ["node", "jest"],
"module": "es6",
+ "resolveJsonModule": true
},
"files": [
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
diff --git a/libs/remix-core-plugin/src/index.ts b/libs/remix-core-plugin/src/index.ts
index fe8a5c661e..b91e6b76a6 100644
--- a/libs/remix-core-plugin/src/index.ts
+++ b/libs/remix-core-plugin/src/index.ts
@@ -4,3 +4,4 @@ export { FetchAndCompile } from './lib/compiler-fetch-and-compile'
export { CompilerImports } from './lib/compiler-content-imports'
export { CompilerArtefacts } from './lib/compiler-artefacts'
export { EditorContextListener } from './lib/editor-context-listener'
+export { GistHandler } from './lib/gist-handler'
diff --git a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts
index 8c243e37a8..7eab9205ce 100644
--- a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts
+++ b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts
@@ -146,6 +146,8 @@ export class CompilerImports extends Plugin {
const splitted = /([^/]+)\/(.*)$/g.exec(url)
const possiblePaths = ['localhost/installed_contracts/' + url]
+ // pick remix-tests library contracts from '.deps'
+ if (url.startsWith('remix_')) possiblePaths.push('localhost/.deps/remix-tests/' + url)
if (splitted) possiblePaths.push('localhost/installed_contracts/' + splitted[1] + '/contracts/' + splitted[2])
possiblePaths.push('localhost/node_modules/' + url)
if (splitted) possiblePaths.push('localhost/node_modules/' + splitted[1] + '/contracts/' + splitted[2])
diff --git a/libs/remix-core-plugin/src/lib/gist-handler.ts b/libs/remix-core-plugin/src/lib/gist-handler.ts
new file mode 100644
index 0000000000..6c22c29aa8
--- /dev/null
+++ b/libs/remix-core-plugin/src/lib/gist-handler.ts
@@ -0,0 +1,138 @@
+/* global fetch */
+'use strict'
+import { Plugin } from '@remixproject/engine'
+
+interface StringByString {
+ [key: string]: string;
+}
+
+const profile = {
+ name: 'gistHandler',
+ methods: ['load'],
+ events: [],
+ version: '0.0.1'
+}
+
+export class GistHandler extends Plugin {
+ constructor () {
+ super(profile)
+ }
+
+ async handleLoad (gistId: String | null, cb: Function) {
+ if (!cb) cb = () => {}
+
+ var loadingFromGist = false
+ if (!gistId) {
+ loadingFromGist = true
+ let value
+ try {
+ value = await (() => {
+ return new Promise((resolve, reject) => {
+ const modalContent = {
+ id: 'gisthandler',
+ title: 'Load a Gist',
+ message: 'Enter the ID of the Gist or URL you would like to load.',
+ modalType: 'prompt',
+ okLabel: 'OK',
+ cancelLabel: 'Cancel',
+ okFn: (value) => {
+ setTimeout(() => resolve(value), 0)
+ },
+ cancelFn: () => {
+ setTimeout(() => reject(new Error('Canceled')), 0)
+ },
+ hideFn: () => {
+ setTimeout(() => reject(new Error('Hide')), 0)
+ }
+ }
+ this.call('modal', 'modal', modalContent)
+ })
+ })()
+ } catch (e) {
+ // the modal has been canceled
+ return
+ }
+
+ if (value !== '') {
+ gistId = getGistId(value)
+ if (gistId) {
+ cb(gistId)
+ } else {
+ const modalContent = {
+ id: 'gisthandler',
+ title: 'Gist load error',
+ message: 'Error while loading gist. Please provide a valid Gist ID or URL.'
+ }
+ this.call('modal', 'alert', modalContent)
+ }
+ } else {
+ const modalContent = {
+ id: 'gisthandlerEmpty',
+ title: 'Gist load error',
+ message: 'Error while loading gist. Id cannot be empty.'
+ }
+ this.call('modal', 'alert', modalContent)
+ }
+ return loadingFromGist
+ } else {
+ loadingFromGist = !!gistId
+ }
+ if (loadingFromGist) {
+ cb(gistId)
+ }
+ return loadingFromGist
+ }
+
+ load (gistId: String | null) {
+ const self = this
+ return self.handleLoad(gistId, async (gistId: String | null) => {
+ let data: any
+ try {
+ data = await (await fetch(`https://api.github.com/gists/${gistId}`)).json() as any
+ if (!data.files) {
+ const modalContent = {
+ id: 'gisthandler',
+ title: 'Gist load error',
+ message: data.message,
+ modalType: 'alert',
+ okLabel: 'OK'
+ }
+ await this.call('modal', 'modal', modalContent)
+ return
+ }
+ } catch (e: any) {
+ const modalContent = {
+ id: 'gisthandler',
+ title: 'Gist load error',
+ message: e.message
+
+ }
+ await this.call('modal', 'alert', modalContent)
+ return
+ }
+
+ const obj: StringByString = {}
+ Object.keys(data.files).forEach((element) => {
+ const path = element.replace(/\.\.\./g, '/')
+ obj['/' + 'gist-' + gistId + '/' + path] = data.files[element]
+ })
+ this.call('fileManager', 'setBatchFiles', obj, 'workspace', true, async (errorSavingFiles: any) => {
+ if (errorSavingFiles) {
+ const modalContent = {
+ id: 'gisthandler',
+ title: 'Gist load error',
+ message: errorSavingFiles.message || errorSavingFiles
+
+ }
+ this.call('modal', 'alert', modalContent)
+ }
+ })
+ })
+ }
+}
+
+const getGistId = (str) => {
+ var idr = /[0-9A-Fa-f]{8,}/
+ var match = idr.exec(str)
+ return match ? match[0] : null
+}
diff --git a/libs/remix-ui/app/src/index.ts b/libs/remix-ui/app/src/index.ts
index e47f8690e7..d02ade520c 100644
--- a/libs/remix-ui/app/src/index.ts
+++ b/libs/remix-ui/app/src/index.ts
@@ -1 +1,6 @@
export { default as RemixApp } from './lib/remix-app/remix-app'
+export { dispatchModalContext } from './lib/remix-app/context/context'
+export { ModalProvider } from './lib/remix-app/context/provider'
+export { AppModal } from './lib/remix-app/interface/index'
+export { AlertModal } from './lib/remix-app/interface/index'
+export * from './lib/remix-app/types/index'
diff --git a/libs/remix-ui/app/src/lib/remix-app/actions/modals.ts b/libs/remix-ui/app/src/lib/remix-app/actions/modals.ts
new file mode 100644
index 0000000000..95400ca77b
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/actions/modals.ts
@@ -0,0 +1,30 @@
+import { AppModal } from '../interface'
+
+type ActionMap
= {
+ [Key in keyof M]: M[Key] extends undefined
+ ? {
+ type: Key;
+ }
+ : {
+ type: Key;
+ payload: M[Key];
+ }
+}
+
+export const enum modalActionTypes {
+ setModal = 'SET_MODAL',
+ setToast = 'SET_TOAST',
+ handleHideModal = 'HANDLE_HIDE_MODAL',
+ handleToaster = 'HANDLE_HIDE_TOAST'
+}
+
+type ModalPayload = {
+ [modalActionTypes.setModal]: AppModal
+ [modalActionTypes.handleHideModal]: any
+ [modalActionTypes.setToast]: string
+ [modalActionTypes.handleToaster]: any
+}
+
+export type ModalAction = ActionMap[keyof ActionMap<
+ ModalPayload
+>]
diff --git a/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.css b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.css
new file mode 100644
index 0000000000..1330c1179c
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.css
@@ -0,0 +1,27 @@
+/* dragbar UI */
+
+.dragbar {
+ display: block;
+ height: 100%;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 0.3em;
+ z-index: 9999;
+}
+
+.overlay {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100vw;
+ height: 100vh;
+ display: block;
+ z-index: 9998;
+}
+
+.dragbar:hover,
+.dragbar.ondrag {
+ background-color: var(--secondary);
+ cursor: col-resize;
+}
diff --git a/libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.tsx b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
similarity index 77%
rename from libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.tsx
rename to libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
index 29c4eeda6b..429e49f638 100644
--- a/libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.tsx
+++ b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
@@ -15,18 +15,23 @@ const DragBar = (props: IRemixDragBarUi) => {
const [offset, setOffSet] = useState(0)
const nodeRef = React.useRef(null) // fix for strictmode
- useEffect(() => {
- // arbitrary time out to wait the the UI to be completely done
- setTimeout(() => {
- setOffSet(props.refObject.current.offsetLeft)
- setDragBarPosX(offset + props.refObject.current.offsetWidth)
- }, 1000)
- }, [])
-
useEffect(() => {
setDragBarPosX(offset + (props.hidden ? 0 : props.refObject.current.offsetWidth))
}, [props.hidden, offset])
+ const handleResize = () => {
+ setOffSet(props.refObject.current.offsetLeft)
+ setDragBarPosX(props.refObject.current.offsetLeft + props.refObject.current.offsetWidth)
+ }
+
+ useEffect(() => {
+ window.addEventListener('resize', handleResize)
+ // TODO: not a good way to wait on the ref doms element to be rendered of course
+ setTimeout(() =>
+ handleResize(), 2000)
+ return () => window.removeEventListener('resize', handleResize)
+ }, [])
+
function stopDrag (e: MouseEvent, data: any) {
setDragState(false)
if (data.x < props.minWidth) {
diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx
new file mode 100644
index 0000000000..d5610de56c
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx
@@ -0,0 +1,15 @@
+import React, { useContext, useEffect } from 'react'
+import { AppContext } from '../../context/context'
+import { useDialogDispatchers } from '../../context/provider'
+
+const DialogViewPlugin = () => {
+ const { modal, alert, toast } = useDialogDispatchers()
+ const app = useContext(AppContext)
+
+ useEffect(() => {
+ app.modal.setDispatcher({ modal, alert, toast })
+ }, [])
+ return <>>
+}
+
+export default DialogViewPlugin
diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogs.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogs.tsx
new file mode 100644
index 0000000000..7aba74f73b
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogs.tsx
@@ -0,0 +1,16 @@
+import React from 'react'
+import { useDialogDispatchers, useDialogs } from '../../context/provider'
+import { Toaster } from '@remix-ui/toaster'
+import ModalWrapper from './modal-wrapper'
+
+const AppDialogs = () => {
+ const { handleHideModal, handleToaster } = useDialogDispatchers()
+ const { focusModal, focusToaster } = useDialogs()
+
+ return (
+ <>
+
+
+ >)
+}
+export default AppDialogs
diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/matomo.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/matomo.tsx
new file mode 100644
index 0000000000..4d4daaed3e
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/matomo.tsx
@@ -0,0 +1,45 @@
+import React, { useContext, useEffect, useState } from 'react'
+import { AppContext } from '../../context/context'
+import { useDialogDispatchers } from '../../context/provider'
+const _paq = window._paq = window._paq || []
+
+const MatomoDialog = (props) => {
+ const { settings, showMatamo, appManager } = useContext(AppContext)
+ const { modal } = useDialogDispatchers()
+ const [visible, setVisible] = useState(props.hide)
+
+ const message = () => {
+ return (<>An Opt-in version of Matomo , an open source data analytics platform is being used to improve Remix IDE.
+ We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.
+ All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public: take a look .
+ We do not collect nor store any personally identifiable information (PII).
+ For more info, see: Matomo Analyitcs on Remix iDE .
+ You can change your choice in the Settings panel anytime.
>)
+ }
+
+ useEffect(() => {
+ if (visible && showMatamo) {
+ modal({ id: 'matomoModal', title: 'Help us to improve Remix IDE', message: message(), okLabel: 'Accept', okFn: handleModalOkClick, cancelLabel: 'Decline', cancelFn: declineModal })
+ }
+ }, [visible])
+
+ const declineModal = async () => {
+ settings.updateMatomoAnalyticsChoice(false)
+ _paq.push(['optUserOut'])
+ appManager.call('walkthrough', 'start')
+ setVisible(false)
+ }
+
+ const handleModalOkClick = async () => {
+ _paq.push(['forgetUserOptOut'])
+ // @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used
+ document.cookie = 'mtm_consent_removed=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
+ settings.updateMatomoAnalyticsChoice(true)
+ appManager.call('walkthrough', 'start')
+ setVisible(false)
+ }
+
+ return (<>>)
+}
+
+export default MatomoDialog
diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/modal-wrapper.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/modal-wrapper.tsx
new file mode 100644
index 0000000000..cff3215e1f
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/modal-wrapper.tsx
@@ -0,0 +1,56 @@
+import React, { useEffect, useRef, useState } from 'react'
+import { ModalDialog } from '@remix-ui/modal-dialog'
+import { ModalDialogProps } from 'libs/remix-ui/modal-dialog/src/lib/types'
+import { ModalTypes } from '../../types'
+
+interface ModalWrapperProps extends ModalDialogProps {
+ modalType?: ModalTypes
+ defaultValue?: string
+}
+
+const ModalWrapper = (props: ModalWrapperProps) => {
+ const [state, setState] = useState()
+ const ref = useRef()
+
+ const onFinishPrompt = async () => {
+ if (ref.current === undefined) {
+ props.okFn()
+ } else {
+ // @ts-ignore: Object is possibly 'null'.
+ props.okFn(ref.current.value)
+ }
+ }
+
+ const createModalMessage = (defaultValue: string) => {
+ return (
+ <>
+ {props.message}
+ >
+ )
+ }
+
+ useEffect(() => {
+ if (props.modalType) {
+ switch (props.modalType) {
+ case ModalTypes.prompt:
+ case ModalTypes.password:
+ setState({
+ ...props,
+ okFn: onFinishPrompt,
+ message: createModalMessage(props.defaultValue)
+ })
+ break
+ default:
+ setState({ ...props })
+ break
+ }
+ } else {
+ setState({ ...props })
+ }
+ }, [props])
+
+ return (
+
+ )
+}
+export default ModalWrapper
diff --git a/libs/remix-ui/app/src/lib/remix-app/modals/alert.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/origin-warning.tsx
similarity index 68%
rename from libs/remix-ui/app/src/lib/remix-app/modals/alert.tsx
rename to libs/remix-ui/app/src/lib/remix-app/components/modals/origin-warning.tsx
index b61abbb1d1..61d25db2f6 100644
--- a/libs/remix-ui/app/src/lib/remix-app/modals/alert.tsx
+++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/origin-warning.tsx
@@ -1,9 +1,10 @@
import React, { useEffect, useState } from 'react'
import { ModalDialog } from '@remix-ui/modal-dialog'
+import { useDialogDispatchers } from '../../context/provider'
-const AlertModal = () => {
- const [visible, setVisible] = useState(true)
- const [content, setContent] = useState('')
+const OriginWarning = () => {
+ const { alert } = useDialogDispatchers()
+ const [content, setContent] = useState(null)
useEffect(() => {
// check the origin and warn message
@@ -20,24 +21,15 @@ const AlertModal = () => {
This instance of Remix you are visiting WILL NOT BE UPDATED.\n
Please make a backup of your contracts and start using http://remix.ethereum.org`)
}
- setVisible(content !== '')
}, [])
- const closeModal = async () => {
- setVisible(false)
- }
- const handleModalOkClick = async () => {
- setVisible(false)
- }
- return ({content} )
+ useEffect(() => {
+ if (content) {
+ alert({ id: 'warningOriging', title: null, message: content })
+ }
+ }, [content])
+
+ return (<>>)
}
-export default AlertModal
+export default OriginWarning
diff --git a/libs/remix-ui/app/src/lib/remix-app/modals/splashscreen.tsx b/libs/remix-ui/app/src/lib/remix-app/components/splashscreen.tsx
similarity index 100%
rename from libs/remix-ui/app/src/lib/remix-app/modals/splashscreen.tsx
rename to libs/remix-ui/app/src/lib/remix-app/components/splashscreen.tsx
diff --git a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx
index f9f97a4555..3745fcddf0 100644
--- a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx
+++ b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx
@@ -1,5 +1,24 @@
import React from 'react'
+import { AlertModal, AppModal } from '../interface'
+import { ModalInitialState } from '../state/modals'
+import { ModalTypes } from '../types'
-const AppContext = React.createContext(null)
+export const AppContext = React.createContext(null)
-export default AppContext
+export interface dispatchModalInterface {
+ modal: (data: AppModal) => void
+ toast: (message: string) => void
+ alert: (data: AlertModal) => void
+ handleHideModal: () => void,
+ handleToaster: () => void
+}
+
+export const dispatchModalContext = React.createContext({
+ modal: (data: AppModal) => { },
+ toast: (message: string) => {},
+ alert: (data: AlertModal) => {},
+ handleHideModal: () => {},
+ handleToaster: () => {}
+})
+
+export const modalContext = React.createContext(ModalInitialState)
diff --git a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx
new file mode 100644
index 0000000000..73a3a97305
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx
@@ -0,0 +1,64 @@
+import React, { useReducer } from 'react'
+import { modalActionTypes } from '../actions/modals'
+import { AlertModal, AppModal } from '../interface'
+import { modalReducer } from '../reducer/modals'
+import { ModalInitialState } from '../state/modals'
+import { ModalTypes } from '../types'
+import { AppContext, dispatchModalContext, modalContext } from './context'
+
+export const ModalProvider = ({ children = [], reducer = modalReducer, initialState = ModalInitialState } = {}) => {
+ const [{ modals, toasters, focusModal, focusToaster }, dispatch] = useReducer(reducer, initialState)
+
+ const modal = (data: AppModal) => {
+ const { id, title, message, okLabel, okFn, cancelLabel, cancelFn, modalType, defaultValue, hideFn } = data
+ dispatch({
+ type: modalActionTypes.setModal,
+ payload: { id, title, message, okLabel, okFn, cancelLabel, cancelFn, modalType: modalType || ModalTypes.default, defaultValue: defaultValue, hideFn }
+ })
+ }
+
+ const alert = (data: AlertModal) => {
+ modal({ id: data.id, title: data.title || 'Alert', message: data.message || data.title, okLabel: 'OK', okFn: (value?:any) => {}, cancelLabel: '', cancelFn: () => {} })
+ }
+
+ const handleHideModal = () => {
+ dispatch({
+ type: modalActionTypes.handleHideModal,
+ payload: null
+ })
+ }
+
+ const toast = (message: string) => {
+ dispatch({
+ type: modalActionTypes.setToast,
+ payload: message
+ })
+ }
+
+ const handleToaster = () => {
+ dispatch({
+ type: modalActionTypes.handleToaster,
+ payload: null
+ })
+ }
+
+ return (
+
+ {children}
+
+ )
+}
+
+export const AppProvider = ({ children = [], value = {} } = {}) => {
+ return
+ {children}
+
+}
+
+export const useDialogs = () => {
+ return React.useContext(modalContext)
+}
+
+export const useDialogDispatchers = () => {
+ return React.useContext(dispatchModalContext)
+}
diff --git a/libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.css b/libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.css
deleted file mode 100644
index a423dd6605..0000000000
--- a/libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.css
+++ /dev/null
@@ -1,26 +0,0 @@
-/* dragbar UI */
-
-.dragbar {
- display : block;
- height : 100%;
- position : absolute;
- left: 0px;
- top: 0px;
- width: 0.3em;
- z-index: 9999;
- }
-
- .overlay {
- position: absolute;
- left: 0;
- top: 0;
- width: 100vw;
- height: 100vh;
- display: block;
- z-index: 9998;
- }
-
- .dragbar:hover, .dragbar.ondrag{
- background-color: var(--secondary);
- cursor:col-resize;
- }
\ No newline at end of file
diff --git a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts
new file mode 100644
index 0000000000..dcfcd7a1eb
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts
@@ -0,0 +1,29 @@
+import { ModalTypes } from '../types'
+
+export interface AppModal {
+ id: string
+ hide?: boolean
+ title: string
+ // eslint-disable-next-line no-undef
+ message: string | JSX.Element
+ okLabel: string
+ okFn: (value?:any) => void
+ cancelLabel: string
+ cancelFn: () => void,
+ modalType?: ModalTypes,
+ defaultValue?: string
+ hideFn?: () => void
+}
+
+export interface AlertModal {
+ id: string
+ title?: string,
+ message: string | JSX.Element,
+}
+
+export interface ModalState {
+ modals: AppModal[],
+ toasters: string[],
+ focusModal: AppModal,
+ focusToaster: string
+}
diff --git a/libs/remix-ui/app/src/lib/remix-app/modals/matomo.tsx b/libs/remix-ui/app/src/lib/remix-app/modals/matomo.tsx
deleted file mode 100644
index 2ab56fa02d..0000000000
--- a/libs/remix-ui/app/src/lib/remix-app/modals/matomo.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React, { useContext, useEffect, useState } from 'react'
-import { ModalDialog } from '@remix-ui/modal-dialog'
-import AppContext from '../context/context'
-const _paq = window._paq = window._paq || []
-
-const MatomoDialog = (props) => {
- const { settings, showMatamo, appManager } = useContext(AppContext)
- const [visible, setVisible] = useState(props.hide)
- useEffect(() => {
- if (showMatamo) {
- setVisible(true)
- } else {
- setVisible(false)
- }
- }, [])
- const declineModal = async () => {
- settings.updateMatomoAnalyticsChoice(false)
- _paq.push(['optUserOut'])
- appManager.call('walkthrough', 'start')
- setVisible(false)
- }
- const hideModal = async () => {
- setVisible(false)
- }
- const handleModalOkClick = async () => {
- _paq.push(['forgetUserOptOut'])
- // @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used
- document.cookie = 'mtm_consent_removed=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
- settings.updateMatomoAnalyticsChoice(true)
- appManager.call('walkthrough', 'start')
- setVisible(false)
- }
- return (
- An Opt-in version of Matomo , an open source data analytics platform is being used to improve Remix IDE.
- We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.
- All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public: take a look .
- We do not collect nor store any personally identifiable information (PII).
- For more info, see: Matomo Analyitcs on Remix iDE .
- You can change your choice in the Settings panel anytime.
- )
-}
-
-export default MatomoDialog
diff --git a/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts b/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts
new file mode 100644
index 0000000000..cf202585f4
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts
@@ -0,0 +1,50 @@
+import { modalActionTypes, ModalAction } from '../actions/modals'
+import { ModalInitialState } from '../state/modals'
+import { AppModal, ModalState } from '../interface'
+
+export const modalReducer = (state: ModalState = ModalInitialState, action: ModalAction) => {
+ switch (action.type) {
+ case modalActionTypes.setModal: {
+ let modalList:AppModal[] = state.modals
+ modalList.push(action.payload)
+ if (state.modals.length === 1 && state.focusModal.hide === true) { // if it's the first one show it
+ const focusModal: AppModal = {
+ id: modalList[0].id,
+ hide: false,
+ title: modalList[0].title,
+ message: modalList[0].message,
+ okLabel: modalList[0].okLabel,
+ okFn: modalList[0].okFn,
+ cancelLabel: modalList[0].cancelLabel,
+ cancelFn: modalList[0].cancelFn,
+ modalType: modalList[0].modalType,
+ defaultValue: modalList[0].defaultValue,
+ hideFn: modalList[0].hideFn
+ }
+
+ modalList = modalList.slice()
+ modalList.shift()
+ return { ...state, modals: modalList, focusModal: focusModal }
+ }
+ return { ...state, modals: modalList }
+ }
+ case modalActionTypes.handleHideModal:
+ if (state.focusModal.hideFn) {
+ state.focusModal.hideFn()
+ }
+ state.focusModal = { ...state.focusModal, hide: true, message: null }
+ return { ...state }
+
+ case modalActionTypes.setToast:
+ state.toasters.push(action.payload)
+ if (state.toasters.length > 0) {
+ const focus = state.toasters[0]
+ state.toasters.shift()
+ return { ...state, focusToaster: focus }
+ }
+ return { ...state }
+
+ case modalActionTypes.handleToaster:
+ return { ...state, focusToaster: '' }
+ }
+}
diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
index d8430eac52..27d5a7b832 100644
--- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
+++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
@@ -1,10 +1,14 @@
-import React, { useContext, useEffect, useRef, useState } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
import './style/remix-app.css'
-import RemixSplashScreen from './modals/splashscreen'
-import MatomoDialog from './modals/matomo'
-import AlertModal from './modals/alert'
-import AppContext from './context/context'
-import DragBar from './dragbar/dragbar'
+import { RemixUIMainPanel } from '@remix-ui/panel'
+import RemixSplashScreen from './components/splashscreen'
+import MatomoDialog from './components/modals/matomo'
+import OriginWarning from './components/modals/origin-warning'
+import DragBar from './components/dragbar/dragbar'
+import { AppProvider } from './context/provider'
+import AppDialogs from './components/modals/dialogs'
+import DialogViewPlugin from './components/modals/dialogViewPlugin'
+
interface IRemixAppUi {
app: any
}
@@ -59,6 +63,13 @@ const RemixApp = (props: IRemixAppUi) => {
props.app.sidePanel.events.on('showing', () => {
setHideSidePanel(false)
})
+
+ props.app.layout.event.on('minimizesidepanel', () => {
+ // the 'showing' event always fires from sidepanel, so delay this a bit
+ setTimeout(() => {
+ setHideSidePanel(true)
+ }, 1000)
+ })
}
const components = {
@@ -68,22 +79,32 @@ const RemixApp = (props: IRemixAppUi) => {
hiddenPanel:
}
+ const value = {
+ settings: props.app.settings,
+ showMatamo: props.app.showMatamo,
+ appManager: props.app.appManager,
+ modal: props.app.modal,
+ layout: props.app.layout
+ }
+
return (
-
+
-
+
{components.iconPanel}
{components.sidePanel}
- {components.mainPanel}
-
+
+
+
{components.hiddenPanel}
-
-
+
+
+
)
}
diff --git a/libs/remix-ui/app/src/lib/remix-app/state/modals.ts b/libs/remix-ui/app/src/lib/remix-app/state/modals.ts
new file mode 100644
index 0000000000..8332d60120
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/state/modals.ts
@@ -0,0 +1,17 @@
+import { ModalState } from '../interface'
+
+export const ModalInitialState: ModalState = {
+ modals: [],
+ toasters: [],
+ focusModal: {
+ id: '',
+ hide: true,
+ title: '',
+ message: '',
+ okLabel: '',
+ okFn: () => { },
+ cancelLabel: '',
+ cancelFn: () => { }
+ },
+ focusToaster: ''
+}
diff --git a/libs/remix-ui/app/src/lib/remix-app/types/index.ts b/libs/remix-ui/app/src/lib/remix-app/types/index.ts
new file mode 100644
index 0000000000..edca9e147c
--- /dev/null
+++ b/libs/remix-ui/app/src/lib/remix-app/types/index.ts
@@ -0,0 +1,7 @@
+export const enum ModalTypes {
+ alert = 'alert',
+ confirm = 'confirm',
+ prompt = 'prompt',
+ password = 'password',
+ default = 'default',
+}
diff --git a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx
index 4c41c7968f..c130d35a64 100644
--- a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx
+++ b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx
@@ -136,7 +136,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
plugin.appManager.activatePlugin('remixd')
}
const importFromGist = () => {
- plugin.gistHandler.loadFromGist({ gist: '' }, fileManager)
+ plugin.call('gistHandler', 'load', '')
plugin.verticalIcons.select('filePanel')
}
const switchToPreviousVersion = () => {
diff --git a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx
index bd3a07cf00..714255aa93 100644
--- a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx
+++ b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx
@@ -12,12 +12,15 @@ export const ModalDialog = (props: ModalDialogProps) => {
const [state, setState] = useState({
toggleBtn: true
})
+ const calledHideFunctionOnce = useRef()
const modal = useRef(null)
const handleHide = () => {
- props.handleHide()
+ if (!calledHideFunctionOnce.current) { props.handleHide() }
+ calledHideFunctionOnce.current = true
}
useEffect(() => {
+ calledHideFunctionOnce.current = props.hide
modal.current.focus()
}, [props.hide])
@@ -32,12 +35,9 @@ export const ModalDialog = (props: ModalDialogProps) => {
}
if (modal.current) {
modal.current.addEventListener('blur', handleBlur)
-
- return () => {
- if (modal.current) {
- modal.current.removeEventListener('blur', handleBlur)
- }
- }
+ }
+ return () => {
+ modal.current.removeEventListener('blur', handleBlur)
}
}, [modal.current])
@@ -86,40 +86,38 @@ export const ModalDialog = (props: ModalDialogProps) => {
{props.title && props.title}
{!props.showCancelIcon &&
- handleHide()}>
-
-
+ handleHide()}>
+
+
}
- { props.children ? props.children : props.message }
+ {props.children ? props.children : props.message}
{/* todo add autofocus ^^ */}
- { props.okLabel &&
- {
- if (props.okFn) props.okFn()
- handleHide()
- }}
- >
- { props.okLabel ? props.okLabel : 'OK' }
-
+ { props.okLabel && {
+ if (props.okFn) props.okFn()
+ handleHide()
+ }}
+ >
+ {props.okLabel ? props.okLabel : 'OK'}
+
}
- { props.cancelLabel &&
- {
- if (props.cancelFn) props.cancelFn()
- handleHide()
- }}
- >
- { props.cancelLabel ? props.cancelLabel : 'Cancel' }
-
+ { props.cancelLabel && {
+ if (props.cancelFn) props.cancelFn()
+ handleHide()
+ }}
+ >
+ {props.cancelLabel ? props.cancelLabel : 'Cancel'}
+
}
diff --git a/libs/remix-ui/modal-dialog/src/lib/types/index.ts b/libs/remix-ui/modal-dialog/src/lib/types/index.ts
index b03cb16c94..acb171fc0f 100644
--- a/libs/remix-ui/modal-dialog/src/lib/types/index.ts
+++ b/libs/remix-ui/modal-dialog/src/lib/types/index.ts
@@ -4,7 +4,7 @@ export interface ModalDialogProps {
title?: string,
message?: string | JSX.Element,
okLabel?: string,
- okFn?: () => void,
+ okFn?: (value?:any) => void,
cancelLabel?: string,
cancelFn?: () => void,
modalClass?: string,
diff --git a/libs/remix-ui/panel/.babelrc b/libs/remix-ui/panel/.babelrc
new file mode 100644
index 0000000000..64a3748691
--- /dev/null
+++ b/libs/remix-ui/panel/.babelrc
@@ -0,0 +1,4 @@
+{
+ "presets": ["@nrwl/react/babel"],
+ "plugins": []
+}
\ No newline at end of file
diff --git a/libs/remix-ui/panel/.eslintrc.json b/libs/remix-ui/panel/.eslintrc.json
new file mode 100644
index 0000000000..5a1c541d11
--- /dev/null
+++ b/libs/remix-ui/panel/.eslintrc.json
@@ -0,0 +1,18 @@
+{
+ "extends": ["plugin:@nrwl/nx/react", "../../../.eslintrc"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.ts", "*.tsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.js", "*.jsx"],
+ "rules": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libs/remix-ui/panel/README.md b/libs/remix-ui/panel/README.md
new file mode 100644
index 0000000000..fa765fcb39
--- /dev/null
+++ b/libs/remix-ui/panel/README.md
@@ -0,0 +1,7 @@
+# remix-ui-side-panel
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test remix-ui-side-panel` to execute the unit tests via [Jest](https://jestjs.io).
diff --git a/libs/remix-ui/panel/src/index.ts b/libs/remix-ui/panel/src/index.ts
new file mode 100644
index 0000000000..c61d9612f1
--- /dev/null
+++ b/libs/remix-ui/panel/src/index.ts
@@ -0,0 +1,2 @@
+export { default as RemixPluginPanel } from './lib/plugins/remix-ui-panel'
+export { default as RemixUIMainPanel } from './lib/main/main-panel'
diff --git a/libs/remix-ui/panel/src/lib/dragbar/dragbar.css b/libs/remix-ui/panel/src/lib/dragbar/dragbar.css
new file mode 100644
index 0000000000..1ad9f9de85
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/dragbar/dragbar.css
@@ -0,0 +1,27 @@
+/* dragbar UI */
+
+.dragbar_terminal {
+ display: block;
+ width: 100%;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ height: 0.3em;
+ z-index: 9999;
+}
+
+.overlay {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100vw;
+ height: 100vh;
+ display: block;
+ z-index: 900;
+}
+
+.dragbar_terminal:hover,
+.dragbar_terminal.ondrag {
+ background-color: var(--secondary);
+ cursor: row-resize;
+}
diff --git a/libs/remix-ui/panel/src/lib/dragbar/dragbar.tsx b/libs/remix-ui/panel/src/lib/dragbar/dragbar.tsx
new file mode 100644
index 0000000000..232f23ff10
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/dragbar/dragbar.tsx
@@ -0,0 +1,51 @@
+// eslint-disable-next-line no-use-before-define
+import React, { useEffect, useState } from 'react'
+import Draggable from 'react-draggable'
+import './dragbar.css'
+
+interface IRemixDragBarUi {
+ refObject: React.MutableRefObject
;
+ setHideStatus: (hide: boolean) => void;
+ hidden: boolean
+ minHeight?: number
+}
+
+const DragBar = (props: IRemixDragBarUi) => {
+ const [dragState, setDragState] = useState(false)
+ const [dragBarPosY, setDragBarPosY] = useState(0)
+ const nodeRef = React.useRef(null) // fix for strictmode
+
+ function stopDrag (e: MouseEvent, data: any) {
+ const h = window.innerHeight - data.y
+ props.refObject.current.setAttribute('style', `height: ${h}px;`)
+ setDragBarPosY(window.innerHeight - props.refObject.current.offsetHeight)
+ setDragState(false)
+ }
+ const handleResize = () => {
+ setDragBarPosY(window.innerHeight - props.refObject.current.offsetHeight)
+ }
+
+ useEffect(() => {
+ handleResize()
+ }, [props.hidden])
+
+ useEffect(() => {
+ window.addEventListener('resize', handleResize)
+ // TODO: not a good way to wait on the ref doms element to be rendered of course
+ setTimeout(() =>
+ handleResize(), 2000)
+ return () => window.removeEventListener('resize', handleResize)
+ }, [])
+
+ function startDrag () {
+ setDragState(true)
+ }
+ return <>
+
+
+
+
+ >
+}
+
+export default DragBar
diff --git a/libs/remix-ui/panel/src/lib/main/main-panel.css b/libs/remix-ui/panel/src/lib/main/main-panel.css
new file mode 100644
index 0000000000..d569338fab
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/main/main-panel.css
@@ -0,0 +1,8 @@
+.mainview {
+ display : flex;
+ flex-direction : column;
+ height : 100%;
+ width : 100%;
+ position: relative;
+ }
+
diff --git a/libs/remix-ui/panel/src/lib/main/main-panel.tsx b/libs/remix-ui/panel/src/lib/main/main-panel.tsx
new file mode 100644
index 0000000000..4fb00ddf65
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/main/main-panel.tsx
@@ -0,0 +1,60 @@
+/* eslint-disable no-unused-expressions */
+import { AppContext } from 'libs/remix-ui/app/src/lib/remix-app/context/context'
+import React, { useContext, useEffect, useLayoutEffect, useRef, useState } from 'react' // eslint-disable-line
+import DragBar from '../dragbar/dragbar'
+import RemixUIPanelPlugin from '../plugins/panel-plugin'
+import { PluginRecord } from '../types'
+import './main-panel.css'
+
+const RemixUIMainPanel = () => {
+ const appContext = useContext(AppContext)
+ const [plugins, setPlugins] = useState([])
+ const editorRef = useRef(null)
+ const mainPanelRef = useRef(null)
+ const tabsRef = useRef(null)
+ const terminalRef = useRef(null)
+
+ const refs = [tabsRef, editorRef, mainPanelRef, terminalRef]
+
+ const renderPanels = () => {
+ if (appContext) {
+ const pluginPanels: PluginRecord[] = []
+ Object.values(appContext.layout.panels).map((panel: any) => {
+ pluginPanels.push({
+ profile: panel.plugin.profile,
+ active: panel.active,
+ view: panel.plugin.profile.name === 'tabs' ? panel.plugin.renderTabsbar() : panel.plugin.render(),
+ class: panel.plugin.profile.name + '-wrap ' + (panel.minimized ? 'minimized' : ''),
+ minimized: panel.minimized
+ })
+ })
+ setPlugins(pluginPanels)
+ }
+ }
+
+ useEffect(() => {
+ renderPanels()
+ appContext.layout.event.on('change', () => {
+ renderPanels()
+ })
+ }, [])
+
+ return (
+
+ {Object.values(plugins).map((pluginRecord, i) => {
+ return (
+
+ {(pluginRecord.profile.name === 'terminal') ? {}} refObject={terminalRef}> : null}
+
+
+ )
+ })}
+
+ )
+}
+
+export default RemixUIMainPanel
diff --git a/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
new file mode 100644
index 0000000000..5acd50541a
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
@@ -0,0 +1,27 @@
+/* eslint-disable jsx-a11y/anchor-has-content */
+import React, { useEffect, useRef, useState } from 'react' // eslint-disable-line
+import { PluginRecord } from '../types'
+import './panel.css'
+
+export interface RemixPanelProps {
+ plugins: Record;
+ }
+const RemixUIPanelHeader = (props: RemixPanelProps) => {
+ const [plugin, setPlugin] = useState()
+
+ useEffect(() => {
+ if (props.plugins) {
+ const p = Object.values(props.plugins).find((pluginRecord) => {
+ return pluginRecord.active === true
+ })
+ setPlugin(p)
+ }
+ }, [props])
+
+ return (
+ {plugin?.profile.displayName || plugin?.profile.name}
+ {plugin?.profile.documentation ? ( ) : ''}
+ )
+}
+
+export default RemixUIPanelHeader
diff --git a/libs/remix-ui/panel/src/lib/plugins/panel-plugin.tsx b/libs/remix-ui/panel/src/lib/plugins/panel-plugin.tsx
new file mode 100644
index 0000000000..9eb30391bc
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/plugins/panel-plugin.tsx
@@ -0,0 +1,37 @@
+/* eslint-disable no-undef */
+import React, { forwardRef, useEffect, useRef, useState } from 'react' // eslint-disable-line
+import { PluginRecord } from '../types'
+import './panel.css'
+interface panelPLuginProps {
+ pluginRecord: PluginRecord
+}
+
+const RemixUIPanelPlugin = (props: panelPLuginProps, panelRef: any) => {
+ const localRef = useRef(null)
+ const [view, setView] = useState()
+ useEffect(() => {
+ const ref:any = panelRef || localRef
+ if (ref.current) {
+ if (props.pluginRecord.view) {
+ if (React.isValidElement(props.pluginRecord.view)) {
+ setView(props.pluginRecord.view)
+ } else {
+ ref.current.appendChild(props.pluginRecord.view)
+ }
+ }
+ }
+ }, [])
+
+ return (
+
+ {view}
+
+ )
+}
+
+export default forwardRef(RemixUIPanelPlugin)
diff --git a/libs/remix-ui/panel/src/lib/plugins/panel.css b/libs/remix-ui/panel/src/lib/plugins/panel.css
new file mode 100644
index 0000000000..d2b2133667
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/plugins/panel.css
@@ -0,0 +1,110 @@
+.panel {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ flex: auto;
+}
+
+.swapitTitle {
+ margin: 0;
+ text-transform: uppercase;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.swapitTitle i {
+ padding-left: 6px;
+ font-size: 14px;
+}
+
+.swapitHeader {
+ display: flex;
+ align-items: center;
+ padding: 16px 24px 15px;
+ justify-content: space-between;
+ text-transform: uppercase;
+}
+
+.icons i {
+ height: 80%;
+ cursor: pointer;
+}
+
+.pluginsContainer {
+ height: 100%;
+ overflow-y: auto;
+}
+
+.titleInfo {
+ padding-left: 10px;
+}
+
+.versionBadge {
+ background-color: var(--light);
+ padding: 0 7px;
+ font-weight: bolder;
+ margin-left: 5px;
+ text-transform: lowercase;
+ cursor: default;
+}
+
+iframe {
+ height: 100%;
+ width: 100%;
+ border: 0;
+}
+
+.plugins {
+ height: 100%;
+}
+
+.plugItIn {
+ display: none;
+ height: 100%;
+}
+
+.plugItIn>div {
+ overflow-y: auto;
+ overflow-x: hidden;
+ height: 100%;
+ width: 100%;
+}
+
+.plugItIn.active {
+ display: block;
+}
+
+.pluginsContainer {
+ height: 100%;
+ overflow-y: hidden;
+}
+
+#editorView {
+ height: 100%;
+ width: 100%;
+ border: 0;
+ display: block;
+}
+
+#mainPanel {
+ height: 100%;
+ width: 100%;
+ border: 0;
+ display: block;
+}
+
+.mainPanel-wrap, .editor-wrap {
+ flex: 1;
+ min-height: 100px;
+}
+
+.terminal-wrap {
+ min-height: 35px;
+ height: 20%;
+}
+
+.terminal-wrap.minimized {
+ height: 2rem !important;
+}
diff --git a/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx
new file mode 100644
index 0000000000..37fa018c92
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx
@@ -0,0 +1,29 @@
+/* eslint-disable no-undef */
+import React, { useEffect, useState } from 'react' // eslint-disable-line
+import './panel.css'
+import RemixUIPanelPlugin from './panel-plugin'
+import { PluginRecord } from '../types'
+
+/* eslint-disable-next-line */
+export interface RemixPanelProps {
+ plugins: Record
+ header: JSX.Element
+}
+
+export function RemixPluginPanel (props: RemixPanelProps) {
+ return (
+ <>
+ {props.header}
+
+
+ {Object.values(props.plugins).map((pluginRecord) => {
+ return
+ })}
+
+
+ >
+
+ )
+}
+
+export default RemixPluginPanel
diff --git a/libs/remix-ui/panel/src/lib/types/index.ts b/libs/remix-ui/panel/src/lib/types/index.ts
new file mode 100644
index 0000000000..f8407033ab
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/types/index.ts
@@ -0,0 +1,9 @@
+import { Profile } from '@remixproject/plugin-utils'
+
+export type PluginRecord = {
+ profile: Profile
+ view: any
+ active: boolean
+ class?: string
+ minimized?: boolean
+ }
diff --git a/libs/remix-ui/panel/tsconfig.json b/libs/remix-ui/panel/tsconfig.json
new file mode 100644
index 0000000000..8bd701c578
--- /dev/null
+++ b/libs/remix-ui/panel/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "allowJs": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.lib.json"
+ }
+ ]
+}
diff --git a/libs/remix-ui/panel/tsconfig.lib.json b/libs/remix-ui/panel/tsconfig.lib.json
new file mode 100644
index 0000000000..b560bc4dec
--- /dev/null
+++ b/libs/remix-ui/panel/tsconfig.lib.json
@@ -0,0 +1,13 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "types": ["node"]
+ },
+ "files": [
+ "../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
+ "../../../node_modules/@nrwl/react/typings/image.d.ts"
+ ],
+ "exclude": ["**/*.spec.ts", "**/*.spec.tsx"],
+ "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
+}
diff --git a/libs/remix-ui/plugin-manager/src/types.d.ts b/libs/remix-ui/plugin-manager/src/types.d.ts
index d30ae31457..66ee57bc77 100644
--- a/libs/remix-ui/plugin-manager/src/types.d.ts
+++ b/libs/remix-ui/plugin-manager/src/types.d.ts
@@ -4,6 +4,7 @@ import { EventEmitter } from 'events'
import { Engine } from '@remixproject/engine/lib/engine'
import { PluginBase, Profile } from '@remixproject/plugin-utils'
import { IframePlugin, ViewPlugin, WebsocketPlugin } from '@remixproject/engine-web'
+import { IframeReactPlugin } from '@remix-ui/app'
/* eslint-disable camelcase */
interface SetPluginOptionType {
@@ -88,7 +89,7 @@ export class PluginManagerComponent extends ViewPlugin extends Plugin implements
render(): HTMLDivElement
getAndFilterPlugins: (filter?: string, profiles?: Profile[]) => void
triggerEngineEventListener: () => void
- activateAndRegisterLocalPlugin: (localPlugin: IframePlugin | WebsocketPlugin) => Promise
+ activateAndRegisterLocalPlugin: (localPlugin: IframePlugin | IframeReactPlugin | WebsocketPlugin) => Promise
activeProfiles: string[]
_paq: any
}
diff --git a/libs/remix-ui/solidity-unit-testing/.babelrc b/libs/remix-ui/solidity-unit-testing/.babelrc
index 09d67939cc..64a3748691 100644
--- a/libs/remix-ui/solidity-unit-testing/.babelrc
+++ b/libs/remix-ui/solidity-unit-testing/.babelrc
@@ -1,4 +1,4 @@
{
"presets": ["@nrwl/react/babel"],
"plugins": []
-}
+}
\ No newline at end of file
diff --git a/libs/remix-ui/solidity-unit-testing/.eslintrc.json b/libs/remix-ui/solidity-unit-testing/.eslintrc.json
index 5e100bf955..50e59482cf 100644
--- a/libs/remix-ui/solidity-unit-testing/.eslintrc.json
+++ b/libs/remix-ui/solidity-unit-testing/.eslintrc.json
@@ -1,9 +1,6 @@
{
"extends": ["plugin:@nrwl/nx/react", "../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
- "rules": {
- "@typescript-eslint/no-explicit-any": "off"
- },
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
diff --git a/libs/remix-ui/solidity-unit-testing/src/lib/logic/testTabLogic.ts b/libs/remix-ui/solidity-unit-testing/src/lib/logic/testTabLogic.ts
index 6b42bc128a..6e1af409a4 100644
--- a/libs/remix-ui/solidity-unit-testing/src/lib/logic/testTabLogic.ts
+++ b/libs/remix-ui/solidity-unit-testing/src/lib/logic/testTabLogic.ts
@@ -5,6 +5,7 @@ export class TestTabLogic {
fileManager
currentPath
helper
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor (fileManager: any, helper: any) {
this.fileManager = fileManager
this.helper = helper
@@ -26,7 +27,7 @@ export class TestTabLogic {
if (!path || !(/\S/.test(path))) return
path = this.helper.removeMultipleSlashes(path)
const fileProvider = this.fileManager.fileProviderOf(path.split('/')[0])
- fileProvider.exists(path).then((res: any) => {
+ fileProvider.exists(path).then((res: boolean) => {
if (!res) fileProvider.createDir(path)
})
}
@@ -35,11 +36,12 @@ export class TestTabLogic {
// Checking to ignore the value which contains only whitespaces
if (!path || !(/\S/.test(path))) return
const fileProvider = this.fileManager.fileProviderOf(path.split('/')[0])
- const res = await fileProvider.exists(path, (e: any, res: any) => { return res })
+ const res = await fileProvider.exists(path, (e: Error, res: boolean) => { return res })
return res
}
- generateTestFile (errorCb: any) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ generateTestFile (errorCb:any) {
let fileName = this.fileManager.currentFile()
const hasCurrent = !!fileName && this.fileManager.currentFile().split('.').pop().toLowerCase() === 'sol'
if (!hasCurrent) fileName = this.currentPath + '/newFile.sol'
@@ -47,7 +49,7 @@ export class TestTabLogic {
if (!fileProvider) return
const splittedFileName = fileName.split('/')
const fileNameToImport = (!hasCurrent) ? fileName : this.currentPath + '/' + splittedFileName[splittedFileName.length - 1]
- this.helper.createNonClashingNameWithPrefix(fileNameToImport, fileProvider, '_test', (error: any, newFile: any) => {
+ this.helper.createNonClashingNameWithPrefix(fileNameToImport, fileProvider, '_test', (error: Error, newFile: string) => {
if (error) return errorCb('Failed to create file. ' + newFile + ' ' + error)
const isFileCreated = fileProvider.set(newFile, this.generateTestContractSample(hasCurrent, fileName))
if (!isFileCreated) return errorCb('Failed to create test file ' + newFile)
@@ -72,7 +74,7 @@ export class TestTabLogic {
let files = []
try {
if (await this.fileManager.exists(this.currentPath)) files = await this.fileManager.readdir(this.currentPath)
- } catch (e: any) {
+ } catch (e: any) { // eslint-disable-line @typescript-eslint/no-explicit-any
throw e.message
}
for (const file in files) {
@@ -84,7 +86,7 @@ export class TestTabLogic {
// @todo(#2758): If currently selected file is compiled and compilation result is available,
// 'contractName' should be + '_testSuite'
- generateTestContractSample (hasCurrent: any, fileToImport: any, contractName = 'testSuite') {
+ generateTestContractSample (hasCurrent: boolean, fileToImport: string, contractName = 'testSuite') {
let relative = remixPath.relative(this.currentPath, remixPath.dirname(fileToImport))
if (relative === '') relative = '.'
const comment = hasCurrent ? `import "${relative}/${remixPath.basename(fileToImport)}";` : '// '
diff --git a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx
index 0e791fd0ec..6cb5bc3820 100644
--- a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx
+++ b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx
@@ -1,62 +1,84 @@
-import React, { useState, useRef, useEffect } from 'react' // eslint-disable-line
+import React, { useState, useRef, useEffect, ReactElement } from 'react' // eslint-disable-line
import { eachOfSeries } from 'async' // eslint-disable-line
+import type Web3 from 'web3'
import { canUseWorker, urlFromVersion } from '@remix-project/remix-solidity'
import { Renderer } from '@remix-ui/renderer' // eslint-disable-line
import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
import { format } from 'util'
import './css/style.css'
-const _paq = (window as any)._paq = (window as any)._paq || [] // eslint-disable-line
-
-/* eslint-disable-next-line */
-export interface SolidityUnitTestingProps { }
+const _paq = (window as any)._paq = (window as any)._paq || [] // eslint-disable-line @typescript-eslint/no-explicit-any
interface TestObject {
fileName: string
checked: boolean
}
-export const SolidityUnitTesting = (props: Record) => {
+interface TestResultInterface {
+ type: string
+ value: any // eslint-disable-line @typescript-eslint/no-explicit-any
+ time?: number
+ context?: string
+ errMsg?: string
+ filename: string
+ assertMethod?: string
+ returned?: string | number
+ expected?: string | number
+ location?: string
+ hhLogs?: []
+ web3?: Web3
+ debugTxHash?: string
+ rendered?: boolean
+}
+
+interface FinalResult {
+ totalPassing: number,
+ totalFailing: number,
+ totalTime: any, // eslint-disable-line @typescript-eslint/no-explicit-any
+ errors: any[], // eslint-disable-line @typescript-eslint/no-explicit-any
+}
+
+export const SolidityUnitTesting = (props: Record) => { // eslint-disable-line @typescript-eslint/no-explicit-any
const { helper, testTab, initialPath } = props
const { testTabLogic } = testTab
- const [toasterMsg, setToasterMsg] = useState('')
+ const [toasterMsg, setToasterMsg] = useState('')
- const [disableCreateButton, setDisableCreateButton] = useState(true)
- const [disableGenerateButton, setDisableGenerateButton] = useState(false)
- const [disableStopButton, setDisableStopButton] = useState(true)
- const [disableRunButton, setDisableRunButton] = useState(false)
- const [runButtonTitle, setRunButtonTitle] = useState('Run tests')
- const [stopButtonLabel, setStopButtonLabel] = useState('Stop')
+ const [disableCreateButton, setDisableCreateButton] = useState(true)
+ const [disableGenerateButton, setDisableGenerateButton] = useState(false)
+ const [disableStopButton, setDisableStopButton] = useState(true)
+ const [disableRunButton, setDisableRunButton] = useState(false)
+ const [runButtonTitle, setRunButtonTitle] = useState('Run tests')
+ const [stopButtonLabel, setStopButtonLabel] = useState('Stop')
- const [checkSelectAll, setCheckSelectAll] = useState(true)
- const [testsOutput, setTestsOutput] = useState([])
+ const [checkSelectAll, setCheckSelectAll] = useState(true)
+ const [testsOutput, setTestsOutput] = useState([])
- const [testsExecutionStoppedHidden, setTestsExecutionStoppedHidden] = useState(true)
- const [progressBarHidden, setProgressBarHidden] = useState(true)
- const [testsExecutionStoppedErrorHidden, setTestsExecutionStoppedErrorHidden] = useState(true)
+ const [testsExecutionStoppedHidden, setTestsExecutionStoppedHidden] = useState(true)
+ const [progressBarHidden, setProgressBarHidden] = useState(true)
+ const [testsExecutionStoppedErrorHidden, setTestsExecutionStoppedErrorHidden] = useState(true)
let [testFiles, setTestFiles] = useState([]) // eslint-disable-line
- const [pathOptions, setPathOptions] = useState([''])
+ const [pathOptions, setPathOptions] = useState([''])
- const [inputPathValue, setInputPathValue] = useState('tests')
+ const [inputPathValue, setInputPathValue] = useState('tests')
- let [readyTestsNumber, setReadyTestsNumber] = useState(0) // eslint-disable-line
- let [runningTestsNumber, setRunningTestsNumber] = useState(0) // eslint-disable-line
+ let [readyTestsNumber, setReadyTestsNumber] = useState(0) // eslint-disable-line
+ let [runningTestsNumber, setRunningTestsNumber] = useState(0) // eslint-disable-line
- const hasBeenStopped = useRef(false)
- const isDebugging = useRef(false)
- const allTests: any = useRef([])
- const selectedTests: any = useRef([])
- const currentErrors: any = useRef([])
+ const hasBeenStopped = useRef(false)
+ const isDebugging = useRef(false)
+ const allTests = useRef([])
+ const selectedTests = useRef([])
+ const currentErrors:any = useRef([]) // eslint-disable-line @typescript-eslint/no-explicit-any
const defaultPath = 'tests'
let areTestsRunning = false
- let runningTestFileName: any
- const filesContent: any = {}
- const testsResultByFilename: Record = {}
+ let runningTestFileName: string
+ const filesContent: Record> = {}
+ const testsResultByFilename: Record>> = {} // eslint-disable-line @typescript-eslint/no-explicit-any
const trimTestDirInput = (input: string) => {
if (input.includes('/')) return input.split('/').map(e => e.trim()).join('/')
@@ -71,7 +93,7 @@ export const SolidityUnitTesting = (props: Record) => {
setTestsExecutionStoppedErrorHidden(true)
}
- const updateForNewCurrent = async (file = null) => {
+ const updateForNewCurrent = async (file: string | null = null) => {
// Ensure that when someone clicks on compilation error and that opens a new file
// Test result, which is compilation error in this case, is not cleared
if (currentErrors.current) {
@@ -92,7 +114,7 @@ export const SolidityUnitTesting = (props: Record) => {
selectedTests.current = [...allTests.current]
updateTestFileList()
if (!areTestsRunning) await updateRunAction(file)
- } catch (e: any) {
+ } catch (e: any) { // eslint-disable-line @typescript-eslint/no-explicit-any
console.log(e)
setToasterMsg(e)
}
@@ -132,17 +154,17 @@ export const SolidityUnitTesting = (props: Record) => {
})
testTab.fileManager.events.on('noFileSelected', () => { }) // eslint-disable-line
- testTab.fileManager.events.on('currentFileChanged', async (file: any, provider: any) => await updateForNewCurrent(file))
+ testTab.fileManager.events.on('currentFileChanged', async (file: string) => await updateForNewCurrent(file))
}, []) // eslint-disable-line
const updateDirList = (path: string) => {
- testTabLogic.dirList(path).then((options: any) => {
+ testTabLogic.dirList(path).then((options: string[]) => {
setPathOptions(options)
})
}
- const handleTestDirInput = async (e: any) => {
+ const handleTestDirInput = async (e: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
let testDirInput = trimTestDirInput(e.target.value)
testDirInput = helper.removeMultipleSlashes(testDirInput)
if (testDirInput !== '/') testDirInput = helper.removeTrailingSlashes(testDirInput)
@@ -183,7 +205,7 @@ export const SolidityUnitTesting = (props: Record) => {
}
}
- const handleEnter = async (e: any) => {
+ const handleEnter = async (e: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
let inputPath = e.target.value
inputPath = helper.removeMultipleSlashes(trimTestDirInput(inputPath))
setInputPathValue(inputPath)
@@ -210,18 +232,18 @@ export const SolidityUnitTesting = (props: Record) => {
setPathOptions(pathOptions)
}
- const cleanFileName = (fileName: any, testSuite: any) => {
+ const cleanFileName = (fileName: string, testSuite: string) => {
return fileName ? fileName.replace(/\//g, '_').replace(/\./g, '_') + testSuite : fileName
}
- const startDebug = async (txHash: any, web3: any) => {
+ const startDebug = async (txHash: string, web3: Web3) => {
isDebugging.current = true
if (!await testTab.appManager.isActive('debugger')) await testTab.appManager.activatePlugin('debugger')
testTab.call('menuicons', 'select', 'debugger')
testTab.call('debugger', 'debug', txHash, web3)
}
- const printHHLogs = (logsArr: any, testName: any) => {
+ const printHHLogs = (logsArr: Record[], testName: string) => { // eslint-disable-line @typescript-eslint/no-explicit-any
let finalLogs = `${testName}: \n`
for (const log of logsArr) {
let formattedLog
@@ -262,9 +284,9 @@ export const SolidityUnitTesting = (props: Record) => {
}
}
- const renderContract = (filename: any, contract: any, index: number, withoutLabel = false) => {
+ const renderContract = (filename: string, contract: string|null, index: number, withoutLabel = false) => {
if (withoutLabel) {
- const contractCard: any = (
+ const contractCard: ReactElement = (
{contract ? contract : ''} ({filename})
@@ -291,20 +313,20 @@ export const SolidityUnitTesting = (props: Record) => {
)
}
// show contract and file name with label
- const ContractCard: any = (
+ const ContractCard: ReactElement = (
{label}{contract} ({filename})
)
setTestsOutput(prevCards => {
- const index = prevCards.findIndex((card: any) => card.props.id === runningTestFileName)
+ const index = prevCards.findIndex((card: ReactElement) => card.props.id === runningTestFileName)
prevCards[index] = ContractCard
return prevCards
})
}
- const renderTests = (tests: any, contract: any, filename: any) => {
- const index = tests.findIndex((test: any) => test.type === 'testFailure')
+ const renderTests = (tests: TestResultInterface[], contract: string, filename: string) => {
+ const index = tests.findIndex((test: TestResultInterface) => test.type === 'testFailure')
// show filename and contract
renderContract(filename, contract, index)
// show tests
@@ -321,7 +343,7 @@ export const SolidityUnitTesting = (props: Record
) => {
}
if (test.type === 'testPass') {
if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value)
- const testPassCard: any = (
+ const testPassCard: ReactElement = (
) => {
} else if (test.type === 'testFailure') {
if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value)
if (!test.assertMethod) {
- const testFailCard1: any = (
highlightLocation(test.location, test.filename)}
+ onClick={() => { if(test.location) highlightLocation(test.location, test.filename)}}
>
✘ {test.value}
@@ -356,10 +378,10 @@ export const SolidityUnitTesting = (props: Record
) => {
const preposition = test.assertMethod === 'equal' || test.assertMethod === 'notEqual' ? 'to' : ''
const method = test.assertMethod === 'ok' ? '' : test.assertMethod
const expected = test.assertMethod === 'ok' ? '\'true\'' : test.expected
- const testFailCard2: any = ( highlightLocation(test.location, test.filename)}
+ onClick={() => { if(test.location) highlightLocation(test.location, test.filename)}}
>
✘ {test.value}
@@ -396,7 +418,7 @@ export const SolidityUnitTesting = (props: Record
) => {
for (const contract of contracts) {
if (contract && contract !== 'summary' && contract !== 'errors') {
runningTestFileName = cleanFileName(filename, contract)
- const tests = fileTestsResult[contract]
+ const tests = fileTestsResult[contract] as TestResultInterface[]
if (tests?.length) {
renderTests(tests, contract, filename)
} else {
@@ -406,18 +428,18 @@ export const SolidityUnitTesting = (props: Record) => {
} else if (contract === 'errors' && fileTestsResult['errors']) {
const errors = fileTestsResult['errors']
if (errors && errors.errors) {
- errors.errors.forEach((err: any) => {
- const errorCard: any =
+ errors.errors.forEach((err: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
+ const errorCard: ReactElement =
setTestsOutput(prevCards => ([...prevCards, errorCard]))
})
} else if (errors && Array.isArray(errors) && (errors[0].message || errors[0].formattedMessage)) {
errors.forEach((err) => {
- const errorCard: any =
+ const errorCard: ReactElement =
setTestsOutput(prevCards => ([...prevCards, errorCard]))
})
} else if (errors && !errors.errors && !Array.isArray(errors)) {
// To track error like this: https://github.com/ethereum/remix/pull/1438
- const errorCard: any =
+ const errorCard: ReactElement =
setTestsOutput(prevCards => ([...prevCards, errorCard]))
}
}
@@ -425,7 +447,7 @@ export const SolidityUnitTesting = (props: Record) => {
// show summary
const testSummary = fileTestsResult['summary']
if (testSummary && testSummary.filename && !testSummary.rendered) {
- const summaryCard: any = (
+ const summaryCard: ReactElement = (
Result for {testSummary.filename}
Passed: {testSummary.passed}
Failed: {testSummary.failed}
@@ -437,7 +459,7 @@ export const SolidityUnitTesting = (props: Record) => {
}
}
- const testCallback = (result: any) => {
+ const testCallback = (result: Record) => { // eslint-disable-line @typescript-eslint/no-explicit-any
if (result.filename) {
if (!testsResultByFilename[result.filename]) {
testsResultByFilename[result.filename] = {}
@@ -455,7 +477,7 @@ export const SolidityUnitTesting = (props: Record) => {
}
}
- const resultsCallback = (_err: any, result: any, cb: any) => {
+ const resultsCallback = (_err: any, result: any, cb: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
// total stats for the test
// result.passingNum
// result.failureNum
@@ -463,7 +485,7 @@ export const SolidityUnitTesting = (props: Record) => {
cb()
}
- const updateFinalResult = (_errors: any, result: any, filename: any) => {
+ const updateFinalResult = (_errors: any, result: FinalResult|null, filename: string) => { // eslint-disable-line @typescript-eslint/no-explicit-any
++readyTestsNumber
setReadyTestsNumber(readyTestsNumber)
if (!result && (_errors && (_errors.errors || (Array.isArray(_errors) && (_errors[0].message || _errors[0].formattedMessage))))) {
@@ -500,14 +522,14 @@ export const SolidityUnitTesting = (props: Record) => {
}
}
- const runTest = (testFilePath: any, callback: any) => {
+ const runTest = (testFilePath: string, callback: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
isDebugging.current = false
if (hasBeenStopped.current) {
- updateFinalResult(null, null, null)
+ updateFinalResult(null, null, testFilePath)
return
}
- testTab.fileManager.readFile(testFilePath).then((content: any) => {
- const runningTests: any = {}
+ testTab.fileManager.readFile(testFilePath).then((content: string) => {
+ const runningTests: Record> = {}
runningTests[testFilePath] = { content }
filesContent[testFilePath] = { content }
const { currentVersion, evmVersion, optimize, runs, isUrl } = testTab.compileTab.getCurrentCompilerConfig()
@@ -519,24 +541,24 @@ export const SolidityUnitTesting = (props: Record) => {
usingWorker: canUseWorker(currentVersion),
runs
}
- const deployCb = async (file: any, contractAddress: any) => {
+ const deployCb = async (file: string, contractAddress: string) => {
const compilerData = await testTab.call('compilerArtefacts', 'getCompilerAbstract', file)
await testTab.call('compilerArtefacts', 'addResolvedContract', contractAddress, compilerData)
}
testTab.testRunner.runTestSources(
runningTests,
compilerConfig,
- (result: any) => testCallback(result),
- (_err: any, result: any, cb: any) => resultsCallback(_err, result, cb),
+ (result: Record) => testCallback(result), // eslint-disable-line @typescript-eslint/no-explicit-any
+ (_err: any, result: any, cb: any) => resultsCallback(_err, result, cb), // eslint-disable-line @typescript-eslint/no-explicit-any
deployCb,
- (error: any, result: any) => {
+ (error: any, result: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
updateFinalResult(error, result, testFilePath)
callback(error)
- }, (url: any, cb: any) => {
- return testTab.contentImport.resolveAndSave(url).then((result: any) => cb(null, result)).catch((error: any) => cb(error.message))
+ }, (url: string, cb: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
+ return testTab.contentImport.resolveAndSave(url).then((result: any) => cb(null, result)).catch((error: Error) => cb(error.message)) // eslint-disable-line @typescript-eslint/no-explicit-any
}, { testFilePath }
)
- }).catch((error: any) => {
+ }).catch((error: Error) => {
console.log(error)
if (error) return // eslint-disable-line
})
@@ -552,17 +574,17 @@ export const SolidityUnitTesting = (props: Record) => {
setDisableStopButton(false)
clearResults()
setProgressBarHidden(false)
- const tests = selectedTests.current
+ const tests: string[] = selectedTests.current
if (!tests || !tests.length) return
else setProgressBarHidden(false)
_paq.push(['trackEvent', 'solidityUnitTesting', 'runTests'])
- eachOfSeries(tests, (value: any, key: any, callback: any) => {
+ eachOfSeries(tests, (value: string, key: string, callback: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
if (hasBeenStopped.current) return
runTest(value, callback)
})
}
- const updateRunAction = async (currentFile: any = null) => {
+ const updateRunAction = async (currentFile: any = null) => { // eslint-disable-line @typescript-eslint/no-explicit-any
const isSolidityActive = await testTab.appManager.isActive('solidity')
if (!isSolidityActive || !selectedTests.current?.length) {
// setDisableRunButton(true)
@@ -586,7 +608,7 @@ export const SolidityUnitTesting = (props: Record) => {
return selectedTestsList.map(testFileObj => testFileObj.fileName)
}
- const toggleCheckbox = (eChecked: any, index: any) => {
+ const toggleCheckbox = (eChecked: boolean, index: number) => {
testFiles[index].checked = eChecked
setTestFiles(testFiles)
selectedTests.current = getCurrentSelectedTests()
@@ -603,7 +625,7 @@ export const SolidityUnitTesting = (props: Record) => {
} else setCheckSelectAll(false)
}
- const checkAll = (event: any) => {
+ const checkAll = (event: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
testFiles.forEach((testFileObj) => testFileObj.checked = event.target.checked)
setTestFiles(testFiles)
setCheckSelectAll(event.target.checked)
@@ -618,7 +640,7 @@ export const SolidityUnitTesting = (props: Record) => {
const updateTestFileList = () => {
if (allTests.current?.length) {
- testFiles = allTests.current.map((testFile: any) => { return { 'fileName': testFile, 'checked': true } })
+ testFiles = allTests.current.map((testFile: string) => { return { 'fileName': testFile, 'checked': true } })
setCheckSelectAll(true)
}
else
@@ -674,7 +696,7 @@ export const SolidityUnitTesting = (props: Record) => {
title="Generate sample test file."
disabled={disableGenerateButton}
onClick={async () => {
- testTabLogic.generateTestFile((err:any) => { if (err) setToasterMsg(err)})
+ testTabLogic.generateTestFile((err:any) => { if (err) setToasterMsg(err)}) // eslint-disable-line @typescript-eslint/no-explicit-any
await updateForNewCurrent()
}}
>
@@ -704,7 +726,7 @@ export const SolidityUnitTesting = (props: Record) => {
/>
Select all
-
{testFiles?.length ? testFiles.map((testFileObj: any, index) => {
+
{testFiles?.length ? testFiles.map((testFileObj: TestObject, index) => {
const elemId = `singleTest${testFileObj.fileName}`
return (
diff --git a/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts b/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts
index dafe6f78cf..d0efd289b5 100644
--- a/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts
+++ b/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts
@@ -106,8 +106,8 @@ export const registerErrorScriptRunnerAction = (on, commandName, commandFn, disp
})
}
-export const listenOnNetworkAction = async (event, isListening) => {
- event.trigger('listenOnNetWork', [isListening])
+export const listenOnNetworkAction = async (plugins, isListening) => {
+ plugins.txListener.setListenOnNetwork(isListening)
}
export const initListeningOnNetwork = (plugins, dispatch: React.Dispatch
) => {
diff --git a/libs/remix-ui/terminal/src/lib/custom-hooks/useDragTerminal.tsx b/libs/remix-ui/terminal/src/lib/custom-hooks/useDragTerminal.tsx
deleted file mode 100644
index aba4bbf6a5..0000000000
--- a/libs/remix-ui/terminal/src/lib/custom-hooks/useDragTerminal.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import React, { useEffect, useState } from 'react'
-
-export const useDragTerminal = (minHeight: number, defaultPosition: number) => {
- const [isOpen, setIsOpen] = useState(defaultPosition > minHeight)
- const [lastYPosition, setLastYPosition] = useState(0)
- const [terminalPosition, setTerminalPosition] = useState(defaultPosition)
- // Used to save position of the terminal when it is closed
- const [lastTerminalPosition, setLastTerminalPosition] = useState(defaultPosition)
- const [isDragging, setIsDragging] = useState(false)
-
- const handleDraggingStart = (event: React.MouseEvent) => {
- setLastYPosition(event.clientY)
- setIsDragging(true)
- }
-
- const handleDragging = (event: MouseEvent) => {
- event.preventDefault()
-
- if (isDragging) {
- const mouseYPosition = event.clientY
- const difference = lastYPosition - mouseYPosition
- const newTerminalPosition = terminalPosition + difference
- setTerminalPosition(newTerminalPosition)
- setLastYPosition(mouseYPosition)
- }
- }
-
- const handleDraggingEnd = () => {
- if (!isDragging) return
-
- setIsDragging(false)
-
- // Check terminal position to determine if it should be open or closed
- setIsOpen(terminalPosition > minHeight)
- }
-
- const handleToggleTerminal = (event: React.MouseEvent) => {
- event.preventDefault()
- event.stopPropagation()
-
- if (isOpen) {
- setLastTerminalPosition(terminalPosition)
- setLastYPosition(0)
- setTerminalPosition(minHeight)
- } else {
- setTerminalPosition(lastTerminalPosition <= minHeight ? 323 : lastTerminalPosition)
- }
-
- setIsOpen(!isOpen)
- }
-
- // Add event listeners for dragging
- useEffect(() => {
- document.addEventListener('mousemove', handleDragging)
- document.addEventListener('mouseup', handleDraggingEnd)
-
- return () => {
- document.removeEventListener('mousemove', handleDragging)
- document.removeEventListener('mouseup', handleDraggingEnd)
- }
- }, [handleDragging, handleDraggingEnd])
-
- // Reset terminal position
- useEffect(() => {
- if (!terminalPosition) {
- setTerminalPosition(defaultPosition)
- }
- }, [terminalPosition, setTerminalPosition])
-
- return {
- isOpen,
- terminalPosition,
- isDragging,
- handleDraggingStart,
- handleToggleTerminal
- }
-}
diff --git a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
index acb13ecd68..3536750efc 100644
--- a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
+++ b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useState, useEffect, useReducer, useRef, SyntheticEvent, MouseEvent } from 'react' // eslint-disable-line
import { registerCommandAction, registerLogScriptRunnerAction, registerInfoScriptRunnerAction, registerErrorScriptRunnerAction, registerWarnScriptRunnerAction, listenOnNetworkAction, initListeningOnNetwork } from './actions/terminalAction'
import { initialState, registerCommandReducer, addCommandHistoryReducer, registerScriptRunnerReducer } from './reducers/terminalReducer'
@@ -17,7 +18,6 @@ import RenderKnownTransactions from './components/RenderKnownTransactions' // es
import parse from 'html-react-parser'
import { EMPTY_BLOCK, KNOWN_TRANSACTION, RemixUiTerminalProps, UNKNOWN_TRANSACTION } from './types/terminalTypes'
import { wrapScript } from './utils/wrapScript'
-import { useDragTerminal } from './custom-hooks/useDragTerminal'
/* eslint-disable-next-line */
export interface ClipboardEvent extends SyntheticEvent {
@@ -25,10 +25,10 @@ export interface ClipboardEvent extends SyntheticEvent {
}
export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
- const { call, _deps, on, config, event, gistHandler, version } = props.plugin
+ const { call, _deps, on, config, event, version } = props.plugin
const [_cmdIndex, setCmdIndex] = useState(-1)
const [_cmdTemp, setCmdTemp] = useState('')
-
+ const [isOpen, setIsOpen] = useState(true)
const [newstate, dispatch] = useReducer(registerCommandReducer, initialState)
const [cmdHistory, cmdHistoryDispatch] = useReducer(addCommandHistoryReducer, initialState)
const [, scriptRunnerDispatch] = useReducer(registerScriptRunnerReducer, initialState)
@@ -79,24 +79,6 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const terminalMenuOffsetHeight = (terminalMenu.current && terminalMenu.current.offsetHeight) || 35
const terminalDefaultPosition = config.get('terminal-top-offset')
- const {
- isOpen,
- isDragging,
- terminalPosition,
- handleDraggingStart,
- handleToggleTerminal
- } = useDragTerminal(terminalMenuOffsetHeight, terminalDefaultPosition)
-
- // Check open state
- useEffect(() => {
- const resizeValue = isOpen ? [config.get('terminal-top-offset')] : []
- event.trigger('resize', resizeValue)
- }, [isOpen])
-
- useEffect(() => {
- event.trigger('resize', [terminalPosition])
- }, [terminalPosition])
-
const scrollToBottom = () => {
messagesEndRef.current.scrollIntoView({ behavior: 'smooth' })
}
@@ -106,6 +88,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
logHtml: (html) => {
scriptRunnerDispatch({ type: 'html', payload: { message: [html.innerText] } })
},
+
log: (message) => {
scriptRunnerDispatch({ type: 'log', payload: { message: [message] } })
}
@@ -178,7 +161,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
function loadgist (id, cb) {
- gistHandler.loadFromGist({ gist: id }, _deps.fileManager)
+ props.plugin.call('gistHandler', 'load', id)
if (cb) cb()
}
@@ -332,8 +315,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const listenOnNetwork = (e: any) => {
const isListening = e.target.checked
- // setIsListeningOnNetwork(isListening)
- listenOnNetworkAction(event, isListening)
+ listenOnNetworkAction(props.plugin, isListening)
}
const onChange = (event: any) => {
@@ -426,10 +408,14 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
setAutoCompleteState(prevState => ({ ...prevState, activeSuggestion: 0, showSuggestions: false }))
}
+ const handleToggleTerminal = () => {
+ setIsOpen(!isOpen)
+ props.plugin.call('layout', 'minimize', props.plugin.profile.name, isOpen)
+ }
+
return (
-
+
-
diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts
index fddabeba59..3dd6b16bbb 100644
--- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts
+++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts
@@ -117,11 +117,7 @@ export const loadWorkspacePreset = async (template: 'gist-template' | 'code-temp
obj['/' + 'gist-' + gistId + '/' + path] = data.files[element]
})
plugin.fileManager.setBatchFiles(obj, 'workspace', true, (errorLoadingFile) => {
- if (!errorLoadingFile) {
- const provider = plugin.fileManager.getProvider('workspace')
-
- provider.lastLoadedGistId = gistId
- } else {
+ if (errorLoadingFile) {
dispatch(displayNotification('', errorLoadingFile.message || errorLoadingFile, 'OK', null, () => {}, null))
}
})
diff --git a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts
index e046892df9..ef769f5c5b 100644
--- a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts
+++ b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts
@@ -672,9 +672,11 @@ const fetchDirectoryContent = (state: BrowserState, payload: { fileTree, path: s
return files
}
} else {
- if (payload.path === state.mode || payload.path === '/') {
+ if (payload.path === '/') {
+ const files = normalize(payload.fileTree, payload.path, payload.type)
+ return { [state.mode]: files }
+ } else if (payload.path === state.mode) {
let files = normalize(payload.fileTree, payload.path, payload.type)
-
files = _.merge(files, state[state.mode].files[state.mode])
if (deletePath) delete files[deletePath]
return { [state.mode]: files }
diff --git a/nx.json b/nx.json
index e1bc0d858a..f2aa009899 100644
--- a/nx.json
+++ b/nx.json
@@ -145,6 +145,9 @@
"remix-ui-tabs": {
"tags": []
},
+ "remix-ui-panel": {
+ "tags": []
+ },
"remix-ui-theme-module": {
"tags": []
},
diff --git a/package.json b/package.json
index a32a38bdb3..0a838a7a40 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,7 @@
"workspace-schematic": "nx workspace-schematic",
"dep-graph": "nx dep-graph",
"help": "nx help",
- "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-helper,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,remix-ui-app,remix-ui-tabs",
+ "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-helper,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,solidity-unit-testing,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,remix-ui-app,remix-ui-tabs,remix-ui-panel",
"build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"publish:libs": "npm run build:libs && lerna publish --skip-git && npm run bumpVersion:libs",
@@ -162,7 +162,7 @@
"chokidar": "^2.1.8",
"color-support": "^1.1.3",
"commander": "^2.20.3",
- "core-js": "^3.19.3",
+ "core-js": "^3.6.5",
"deep-equal": "^1.0.1",
"document-register-element": "1.13.1",
"ethereumjs-util": "^7.0.10",
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 4ef2c10dcb..21dfeb4ee8 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -69,8 +69,11 @@
"@remix-ui/tabs": ["libs/remix-ui/tabs/src/index.ts"],
"@remix-ui/helper": ["libs/remix-ui/helper/src/index.ts"],
"@remix-ui/app": ["libs/remix-ui/app/src/index.ts"],
- "@remix-ui/vertical-icons-panel": ["libs/remix-ui/vertical-icons-panel/src/index.ts"],
+ "@remix-ui/vertical-icons-panel": [
+ "libs/remix-ui/vertical-icons-panel/src/index.ts"
+ ],
"@remix-ui/theme-module": ["libs/remix-ui/theme-module/src/index.ts"],
+ "@remix-ui/panel": ["libs/remix-ui/panel/src/index.ts"],
"@remix-ui/editor-context-view": ["libs/remix-ui/editor-context-view/src/index.ts"],
"@remix-ui/solidity-unit-testing": [
"libs/remix-ui/solidity-unit-testing/src/index.ts"
diff --git a/workspace.json b/workspace.json
index 1718e70f69..76b236717f 100644
--- a/workspace.json
+++ b/workspace.json
@@ -82,16 +82,6 @@
"apps/remix-ide/src/assets/js/**/*.js"
]
}
- },
- "test": {
- "builder": "@nrwl/workspace:run-commands",
- "options": {
- "commands": [
- {
- "command": "csslint && node apps/remix-ide/test/index.js"
- }
- ]
- }
}
}
},
@@ -1117,6 +1107,21 @@
}
}
},
+ "remix-ui-panel": {
+ "root": "libs/remix-ui/panel",
+ "sourceRoot": "libs/remix-ui/panel/src",
+ "projectType": "library",
+ "architect": {
+ "lint": {
+ "builder": "@nrwl/linter:lint",
+ "options": {
+ "linter": "eslint",
+ "tsConfig": ["libs/remix-ui/panel/tsconfig.lib.json"],
+ "exclude": ["**/node_modules/**", "!libs/remix-ui/panel/**/*"]
+ }
+ }
+ }
+ },
"solidity-unit-testing": {
"root": "libs/remix-ui/solidity-unit-testing",
"sourceRoot": "libs/remix-ui/solidity-unit-testing/src",