From 761febe0836b1b0d8f262959de369e91f4e632c3 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Wed, 5 Jan 2022 17:56:29 +0100 Subject: [PATCH 1/4] handle cancels & hide --- apps/remix-ide/src/app/panels/file-panel.js | 2 +- .../remixd-handle.tsx} | 143 +++++++++--------- apps/remix-ide/tsconfig.json | 1 + libs/remix-ui/app/src/index.ts | 1 + .../components/modals/dialogViewPlugin.tsx | 1 - .../src/lib/remix-app/context/provider.tsx | 4 +- .../app/src/lib/remix-app/interface/index.ts | 1 + .../app/src/lib/remix-app/reducer/modals.ts | 6 +- .../src/lib/remix-ui-modal-dialog.tsx | 14 +- 9 files changed, 91 insertions(+), 82 deletions(-) rename apps/remix-ide/src/app/{files/remixd-handle.js => plugins/remixd-handle.tsx} (56%) 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/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.
-
-
+
+
Before using, make sure remixd version is latest i.e. ${remixdVersion} -
Read here how to update it +

Read here how to update it
- ` + ) } diff --git a/apps/remix-ide/tsconfig.json b/apps/remix-ide/tsconfig.json index b3e2e7d0ca..052537730e 100644 --- a/apps/remix-ide/tsconfig.json +++ b/apps/remix-ide/tsconfig.json @@ -7,6 +7,7 @@ "allowSyntheticDefaultImports": true, "types": ["node", "jest"], "module": "es6", + "resolveJsonModule": true }, "files": [ "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", diff --git a/libs/remix-ui/app/src/index.ts b/libs/remix-ui/app/src/index.ts index 00999a2115..e00682a41b 100644 --- a/libs/remix-ui/app/src/index.ts +++ b/libs/remix-ui/app/src/index.ts @@ -2,3 +2,4 @@ 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' 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 index 248527075e..d5610de56c 100644 --- 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 @@ -7,7 +7,6 @@ const DialogViewPlugin = () => { const app = useContext(AppContext) useEffect(() => { - console.log(modal, app) app.modal.setDispatcher({ modal, alert, toast }) }, []) return <> 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 index cc25c381fd..73a3a97305 100644 --- a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx @@ -10,10 +10,10 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt const [{ modals, toasters, focusModal, focusToaster }, dispatch] = useReducer(reducer, initialState) const modal = (data: AppModal) => { - const { id, title, message, okLabel, okFn, cancelLabel, cancelFn, modalType, defaultValue } = data + 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 } + payload: { id, title, message, okLabel, okFn, cancelLabel, cancelFn, modalType: modalType || ModalTypes.default, defaultValue: defaultValue, hideFn } }) } 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 index feb7c5761f..dcfcd7a1eb 100644 --- a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts +++ b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts @@ -12,6 +12,7 @@ export interface AppModal { cancelFn: () => void, modalType?: ModalTypes, defaultValue?: string + hideFn?: () => void } export interface AlertModal { 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 index 951b547f16..cf202585f4 100644 --- a/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts +++ b/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts @@ -18,7 +18,8 @@ export const modalReducer = (state: ModalState = ModalInitialState, action: Moda cancelLabel: modalList[0].cancelLabel, cancelFn: modalList[0].cancelFn, modalType: modalList[0].modalType, - defaultValue: modalList[0].defaultValue + defaultValue: modalList[0].defaultValue, + hideFn: modalList[0].hideFn } modalList = modalList.slice() @@ -28,6 +29,9 @@ export const modalReducer = (state: ModalState = ModalInitialState, action: Moda return { ...state, modals: modalList } } case modalActionTypes.handleHideModal: + if (state.focusModal.hideFn) { + state.focusModal.hideFn() + } state.focusModal = { ...state.focusModal, hide: true, message: null } return { ...state } 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..524caaad62 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]) From 91053fb6b5e392581a5bafb1b3540c0646e8d693 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Wed, 5 Jan 2022 18:09:16 +0100 Subject: [PATCH 2/4] fix test --- apps/remix-ide-e2e/src/tests/remixd.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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"]') } From 3abfbdec6285f630483ef863e8490b911d147004 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Thu, 6 Jan 2022 10:15:44 +0100 Subject: [PATCH 3/4] flaky test --- apps/remix-ide-e2e/src/tests/importFromGithub.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts b/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts index 036d9ceae9..6bdd0b4b0c 100644 --- a/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts +++ b/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts @@ -48,8 +48,8 @@ module.exports = { 'Import From Github For Valid URL': function (browser: NightwatchBrowser) { browser .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) - .clickLaunchIcon('settings') - .clickLaunchIcon('filePanel') + .clickLaunchIcon('settings').pause(1000) + .clickLaunchIcon('filePanel').pause(1000) .scrollAndClick('*[data-id="landingPageImportFromGitHubButton"]') .waitForElementVisible('*[data-id="homeTabModalDialogCustomPromptText"]') .clearValue('*[data-id="homeTabModalDialogCustomPromptText"]') From a394e72debe3d21579f59acfa28a036ff26c321a Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Thu, 6 Jan 2022 10:24:57 +0100 Subject: [PATCH 4/4] flaky fix --- apps/remix-ide-e2e/src/tests/importFromGithub.test.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts b/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts index 6bdd0b4b0c..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').pause(1000) - .clickLaunchIcon('filePanel').pause(1000) .scrollAndClick('*[data-id="landingPageImportFromGitHubButton"]') .waitForElementVisible('*[data-id="homeTabModalDialogCustomPromptText"]') .clearValue('*[data-id="homeTabModalDialogCustomPromptText"]')