add test app

rdesktop^2
filip mertens 2 years ago
parent c9297a4d8f
commit f275f0ae8a
  1. 2
      .gitignore
  2. 16
      apps/1test/.eslintrc.json
  3. 92
      apps/1test/.gitignore
  4. 35
      apps/1test/forge.config.ts
  5. 44
      apps/1test/package.json
  6. 38
      apps/1test/src/electron/electronPluginClient.ts
  7. 18
      apps/1test/src/electron/engine.ts
  8. 72
      apps/1test/src/electron/fsPlugin.ts
  9. 46
      apps/1test/src/electron/gitPlugin.ts
  10. 13
      apps/1test/src/global.d.ts
  11. 7
      apps/1test/src/index.css
  12. 12
      apps/1test/src/index.html
  13. 58
      apps/1test/src/index.ts
  14. 16
      apps/1test/src/preload.ts
  15. 157
      apps/1test/src/remix/lib/electronPluginConnector.ts
  16. 36
      apps/1test/src/remix/lib/fsPlugin.ts
  17. 36
      apps/1test/src/remix/lib/gitPlugin.ts
  18. 25
      apps/1test/src/renderer.ts
  19. 19
      apps/1test/tsconfig.json
  20. 18
      apps/1test/webpack.main.config.ts
  21. 10
      apps/1test/webpack.plugins.ts
  22. 19
      apps/1test/webpack.renderer.config.ts
  23. 31
      apps/1test/webpack.rules.ts
  24. 5961
      apps/1test/yarn.lock
  25. 4
      apps/remix-ide/project.json
  26. 4
      apps/remix-ide/src/app.js
  27. 3
      apps/remix-ide/src/app/plugins/parser/services/code-parser-antlr-service.ts
  28. 3
      apps/remix-ide/src/index.tsx
  29. 2
      apps/remixdesktop/project.json
  30. 7
      apps/remixdesktop/src/electronPluginClient.ts
  31. 14
      apps/remixdesktop/src/engine.ts
  32. 70
      apps/remixdesktop/src/fsPlugin.ts
  33. 14
      apps/remixdesktop/src/index.ts
  34. 12
      apps/remixdesktop/src/preload.ts
  35. 26
      apps/remixdesktop/webpack.config.js
  36. 4
      libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx

2
.gitignore vendored

@ -57,6 +57,6 @@ testem.log
.DS_Store .DS_Store
.vscode/settings.json .vscode/settings.json
.vscode/launch.json .vscode/launch.json
apps/1test/
apps/remixdesktop/.webpack apps/remixdesktop/.webpack
apps/remixdesktop/out apps/remixdesktop/out

@ -0,0 +1,16 @@
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/electron",
"plugin:import/typescript"
],
"parser": "@typescript-eslint/parser"
}

@ -0,0 +1,92 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
.DS_Store
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# Webpack
.webpack/
# Vite
.vite/
# Electron-Forge
out/

@ -0,0 +1,35 @@
import type { ForgeConfig } from '@electron-forge/shared-types';
import { MakerSquirrel } from '@electron-forge/maker-squirrel';
import { MakerZIP } from '@electron-forge/maker-zip';
import { MakerDeb } from '@electron-forge/maker-deb';
import { MakerRpm } from '@electron-forge/maker-rpm';
import { WebpackPlugin } from '@electron-forge/plugin-webpack';
import { mainConfig } from './webpack.main.config';
import { rendererConfig } from './webpack.renderer.config';
const config: ForgeConfig = {
packagerConfig: {},
rebuildConfig: {},
makers: [new MakerSquirrel({}), new MakerZIP({}, ['darwin']), new MakerRpm({}), new MakerDeb({})],
plugins: [
new WebpackPlugin({
mainConfig,
renderer: {
config: rendererConfig,
entryPoints: [
{
html: './src/index.html',
js: './src/renderer.ts',
name: 'main_window',
preload: {
js: './src/preload.ts',
},
},
],
},
}),
],
};
export default config;

