From 24956e430c5a32d947c10983a5c5a6be2a8cee26 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Sun, 8 Sep 2024 10:49:10 +0200 Subject: [PATCH] add script runner bridge --- apps/remix-ide/src/app.js | 9 +- apps/remix-ide/src/app/panels/terminal.tsx | 8 +- apps/remix-ide/src/app/plugins/matomo.ts | 2 +- .../remix-ide/src/app/tabs/compile-and-run.ts | 2 +- .../src/app/tabs/script-runner-ui.tsx | 87 +++++++++++++++++++ apps/remix-ide/src/assets/list.json | 14 ++- apps/remix-ide/src/remixAppManager.js | 10 ++- libs/remix-ui/scriptrunner/src/index.ts | 1 + .../scriptrunner/src/lib/script-runner-ui.tsx | 83 ++++++++++++++++++ libs/remix-ui/scriptrunner/src/lib/types.ts | 20 +++++ libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx | 2 +- .../src/lib/actions/terminalAction.ts | 9 +- .../terminal/src/lib/remix-ui-terminal.tsx | 2 +- .../workspace/src/lib/actions/index.ts | 2 +- tsconfig.paths.json | 5 +- 15 files changed, 238 insertions(+), 18 deletions(-) create mode 100644 apps/remix-ide/src/app/tabs/script-runner-ui.tsx create mode 100644 libs/remix-ui/scriptrunner/src/index.ts create mode 100644 libs/remix-ui/scriptrunner/src/lib/script-runner-ui.tsx create mode 100644 libs/remix-ui/scriptrunner/src/lib/types.ts diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index a3722c7572..17a84f0dc4 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -69,6 +69,7 @@ const remixLib = require('@remix-project/remix-lib') import { QueryParams } from '@remix-project/remix-lib' import { SearchPlugin } from './app/tabs/search' +import { ScriptRunnerUIPlugin } from './app/tabs/script-runner-ui' import { ElectronProvider } from './app/files/electronProvider' const Storage = remixLib.Storage @@ -221,6 +222,9 @@ class AppComponent { //----- search const search = new SearchPlugin() + //---------------- Script Runner UI Plugin ------------------------- + const scriptRunnerUI = new ScriptRunnerUIPlugin(this.engine) + //---- templates const templates = new TemplatesPlugin() @@ -371,7 +375,8 @@ class AppComponent { git, pluginStateLogger, matomo, - templateSelection + templateSelection, + scriptRunnerUI ]) //---- fs plugin @@ -611,7 +616,7 @@ class AppComponent { }) // activate solidity plugin - this.appManager.activatePlugin(['solidity', 'udapp', 'deploy-libraries', 'link-libraries', 'openzeppelin-proxy']) + this.appManager.activatePlugin(['solidity', 'udapp', 'deploy-libraries', 'link-libraries', 'openzeppelin-proxy', 'scriptRunnerBridge']) } } diff --git a/apps/remix-ide/src/app/panels/terminal.tsx b/apps/remix-ide/src/app/panels/terminal.tsx index 2cb89e3fcb..a30cf085bd 100644 --- a/apps/remix-ide/src/app/panels/terminal.tsx +++ b/apps/remix-ide/src/app/panels/terminal.tsx @@ -117,10 +117,10 @@ class Terminal extends Plugin { } onDeactivation() { - this.off('scriptRunner', 'log') - this.off('scriptRunner', 'info') - this.off('scriptRunner', 'warn') - this.off('scriptRunner', 'error') + this.off('scriptRunnerBridge', 'log') + this.off('scriptRunnerBridge', 'info') + this.off('scriptRunnerBridge', 'warn') + this.off('scriptRunnerBridge', 'error') } logHtml(html) { diff --git a/apps/remix-ide/src/app/plugins/matomo.ts b/apps/remix-ide/src/app/plugins/matomo.ts index 8aa8f61f70..688139d113 100644 --- a/apps/remix-ide/src/app/plugins/matomo.ts +++ b/apps/remix-ide/src/app/plugins/matomo.ts @@ -11,7 +11,7 @@ const profile = { version: '1.0.0' } -const allowedPlugins = ['LearnEth', 'etherscan', 'vyper', 'circuit-compiler', 'doc-gen', 'doc-viewer', 'solhint', 'walletconnect', 'scriptRunner', 'dgit'] +const allowedPlugins = ['LearnEth', 'etherscan', 'vyper', 'circuit-compiler', 'doc-gen', 'doc-viewer', 'solhint', 'walletconnect', 'scriptRunner', 'scriptRunnerBridge', 'dgit'] export class Matomo extends Plugin { diff --git a/apps/remix-ide/src/app/tabs/compile-and-run.ts b/apps/remix-ide/src/app/tabs/compile-and-run.ts index 63952747c9..9643cd78e9 100644 --- a/apps/remix-ide/src/app/tabs/compile-and-run.ts +++ b/apps/remix-ide/src/app/tabs/compile-and-run.ts @@ -62,7 +62,7 @@ export class CompileAndRun extends Plugin { if (clearAllInstances) { await this.call('udapp', 'clearAllInstances') } - await this.call('scriptRunner', 'execute', content, fileName) + await this.call('scriptRunnerBridge', 'execute', content, fileName) } catch (e) { this.call('notification', 'toast', e.message || e) } diff --git a/apps/remix-ide/src/app/tabs/script-runner-ui.tsx b/apps/remix-ide/src/app/tabs/script-runner-ui.tsx new file mode 100644 index 0000000000..d5072b80cd --- /dev/null +++ b/apps/remix-ide/src/app/tabs/script-runner-ui.tsx @@ -0,0 +1,87 @@ +import { IframePlugin, IframeProfile, ViewPlugin } from '@remixproject/engine-web' +import * as packageJson from '../../../../../package.json' +import React from 'react' // eslint-disable-line +import { ScriptRunnerUI } from '@remix-scriptrunner' // eslint-disable-line +import { Profile } from '@remixproject/plugin-utils' +import { Engine } from '@remixproject/engine' +const profile = { + name: 'scriptRunnerBridge', + displayName: 'Script Bridge', + methods: ['execute'], + events: ['log', 'info', 'warn', 'error'], + icon: 'assets/img/settings.webp', + description: 'Set up a script runner', + kind: '', + location: 'sidePanel', + version: packageJson.version, + maintainedBy: 'Remix' +} + +export class ScriptRunnerUIPlugin extends ViewPlugin { + engine: Engine + current: string + constructor(engine: Engine) { + super(profile) + console.log('ScriptRunnerUIPlugin', this) + this.engine = engine + } + + async onActivation () { + console.log('onActivation', this) + } + + async loadScriptRunner(name: string) { + console.log('loadScriptRunner', name, this) + const profile: IframeProfile = await this.call('manager', 'getProfile', 'scriptRunner') + const newProfile: IframeProfile = { + ...profile, + name: profile.name + name, + url: 'http://localhost:3000?template=' + name + } + console.log('loadScriptRunner', newProfile) + const plugin: IframePlugin = new IframePlugin(newProfile) + await this.engine.register(plugin) + + await this.call('manager', 'activatePlugin', newProfile.name) + this.current = newProfile.name + this.on(newProfile.name, 'log', this.log.bind(this)) + this.on(newProfile.name, 'info', this.log.bind(this)) + this.on(newProfile.name, 'warn', this.log.bind(this)) + this.on(newProfile.name, 'error', this.log.bind(this)) + } + + async execute (script: string, filePath: string) { + if(!this.current) await this.loadScriptRunner('default') + console.log('execute', script, filePath) + this.call(this.current, 'execute', script, filePath) + } + + async log(data: any){ + console.log('log', data) + this.emit('log', data) + } + + async warn(data: any){ + console.log('warn', data) + this.emit('warn', data) + } + + async error(data: any){ + console.log('error', data) + this.emit('error', data) + } + + async info(data: any){ + console.log('info', data) + this.emit('info', data) + } + + + render() { + return ( +
+ +
+ ) + } +} \ No newline at end of file diff --git a/apps/remix-ide/src/assets/list.json b/apps/remix-ide/src/assets/list.json index 6a55fff4f7..82f8fe17bb 100644 --- a/apps/remix-ide/src/assets/list.json +++ b/apps/remix-ide/src/assets/list.json @@ -1022,9 +1022,21 @@ "urls": [ "dweb:/ipfs/QmS5JdeXtYhGBvdgNTLWuBNHupyP623X4sf43fRbrgiTaA" ] + }, + { + "path": "soljson-v0.8.27+commit.40a35a09.js", + "version": "0.8.27", + "build": "commit.40a35a09", + "longVersion": "0.8.27+commit.40a35a09", + "keccak256": "0x68c7a06651a847fc9a60886a6ba590a2b20d87f2d4f9570bf70fbb2b901e7713", + "sha256": "0xd91c08277f801321af4e80958015aea18b41c01d2c6a38310a23014485b0e51c", + "urls": [ + "dweb:/ipfs/QmVTALD1WUQwRvEL19jgwrEFyBJMQmy9z32zvT6TAtYPY1" + ] } ], "releases": { + "0.8.27": "soljson-v0.8.27+commit.40a35a09.js", "0.8.26": "soljson-v0.8.26+commit.8a97fa7a.js", "0.8.25": "soljson-v0.8.25+commit.b61c2a91.js", "0.8.24": "soljson-v0.8.24+commit.e11b9ed9.js", @@ -1119,5 +1131,5 @@ "0.4.0": "soljson-v0.4.0+commit.acd334c9.js", "0.3.6": "soljson-v0.3.6+commit.3fc68da5.js" }, - "latestRelease": "0.8.26" + "latestRelease": "0.8.27" } \ No newline at end of file diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index f823069585..bf70a26fdb 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -24,6 +24,7 @@ let requiredModules = [ // services + layout views + system views 'blockchain', 'web3Provider', 'scriptRunner', + 'scriptRunnerBridge', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', @@ -107,6 +108,10 @@ const isVM = (name) => { return name.startsWith('vm') } +const isScriptRunner = (name) => { + return name.startsWith('scriptRunner') +} + export function isNative(name) { // nativePlugin allows to bypass the permission request @@ -139,7 +144,7 @@ export function isNative(name) { 'templateSelection', 'walletconnect' ] - return nativePlugins.includes(name) || requiredModules.includes(name) || isInjectedProvider(name) || isVM(name) + return nativePlugins.includes(name) || requiredModules.includes(name) || isInjectedProvider(name) || isVM(name) || isScriptRunner(name) } /** @@ -192,6 +197,8 @@ export class RemixAppManager extends PluginManager { } } await this.toggleActive(name) + }else{ + console.log('cannot deactivate', name) } } @@ -294,6 +301,7 @@ export class RemixAppManager extends PluginManager { return plugins.map(plugin => { if (plugin.name === 'dgit' && Registry.getInstance().get('platform').api.isDesktop()) { plugin.url = 'https://dgit4-76cc9.web.app/' } // temporary fix if (plugin.name === testPluginName) plugin.url = testPluginUrl + //console.log('plugin', plugin) return new IframePlugin(plugin) }) } diff --git a/libs/remix-ui/scriptrunner/src/index.ts b/libs/remix-ui/scriptrunner/src/index.ts new file mode 100644 index 0000000000..be8e8bb09c --- /dev/null +++ b/libs/remix-ui/scriptrunner/src/index.ts @@ -0,0 +1 @@ +export { ScriptRunnerUI } from './lib/script-runner-ui'; \ No newline at end of file diff --git a/libs/remix-ui/scriptrunner/src/lib/script-runner-ui.tsx b/libs/remix-ui/scriptrunner/src/lib/script-runner-ui.tsx new file mode 100644 index 0000000000..5fe5ad0bf4 --- /dev/null +++ b/libs/remix-ui/scriptrunner/src/lib/script-runner-ui.tsx @@ -0,0 +1,83 @@ +import React, { useEffect, useState } from "react"; +import { Accordion, Card, Button } from "react-bootstrap"; +import axios from "axios"; +import { ProjectConfiguration } from "./types"; +import { FormattedMessage } from "react-intl"; +import { faCheck, faToggleOn } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Profile } from "@remixproject/plugin-utils"; +import { IframeProfile, ViewProfile } from "@remixproject/engine-web"; +import { Plugin } from "@remixproject/engine"; + +export interface ScriptRunnerUIProps { + // Add your props here + loadScriptRunner: (name: string) => void; +} + +export const ScriptRunnerUI = (props: ScriptRunnerUIProps) => { + const { loadScriptRunner } = props; + const [configurations, setConfigurations] = useState([]); + const [activeKey, setActiveKey] = useState('default'); + const [activeConfig, setActiveConfig] = useState('default'); + + useEffect(() => { + // Fetch the JSON data from the localhost server using Axios + const fetchData = async () => { + try { + const response = await axios.get('http://localhost:3000/projects.json'); + setConfigurations(response.data); + } catch (error) { + console.error("Error fetching the projects data:", error); + } + }; + + fetchData(); + }, []); // Empty array ensures this effect runs once when the component mounts + + const handleSelect = (key) => { + console.log("Selected key:", key, activeKey); + setActiveConfig(key); + console.log(loadScriptRunner) + loadScriptRunner(key) + }; + + // Filter out unpublished configurations + const publishedConfigurations = configurations.filter((config) => config.publish); + + return ( +
+ + {publishedConfigurations.map((config: ProjectConfiguration, index) => ( +
+
+ + {config.name} + +
handleSelect(config.name)} className="pointer px-2"> + {activeConfig !== config.name ? + : + + } +
+
+ + + + <> +

Description: {config.description}

+

Dependencies:

+
    + {config.dependencies.map((dep, depIndex) => ( +
  • + {dep.name} (v{dep.version}) +
  • + ))} +
+
))} +
+ +
+ ); +}; + + diff --git a/libs/remix-ui/scriptrunner/src/lib/types.ts b/libs/remix-ui/scriptrunner/src/lib/types.ts new file mode 100644 index 0000000000..ff093b428b --- /dev/null +++ b/libs/remix-ui/scriptrunner/src/lib/types.ts @@ -0,0 +1,20 @@ +export interface Dependency { + version: string; + name: string; + alias?: string; + import: boolean; + require?: boolean; + windowImport?: boolean; + } + + export interface Replacements { + [key: string]: string; + } + + export interface ProjectConfiguration { + name: string; + publish: boolean; + description: string; + dependencies: Dependency[]; + replacements: Replacements; + } diff --git a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx index 311b4c166a..3f57709eca 100644 --- a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx +++ b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx @@ -209,7 +209,7 @@ export const TabsUI = (props: TabsUIProps) => { const path = active().substr(active().indexOf('/') + 1, active().length) const content = await props.plugin.call('fileManager', 'readFile', path) if (tabsState.currentExt === 'js' || tabsState.currentExt === 'ts') { - await props.plugin.call('scriptRunner', 'execute', content, path) + await props.plugin.call('scriptRunnerBridge', 'execute', content, path) _paq.push(['trackEvent', 'editor', 'clickRunFromEditor', tabsState.currentExt]) } else if (tabsState.currentExt === 'sol' || tabsState.currentExt === 'yul') { await props.plugin.call('solidity', 'compile', path) diff --git a/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts b/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts index ceeea496f7..0a8a6b5891 100644 --- a/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts +++ b/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts @@ -79,28 +79,29 @@ export const filterFnAction = (name: string, filterFn, dispatch: React.Dispatch< } export const registerLogScriptRunnerAction = (on, commandName, commandFn, dispatch: React.Dispatch) => { - on('scriptRunner', commandName, (msg) => { + console.log('registerLogScriptRunnerAction', commandName) + on('scriptRunnerBridge', commandName, (msg) => { commandFn.log.apply(commandFn, msg.data) // eslint-disable-line dispatch({ type: commandName, payload: { commandFn, message: msg.data } }) }) } export const registerInfoScriptRunnerAction = (on, commandName, commandFn, dispatch: React.Dispatch) => { - on('scriptRunner', commandName, (msg) => { + on('scriptRunnerBridge', commandName, (msg) => { commandFn.info.apply(commandFn, msg.data) // eslint-disable-line dispatch({ type: commandName, payload: { commandFn, message: msg.data } }) }) } export const registerWarnScriptRunnerAction = (on, commandName, commandFn, dispatch: React.Dispatch) => { - on('scriptRunner', commandName, (msg) => { + on('scriptRunnerBridge', commandName, (msg) => { commandFn.warn.apply(commandFn, msg.data) // eslint-disable-line dispatch({ type: commandName, payload: { commandFn, message: msg.data } }) }) } export const registerErrorScriptRunnerAction = (on, commandName, commandFn, dispatch: React.Dispatch) => { - on('scriptRunner', commandName, (msg) => { + on('scriptRunnerBridge', commandName, (msg) => { commandFn.error.apply(commandFn, msg.data) // eslint-disable-line dispatch({ type: commandName, payload: { commandFn, message: msg.data } }) }) 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 29f471be3a..b88b7da73e 100644 --- a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx +++ b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx @@ -245,7 +245,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => { await call('solcoder', 'solidity_answer', script) _paq.push(['trackEvent', 'ai', 'solcoder', 'askFromTerminal']) } else { - await call('scriptRunner', 'execute', script) + await call('scriptRunnerBridge', 'execute', script) } done() } catch (error) { diff --git a/libs/remix-ui/workspace/src/lib/actions/index.ts b/libs/remix-ui/workspace/src/lib/actions/index.ts index e10fa20d43..23b9598ce4 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.ts +++ b/libs/remix-ui/workspace/src/lib/actions/index.ts @@ -506,7 +506,7 @@ export const runScript = async (path: string) => { if (error) { return dispatch(displayPopUp(error)) } - plugin.call('scriptRunner', 'execute', content, path) + plugin.call('scriptRunnerBridge', 'execute', content, path) }) } diff --git a/tsconfig.paths.json b/tsconfig.paths.json index 3b4433ee92..c1c11be318 100644 --- a/tsconfig.paths.json +++ b/tsconfig.paths.json @@ -180,7 +180,10 @@ ], "@remix-api": [ "libs/remix-api/src/index.ts" - ] + ], + "@remix-scriptrunner": [ + "libs/remix-ui/scriptrunner/src/index.ts" + ], } } }