hometab & clone

rdesktop
filip mertens 1 year ago
parent e58d67345b
commit a1dceb706d
  1. 22
      apps/remix-ide/src/app.js
  2. 6
      apps/remix-ide/src/app/files/dgitProvider.js
  3. 44
      apps/remix-ide/src/app/files/electronProvider.ts
  4. 2
      apps/remix-ide/src/app/files/fileManager.ts
  5. 1
      apps/remix-ide/src/app/files/remixDProvider.js
  6. 2
      apps/remix-ide/src/app/panels/file-panel.js
  7. 0
      apps/remix-ide/src/app/plugins/electron/electronConfigPlugin.ts
  8. 1
      apps/remix-ide/src/app/plugins/electron/fsPlugin.ts
  9. 0
      apps/remix-ide/src/app/plugins/electron/isoGitPlugin.ts
  10. 15
      apps/remix-ide/src/app/plugins/electron/templatesPlugin.ts
  11. 31
      apps/remix-ide/src/app/plugins/remix-templates.ts
  12. 2
      apps/remix-ide/src/remixEngine.js
  13. 1
      apps/remixdesktop/package.json
  14. 15
      apps/remixdesktop/src/engine.ts
  15. 9
      apps/remixdesktop/src/main.ts
  16. 10
      apps/remixdesktop/src/menus/commands.ts
  17. 17
      apps/remixdesktop/src/menus/darwin.ts
  18. 6
      apps/remixdesktop/src/menus/file.ts
  19. 20
      apps/remixdesktop/src/menus/git.ts
  20. 48
      apps/remixdesktop/src/plugins/fsPlugin.ts
  21. 2
      apps/remixdesktop/src/plugins/gitPlugin.ts
  22. 33
      apps/remixdesktop/src/plugins/isoGitPlugin.ts
  23. 75
      apps/remixdesktop/src/plugins/templates.ts
  24. 2
      apps/remixdesktop/src/plugins/xtermPlugin.ts
  25. 2
      apps/remixdesktop/src/preload.ts
  26. 2807
      apps/remixdesktop/yarn.lock
  27. 34
      libs/remix-ui/home-tab/src/lib/components/homeTabFileElectron.tsx
  28. 7
      libs/remix-ui/home-tab/src/lib/components/homeTabGetStarted.tsx
  29. 6
      libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx
  30. 3
      libs/remix-ui/workspace/src/lib/actions/index.ts
  31. 24
      libs/remix-ui/workspace/src/lib/actions/workspace.ts
  32. 12
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx

@ -45,9 +45,13 @@ import { FileDecorator } from './app/plugins/file-decorator'
import { CodeFormat } from './app/plugins/code-format' import { CodeFormat } from './app/plugins/code-format'
import { SolidityUmlGen } from './app/plugins/solidity-umlgen' import { SolidityUmlGen } from './app/plugins/solidity-umlgen'
import { ContractFlattener } from './app/plugins/contractFlattener' import { ContractFlattener } from './app/plugins/contractFlattener'
import { fsPlugin } from './app/plugins/fsPlugin' import { TemplatesPlugin } from './app/plugins/remix-templates'
import { isoGitPlugin } from './app/plugins/isoGitPlugin' import { fsPlugin } from './app/plugins/electron/fsPlugin'
import { electronConfig } from './app/plugins/electronConfigPlugin' import { isoGitPlugin } from './app/plugins/electron/isoGitPlugin'
import { electronConfig } from './app/plugins/electron/electronConfigPlugin'
import { electronTemplates } from './app/plugins/electron/templatesPlugin'
const isElectron = require('is-electron') const isElectron = require('is-electron')
@ -116,7 +120,7 @@ class AppComponent {
name: 'fileproviders/workspace' name: 'fileproviders/workspace'
}) })
this._components.filesProviders.electron = new ElectronProvider() this._components.filesProviders.electron = new ElectronProvider(this.appManager)
Registry.getInstance().put({ Registry.getInstance().put({
api: this._components.filesProviders.electron, api: this._components.filesProviders.electron,
name: 'fileproviders/electron' name: 'fileproviders/electron'
@ -197,7 +201,8 @@ class AppComponent {
//----- search //----- search
const search = new SearchPlugin() const search = new SearchPlugin()
//---- templates
const templates = new TemplatesPlugin()
//---------------- Solidity UML Generator ------------------------- //---------------- Solidity UML Generator -------------------------
const solidityumlgen = new SolidityUmlGen(appManager) const solidityumlgen = new SolidityUmlGen(appManager)
@ -322,6 +327,7 @@ class AppComponent {
solidityumlgen, solidityumlgen,
contractFlattener, contractFlattener,
solidityScript, solidityScript,
templates
]) ])
//---- fs plugin //---- fs plugin
@ -332,6 +338,8 @@ class AppComponent {
this.engine.register([isoGit]) this.engine.register([isoGit])
const electronConfigPlugin = new electronConfig() const electronConfigPlugin = new electronConfig()
this.engine.register([electronConfigPlugin]) this.engine.register([electronConfigPlugin])
const templatesPlugin = new electronTemplates()
this.engine.register([templatesPlugin])
} }
// LAYOUT & SYSTEM VIEWS // LAYOUT & SYSTEM VIEWS
@ -447,10 +455,10 @@ class AppComponent {
await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'codeParser', 'codeFormatter', 'fileDecorator', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler']) await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'codeParser', 'codeFormatter', 'fileDecorator', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler'])
await this.appManager.activatePlugin(['settings']) await this.appManager.activatePlugin(['settings'])
await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder']) await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder'])
await this.appManager.activatePlugin(['solidity-script']) await this.appManager.activatePlugin(['solidity-script', 'remix-templates'])
if(isElectron()){ if(isElectron()){
await this.appManager.activatePlugin(['fs', 'isogit', 'electronconfig']) await this.appManager.activatePlugin(['fs', 'isogit', 'electronconfig', 'electronTemplates'])
} }
this.appManager.on( this.appManager.on(

@ -366,7 +366,7 @@ class DGitProvider extends Plugin {
async clone(input, workspaceName, workspaceExists = false) { async clone(input, workspaceName, workspaceExists = false) {
if (isElectron()) { if (isElectron()) {
const folder = await this.call('isogit', 'openFolder') const folder = await this.call('fs', 'selectFolder')
if (!folder) return false if (!folder) return false
console.log('folder', folder) console.log('folder', folder)
const cmd = { const cmd = {
@ -378,8 +378,8 @@ class DGitProvider extends Plugin {
input input
} }
const result = await this.call('isogit', 'clone', cmd) const result = await this.call('isogit', 'clone', cmd)
await this.call('fs', 'openWindow', folder) this.call('fs', 'openWindow', folder)
return result
} else { } else {
const permission = await this.askUserPermission('clone', 'Import multiple files into your workspaces.') const permission = await this.askUserPermission('clone', 'Import multiple files into your workspaces.')
if (!permission) return false if (!permission) return false

@ -7,8 +7,35 @@ declare global {
} }
export class ElectronProvider extends FileProvider { export class ElectronProvider extends FileProvider {
constructor () { constructor(appManager) {
super('') super('')
this._appManager = appManager
}
async init() {
this._appManager.on('fs', 'change', (event, path) => {
console.log('change', event, path)
switch (event) {
case 'add':
this.event.emit('fileAdded', path)
break
case 'unlink':
this.event.emit('fileRemoved', path)
break
case 'change':
this.event.emit('fileChanged', path)
break
case 'rename':
this.event.emit('fileRenamed', path)
break
case 'addDir':
this.event.emit('folderAdded', path)
break
case 'unlinkDir':
this.event.emit('fileRemoved', path)
}
})
} }
// isDirectory is already included // isDirectory is already included
@ -18,7 +45,7 @@ export class ElectronProvider extends FileProvider {
if (path.indexOf('/') !== 0) path = '/' + path if (path.indexOf('/') !== 0) path = '/' + path
try { try {
const files = await window.remixFileSystem.readdir(path) const files = await window.remixFileSystem.readdir(path)
console.log(files, 'files resolveDirectory ELECTRON') console.log(files.length, 'files resolveDirectory ELECTRON')
const ret = {} const ret = {}
if (files) { if (files) {
for (let element of files) { for (let element of files) {
@ -37,4 +64,17 @@ export class ElectronProvider extends FileProvider {
} }
} }
/**
* Removes the folder recursively
* @param {*} path is the folder to be removed
*/
async remove(path) {
console.log('remove', path)
try {
await window.remixFileSystem.rmdir(path)
} catch (error) {
console.log(error)
}
}
} }

@ -24,7 +24,7 @@ const profile = {
permission: true, permission: true,
version: packageJson.version, version: packageJson.version,
methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir',
'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'selectFolder', 'setFile', 'switchFile', 'refresh',
'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles', 'isGitRepo'], 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles', 'isGitRepo'],
kind: 'file-system' kind: 'file-system'
} }

@ -26,6 +26,7 @@ module.exports = class RemixDProvider extends FileProvider {
}) })
this._appManager.on('remixd', 'fileAdded', (path) => { this._appManager.on('remixd', 'fileAdded', (path) => {
console.log('fileAdded remixd', path)
this.event.emit('fileAdded', path) this.event.emit('fileAdded', path)
}) })

@ -30,7 +30,7 @@ const { SlitherHandle } = require('../files/slither-handle.js')
const profile = { const profile = {
name: 'filePanel', name: 'filePanel',
displayName: 'File explorer', displayName: 'File explorer',
methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getAvailableWorkspaceName', 'getWorkspaces', 'createWorkspace', 'setWorkspace', 'registerContextMenuItem', 'renameWorkspace', 'deleteWorkspace'], methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getAvailableWorkspaceName', 'getWorkspaces', 'createWorkspace', 'setWorkspace', 'registerContextMenuItem', 'renameWorkspace', 'deleteWorkspace', 'loadTemplate', 'clone'],
events: ['setWorkspace', 'workspaceRenamed', 'workspaceDeleted', 'workspaceCreated'], events: ['setWorkspace', 'workspaceRenamed', 'workspaceDeleted', 'workspaceCreated'],
icon: 'assets/img/fileManager.webp', icon: 'assets/img/fileManager.webp',
description: 'Remix IDE file explorer', description: 'Remix IDE file explorer',

@ -43,7 +43,6 @@ export class fsPlugin extends ElectronPlugin {
rmdir: async (path: string) => { rmdir: async (path: string) => {
path = fixPath(path) path = fixPath(path)
return await this.call('fs', 'rmdir', path) return await this.call('fs', 'rmdir', path)
}, },
readdir: async (path: string) => { readdir: async (path: string) => {
path = fixPath(path) path = fixPath(path)

@ -0,0 +1,15 @@
import { ElectronPlugin } from '@remixproject/engine-electron';
export class electronTemplates extends ElectronPlugin {
constructor() {
super({
displayName: 'electronTemplates',
name: 'electronTemplates',
description: 'templates',
})
}
onActivation(): void {
}
}

@ -0,0 +1,31 @@
import { Plugin } from '@remixproject/engine'
import * as templateWithContent from '@remix-project/remix-ws-templates'
const profile = {
name: 'remix-templates',
displayName: 'remix-templates',
description: 'Remix Templates plugin',
methods: ['getTemplate', 'loadTemplateInNewWindow'],
}
export class TemplatesPlugin extends Plugin {
constructor() {
super(profile)
}
async getTemplate (template: string, opts?: any) {
const templateList = Object.keys(templateWithContent)
if (!templateList.includes(template)) return
// @ts-ignore
const files = await templateWithContent[template](opts)
console.log('files for template ', files)
return files
}
// electron only method
async loadTemplateInNewWindow (template: string, opts?: any) {
const files = await this.getTemplate(template, opts)
this.call('electronTemplates', 'loadTemplateInNewWindow', files)
}
}

@ -20,6 +20,8 @@ export class RemixEngine extends Engine {
if (name === 'fetchAndCompile') return { queueTimeout: 60000 * 4 } if (name === 'fetchAndCompile') return { queueTimeout: 60000 * 4 }
if (name === 'walletconnect') return { queueTimeout: 60000 * 4 } if (name === 'walletconnect') return { queueTimeout: 60000 * 4 }
if (name === 'udapp') return { queueTimeout: 60000 * 4 } if (name === 'udapp') return { queueTimeout: 60000 * 4 }
if (name === 'fs') return { queueTimeout: 60000 * 4 }
if (name === 'isogit') return { queueTimeout: 60000 * 4 }
return { queueTimeout: 10000 } return { queueTimeout: 10000 }
} }

@ -22,6 +22,7 @@
"typescript": "^5.1.3" "typescript": "^5.1.3"
}, },
"dependencies": { "dependencies": {
"@remix-project/remix-ws-templates": "^1.0.19",
"electron-is-packaged": "^1.0.2", "electron-is-packaged": "^1.0.2",
"glob": "^10.2.7", "glob": "^10.2.7",
"node-pty": "^0.10.1" "node-pty": "^0.10.1"

@ -7,6 +7,7 @@ import { XtermPlugin } from './plugins/xtermPlugin';
import git from 'isomorphic-git' import git from 'isomorphic-git'
import { IsoGitPlugin } from './plugins/isoGitPlugin'; import { IsoGitPlugin } from './plugins/isoGitPlugin';
import { ConfigPlugin } from './plugins/configPlugin'; import { ConfigPlugin } from './plugins/configPlugin';
import { TemplatesPlugin } from './plugins/templates';
const engine = new Engine() const engine = new Engine()
const appManager = new PluginManager() const appManager = new PluginManager()
@ -15,12 +16,14 @@ const gitPlugin = new GitPlugin()
const xtermPlugin = new XtermPlugin() const xtermPlugin = new XtermPlugin()
const isoGitPlugin = new IsoGitPlugin() const isoGitPlugin = new IsoGitPlugin()
const configPlugin = new ConfigPlugin() const configPlugin = new ConfigPlugin()
const templatesPlugin = new TemplatesPlugin()
engine.register(appManager) engine.register(appManager)
engine.register(fsPlugin) engine.register(fsPlugin)
engine.register(gitPlugin) engine.register(gitPlugin)
engine.register(xtermPlugin) engine.register(xtermPlugin)
engine.register(isoGitPlugin) engine.register(isoGitPlugin)
engine.register(configPlugin) engine.register(configPlugin)
engine.register(templatesPlugin)
appManager.activatePlugin('electronconfig') appManager.activatePlugin('electronconfig')
appManager.activatePlugin('fs') appManager.activatePlugin('fs')
@ -36,6 +39,18 @@ ipcMain.on('fs:openFolder', async (event) => {
fsPlugin.openFolder(event) fsPlugin.openFolder(event)
}) })
ipcMain.on('template:open', async (event) => {
console.log('template:open', event)
templatesPlugin.openTemplate(event)
})
ipcMain.on('git:startclone', async (event) => {
console.log('git:startclone', event)
isoGitPlugin.startClone(event)
})
ipcMain.handle('getWebContentsID', (event, message) => { ipcMain.handle('getWebContentsID', (event, message) => {
return event.sender.id return event.sender.id
}) })

@ -46,10 +46,7 @@ export const createWindow = async (dir?: string): Promise<void> => {
}) })
windowSet.add(mainWindow) windowSet.add(mainWindow)
//mainWindow.webContents.openDevTools();
// Open the DevTools.
mainWindow.webContents.openDevTools();
}; };
// This method will be called when Electron has finished // This method will be called when Electron has finished
@ -97,6 +94,7 @@ import MainMenu from './menus/main';
import darwinMenu from './menus/darwin'; import darwinMenu from './menus/darwin';
import WindowMenu from './menus/window'; import WindowMenu from './menus/window';
import EditMenu from './menus/edit'; import EditMenu from './menus/edit';
import GitMenu from './menus/git';
import { execCommand } from './menus/commands'; import { execCommand } from './menus/commands';
const commandKeys: Record<string, string> = { const commandKeys: Record<string, string> = {
@ -107,7 +105,8 @@ const commandKeys: Record<string, string> = {
const menu = [...(process.platform === 'darwin' ? [darwinMenu(commandKeys, execCommand, showAbout)] : []), const menu = [...(process.platform === 'darwin' ? [darwinMenu(commandKeys, execCommand, showAbout)] : []),
FileMenu(commandKeys, execCommand), FileMenu(commandKeys, execCommand),
EditMenu(commandKeys, execCommand), EditMenu(commandKeys, execCommand),
WindowMenu(commandKeys, execCommand, []) WindowMenu(commandKeys, execCommand, []),
GitMenu(commandKeys, execCommand)
] ]
Menu.setApplicationMenu(Menu.buildFromTemplate(menu)) Menu.setApplicationMenu(Menu.buildFromTemplate(menu))

@ -11,6 +11,16 @@ const commands: Record<string, (focusedWindow?: BrowserWindow) => void> = {
if (focusedWindow) { if (focusedWindow) {
ipcMain.emit('fs:openFolder', focusedWindow.webContents.id); ipcMain.emit('fs:openFolder', focusedWindow.webContents.id);
} }
},
'template:open': (focusedWindow) => {
if (focusedWindow) {
ipcMain.emit('template:open', focusedWindow.webContents.id);
}
},
'git:startclone': (focusedWindow) => {
if (focusedWindow) {
ipcMain.emit('git:startclone', focusedWindow.webContents.id);
}
} }
}; };

@ -19,23 +19,6 @@ export default (
{ {
type: 'separator' type: 'separator'
}, },
{
label: 'Preferences...',
accelerator: commandKeys['window:preferences'],
click() {
execCommand('window:preferences');
}
},
{
type: 'separator'
},
{
role: 'services',
submenu: []
},
{
type: 'separator'
},
{ {
role: 'hide' role: 'hide'
}, },

@ -22,7 +22,13 @@ export default (
click(item, focusedWindow) { click(item, focusedWindow) {
execCommand('folder:open', focusedWindow); execCommand('folder:open', focusedWindow);
} }
},
{
label: 'Load Template in New Window',
click(item, focusedWindow) {
execCommand('template:open', focusedWindow);
} }
},
] ]
}; };
}; };