@ -0,0 +1,44 @@
{
"name": "1test",
"productName": "1test",
"version": "1.0.0",
"description": "My Electron application description",
"main": ".webpack/main",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "eslint --ext .ts,.tsx ."
},
"keywords": [],
"author": {
"name": "filip mertens",
"email": "filip.mertens@ethereum.org"
},
"license": "MIT",
"devDependencies": {
"@electron-forge/cli": "^6.1.1",
"@electron-forge/maker-deb": "^6.1.1",
"@electron-forge/maker-rpm": "^6.1.1",
"@electron-forge/maker-squirrel": "^6.1.1",
"@electron-forge/maker-zip": "^6.1.1",
"@electron-forge/plugin-webpack": "^6.1.1",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"@vercel/webpack-asset-relocator-loader": "1.7.3",
"css-loader": "^6.0.0",
"electron": "25.0.0",
"eslint": "^8.0.1",
"eslint-plugin-import": "^2.25.0",
"fork-ts-checker-webpack-plugin": "^7.2.13",
"node-loader": "^2.0.0",
"style-loader": "^3.0.0",
"ts-loader": "^9.2.2",
"ts-node": "^10.0.0",
"typescript": "~4.5.4"
},
"dependencies": {
"electron-squirrel-startup": "^1.0.0"
}
}

@ -0,0 +1,38 @@
import { ClientConnector, connectClient, applyApi, Client, PluginClient } from '@remixproject/plugin'
import type { Message, Api, ApiMap } from '@remixproject/plugin-utils'
import { IRemixApi } from '@remixproject/plugin-api'
import { ipcMain } from 'electron'
import { mainWindow } from '..'
export class ElectronPluginClientConnector implements ClientConnector {
constructor(public IPCName: string) {
console.log('ElectronPluginClientConnector constructor', IPCName)
}
/** Send a message to the engine */
send(message: Partial<Message>) {
console.log('ElectronPluginConnector send', message)
mainWindow.webContents.send(this.IPCName + ':send', message)
}
/** Listen to message from the engine */
on(cb: (message: Partial<Message>) => void) {
console.log('ElectronPluginConnector on', cb)
ipcMain.on(this.IPCName + ':on', (event, message) => {
console.log('ElectronPluginConnector on message received', message)
cb(message)
})
}
}
export const createClient = <
P extends Api,
App extends ApiMap = Readonly<IRemixApi>
>(client: PluginClient<P, App> = new PluginClient(), IPCName: string): Client<P, App> => {
const c = client as any
connectClient(new ElectronPluginClientConnector(IPCName), c)
applyApi(c)
return c
}

@ -0,0 +1,18 @@
import { Engine, PluginManager, Plugin } from '@remixproject/engine';
import { ipcMain, ipcRenderer } from 'electron';
import { FSPlugin } from './fsPlugin';
import { GitPlugin } from './gitPlugin';
const engine = new Engine()
const appManager = new PluginManager()
const fsPlugin = new FSPlugin()
const gitPlugin = new GitPlugin()
engine.register(appManager)
engine.register(fsPlugin)
engine.register(gitPlugin)
//appManager.activatePlugin('fs')
ipcMain.on('engine:activatePlugin', (event, arg) => {
console.log('engine:activatePlugin', arg)
appManager.activatePlugin(arg)
})

@ -0,0 +1,72 @@
import { PluginClient } from "@remixproject/plugin";
import { createClient } from "./electronPluginClient"
import { Engine, PluginManager, Plugin } from '@remixproject/engine';
import fs from 'fs'
import { existsSync } from "fs-extra";
const profile = {
displayName: 'fs',
name: 'fs',
description: 'fs',
}
export class FSPlugin extends Plugin {
client: PluginClient
constructor(){
super(profile)
}
onActivation(): void {
console.log('fsPlugin onActivation')
this.client = new FSPluginClient()
}
}
class FSPluginClient extends PluginClient {
constructor(){
super()
this.methods = ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'exists']
createClient(this, 'fs')
this.onload(() => {
console.log('fsPluginClient onload')
})
}
async readdir(path: string): Promise<string[]> {
// call node fs.readdir
return fs.readdirSync(path)
}
async readFile(path: string): Promise<string> {
return fs.readFileSync(path, 'utf8')
}
async writeFile(path: string, content: string): Promise<void> {
return fs.writeFileSync(path, content, 'utf8')
}
async mkdir(path: string): Promise<void> {
return fs.mkdirSync(path)
}
async rmdir(path: string): Promise<void> {
return fs.rmdirSync(path)
}
async unlink(path: string): Promise<void> {
return fs.unlinkSync(path)
}
async rename(oldPath: string, newPath: string): Promise<void> {
return fs.renameSync(oldPath, newPath)
}
async stat(path: string): Promise<fs.Stats> {
return fs.statSync(path)
}
async exists(path: string): Promise<boolean> {
return existsSync(path)
}
}

