rdesktop
filip mertens 1 year ago
parent ac28db3a52
commit b106cc8cdf
  1. 13
      apps/1test/src/remix/lib/electronPlugin.ts
  2. 8
      apps/remix-ide/src/app/files/fileManager.ts
  3. 2
      apps/remix-ide/src/app/files/fileProvider.js
  4. 111
      apps/remix-ide/src/app/plugins/fsPlugin.ts
  5. 5
      apps/remixdesktop/src/engine.ts
  6. 37
      apps/remixdesktop/src/fsPlugin.ts
  7. 15
      apps/remixdesktop/src/gitPlugin.ts
  8. 36
      apps/remixdesktop/src/main.ts
  9. 24
      apps/remixdesktop/src/menus/commands.ts
  10. 56
      apps/remixdesktop/src/menus/darwin.ts
  11. 28
      apps/remixdesktop/src/menus/file.ts
  12. 26
      apps/remixdesktop/src/menus/main.ts
  13. 15
      apps/remixdesktop/src/xtermPlugin.ts
  14. 5
      libs/remix-ui/workspace/src/lib/actions/events.ts
  15. 99
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  16. 21
      package.json
  17. 139
      yarn.lock

@ -47,16 +47,11 @@ export abstract class ElectronPlugin extends Plugin {
* @param name The name of the plugin should connect to
*/
protected async connect(name: string) {
console.log('ElectronPluginConnector connect', name)
const r = await window.electronAPI.activatePlugin(name)
console.log('ElectronPluginConnector is connected', name, r)
/*
if(await window.electronAPI.activatePlugin(name) && !this.loaded){
console.log('ElectronPluginConnector calling handshake', name)
const connected = await window.electronAPI.activatePlugin(name)
if(connected && !this.loaded){
this.handshake()
}
*/
}
/** Close connection with the plugin */
protected disconnect(): any | Promise<any> {
@ -89,7 +84,6 @@ export abstract class ElectronPlugin extends Plugin {
/** 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[];
@ -170,7 +164,6 @@ export abstract class ElectronPlugin extends Plugin {
// Return result from exposed method
case 'response': {
const { id, payload, error } = message
console.log('ElectronPluginConnector getMessage response', message, this.pendingRequest)
this.pendingRequest[id](payload, error)
delete this.pendingRequest[id]
break

@ -155,8 +155,12 @@ class FileManager extends Plugin {
refresh() {
const provider = this.fileProviderOf('/')
// emit rootFolderChanged so that File Explorer reloads the file tree
provider.event.emit('rootFolderChanged', provider.workspace || '/')
this.emit('rootFolderChanged', provider.workspace || '/')
if(isElectron()){
provider.event.emit('refresh')
}else{
provider.event.emit('rootFolderChanged', provider.workspace || '/')
this.emit('rootFolderChanged', provider.workspace || '/')
}
}
/**

@ -286,12 +286,14 @@ class FileProvider {
if (path.indexOf('/') !== 0) path = '/' + path
try {
const files = await window.remixFileSystem.readdir(path)
console.log(files, 'files resolveDirectory')
const ret = {}
if (files) {
for (let element of files) {
path = path.replace(/^\/|\/$/g, '') // remove first and last slash
element = element.replace(/^\/|\/$/g, '') // remove first and last slash
const absPath = (path === '/' ? '' : path) + '/' + element
console.log(absPath, 'absPath')
ret[absPath.indexOf('/') === 0 ? absPath.substr(1, absPath.length) : absPath] = { isDirectory: (await window.remixFileSystem.stat(absPath)).isDirectory() }
// ^ ret does not accept path starting with '/'
}

@ -1,23 +1,25 @@
import { ElectronPlugin } from '@remixproject/engine-electron';
import once from 'just-once';
let workingDir = '/Volumes/bunsen/code/rmproject2/remix-project/apps/remix-ide/contracts/'
const fixPath = (path: string) => {
/*
// if it starts with /, it's an absolute path remove it
if (path.startsWith('/')) {
path = path.slice(1)
}
let workingDir = null
path = workingDir + path
*/
const fixPath = (path: string) => {
return path
}
function wrapCallback(opts, cb) {
if (typeof opts === "function") {
cb = opts;
}
cb = once(cb);
const resolve = (...args) => cb(null, ...args)
return [resolve, cb];
}
export class fsPlugin extends ElectronPlugin {
public fs: any
public fsSync: any
constructor() {
super({
@ -27,6 +29,20 @@ export class fsPlugin extends ElectronPlugin {
})
this.methods = ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'exists', 'setWorkingDir']
// List of commands all filesystems are expected to provide. `rm` is not
// included since it may not exist and must be handled as a special case
const commands = [
'readFile',
'writeFile',
'mkdir',
'rmdir',
'unlink',
'stat',
'lstat',
'readdir',
'readlink',
'symlink',
]
this.fs = {
@ -43,7 +59,7 @@ export class fsPlugin extends ElectronPlugin {
readdir: async (path: string) => {
path = fixPath(path)
console.log('readdir', path)
const files = await this.call('fs', 'readdir', path)
const files = await this.call('fs', 'readdir', path)
console.log('readdir', path, files)
return files
},
@ -55,9 +71,12 @@ export class fsPlugin extends ElectronPlugin {
path = fixPath(path)
return await this.call('fs', 'mkdir', path)
},
readFile: async (path: string) => {
readFile: async (path: string, options) => {
console.log('readFile', path, options)
path = fixPath(path)
return await this.call('fs', 'readFile', path)
const file = await this.call('fs', 'readFile', path)
console.log('readFile', path, file)
return file
}
,
rename: async (from: string, to: string) => {
@ -70,28 +89,86 @@ export class fsPlugin extends ElectronPlugin {
,
stat: async (path: string) => {
path = fixPath(path)
const stat = await this.call('fs', 'stat', path)
const stat = await this.call('fs', 'stat', path)
stat.isDirectory = () => stat.isDirectoryValue
stat.isFile = () => !stat.isDirectoryValue
//console.log('stat', path, stat)
return stat
},
lstat: async (path: string) => {
path = fixPath(path)
const stat = await this.call('fs', 'lstat', path)
stat.isDirectory = () => stat.isDirectoryValue
stat.isFile = () => !stat.isDirectoryValue
//console.log('stat', path, stat)
return stat
},
readlink: async (path: string) => {
path = fixPath(path)
return await this.call('fs', 'readlink', path)
},
symlink: async (target: string, path: string) => {
path = fixPath(path)
return await this.call('fs', 'symlink', target, path)
}
}
}
async onActivation() {
console.log('fsPluginClient onload', this.fs);
(window as any).remixFileSystem = this.fs
(window as any).remixFileSystem = this.fs;
/*(window as any).remixFileSystemCallback = {
readdir: (filepath, opts, cb) => {
console.log('readdir', filepath, opts)
const [resolve, reject] = wrapCallback(opts, cb);
(window as any).remixFileSystem.fs.readdir(filepath, opts).then(resolve).catch(reject);
},
readFile: (filepath, opts, cb) => {
console.log('readFile', filepath, opts)
const [resolve, reject] = wrapCallback(opts, cb);
(window as any).remixFileSystem.fs.readFile(filepath, opts).then(resolve).catch(reject)
},
writeFile: (filepath, content, opts, cb) => {
const [resolve, reject] = wrapCallback(opts, cb);
(window as any).remixFileSystem.fs.writeFile(filepath, content, opts).then(resolve).catch(reject)
},
mkdir: (filepath, opts, cb) => {
const [resolve, reject] = wrapCallback(opts, cb);
(window as any).remixFileSystem.fs.mkdir(filepath, opts).then(resolve).catch(reject)
},
rmdir: (filepath, opts, cb) => {
const [resolve, reject] = wrapCallback(opts, cb);
(window as any).remixFileSystem.fs.rmdir(filepath, opts).then(resolve).catch(reject)
},
unlink: (filepath, opts, cb) => {
const [resolve, reject] = wrapCallback(opts, cb);
(window as any).remixFileSystem.fs.unlink(filepath, opts).then(resolve).catch(reject)
},
stat: (filepath, opts, cb) => {
const [resolve, reject] = wrapCallback(opts, cb);
(window as any).remixFileSystem.fs.stat(filepath, opts).then(resolve).catch(reject)
}
};
*/
this.on('fs', 'workingDirChanged', (path: string) => {
this.on('fs', 'workingDirChanged', async (path: string) => {
console.log('change working dir', path)
workingDir = path
await this.call('fileManager', 'refresh')
})
}

@ -22,6 +22,11 @@ ipcMain.handle('manager:activatePlugin', async (event, plugin) => {
return await appManager.call(plugin, 'createClient', event.sender.id)
})
ipcMain.on('fs:openFolder', async (event) => {
console.log('fs:openFolder', event)
fsPlugin.openFolder(event)
})
ipcMain.handle('getWebContentsID', (event, message) => {
return event.sender.id
})

@ -13,25 +13,23 @@ const profile: Profile = {
export class FSPlugin extends ElectronBasePlugin {
clients: FSPluginClient[] = []
constructor() {
super(profile)
super(profile, clientProfile, FSPluginClient)
this.methods = [...super.methods, 'closeWatch']
}
async createClient(webContentsId: number): Promise<void> {
this.clients.push(new FSPluginClient(webContentsId))
}
async closeClient(webContentsId: number): Promise<void> {
console.log('closeClient', webContentsId)
}
async closeWatch(): Promise<void> {
for (const client of this.clients) {
await client.closeWatch()
}
}
openFolder(webContentsId: any): void {
const client = this.clients.find(c => c.webContentsId === webContentsId)
if (client) {
client.setWorkingDir()
}
}
}
const clientProfile: Profile = {
@ -45,13 +43,14 @@ class FSPluginClient extends ElectronBasePluginClient {
watcher: chokidar.FSWatcher
workingDir: string = '/Volumes/bunsen/code/rmproject2/remix-project/apps/remix-ide/contracts/'
constructor(webContentsId: number) {
super(webContentsId, clientProfile)
constructor(webContentsId: number, profile: Profile) {
super(webContentsId, profile)
this.onload(() => {
console.log('fsPluginClient onload')
})
}
async readdir(path: string): Promise<string[]> {
// call node fs.readdir
console.log('readdir', path)
@ -59,8 +58,8 @@ class FSPluginClient extends ElectronBasePluginClient {
return files
}
async readFile(path: string): Promise<string> {
return fs.readFile(this.fixPath(path), 'utf8')
async readFile(path: string, options: any ): Promise<string> {
return fs.readFile(this.fixPath(path), 'utf8')
}
async writeFile(path: string, content: string): Promise<void> {
@ -84,7 +83,7 @@ class FSPluginClient extends ElectronBasePluginClient {
}
async stat(path: string): Promise<any> {
const stat = await fs.stat(path)
const stat = await fs.stat(this.fixPath(path))
//console.log('stat', path, stat)
const isDirectory = stat.isDirectory()
return {
@ -93,6 +92,13 @@ class FSPluginClient extends ElectronBasePluginClient {
}
}
async lstat(path: string): Promise<any> {
const lstat = await fs.lstat(this.fixPath(path))
return lstat
}
async exists(path: string): Promise<boolean> {
return fs.access(this.fixPath(path)).then(() => true).catch(() => false)
}
@ -131,6 +137,7 @@ class FSPluginClient extends ElectronBasePluginClient {
if (path.startsWith('/')) {
path = path.slice(1)
}
if(!this.workingDir.endsWith('/')) this.workingDir = this.workingDir + '/'
path = this.workingDir + path
return path
}

@ -12,18 +12,9 @@ const profile: Profile = {
export class GitPlugin extends ElectronBasePlugin {
client: PluginClient
constructor() {
super(profile)
super(profile, clientProfile, GitPluginClient)
}
async createClient(webContentsId: number): Promise<void> {
this.clients.push(new GitPluginClient(webContentsId))
}
async closeClient(webContentsId: number): Promise<void> {
console.log('closeClient', webContentsId)
}
}
const clientProfile: Profile = {
@ -35,8 +26,8 @@ const clientProfile: Profile = {
class GitPluginClient extends ElectronBasePluginClient {
constructor(webContentsId: number) {
super(webContentsId, clientProfile)
constructor(webContentsId: number, profile: Profile) {
super(webContentsId, profile)
this.onload(() => {
console.log('GitPluginClient onload')
})

@ -1,4 +1,4 @@
import { app, BrowserWindow } from 'electron';
import { app, BrowserWindow, dialog, Menu } from 'electron';
import path from 'path';
@ -13,13 +13,8 @@ if (
isPackaged = true;
}
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) {
app.quit();
}
export let mainWindow: BrowserWindow;
const createWindow = (): void => {
export const createWindow = (): void => {
// Create the browser window.
mainWindow = new BrowserWindow({
height: 800,
@ -62,5 +57,32 @@ app.on('activate', () => {
}
});
const showAbout = () => {
void dialog.showMessageBox({
title: `About Remix`,
message: `Remix`,
detail: `Remix`,
buttons: [],
});
};
// 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.
const isMac = process.platform === 'darwin'
import FileMenu from './menus/file';
import MainMenu from './menus/main';
import darwinMenu from './menus/darwin';
import { execCommand } from './menus/commands';
const commandKeys: Record<string, string> = {
'window:new': 'CmdOrCtrl+N',
'folder:open': 'CmdOrCtrl+O',
};
const menu = [...(process.platform === 'darwin' ? [darwinMenu(commandKeys, execCommand, showAbout)] : []), FileMenu(commandKeys, execCommand)]
Menu.setApplicationMenu(Menu.buildFromTemplate(menu))

@ -0,0 +1,24 @@
import {app, Menu, BrowserWindow, ipcMain} from 'electron';
import { createWindow } from '../main';
const commands: Record<string, (focusedWindow?: BrowserWindow) => void> = {
'window:new': () => {
// If window is created on the same tick, it will consume event too
setTimeout(createWindow, 0);
},
'folder:open': (focusedWindow) => {
if (focusedWindow) {
ipcMain.emit('fs:openFolder', focusedWindow.webContents.id);
}
}
};
export const execCommand = (command: string, focusedWindow?: BrowserWindow) => {
const fn = commands[command];
if (fn) {
fn(focusedWindow);
}
};

@ -0,0 +1,56 @@
// This menu label is overrided by OSX to be the appName
// The label is set to appName here so it matches actual behavior
import {app, BrowserWindow, MenuItemConstructorOptions} from 'electron';
export default (
commandKeys: Record<string, string>,
execCommand: (command: string, focusedWindow?: BrowserWindow) => void,
showAbout: () => void
): MenuItemConstructorOptions => {
return {
label: `${app.name}`,
submenu: [
{
label: 'About Remix',
click() {
showAbout();
}
},
{
type: 'separator'
},
{
label: 'Preferences...',
accelerator: commandKeys['window:preferences'],
click() {
execCommand('window:preferences');
}
},
{
type: 'separator'
},
{
role: 'services',
submenu: []
},
{
type: 'separator'
},
{
role: 'hide'
},
{
role: 'hideOthers'
},
{
role: 'unhide'
},
{
type: 'separator'
},
{
role: 'quit'
}
]
};
};

@ -0,0 +1,28 @@
import {BrowserWindow, MenuItemConstructorOptions} from 'electron';
export default (
commandKeys: Record<string, string>,
execCommand: (command: string, focusedWindow?: BrowserWindow) => void
): MenuItemConstructorOptions => {
const isMac = process.platform === 'darwin';
return {
label: 'File',
submenu: [
{
label: 'New Window',
accelerator: commandKeys['window:new'],
click(item, focusedWindow) {
execCommand('window:new', focusedWindow);
}
},
{
label: 'Open Folder',
accelerator: commandKeys['folder:open'],
click(item, focusedWindow) {
execCommand('folder:open', focusedWindow);
}
}
]
};
};

@ -0,0 +1,26 @@
import {BrowserWindow, MenuItemConstructorOptions} from 'electron';
export default (
commandKeys: Record<string, string>,
execCommand: (command: string, focusedWindow?: BrowserWindow) => void
): MenuItemConstructorOptions => {
const isMac = process.platform === 'darwin';
return {
label: 'REMIX',
submenu: [
{
label: 'Close',
accelerator: commandKeys['pane:close'],
click(item, focusedWindow) {
execCommand('pane:close', focusedWindow);
}
},
{
label: isMac ? 'Close Window' : 'Quit',
role: 'close',
accelerator: commandKeys['window:close']
}
]
};
};

@ -14,16 +14,7 @@ const profile: Profile = {
export class XtermPlugin extends ElectronBasePlugin {
client: PluginClient
constructor() {
super(profile)
}
async createClient(webContentsId: number): Promise<void> {
console.log('createClient', webContentsId)
this.clients.push(new XtermPluginClient(webContentsId))
}
async closeClient(webContentsId: number): Promise<void> {
console.log('closeClient', webContentsId)
super(profile, clientProfile, XtermPluginClient)
}
}
@ -38,8 +29,8 @@ const clientProfile: Profile = {
class XtermPluginClient extends ElectronBasePluginClient {
terminals: pty.IPty[] = []
constructor(webContentsId: number) {
super(webContentsId, clientProfile)
constructor(webContentsId: number, profile: Profile) {
super(webContentsId, profile)
this.onload(() => {
console.log('XtermPluginClient onload')
})

@ -49,6 +49,7 @@ export const listenOnPluginEvents = (filePanelPlugin) => {
})
plugin.on('fileManager', 'rootFolderChanged', async (path: string) => {
console.log('rootFolderChanged', path)
rootFolderChanged(path)
})
@ -96,6 +97,10 @@ export const listenOnProviderEvents = (provider) => (reducerDispatch: React.Disp
await switchToWorkspace(workspaceProvider.workspace)
})
provider.event.on('refresh', () => {
fetchWorkspaceDirectory('/')
})
provider.event.on('connected', () => {
plugin.fileManager.setMode('localhost')
dispatch(setMode('localhost'))

@ -12,6 +12,7 @@ import { MenuItems, WorkSpaceState } from './types'
import { contextMenuActions } from './utils'
import FileExplorerContextMenu from './components/file-explorer-context-menu'
import { customAction } from '@remixproject/plugin-api'
import isElectron from 'is-electron'
const _paq = window._paq = window._paq || []
@ -684,45 +685,66 @@ export function Workspace () {
<div className='d-flex flex-column w-100 remixui_fileexplorer' data-id="remixUIWorkspaceExplorer" onClick={resetFocus}>
<div>
<header>
<div className="mx-2 my-2 d-flex flex-column">
<div className="d-flex">
{currentWorkspace !== LOCALHOST ? (<span className="remixui_topmenu d-flex">
<Dropdown id="workspacesMenuDropdown" data-id="workspacesMenuDropdown" onToggle={() => hideIconsMenu(!showIconsMenu)} show={showIconsMenu}>
<Dropdown.Toggle
as={CustomIconsToggle}
onClick={() => {
hideIconsMenu(!showIconsMenu)
}}
icon={'fas fa-bars'}
></Dropdown.Toggle>
<Dropdown.Menu as={CustomMenu} data-id="wsdropdownMenu" className='custom-dropdown-items remixui_menuwidth' rootCloseEvent="click">
<HamburgerMenu
createWorkspace={createWorkspace}
renameCurrentWorkspace={renameCurrentWorkspace}
downloadCurrentWorkspace={downloadCurrentWorkspace}
deleteCurrentWorkspace={deleteCurrentWorkspace}
deleteAllWorkspaces={deleteAllWorkspaces}
cloneGitRepository={cloneGitRepository}
downloadWorkspaces={downloadWorkspaces}
restoreBackup={restoreBackup}
hideIconsMenu={hideIconsMenu}
addGithubAction={addGithubAction}
addSlitherGithubAction={addSlitherGithubAction}
addHelperScripts={addHelperScripts}
addTsSolTestGithubAction={addTsSolTestGithubAction}
showIconsMenu={showIconsMenu}
hideWorkspaceOptions={ currentWorkspace === LOCALHOST }
hideLocalhostOptions={ currentWorkspace === NO_WORKSPACE }
/>
</Dropdown.Menu>
</Dropdown>
</span>) : null}
<span className="d-flex">
<label className="pl-1 form-check-label" htmlFor="workspacesSelect" style={{wordBreak: 'keep-all'}}>
<FormattedMessage id='filePanel.workspace' />
</label>
</span>
<div className="mx-2 mb-2 d-flex flex-column">
<div className="d-flex justify-content-between">
{!isElectron() ?
<span className="d-flex align-items-end">
<label className="pl-1 form-check-label" htmlFor="workspacesSelect" style={{wordBreak: 'keep-all'}}>
<FormattedMessage id='filePanel.workspace' />
</label>
</span>: null}
{currentWorkspace !== LOCALHOST && !isElectron() ? (<span className="remixui_menu remixui_topmenu d-flex justify-content-between align-items-end w-75">
<CustomTooltip
placement="top"
tooltipId="createWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.create' />}
>
<span
hidden={currentWorkspace === LOCALHOST}
id='workspaceCreate'
data-id='workspaceCreate'
onClick={(e) => {
e.stopPropagation()
createWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceCreate'])
}}
style={{ fontSize: 'medium' }}
className='far fa-plus remixui_menuicon d-flex align-self-end'
>
</span>
</CustomTooltip>
<Dropdown id="workspacesMenuDropdown" data-id="workspacesMenuDropdown" onToggle={() => hideIconsMenu(!showIconsMenu)} show={showIconsMenu}>
<Dropdown.Toggle
as={CustomIconsToggle}
onClick={() => {
hideIconsMenu(!showIconsMenu)
}}
icon={'fas fa-bars'}
></Dropdown.Toggle>
<Dropdown.Menu as={CustomMenu} data-id="wsdropdownMenu" className='custom-dropdown-items remixui_menuwidth' rootCloseEvent="click">
<HamburgerMenu
createWorkspace={createWorkspace}
renameCurrentWorkspace={renameCurrentWorkspace}
downloadCurrentWorkspace={downloadCurrentWorkspace}
deleteCurrentWorkspace={deleteCurrentWorkspace}
deleteAllWorkspaces={deleteAllWorkspaces}
cloneGitRepository={cloneGitRepository}
downloadWorkspaces={downloadWorkspaces}
restoreBackup={restoreBackup}
hideIconsMenu={hideIconsMenu}
addGithubAction={addGithubAction}
addSlitherGithubAction={addSlitherGithubAction}
addTsSolTestGithubAction={addTsSolTestGithubAction}
showIconsMenu={showIconsMenu}
hideWorkspaceOptions={ currentWorkspace === LOCALHOST }
hideLocalhostOptions={ currentWorkspace === NO_WORKSPACE }
/>
</Dropdown.Menu>
</Dropdown>
</span>) : null}
</div>
{!isElectron() ? (
<Dropdown id="workspacesSelect" data-id="workspacesSelect" onToggle={toggleDropdown} show={showDropdown}>
<Dropdown.Toggle
as={CustomToggle}
@ -767,6 +789,7 @@ export function Workspace () {
{ ((global.fs.browser.workspaces.length <= 0) || currentWorkspace === NO_WORKSPACE) && <Dropdown.Item onClick={() => { switchWorkspace(NO_WORKSPACE) }}>{ <span className="pl-3">NO_WORKSPACE</span> }</Dropdown.Item> }
</Dropdown.Menu>
</Dropdown>
) : null}
</div>
</header>
</div>

@ -134,15 +134,15 @@
"@openzeppelin/contracts": "^4.7.3",
"@openzeppelin/upgrades-core": "^1.22.0",
"@openzeppelin/wizard": "0.2.0",
"@remixproject/engine": "0.3.36",
"@remixproject/engine-electron": "0.3.36",
"@remixproject/engine-web": "0.3.36",
"@remixproject/plugin": "0.3.36",
"@remixproject/plugin-api": "0.3.36",
"@remixproject/plugin-electron": "0.3.36",
"@remixproject/plugin-utils": "0.3.36",
"@remixproject/plugin-webview": "0.3.36",
"@remixproject/plugin-ws": "0.3.36",
"@remixproject/engine": "0.3.37",
"@remixproject/engine-electron": "0.3.37",
"@remixproject/engine-web": "0.3.37",
"@remixproject/plugin": "0.3.37",
"@remixproject/plugin-api": "0.3.37",
"@remixproject/plugin-electron": "0.3.37",
"@remixproject/plugin-utils": "0.3.37",
"@remixproject/plugin-webview": "0.3.37",
"@remixproject/plugin-ws": "0.3.37",
"@types/nightwatch": "^2.3.1",
"@walletconnect/ethereum-provider": "^2.6.2",
"@walletconnect/sign-client": "^2.6.0",
@ -178,11 +178,12 @@
"http-server": "^14.1.1",
"intro.js": "^4.1.0",
"isbinaryfile": "^3.0.2",
"isomorphic-git": "^1.8.2",
"isomorphic-git": "^1.24.0",
"jquery": "^3.3.1",
"js-yaml": "^4.1.0",
"jspdf": "^2.5.1",
"jszip": "^3.6.0",
"just-once": "^2.2.0",
"latest-version": "^5.1.0",
"merge": "^2.1.1",
"npm-install-version": "^6.0.2",

@ -5131,82 +5131,82 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.2.tgz#0798c03351f0dea1a5a4cabddf26a55a7cbee590"
integrity sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ==
"@remixproject/engine-electron@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@remixproject/engine-electron/-/engine-electron-0.3.36.tgz#24304072b102d23ea76d88dd142c28ed991aa46b"
integrity sha512-ueiO48ViKyYgZgZmMreXyEk62cSlAzwukSyXnxI3T4G5ykKL0G461ocK3cSYfTKoZ/g0/j7oUz25I8wXtU3boA==
dependencies:
"@remixproject/engine" "0.3.36"
"@remixproject/plugin-api" "0.3.36"
"@remixproject/plugin-utils" "0.3.36"
"@remixproject/engine-web@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@remixproject/engine-web/-/engine-web-0.3.36.tgz#105328588fee0eee692f2e64aeb3faf2749ea56c"
integrity sha512-rNYZiEFplg9A3Vfb72zVxqrUE3rVFOss8uBcAhWPt0um8vl7cZ8nRoFc5pxgnvDh+ozRo5YbWR0fqmDA4OiIUw==
dependencies:
"@remixproject/engine" "0.3.36"
"@remixproject/plugin-api" "0.3.36"
"@remixproject/plugin-utils" "0.3.36"
"@remixproject/engine@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@remixproject/engine/-/engine-0.3.36.tgz#aa93210716ab959b1d39e08ea38c7357495381f3"
integrity sha512-D5sf8WJBS5cbjqZBDWo/hN5kT6YhkZysGy0Y1QWcQj48WhOYHawl6VMExMsqVXtPZzJTWHs2N/hXuoc6MF6xfg==
dependencies:
"@remixproject/plugin-api" "0.3.36"
"@remixproject/plugin-utils" "0.3.36"
"@remixproject/plugin-api@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-api/-/plugin-api-0.3.36.tgz#58a77184c17ddece59fc2b8e7dd30a92ddb164a2"
integrity sha512-T7/9FAhm499sFbOh/iuK05GRpTZwYJtXrlMUAGE9qhfo4ep62sJg0TLss1BRnfhkDBvlS10rqdF2wWTPQ9JSPA==
dependencies:
"@remixproject/plugin-utils" "0.3.36"
"@remixproject/plugin-electron@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-electron/-/plugin-electron-0.3.36.tgz#4b0067f3b42454f95625ed774a10751a6557b3ee"
integrity sha512-WM4u4zUs95adZxbC/GrMzfuCXfBde9TuoPeS2Nb9ysRQKj5eRfTIWiYrh9PxoezrEF8EYPo8gVrf9A+PGlKf3w==
dependencies:
"@remixproject/engine" "0.3.36"
"@remixproject/plugin" "0.3.36"
"@remixproject/plugin-api" "0.3.36"
"@remixproject/plugin-utils" "0.3.36"
"@remixproject/plugin-utils@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-utils/-/plugin-utils-0.3.36.tgz#92478cd820e23b42a911a3e6e3f88d759f34d395"
integrity sha512-gbTzp3rHVITVn45vgb/f+huo6C/zogUCTmzqOj+D9INaQR1Fr6XtOL8erKjD0pNBbyw3lxpRsDKEpRQVE7sMbg==
"@remixproject/engine-electron@0.3.37":
version "0.3.37"
resolved "https://registry.yarnpkg.com/@remixproject/engine-electron/-/engine-electron-0.3.37.tgz#5e14bcf08201603cfccff0761d6f8612b1f3d62f"
integrity sha512-XQea0a5SPtYtOl1XH8qu9AN+Fkc/LSZ8FYuxenFUeczqy9t4gxlPibLrCQXSlrcNEdoGhDE/DW/wltQoX8JLtg==
dependencies:
"@remixproject/engine" "0.3.37"
"@remixproject/plugin-api" "0.3.37"
"@remixproject/plugin-utils" "0.3.37"
"@remixproject/engine-web@0.3.37":
version "0.3.37"
resolved "https://registry.yarnpkg.com/@remixproject/engine-web/-/engine-web-0.3.37.tgz#cb9e09a135f9083202207039b2f5104278d4db1b"
integrity sha512-9FcJOm5xMOta5DE/JVMu2TnGcJpoe6MagG/NC89QrxJq8mCQSDgiFeSfqJhgFXye/hjlCmaO96aLgXIeoXMhWQ==
dependencies:
"@remixproject/engine" "0.3.37"
"@remixproject/plugin-api" "0.3.37"
"@remixproject/plugin-utils" "0.3.37"
"@remixproject/engine@0.3.37":
version "0.3.37"
resolved "https://registry.yarnpkg.com/@remixproject/engine/-/engine-0.3.37.tgz#995abd53c505f6f37eaa6550d81ec36f2e60d106"
integrity sha512-+dO32Bdgm2GLlamCnCWIPYX0v57Ft2vWGkFwXil1xiLvPttVOjnSPkqz9Xu0DAqDIqXIr4A15E2pHklVR+shLQ==
dependencies:
"@remixproject/plugin-api" "0.3.37"
"@remixproject/plugin-utils" "0.3.37"
"@remixproject/plugin-api@0.3.37":
version "0.3.37"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-api/-/plugin-api-0.3.37.tgz#2b5c628f81632bb0063e4c6afbce62085d20e883"
integrity sha512-bJ8oIpaI4qP3/Ku7jxXW3XRkTyQ2hjWX6N8yob3d/jjHtaJ/IorDx/vieGXQoJTPKAMPol0KVKCVCxx+xmzcUQ==
dependencies:
"@remixproject/plugin-utils" "0.3.37"
"@remixproject/plugin-electron@0.3.37":
version "0.3.37"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-electron/-/plugin-electron-0.3.37.tgz#e850b6aae55af1e7b0cd74f4583e8eeb946735ce"
integrity sha512-ZmkYLk9LEewPCqXIiMPJC8ZpgRjMW3dh2LbgeSGhKG0ly8pD5VuZj3/07iP/ZvjDNuTliX08gqvCru9/oOskqA==
dependencies:
"@remixproject/engine" "0.3.37"
"@remixproject/plugin" "0.3.37"
"@remixproject/plugin-api" "0.3.37"
"@remixproject/plugin-utils" "0.3.37"
"@remixproject/plugin-utils@0.3.37":
version "0.3.37"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-utils/-/plugin-utils-0.3.37.tgz#7068523398164976c2470f55837e93c6fa210489"
integrity sha512-Ow4gFf15ym7Sysza4hx4+QEYQHvluu0pDEj3GlNAMWAbvbjBGxb7O81b3Tvu7n8ywESYJlbIifNr++vYY63+PQ==
dependencies:
tslib "2.0.1"
"@remixproject/plugin-webview@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-webview/-/plugin-webview-0.3.36.tgz#38997745608952cc40ce5c668d0836d0d5279b12"
integrity sha512-9C/GQLDQzzX6g8MH9L54C+K/2FxBa4tCdlxUbPH9infTFvk/jcMjpd/CSAIBK4EfZCs1mL+1Opc8bX3VrfchpA==
"@remixproject/plugin-webview@0.3.37":
version "0.3.37"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-webview/-/plugin-webview-0.3.37.tgz#b38882fc8f05ba22405c0baa4bef9662652fec1a"
integrity sha512-LeKS05MXnVUM4xS9IUmKBE5HJzs3L5hvuqWcRosB6ASbhzzFu4h7zeDtBbjSK46dL6/3Ym/dDqdJM9e6I+Gltw==
dependencies:
"@remixproject/plugin" "0.3.36"
"@remixproject/plugin-api" "0.3.36"
"@remixproject/plugin-utils" "0.3.36"
"@remixproject/plugin" "0.3.37"
"@remixproject/plugin-api" "0.3.37"
"@remixproject/plugin-utils" "0.3.37"
axios "^0.21.1"
"@remixproject/plugin-ws@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-ws/-/plugin-ws-0.3.36.tgz#a80ccf5e7ae866bc53a79a7da4f36b67a0a33972"
integrity sha512-+vGwHd7KAgGsPoPph8T5mGkGthJagtwsb53LopZwbwDziMEWP7IVu44TcI46qR/+oBHLm0MmH1ukCzRAkbDu+w==
"@remixproject/plugin-ws@0.3.37":
version "0.3.37"
resolved "https://registry.yarnpkg.com/@remixproject/plugin-ws/-/plugin-ws-0.3.37.tgz#1f29d037a1743eb8b3da438f8a9dbdb3d322b9a4"
integrity sha512-fjGBrj3qP0UnraiG/opzMySxk0SdfABrx1PuM8f3c3tmZDdjTrVcsJ11NlNNvztOPkyY5fL4e2gXDUkpELKztg==
dependencies:
"@remixproject/plugin" "0.3.36"
"@remixproject/plugin-api" "0.3.36"
"@remixproject/plugin-utils" "0.3.36"
"@remixproject/plugin" "0.3.37"
"@remixproject/plugin-api" "0.3.37"
"@remixproject/plugin-utils" "0.3.37"
"@remixproject/plugin@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@remixproject/plugin/-/plugin-0.3.36.tgz#393867208ace117c8dbfd08adb4d5feec1b17d4b"
integrity sha512-+lFgfLI3vbiB6OQIkeX2Yx1EyKdIUGU1lJ7K51HwPfbGet5Y4w8qDMXBblRM1HhVe7bDYlBOzzbcil8/03Dsnw==
"@remixproject/plugin@0.3.37":
version "0.3.37"
resolved "https://registry.yarnpkg.com/@remixproject/plugin/-/plugin-0.3.37.tgz#d7b41a7fd03d712717eeb44526399e6c6ce6647c"
integrity sha512-3DgGCPE78ThfqGUJlrWwdArRol2nLZMBHTZpPxLE9K4tpspY7G1KV8HLB55mkX/uPVvVbNTRoFI4TNm87Jjiwg==
dependencies:
"@remixproject/plugin-api" "0.3.36"
"@remixproject/plugin-utils" "0.3.36"
"@remixproject/plugin-api" "0.3.37"
"@remixproject/plugin-utils" "0.3.37"
events "3.2.0"
"@restart/context@^2.1.4":
@ -18344,6 +18344,11 @@ just-once@1.1.0:
resolved "https://registry.yarnpkg.com/just-once/-/just-once-1.1.0.tgz#fe81a185ebaeeb0947a7e705bf01cb6808db0ad8"
integrity sha512-+rZVpl+6VyTilK7vB/svlMPil4pxqIJZkbnN7DKZTOzyXfun6ZiFeq2Pk4EtCEHZ0VU4EkdFzG8ZK5F3PErcDw==
just-once@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/just-once/-/just-once-2.2.0.tgz#e8ebc8c80838d0fdb0d3c888f1591d88ad4be4d7"
integrity sha512-Wo547FgUOUZ98jbrZ1KX8nRezdEdtgIlC2NK1u1RvR1oZ/WoU++FjprP8J8hRbaox776MHyeMZZED4DvhhHVjg==
keccak@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0"

Loading…
Cancel
Save