@ -0,0 +1,20 @@
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: 'Git',
submenu: [
{
label: 'Clone Repository in New Window',
click(item, focusedWindow) {
execCommand('git:startclone', focusedWindow);
}
}
]
};
};

@ -72,7 +72,7 @@ const clientProfile: Profile = {
name: 'fs', name: 'fs',
displayName: 'fs', displayName: 'fs',
description: 'fs', description: 'fs',
methods: ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'lstat', 'exists', 'currentPath', 'watch', 'closeWatch', 'setWorkingDir', 'openFolder', 'getRecentFolders', 'glob', 'openWindow'] methods: ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'lstat', 'exists', 'currentPath', 'watch', 'closeWatch', 'setWorkingDir', 'openFolder', 'getRecentFolders', 'glob', 'openWindow', 'selectFolder']
} }
class FSPluginClient extends ElectronBasePluginClient { class FSPluginClient extends ElectronBasePluginClient {
@ -83,6 +83,7 @@ class FSPluginClient extends ElectronBasePluginClient {
super(webContentsId, profile) super(webContentsId, profile)
this.onload(() => { this.onload(() => {
//console.log('fsPluginClient onload') //console.log('fsPluginClient onload')
this.window.webContents.openDevTools()
this.window.on('close', async () => { this.window.on('close', async () => {
console.log('close', this.webContentsId) console.log('close', this.webContentsId)
await this.removeFromOpenedFolders(this.workingDir) await this.removeFromOpenedFolders(this.workingDir)
@ -96,9 +97,11 @@ class FSPluginClient extends ElectronBasePluginClient {
// call node fs.readdir // call node fs.readdir
console.log('readdir', path) console.log('readdir', path)
if (!path) return [] if (!path) return []
const startTime = Date.now()
const files = await fs.readdir(this.fixPath(path), { const files = await fs.readdir(this.fixPath(path), {
withFileTypes: true withFileTypes: true
}) })
const result: any[] = [] const result: any[] = []
for (const file of files) { for (const file of files) {
const isDirectory = file.isDirectory() const isDirectory = file.isDirectory()
@ -107,6 +110,7 @@ class FSPluginClient extends ElectronBasePluginClient {
isDirectory isDirectory
}) })
} }
console.log('readdir', path, Date.now() - startTime)
return result return result
} }
@ -133,7 +137,7 @@ class FSPluginClient extends ElectronBasePluginClient {
isDirectory: (file as Path).isDirectory(), isDirectory: (file as Path).isDirectory(),
}) })
} }
console.log('glob', result) //console.log('glob', result)
return result return result
} }
@ -159,7 +163,10 @@ class FSPluginClient extends ElectronBasePluginClient {
} }
async rmdir(path: string): Promise<void> { async rmdir(path: string): Promise<void> {
return fs.rmdir(this.fixPath(path)) console.log('rmdir', this.fixPath(path))
return fs.rm(this.fixPath(path), {
recursive: true
})
} }
async unlink(path: string): Promise<void> { async unlink(path: string): Promise<void> {
@ -209,11 +216,25 @@ class FSPluginClient extends ElectronBasePluginClient {
return process.cwd() return process.cwd()
} }
async watch(path: string): Promise<void> { async watch(): Promise<void> {
if (this.watcher) this.watcher.close() if (this.watcher) this.watcher.close()
console.log('watch', this.workingDir)
this.watcher = this.watcher =
chokidar.watch(this.fixPath(path)).on('change', (path, stats) => { chokidar.watch(this.workingDir, {
this.emit('change', path, stats) ignorePermissionErrors: true, ignoreInitial: true,
ignored: [
'**/node_modules/**',
'**/.git/**',
]
}).on('all', (eventName, path, stats) => {
console.log('change', eventName, path, stats)
// remove workingDir from path
path = path.replace(this.workingDir, '')
try {
this.emit('change', eventName, path)
} catch (e) {
console.log('error emitting change', e)
}
}) })
} }
@ -253,6 +274,19 @@ class FSPluginClient extends ElectronBasePluginClient {
} }
async selectFolder(path?: string): Promise<string> {
let dirs: string[] | undefined
if (!path) {
dirs = dialog.showOpenDialogSync(this.window, {
properties: ['openDirectory', 'createDirectory', "showHiddenFiles"]
})
}
path = dirs && dirs.length && dirs[0] ? dirs[0] : path
if (!path) return ''
return path
}
async openFolder(path?: string): Promise<void> { async openFolder(path?: string): Promise<void> {
let dirs: string[] | undefined let dirs: string[] | undefined
@ -268,6 +302,7 @@ class FSPluginClient extends ElectronBasePluginClient {
await this.updateOpenedFolders(path) await this.updateOpenedFolders(path)
this.window.setTitle(this.workingDir) this.window.setTitle(this.workingDir)
console.log('setWorkingDir', path) console.log('setWorkingDir', path)
this.watch()
this.emit('workingDirChanged', path) this.emit('workingDirChanged', path)
} }
@ -277,6 +312,7 @@ class FSPluginClient extends ElectronBasePluginClient {
await this.updateRecentFolders(path) await this.updateRecentFolders(path)
await this.updateOpenedFolders(path) await this.updateOpenedFolders(path)
this.window.setTitle(this.workingDir) this.window.setTitle(this.workingDir)
this.watch()
this.emit('workingDirChanged', path) this.emit('workingDirChanged', path)
} }