@ -0,0 +1,46 @@
import { Plugin } from "@remixproject/engine";
import { PluginClient } from "@remixproject/plugin";
import { Profile } from "@remixproject/plugin-utils";
import { spawn } from "child_process";
import { createClient } from "./electronPluginClient";
const profile: Profile = {
name: 'git',
displayName: 'Git',
description: 'Git plugin',
}
export class GitPlugin extends Plugin {
client: PluginClient
constructor() {
super(profile)
}
onActivation(): void {
console.log('GitPlugin onActivation')
this.client = new GitPluginClient()
}
}
class GitPluginClient extends PluginClient {
constructor() {
super()
this.methods = ['log', 'status', 'add', 'commit', 'push', 'pull', 'clone', 'checkout', 'branch', 'merge', 'reset', 'revert', 'diff', 'stash', 'apply', 'cherryPick', 'rebase', 'tag', 'fetch', 'remote', 'config', 'show', 'init', 'help', 'version']
createClient(this, 'git')
this.onload(() => {
console.log('GitPluginClient onload')
})
}
async log(path: string): Promise<string> {
const log = spawn('git', ['log'], { cwd: path })
return new Promise((resolve, reject) => {
log.stdout.on('data', (data) => {
resolve(data.toString())
})
})
}
}

@ -0,0 +1,13 @@
export interface IElectronAPI {
activatePlugin: (name: string) => void
receiveFromFS: (cb: any) => void
sendToFS: (message: Partial<Message>) => void
receiveFromGit: (cb: any) => void
sendToGit: (message: Partial<Message>) => void
}
declare global {
interface Window {
api: IElectronAPI
}
}

@ -0,0 +1,7 @@
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
Arial, sans-serif;
margin: auto;
max-width: 38rem;
padding: 2rem;
}

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World!</title>
</head>
<body>
<h1>💖 Hello World!</h1>
<p>Welcome to your Electron application.</p>
</body>
</html>

@ -0,0 +1,58 @@
import { app, BrowserWindow } from 'electron';
import path from 'path';
// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
// whether you're running in development or production).
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) {
app.quit();
}
export let mainWindow: BrowserWindow;
const createWindow = (): void => {
// Create the browser window.
mainWindow = new BrowserWindow({
height: 800,
width: 600,
webPreferences: {
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY
},
});
// and load the index.html of the app.
mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
//mainWindow.maximize();
// Open the DevTools.
mainWindow.webContents.openDevTools();
require('./electron/engine')
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.

@ -0,0 +1,16 @@
import { Message } from '@remixproject/plugin-utils'
import { contextBridge, ipcRenderer } from 'electron'
console.log('preload.ts')
contextBridge.exposeInMainWorld('api', {
activatePlugin: (name: string) => {
console.log('activatePlugin', name)
ipcRenderer.send('engine:activatePlugin', name)
},
receiveFromFS: (cb:any) => ipcRenderer.on('fs:send', cb),
sendToFS: (message: Partial<Message>) => ipcRenderer.send('fs:on', message),
receiveFromGit: (cb:any) => ipcRenderer.on('git:send', cb),
sendToGit: (message: Partial<Message>) => ipcRenderer.send('git:on', message)
})

@ -0,0 +1,157 @@
import type { ExternalProfile, Profile, Message, PluginOptions } from '@remixproject/plugin-utils'
import { Plugin } from '@remixproject/engine';
export interface PluginConnectorOptions extends PluginOptions {
engine?:string
}
export abstract class ElectronPluginConnector extends Plugin {
protected loaded: boolean
protected id = 0
protected pendingRequest: Record<number, (result: any, error: Error | string) => void> = {}
protected options: PluginConnectorOptions
profile: Profile
constructor(profile: Profile) {
super(profile)
}
/**
* Send a message to the external plugin
* @param message the message passed to the plugin
*/
protected abstract send(message: Partial<Message>): void
/**
* Open connection with the plugin
* @param url The transformed url the plugin should connect to
*/
protected abstract connect(name: string): any | Promise<any>
/** Close connection with the plugin */
protected abstract disconnect(): any | Promise<any>
async activate() {
await this.connect(this.profile.name)
return super.activate()
}
async deactivate() {
this.loaded = false
await this.disconnect()
return super.deactivate()
}
/** Set options for an external plugin */
setOptions(options: Partial<PluginConnectorOptions> = {}) {
super.setOptions(options)
}
/** Call a method from this plugin */
protected callPluginMethod(key: string, payload: any[] = []): Promise<any> {
const action = 'request'
const id = this.id++
const requestInfo = this.currentRequest
const name = this.name
const promise = new Promise((res, rej) => {
this.pendingRequest[id] = (result: any[], error: Error | string) => error ? rej (error) : res(result)
})
this.send({ id, action, key, payload, requestInfo, name })
return promise
}
/** Perform handshake with the client if not loaded yet */
protected async handshake() {
console.log('ElectronPluginConnector handshake', this.loaded)
if (!this.loaded) {
this.loaded = true
let methods: string[];
try {
console.log('ElectronPluginConnector handshake calling plugin method')
methods = await this.callPluginMethod('handshake', [this.profile.name, this.options?.engine])
console.log('ElectronPluginConnector handshake methods', methods)
} catch (err) {
console.error('ElectronPluginConnector handshake error', err)
this.loaded = false
throw err;
}
if (methods) {
this.profile.methods = methods
this.call('manager', 'updateProfile', this.profile)
}
} else {
// If there is a broken connection we want send back the handshake to the plugin client
console.log('ElectronPluginConnector handshake already loaded')
return this.callPluginMethod('handshake', [this.profile.name, this.options?.engine])
}
}
/**
* React when a message comes from client
* @param message The message sent by the client
*/
protected async getMessage(message: Message) {
console.log('ElectronPluginConnector getMessage', message)
// Check for handshake request from the client
if (message.action === 'request' && message.key === 'handshake') {
return this.handshake()
}
switch (message.action) {
// Start listening on an event
case 'on':
case 'listen': {
const { name, key } = message
const action = 'notification'
this.on(name, key, (...payload: any[]) => this.send({ action, name, key, payload }))
break
}
case 'off': {
const { name, key } = message
this.off(name, key)
break
}
case 'once': {
const { name, key } = message
const action = 'notification'
this.once(name, key, (...payload: any) => this.send({ action, name, key, payload }))
break
}
// Emit an event
case 'emit':
case 'notification': {
if (!message.payload) break
this.emit(message.key, ...message.payload)
break
}
// Call a method
case 'call':
case 'request': {
const action = 'response'
try {
const payload = await this.call(message.name, message.key, ...message.payload)
const error: any = undefined
this.send({ ...message, action, payload, error })
} catch (err) {
const payload: any = undefined
const error = err.message || err
this.send({ ...message, action, payload, error })
}
break
}
case 'cancel': {
const payload = this.cancel(message.name, message.key)
break;
}
// Return result from exposed method
case 'response': {
const { id, payload, error } = message
this.pendingRequest[id](payload, error)
delete this.pendingRequest[id]
break
}
default: {
throw new Error('Message should be a notification, request or response')
}
}
}
}

@ -0,0 +1,36 @@
import { Engine, PluginManager, Plugin, PluginConnector } from '@remixproject/engine';
import { Message, Profile } from '@remixproject/plugin-utils';
import { ElectronPluginConnector } from './electronPluginConnector';
export class fsPlugin extends ElectronPluginConnector {
constructor(){
super({
displayName: 'fs',
name: 'fs',
description: 'fs',
})
}
onActivation(): void {
console.log('fsPlugin onActivation')
//window.api.activatePlugin('fs')
}
protected connect(name: string) {
console.log('fsPlugin connect', name)
window.api.activatePlugin(name)
window.api.receiveFromFS((event: any, message: any) => {
console.log('fsPlugin fsClientSend message received', message)
this.getMessage(message)
})
}
protected send(message: Partial<Message>): void {
console.log('fsPlugin send', message)
window.api.sendToFS(message)
}
protected disconnect() {
console.log('fsPlugin disconnect')
}
}

@ -0,0 +1,36 @@
import { Engine, PluginManager, Plugin, PluginConnector } from '@remixproject/engine';
import { Message, Profile } from '@remixproject/plugin-utils';
import { ElectronPluginConnector } from './electronPluginConnector';
export class gitPlugin extends ElectronPluginConnector {
constructor(){
super({
displayName: 'git',
name: 'git',
description: 'git',
})
}
onActivation(): void {
console.log('git onActivation')
//window.api.activatePlugin('fs')
}
protected connect(name: string) {
console.log('git connect', name)
window.api.activatePlugin(name)
window.api.receiveFromGit((event: any, message: any) => {
console.log('git fsClientSend message received', message)
this.getMessage(message)
})
}
protected send(message: Partial<Message>): void {
console.log('git send', message)
window.api.sendToGit(message)
}
protected disconnect() {
console.log('git disconnect')
}
}

@ -0,0 +1,25 @@
import { Engine, PluginManager, Plugin, PluginConnector } from '@remixproject/engine';
import { Profile } from '@remixproject/plugin-utils';
import { fsPlugin } from './remix/lib/fsPlugin';
import { gitPlugin } from './remix/lib/gitPlugin';
const engine = new Engine()
const appManager = new PluginManager()
const fs = new fsPlugin()
const git = new gitPlugin()
engine.register(appManager)
engine.register(fs)
engine.register(git)
//appManager.activatePlugin('fs')
appManager.activatePlugin('git')
setTimeout(async () => {
//const files = await appManager.call('fs', 'readdir', './')
//console.log('files', files)
const log = await appManager.call('git', 'log', './')
console.log('log', log)
}, 5000)

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ES6",
"allowJs": true,
"module": "commonjs",
"skipLibCheck": true,
"esModuleInterop": true,
"noImplicitAny": true,
"sourceMap": true,
"baseUrl": ".",
"outDir": "dist",
"moduleResolution": "node",
"resolveJsonModule": true,
"paths": {
"*": ["node_modules/*"]
}
},
"include": ["src/**/*"]
}