@ -9,7 +9,7 @@ const profile: Profile = {
} }
export class GitPlugin extends ElectronBasePlugin { export class GitPlugin extends ElectronBasePlugin {
client: PluginClient clients: GitPluginClient[] = []
constructor() { constructor() {
super(profile, clientProfile, GitPluginClient) super(profile, clientProfile, GitPluginClient)
} }

@ -13,10 +13,17 @@ const profile: Profile = {
} }
export class IsoGitPlugin extends ElectronBasePlugin { export class IsoGitPlugin extends ElectronBasePlugin {
client: PluginClient clients: IsoGitPluginClient[] = []
constructor() { constructor() {
super(profile, clientProfile, IsoGitPluginClient) super(profile, clientProfile, IsoGitPluginClient)
} }
startClone(webContentsId: any): void {
const client = this.clients.find(c => c.webContentsId === webContentsId)
if (client) {
client.startClone()
}
}
} }
const parseInput = (input: any) => { const parseInput = (input: any) => {
@ -70,7 +77,7 @@ class IsoGitPluginClient extends ElectronBasePluginClient {
...await this.getGitConfig(), ...await this.getGitConfig(),
...cmd ...cmd
}) })
console.log('STATUS', status, await this.getGitConfig()) //console.log('STATUS', status, await this.getGitConfig())
return status return status
} }
@ -207,6 +214,7 @@ class IsoGitPluginClient extends ElectronBasePluginClient {
async clone(cmd: any) { async clone(cmd: any) {
console.log('clone') console.log('clone')
try {
const clone = await git.clone({ const clone = await git.clone({
...await this.getGitConfig(), ...await this.getGitConfig(),
...cmd, ...cmd,
@ -215,18 +223,10 @@ class IsoGitPluginClient extends ElectronBasePluginClient {
}) })
console.log('CLONE', clone) console.log('CLONE', clone)
return clone return clone
} catch (e) {
console.log('CLONE ERROR', e)
throw e
} }
async openFolder(path?: string): Promise<string> {
let dirs: string[] | undefined
if (!path) {
dirs = dialog.showOpenDialogSync(this.window, {
properties: ['openDirectory', 'createDirectory', "showHiddenFiles"]
})
}
path = dirs && dirs.length && dirs[0] ? dirs[0] : path
if (!path) return ''
return path
} }
async addremote(cmd: any) { async addremote(cmd: any) {
@ -294,10 +294,9 @@ class IsoGitPluginClient extends ElectronBasePluginClient {
} }
async startClone() {
this.call('filePanel' as any, 'clone')
}
} }

@ -0,0 +1,75 @@
import { PluginClient } from "@remixproject/plugin";
import { Profile } from "@remixproject/plugin-utils";
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron"
import * as templateWithContent from '@remix-project/remix-ws-templates'
import fs from 'fs/promises'
import { createWindow } from "../main";
import path from 'path'
const profile: Profile = {
name: 'electronTemplates',
displayName: 'electronTemplates',
description: 'Templates plugin',
}
export class TemplatesPlugin extends ElectronBasePlugin {
clients: TemplatesPluginClient[] = []
constructor() {
super(profile, clientProfile, TemplatesPluginClient)
}
openTemplate(webContentsId: any): void {
const client = this.clients.find(c => c.webContentsId === webContentsId)
if (client) {
client.openTemplate()
}
}
}
const clientProfile: Profile = {
name: 'electronTemplates',
displayName: 'electronTemplates',
description: 'Templates plugin',
methods: ['loadTemplateInNewWindow', 'openTemplate'],
}
export type WorkspaceTemplate = 'gist-template' | 'code-template' | 'remixDefault' | 'blank' | 'ozerc20' | 'zeroxErc20' | 'ozerc721'
class TemplatesPluginClient extends ElectronBasePluginClient {
constructor(webContentsId: number, profile: Profile) {
super(webContentsId, profile)
this.onload(() => {
console.log('TemplatesPluginClient onload')
})
}
async loadTemplateInNewWindow (files: any) {
let folder = await this.call('fs' as any, 'selectFolder')
if (!folder || folder === '') return
// @ts-ignore
console.log('files for template ', files)
for (const file in files) {
try {
if(!folder.endsWith('/')) folder += '/'
console.log('writing file', folder + file)
await fs.mkdir(path.dirname(folder + file), { recursive: true})
await fs.writeFile(folder + file, files[file], {
encoding: 'utf8'
})
} catch (error) {
console.error(error)
}
}
createWindow(folder)
}
async openTemplate(){
this.call('filePanel' as any, 'loadTemplate')
}
}

@ -12,7 +12,7 @@ const profile: Profile = {
} }
export class XtermPlugin extends ElectronBasePlugin { export class XtermPlugin extends ElectronBasePlugin {
client: PluginClient clients: XtermPluginClient[] = []
constructor() { constructor() {
super(profile, clientProfile, XtermPluginClient) super(profile, clientProfile, XtermPluginClient)
} }

@ -6,7 +6,7 @@ console.log('preload.ts')
/* preload script needs statically defined API for each plugin */ /* preload script needs statically defined API for each plugin */
const exposedPLugins = ['fs', 'git', 'xterm', 'isogit', 'electronconfig'] const exposedPLugins = ['fs', 'git', 'xterm', 'isogit', 'electronconfig', 'electronTemplates']
console.log('preload.ts', process) console.log('preload.ts', process)
let webContentsId: number | undefined let webContentsId: number | undefined

File diff suppressed because it is too large Load Diff

@ -0,0 +1,34 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useState, useRef, useReducer } from 'react'
import { FormattedMessage } from 'react-intl'
import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line
import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
const _paq = window._paq = window._paq || [] // eslint-disable-line
import { CustomTooltip } from '@remix-ui/helper';
interface HomeTabFileProps {
plugin: any
}
export const HomeTabFileElectron = ({ plugin }: HomeTabFileProps) => {
const loadTemplate = async () => {
plugin.call('filePanel', 'loadTemplate')
}
const clone = async () => {
plugin.call('filePanel', 'clone')
}
return (
<div className="justify-content-start mt-1 p-2 d-flex flex-column" id="hTFileSection">
<label style={{ fontSize: "1.2rem" }}><FormattedMessage id='home.files' /></label>
<label style={{ fontSize: "0.8rem" }} className="pt-2"><FormattedMessage id='home.loadFrom' /></label>
<div className="d-flex">
<button className="btn p-2 border mr-2" data-id="landingPageImportFromGistButton" onClick={async () => await loadTemplate()}>Project Template</button>
<button className="btn p-2 border mr-2" data-id="landingPageImportFromGistButton" onClick={async () => await clone()}>Clone a Git Repository</button>
</div>
</div>
)
}

@ -7,6 +7,7 @@ import Carousel from 'react-multi-carousel'
import WorkspaceTemplate from './workspaceTemplate' import WorkspaceTemplate from './workspaceTemplate'
import 'react-multi-carousel/lib/styles.css' import 'react-multi-carousel/lib/styles.css'
import CustomNavButtons from './customNavButtons' import CustomNavButtons from './customNavButtons'
import isElectron from 'is-electron'
declare global { declare global {
interface Window { interface Window {
_paq: any _paq: any
@ -58,6 +59,12 @@ function HomeTabGetStarted ({plugin}: HomeTabGetStartedProps) {
} }
const createWorkspace = async (templateName) => { const createWorkspace = async (templateName) => {
if(isElectron()){
await plugin.call('remix-templates', 'loadTemplateInNewWindow', templateName)
return
}
await plugin.appManager.activatePlugin('filePanel') await plugin.appManager.activatePlugin('filePanel')
const timeStamp = Date.now() const timeStamp = Date.now()
let templateDisplayName = TEMPLATE_NAMES[templateName] let templateDisplayName = TEMPLATE_NAMES[templateName]

@ -9,6 +9,8 @@ import HomeTabScamAlert from './components/homeTabScamAlert'
import HomeTabGetStarted from './components/homeTabGetStarted' import HomeTabGetStarted from './components/homeTabGetStarted'
import HomeTabFeatured from './components/homeTabFeatured' import HomeTabFeatured from './components/homeTabFeatured'
import HomeTabFeaturedPlugins from './components/homeTabFeaturedPlugins' import HomeTabFeaturedPlugins from './components/homeTabFeaturedPlugins'
import isElectron from 'is-electron'
import { HomeTabFileElectron } from './components/homeTabFileElectron'
declare global { declare global {
interface Window { interface Window {
@ -50,7 +52,9 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
<div className='d-flex flex-row w-100 custom_home_bg'> <div className='d-flex flex-row w-100 custom_home_bg'>
<div className="px-2 pl-3 justify-content-start d-flex border-right flex-column" id="remixUIHTLeft" style={{ width: 'inherit' }}> <div className="px-2 pl-3 justify-content-start d-flex border-right flex-column" id="remixUIHTLeft" style={{ width: 'inherit' }}>
<HomeTabTitle /> <HomeTabTitle />
<HomeTabFile plugin={plugin} /> {!isElectron()?
<HomeTabFile plugin={plugin} />:
<HomeTabFileElectron plugin={plugin}></HomeTabFileElectron>}
<HomeTabLearn plugin={plugin} /> <HomeTabLearn plugin={plugin} />
</div> </div>
<div className="pl-2 pr-3 justify-content-start d-flex flex-column" style={{width: "65%"}} id="remixUIHTRight"> <div className="pl-2 pr-3 justify-content-start d-flex flex-column" style={{width: "65%"}} id="remixUIHTRight">

@ -124,11 +124,12 @@ export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.
if (params.opendir) { if (params.opendir) {
params.opendir = decodeURIComponent(params.opendir) params.opendir = decodeURIComponent(params.opendir)
plugin.call('notification', 'toast', `opening ${params.opendir}...`) plugin.call('notification', 'toast', `opening ${params.opendir}...`)
plugin.call('fs', 'setWorkingDir', params.opendir) await plugin.call('fs', 'setWorkingDir', params.opendir)
} }
plugin.setWorkspace({ name: 'electron', isLocalhost: false }) plugin.setWorkspace({ name: 'electron', isLocalhost: false })
dispatch(setCurrentWorkspace({ name: 'electron', isGitRepo: false })) dispatch(setCurrentWorkspace({ name: 'electron', isGitRepo: false }))
electrOnProvider.init()
listenOnProviderEvents(electrOnProvider)(dispatch) listenOnProviderEvents(electrOnProvider)(dispatch)
listenOnPluginEvents(plugin) listenOnPluginEvents(plugin)
dispatch(setMode('browser')) dispatch(setMode('browser'))

@ -14,6 +14,7 @@ import { IndexedDBStorage } from '../../../../../../apps/remix-ide/src/app/files
import { getUncommittedFiles } from '../utils/gitStatusFilter' import { getUncommittedFiles } from '../utils/gitStatusFilter'
import { AppModal, ModalTypes } from '@remix-ui/app' import { AppModal, ModalTypes } from '@remix-ui/app'
import { contractDeployerScripts, etherscanScripts } from '@remix-project/remix-ws-templates' import { contractDeployerScripts, etherscanScripts } from '@remix-project/remix-ws-templates'
import isElectron from 'is-electron'
declare global { declare global {
interface Window { remixFileSystemCallback: IndexedDBStorage; } interface Window { remixFileSystemCallback: IndexedDBStorage; }
@ -84,6 +85,15 @@ const removeSlash = (s: string) => {
} }
export const createWorkspace = async (workspaceName: string, workspaceTemplateName: WorkspaceTemplate, opts = null, isEmpty = false, cb?: (err: Error, result?: string | number | boolean | Record<string, any>) => void, isGitRepo: boolean = false, createCommit: boolean = true) => { export const createWorkspace = async (workspaceName: string, workspaceTemplateName: WorkspaceTemplate, opts = null, isEmpty = false, cb?: (err: Error, result?: string | number | boolean | Record<string, any>) => void, isGitRepo: boolean = false, createCommit: boolean = true) => {
if (isElectron()) {
if (workspaceTemplateName) {
await plugin.call('remix-templates', 'loadTemplateInNewWindow', workspaceTemplateName, opts)
}
return
}
await plugin.fileManager.closeAllFiles() await plugin.fileManager.closeAllFiles()
const promise = createWorkspaceTemplate(workspaceName, workspaceTemplateName) const promise = createWorkspaceTemplate(workspaceName, workspaceTemplateName)
dispatch(createWorkspaceRequest(promise)) dispatch(createWorkspaceRequest(promise))
@ -166,6 +176,7 @@ export type UrlParametersType = {
export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDefault', opts?) => { export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDefault', opts?) => {
const workspaceProvider = plugin.fileProviders.workspace const workspaceProvider = plugin.fileProviders.workspace
const electronProvider = plugin.fileProviders.electron
const params = queryParams.get() as UrlParametersType const params = queryParams.get() as UrlParametersType
switch (template) { switch (template) {
@ -244,6 +255,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
_paq.push(['trackEvent', 'workspace', 'template', template]) _paq.push(['trackEvent', 'workspace', 'template', template])
// @ts-ignore // @ts-ignore
const files = await templateWithContent[template](opts) const files = await templateWithContent[template](opts)
console.log('files for template ', files)
for (const file in files) { for (const file in files) {
try { try {
await workspaceProvider.set(file, files[file]) await workspaceProvider.set(file, files[file])
@ -496,6 +508,17 @@ export const cloneRepository = async (url: string) => {
const token = config.get('settings/gist-access-token') const token = config.get('settings/gist-access-token')
const repoConfig = { url, token } const repoConfig = { url, token }
if (isElectron()) {
try {
await plugin.call('dGitProvider', 'clone', repoConfig)
} catch (e) {
console.log(e)
plugin.call('notification', 'alert', {
id: 'cloneGitRepository',
message: e
})
}
} else {
try { try {
const repoName = await getRepositoryTitle(url) const repoName = await getRepositoryTitle(url)
@ -538,6 +561,7 @@ export const cloneRepository = async (url: string) => {
dispatch(displayPopUp('An error occured: ' + e)) dispatch(displayPopUp('An error occured: ' + e))
} }
} }
}
export const checkGit = async () => { export const checkGit = async () => {
const isGitRepo = await plugin.fileManager.isGitRepo() const isGitRepo = await plugin.fileManager.isGitRepo()

@ -104,6 +104,16 @@ export function Workspace() {
} }
setCurrentWorkspace(workspaceName) setCurrentWorkspace(workspaceName)
resetFocus() resetFocus()
// expose some UI to the plugin, perhaps not the best way to do it
if (global.plugin) {
global.plugin.loadTemplate = async () => {
createWorkspace()
}
global.plugin.clone = async () => {
cloneGitRepository()
}
}
}, []) }, [])
useEffect(() => { useEffect(() => {
@ -692,7 +702,7 @@ export function Workspace() {
<FormattedMessage id='filePanel.workspace' /> <FormattedMessage id='filePanel.workspace' />
</label> </label>
</span> : null} </span> : null}
{currentWorkspace !== LOCALHOST && !isElectron() ? (<span className="remixui_menu remixui_topmenu d-flex justify-content-between align-items-end w-75"> {currentWorkspace !== LOCALHOST ? (<span className="remixui_menu remixui_topmenu d-flex justify-content-between align-items-end w-75">
<CustomTooltip <CustomTooltip
placement="top" placement="top"
tooltipId="createWorkspaceTooltip" tooltipId="createWorkspaceTooltip"

Loading…
Cancel
Save