@ -0,0 +1,18 @@
import type { Configuration } from 'webpack';
import { rules } from './webpack.rules';
export const mainConfig: Configuration = {
/**
* This is the main entry point for your application, it's the first file
* that runs in the main process.
*/
entry: './src/index.ts',
// Put your normal webpack config below here
module: {
rules,
},
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css', '.json'],
},
};

@ -0,0 +1,10 @@
import type IForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const ForkTsCheckerWebpackPlugin: typeof IForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
export const plugins = [
new ForkTsCheckerWebpackPlugin({
logger: 'webpack-infrastructure',
}),
];

@ -0,0 +1,19 @@
import type { Configuration } from 'webpack';
import { rules } from './webpack.rules';
import { plugins } from './webpack.plugins';
rules.push({
test: /\.css$/,
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
});
export const rendererConfig: Configuration = {
module: {
rules,
},
plugins,
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css'],
},
};

@ -0,0 +1,31 @@
import type { ModuleOptions } from 'webpack';
export const rules: Required<ModuleOptions>['rules'] = [
// Add support for native node modules
{
// We're specifying native_modules in the test because the asset relocator loader generates a
// "fake" .node file which is really a cjs file.
test: /native_modules[/\\].+\.node$/,
use: 'node-loader',
},
{
test: /[/\\]node_modules[/\\].+\.(m?js|node)$/,
parser: { amd: false },
use: {
loader: '@vercel/webpack-asset-relocator-loader',
options: {
outputAssetBase: 'native_modules',
},
},
},
{
test: /\.tsx?$/,
exclude: /(node_modules|\.webpack)/,
use: {
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
},
];

File diff suppressed because it is too large Load Diff

@ -3,7 +3,7 @@
"$schema": "../../node_modules/nx/schemas/project-schema.json", "$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/remix-ide/src", "sourceRoot": "apps/remix-ide/src",
"projectType": "application", "projectType": "application",
"implicitDependencies": ["doc-gen", "doc-viewer", "etherscan", "vyper", "walletconnect"], "implicitDependencies": [],
"targets": { "targets": {
"build": { "build": {
"executor": "@nrwl/webpack:webpack", "executor": "@nrwl/webpack:webpack",
@ -41,7 +41,7 @@
"vendorChunk": false "vendorChunk": false
}, },
"desktop": { "desktop": {
"optimization": true, "optimization": false,
"generateIndexHtml": true, "generateIndexHtml": true,
"extractCss": false, "extractCss": false,
"vendorChunk": false, "vendorChunk": false,

@ -76,6 +76,10 @@ const { TabProxy } = require('./app/panels/tab-proxy.js')
class AppComponent { class AppComponent {
constructor() { constructor() {
console.log(window.electronAPI)
console.log(window)
this.appManager = new RemixAppManager({}) this.appManager = new RemixAppManager({})
this.queryParams = new QueryParams() this.queryParams = new QueryParams()
this._components = {} this._components = {}

@ -4,6 +4,7 @@ import { AstNode } from "@remix-project/remix-solidity"
import { CodeParser } from "../code-parser" import { CodeParser } from "../code-parser"
import { antlr } from '../types' import { antlr } from '../types'
import { pathToFileURL } from 'url' import { pathToFileURL } from 'url'
import isElectron from 'is-electron'
const SolidityParser = (window as any).SolidityParser = (window as any).SolidityParser || [] const SolidityParser = (window as any).SolidityParser = (window as any).SolidityParser || []
@ -45,7 +46,7 @@ export default class CodeParserAntlrService {
this.worker = new Worker(new URL('./antlr-worker', import.meta.url)) this.worker = new Worker(new URL('./antlr-worker', import.meta.url))
this.worker.postMessage({ this.worker.postMessage({
cmd: 'load', cmd: 'load',
url: document.location.protocol + '//' + document.location.host + '/assets/js/parser/antlr.js', url: isElectron()? 'assets/js/parser/antlr.js': document.location.protocol + '//' + document.location.host + '/assets/js/parser/antlr.js',
}); });
const self = this const self = this

@ -16,13 +16,14 @@ import { Storage } from '@remix-project/remix-lib'
} catch (e) { } } catch (e) { }
const theme = new ThemeModule() const theme = new ThemeModule()
theme.initTheme() theme.initTheme()
/*
render( render(
<React.StrictMode> <React.StrictMode>
<Preload></Preload> <Preload></Preload>
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root') document.getElementById('root')
) )
*/
})() })()

@ -10,7 +10,7 @@
"defaultConfiguration": "development", "defaultConfiguration": "development",
"options": { "options": {
"outputPath": "apps/remixdesktop/.webpack/main", "outputPath": "apps/remixdesktop/.webpack/main",
"main": "apps/remixdesktop/src/main.ts", "main": "apps/remixdesktop/src/index.ts",
"tsConfig": "apps/remixdesktop/tsconfig.json", "tsConfig": "apps/remixdesktop/tsconfig.json",
"assets": [ "assets": [
], ],

@ -1,17 +1,20 @@
import { ClientConnector, connectClient, applyApi, Client, PluginClient } from '@remixproject/plugin' import { ClientConnector, connectClient, applyApi, Client, PluginClient } from '@remixproject/plugin'
import type { Message, Api, ApiMap } from '@remixproject/plugin-utils' import type { Message, Api, ApiMap } from '@remixproject/plugin-utils'
import { IRemixApi } from '@remixproject/plugin-api' import { IRemixApi } from '@remixproject/plugin-api'
import { ipcMain } from 'electron'
import { mainWindow } from '.'
export class ElectronPluginConnector implements ClientConnector { export class ElectronPluginConnector implements ClientConnector {
/** Send a message to the engine */ /** Send a message to the engine */
send(message: Partial<Message>) { send(message: Partial<Message>) {
window.postMessage(message, '*') console.log('ElectronPluginConnector send', message)
mainWindow.webContents.send('fsClient:send', message)
} }
/** Listen to message from the engine */ /** Listen to message from the engine */
on(cb: (message: Partial<Message>) => void) { on(cb: (message: Partial<Message>) => void) {
console.log('ElectronPluginConnector on', cb)
} }
} }

@ -0,0 +1,14 @@
import { Engine, PluginManager, Plugin } from '@remixproject/engine';
import { ipcMain, ipcRenderer } from 'electron';
import { fsPlugin } from './fsPlugin';
const engine = new Engine()
const appManager = new PluginManager()
const plugin = new fsPlugin()
engine.register(appManager)
engine.register(plugin)
//appManager.activatePlugin('fs')
ipcMain.on('engine:activatePlugin', (event, arg) => {
appManager.activatePlugin(arg)
})

@ -0,0 +1,70 @@
import { PluginClient } from "@remixproject/plugin";
import { createClient } from "./electronPluginClient"
import { Engine, PluginManager, Plugin } from '@remixproject/engine';
import fs from 'fs'
import { existsSync } from "fs-extra";
const profile = {
displayName: 'fs',
name: 'fs',
description: 'fs',
}
export class fsPlugin extends Plugin {
client: PluginClient
constructor(){
super(profile)
}
onActivation(): void {
console.log('fsPlugin onActivation')
this.client = new fsPluginClient()
}
}
class fsPluginClient extends PluginClient {
constructor(){
super()
this.methods = ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'exists']
createClient(this)
this.onload()
}
async readdir(path: string): Promise<string[]> {
// call node fs.readdir
return fs.readdirSync(path)
}
async readFile(path: string): Promise<string> {
return fs.readFileSync(path, 'utf8')
}
async writeFile(path: string, content: string): Promise<void> {
return fs.writeFileSync(path, content, 'utf8')
}
async mkdir(path: string): Promise<void> {
return fs.mkdirSync(path)
}
async rmdir(path: string): Promise<void> {
return fs.rmdirSync(path)
}
async unlink(path: string): Promise<void> {
return fs.unlinkSync(path)
}
async rename(oldPath: string, newPath: string): Promise<void> {
return fs.renameSync(oldPath, newPath)
}
async stat(path: string): Promise<fs.Stats> {
return fs.statSync(path)
}
async exists(path: string): Promise<boolean> {
return existsSync(path)
}
}

@ -1,4 +1,5 @@
import { app, BrowserWindow } from 'electron'; import { app, BrowserWindow } from 'electron';
import path from 'path';
// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack // This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on // plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
// whether you're running in development or production). // whether you're running in development or production).
@ -9,15 +10,15 @@ declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
if (require('electron-squirrel-startup')) { if (require('electron-squirrel-startup')) {
app.quit(); app.quit();
} }
export let mainWindow: BrowserWindow;
const createWindow = (): void => { const createWindow = (): void => {
// Create the browser window. // Create the browser window.
const mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
height: 600, height: 600,
width: 800, width: 800,
// webPreferences: { webPreferences: {
// preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY
// }, },
}); });
// and load the index.html of the app. // and load the index.html of the app.
@ -26,6 +27,7 @@ const createWindow = (): void => {
mainWindow.maximize(); mainWindow.maximize();
// Open the DevTools. // Open the DevTools.
mainWindow.webContents.openDevTools(); mainWindow.webContents.openDevTools();
require('./engine')
}; };
// This method will be called when Electron has finished // This method will be called when Electron has finished
@ -52,3 +54,5 @@ app.on('activate', () => {
// In this file you can include the rest of your app's specific main process // In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here. // code. You can also put them in separate files and import them here.

@ -0,0 +1,12 @@
import { Message } from '@remixproject/plugin-utils'
import { contextBridge, ipcRenderer } from 'electron'
console.log('preload.ts')
contextBridge.exposeInMainWorld('api', {
activatePlugin: (name: string) => {
console.log('activatePlugin', name)
ipcRenderer.send('engine:activatePlugin', name)
}
})

@ -4,22 +4,33 @@ const TerserPlugin = require("terser-webpack-plugin")
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
// Nx plugins for webpack. // Nx plugins for webpack.
module.exports = composePlugins(withNx(), (config) => { module.exports = composePlugins((config) => {
config = {}
config.target = 'electron-main' config.target = 'electron-main'
config.devtool = 'source-map' config.devtool = 'source-map'
config.mode = 'production' config.mode = 'production'
config.output = { config.output = {
path: __dirname + '/.webpack/main', path: __dirname + '/.webpack/main',
filename: 'index.js', filename: '[name].js',
libraryTarget: 'commonjs2', }
config.target = 'electron-preload'
config.entry = {
index: ['./apps/remixdesktop/src/index.ts'],
preload: ['./apps/remixdesktop/src/preload.ts'],
} }
config.plugins.push( config.plugins= [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
MAIN_WINDOW_WEBPACK_ENTRY:`\`file://$\{require('path').resolve(__dirname, '..', 'renderer', 'index.html')}\``, MAIN_WINDOW_WEBPACK_ENTRY:`\`file://$\{require('path').resolve(__dirname, '..', 'renderer', 'index.html')}\``,
'process.env.MAIN_WINDOW_WEBPACK_ENTRY': `\`file://$\{require('path').resolve(__dirname, '..', 'renderer', 'index.html')}\``, 'process.env.MAIN_WINDOW_WEBPACK_ENTRY': `\`file://$\{require('path').resolve(__dirname, '..', 'renderer', 'index.html')}\``,
MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: `\`$\{require('path').resolve(__dirname, 'preload.js')}\``,
'process.env.MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY': `\`$\{require('path').resolve(__dirname, '..', 'render', 'preload.js')}\``,
}) })
) ]
config.module = {}
config.module.rules = [ config.module.rules = [
// Add support for native node modules // Add support for native node modules
{ {
@ -28,6 +39,7 @@ module.exports = composePlugins(withNx(), (config) => {
test: /native_modules[/\\].+\.node$/, test: /native_modules[/\\].+\.node$/,
use: 'node-loader', use: 'node-loader',
}, },
/*
{ {
test: /[/\\]node_modules[/\\].+\.(m?js|node)$/, test: /[/\\]node_modules[/\\].+\.(m?js|node)$/,
parser: { amd: false }, parser: { amd: false },
@ -38,6 +50,7 @@ module.exports = composePlugins(withNx(), (config) => {
}, },
}, },
}, },
*/
{ {
test: /\.tsx?$/, test: /\.tsx?$/,
exclude: /(node_modules|\.webpack)/, exclude: /(node_modules|\.webpack)/,
@ -49,6 +62,9 @@ module.exports = composePlugins(withNx(), (config) => {
}, },
}, },
]; ];
config.resolve = {}
config.resolve.extensions = [ '.js', '.ts', '.jsx', '.tsx', '.css' ]
config.target = 'electron-preload'
config.node = { config.node = {

@ -55,7 +55,7 @@ function HomeTabFeatured() {
</div> </div>
<div className="mx-1 px-1 d-flex"> <div className="mx-1 px-1 d-flex">
<a href="https://www.youtube.com/@EthereumRemix/videos" target="__blank"> <a href="https://www.youtube.com/@EthereumRemix/videos" target="__blank">
<img src={"/assets/img/YouTubeLogo.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img> <img src={"assets/img/YouTubeLogo.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img>
</a> </a>
<div className="h6 w-50 p-2 pl-4 align-self-center" style={{ flex: "1" }}> <div className="h6 w-50 p-2 pl-4 align-self-center" style={{ flex: "1" }}>
<h5><FormattedMessage id='home.remixYouTube' /></h5> <h5><FormattedMessage id='home.remixYouTube' /></h5>
@ -73,7 +73,7 @@ function HomeTabFeatured() {
</div> </div>
<div className="mx-1 px-1 d-flex"> <div className="mx-1 px-1 d-flex">
<a href="https://docs.google.com/forms/d/e/1FAIpQLSd0WsJnKbeJo-BGrnf7WijxAdmE4PnC_Z4M0IApbBfHLHZdsQ/viewform" target="__blank"> <a href="https://docs.google.com/forms/d/e/1FAIpQLSd0WsJnKbeJo-BGrnf7WijxAdmE4PnC_Z4M0IApbBfHLHZdsQ/viewform" target="__blank">
<img src={"/assets/img/remixRewardBetaTester_small.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img> <img src={"assets/img/remixRewardBetaTester_small.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img>
</a> </a>
<div className="h6 w-50 p-2 pl-4 align-self-center" style={{ flex: "1" }}> <div className="h6 w-50 p-2 pl-4 align-self-center" style={{ flex: "1" }}>
<h5><FormattedMessage id='home.betaTesting' /></h5> <h5><FormattedMessage id='home.betaTesting' /></h5>

Loading…
Cancel
Save