folder handling

rdesktop
filip mertens 1 year ago
parent b888c2b894
commit f3ec824c62
  1. 6
      apps/remix-ide/src/app.js
  2. 19
      apps/remix-ide/src/app/plugins/electronConfigPlugin.ts
  3. 2
      apps/remix-ide/src/app/plugins/fsPlugin.ts
  4. 4
      apps/remix-ide/src/app/tabs/locales/en/electron.json
  5. 2
      apps/remix-ide/src/app/tabs/locales/en/index.js
  6. 6
      apps/remixdesktop/src/engine.ts
  7. 43
      apps/remixdesktop/src/main.ts
  8. 43
      apps/remixdesktop/src/menus/edit.ts
  9. 63
      apps/remixdesktop/src/menus/window.ts
  10. 17
      apps/remixdesktop/src/plugins/configPlugin.ts
  11. 103
      apps/remixdesktop/src/plugins/fsPlugin.ts
  12. 2
      apps/remixdesktop/src/preload.ts
  13. 2
      apps/remixdesktop/src/utils/config.ts
  14. 2
      libs/remix-ui/panel/src/lib/main/main-panel.tsx
  15. 1
      libs/remix-ui/panel/src/lib/plugins/panel-plugin.tsx
  16. 1
      libs/remix-ui/workspace/src/lib/actions/index.ts
  17. 7
      libs/remix-ui/workspace/src/lib/actions/payload.ts
  18. 19
      libs/remix-ui/workspace/src/lib/actions/workspace.ts
  19. 64
      libs/remix-ui/workspace/src/lib/components/electron-menu.tsx
  20. 3
      libs/remix-ui/workspace/src/lib/contexts/index.ts
  21. 27
      libs/remix-ui/workspace/src/lib/css/electron-menu.css
  22. 14
      libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx
  23. 16
      libs/remix-ui/workspace/src/lib/reducers/workspace.ts
  24. 12
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx

@ -47,6 +47,7 @@ import { SolidityUmlGen } from './app/plugins/solidity-umlgen'
import { ContractFlattener } from './app/plugins/contractFlattener'
import { fsPlugin } from './app/plugins/fsPlugin'
import { isoGitPlugin } from './app/plugins/isoGitPlugin'
import { electronConfig } from './app/plugins/electronConfigPlugin'
const isElectron = require('is-electron')
@ -267,6 +268,7 @@ class AppComponent {
const permissionHandler = new PermissionHandlerPlugin()
this.engine.register([
permissionHandler,
this.layout,
@ -321,6 +323,8 @@ class AppComponent {
this.engine.register([FSPlugin])
const isoGit = new isoGitPlugin()
this.engine.register([isoGit])
const electronConfigPlugin = new electronConfig()
this.engine.register([electronConfigPlugin])
}
// LAYOUT & SYSTEM VIEWS
@ -439,7 +443,7 @@ class AppComponent {
await this.appManager.activatePlugin(['solidity-script'])
if(isElectron()){
await this.appManager.activatePlugin(['fs', 'isogit'])
await this.appManager.activatePlugin(['fs', 'isogit', 'electronconfig'])
}
this.appManager.on(

@ -0,0 +1,19 @@
import { ElectronPlugin } from '@remixproject/engine-electron';
export class electronConfig extends ElectronPlugin {
constructor() {
super({
displayName: 'electronconfig',
name: 'electronconfig',
description: 'electronconfig',
})
this.methods = []
}
onActivation(): void {
}
}

@ -16,7 +16,7 @@ export class fsPlugin extends ElectronPlugin {
name: 'fs',
description: 'fs',
})
this.methods = ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'lstat', 'exists', 'setWorkingDir']
this.methods = ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'lstat', 'exists', 'setWorkingDir', 'getRecentFolders']
// 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

@ -0,0 +1,4 @@
{
"electron.openFolder": "Open Folder",
"electron.recentFolders": "Recent Folders"
}

@ -10,6 +10,7 @@ import terminalJson from './terminal.json';
import udappJson from './udapp.json';
import solidityUnitTestingJson from './solidityUnitTesting.json';
import permissionHandlerJson from './permissionHandler.json';
import electronJson from './electron.json';
export default {
...debuggerJson,
@ -24,4 +25,5 @@ export default {
...udappJson,
...solidityUnitTestingJson,
...permissionHandlerJson,
...electronJson
}

@ -6,6 +6,7 @@ import { app } from 'electron';
import { XtermPlugin } from './plugins/xtermPlugin';
import git from 'isomorphic-git'
import { IsoGitPlugin } from './plugins/isoGitPlugin';
import { ConfigPlugin } from './plugins/configPlugin';
const engine = new Engine()
const appManager = new PluginManager()
@ -13,14 +14,18 @@ const fsPlugin = new FSPlugin()
const gitPlugin = new GitPlugin()
const xtermPlugin = new XtermPlugin()
const isoGitPlugin = new IsoGitPlugin()
const configPlugin = new ConfigPlugin()
engine.register(appManager)
engine.register(fsPlugin)
engine.register(gitPlugin)
engine.register(xtermPlugin)
engine.register(isoGitPlugin)
engine.register(configPlugin)
appManager.activatePlugin('electronconfig')
appManager.activatePlugin('fs')
ipcMain.handle('manager:activatePlugin', async (event, plugin) => {
console.log('manager:activatePlugin', plugin, event.sender.id)
return await appManager.call(plugin, 'createClient', event.sender.id)
@ -35,6 +40,7 @@ ipcMain.handle('getWebContentsID', (event, message) => {
return event.sender.id
})
app.on('before-quit', async () => {
await appManager.call('fs', 'closeWatch')
app.quit()

@ -1,4 +1,4 @@
import { app, BrowserWindow, dialog, Menu } from 'electron';
import { app, BrowserWindow, dialog, Menu, MenuItem } from 'electron';
import path from 'path';
@ -16,34 +16,42 @@ if (
// get system home dir
const homeDir = app.getPath('userData')
export let mainWindow: BrowserWindow;
export const createWindow = async (): Promise<void> => {
const windowSet = new Set<BrowserWindow>([]);
export const createWindow = async (dir?: string): Promise<void> => {
// Create the browser window.
mainWindow = new BrowserWindow({
const mainWindow = new BrowserWindow({
height: 800,
width: 1024,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
preload: path.join(__dirname, 'preload.js')
},
});
let params = dir ? `?opendir=${encodeURIComponent(dir)}` : '';
// and load the index.html of the app.
mainWindow.loadURL(
process.env.NODE_ENV === 'production' || isPackaged? `file://${__dirname}/remix-ide/index.html` :
'http://localhost:8080?opendir=' + homeDir)
process.env.NODE_ENV === 'production' || isPackaged ? `file://${__dirname}/remix-ide/index.html` + params :
'http://localhost:8080' + params)
mainWindow.maximize();
// on close
mainWindow.on('close', (event) => {
console.log('close', event, mainWindow.webContents.id)
windowSet.delete(mainWindow)
})
windowSet.add(mainWindow)
// Open the DevTools.
mainWindow.webContents.openDevTools();
};
// 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', async() => {
await createWindow();
app.on('ready', async () => {
require('./engine')
});
@ -83,6 +91,8 @@ const isMac = process.platform === 'darwin'
import FileMenu from './menus/file';
import MainMenu from './menus/main';
import darwinMenu from './menus/darwin';
import WindowMenu from './menus/window';
import EditMenu from './menus/edit';
import { execCommand } from './menus/commands';
const commandKeys: Record<string, string> = {
@ -90,6 +100,15 @@ const commandKeys: Record<string, string> = {
'folder:open': 'CmdOrCtrl+O',
};
const menu = [...(process.platform === 'darwin' ? [darwinMenu(commandKeys, execCommand, showAbout)] : []),
FileMenu(commandKeys, execCommand),
EditMenu(commandKeys, execCommand),
WindowMenu(commandKeys, execCommand, [])
]
const menu = [...(process.platform === 'darwin' ? [darwinMenu(commandKeys, execCommand, showAbout)] : []), FileMenu(commandKeys, execCommand)]
Menu.setApplicationMenu(Menu.buildFromTemplate(menu))

@ -0,0 +1,43 @@
import { BrowserWindow, MenuItemConstructorOptions } from 'electron';
export default (
commandKeys: Record<string, string>,
execCommand: (command: string, focusedWindow?: BrowserWindow) => void
) => {
const submenu: MenuItemConstructorOptions[] = [
{
label: 'Cut',
accelerator: commandKeys['editor:cut'],
enabled: false
},
{
role: 'copy',
command: 'editor:copy',
accelerator: commandKeys['editor:copy'],
registerAccelerator: true
} as any,
{
role: 'paste',
accelerator: commandKeys['editor:paste'],
registerAccelerator: true
}
];
if (process.platform !== 'darwin') {
submenu.push(
{ type: 'separator' },
{
label: 'Preferences...',
accelerator: commandKeys['window:preferences'],
click() {
execCommand('window:preferences');
}
}
);
}
return {
label: 'Edit',
submenu
};
};

@ -0,0 +1,63 @@
import { BrowserWindow, MenuItemConstructorOptions } from 'electron';
export default (
commandKeys: Record<string, string>,
execCommand: (command: string, focusedWindow?: BrowserWindow) => void,
openedWindows: BrowserWindow[]
): MenuItemConstructorOptions => {
const submenu: MenuItemConstructorOptions[] = [
{
role: 'minimize',
accelerator: commandKeys['window:minimize']
},
{
type: 'separator'
},
{
// It's the same thing as clicking the green traffc-light on macOS
role: 'zoom',
accelerator: commandKeys['window:zoom']
},
{
type: 'separator'
},
{
type: 'separator'
},
{
role: 'front'
},
{
label: 'Toggle Always on Top',
click: (item, focusedWindow) => {
execCommand('window:toggleKeepOnTop', focusedWindow);
}
},
{
role: 'togglefullscreen',
accelerator: commandKeys['window:toggleFullScreen']
},
{
type: 'separator'
},
]
if(openedWindows.length > 1) {
submenu.push({
label: 'Close',
accelerator: commandKeys['pane:close'],
click(item, focusedWindow) {
execCommand('pane:close', focusedWindow);
}
})
}
return {
role: 'window',
id: 'window',
submenu
}
};

@ -1,6 +1,7 @@
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron"
import { Profile } from "@remixproject/plugin-utils";
import { readConfig, writeConfig } from "../utils/config";
const profile: Profile = {
displayName: 'electronconfig',
@ -15,18 +16,12 @@ export class ConfigPlugin extends ElectronBasePlugin {
this.methods = [...super.methods, 'writeConfig', 'readConfig']
}
async writeConfig(webContentsId: any, data: any): Promise<void> {
const client = this.clients.find(c => c.webContentsId === webContentsId)
if (client) {
client.writeConfig(data)
}
async writeConfig(data: any): Promise<void> {
writeConfig(data)
}
async readConfig(webContentsId: any): Promise<any> {
const client = this.clients.find(c => c.webContentsId === webContentsId)
if (client) {
return client.readConfig()
}
return readConfig()
}
}
@ -48,11 +43,11 @@ class ConfigPluginClient extends ElectronBasePluginClient {
}
async writeConfig(data: any): Promise<void> {
writeConfig(data)
}
async readConfig(): Promise<any> {
return readConfig()
}
}

@ -3,6 +3,8 @@ import fs from 'fs/promises'
import { Profile } from "@remixproject/plugin-utils";
import chokidar from 'chokidar'
import { dialog } from "electron";
import { createWindow } from "../main";
import { writeConfig } from "../utils/config";
const profile: Profile = {
displayName: 'fs',
@ -17,6 +19,31 @@ export class FSPlugin extends ElectronBasePlugin {
this.methods = [...super.methods, 'closeWatch']
}
async onActivation(): Promise<void> {
const config = await this.call('electronconfig' as any, 'readConfig')
const openedFolders = config && config.openedFolders || []
this.call('electronconfig', 'writeConfig', { 'openedFolders': openedFolders })
const foldersToDelete: string[] = []
if (openedFolders && openedFolders.length) {
for (const folder of openedFolders) {
console.log('opening folder', folder)
try {
const stat = await fs.stat(folder)
if (stat.isDirectory()) {
createWindow(folder)
}
} catch (e) {
console.log('error opening folder', folder, e)
foldersToDelete.push(folder)
}
}
if (foldersToDelete.length) {
const newFolders = openedFolders.filter((f: string) => !foldersToDelete.includes(f))
this.call('electronconfig', 'writeConfig', { 'recentFolders': newFolders })
}
}
}
async closeWatch(): Promise<void> {
for (const client of this.clients) {
await client.closeWatch()
@ -36,17 +63,20 @@ const clientProfile: Profile = {
name: 'fs',
displayName: 'fs',
description: 'fs',
methods: ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'lstat', 'exists', 'currentPath', 'watch', 'closeWatch', 'setWorkingDir', 'openFolder']
methods: ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'lstat', 'exists', 'currentPath', 'watch', 'closeWatch', 'setWorkingDir', 'openFolder', 'getRecentFolders']
}
class FSPluginClient extends ElectronBasePluginClient {
watcher: chokidar.FSWatcher
workingDir: string = '/Volumes/bunsen/code/empty/'
workingDir: string = ''
constructor(webContentsId: number, profile: Profile) {
super(webContentsId, profile)
this.onload(() => {
//console.log('fsPluginClient onload')
this.window.on('close', () => {
this.closeWatch()
})
})
}
@ -141,35 +171,76 @@ class FSPluginClient extends ElectronBasePluginClient {
}
async closeWatch(): Promise<void> {
//console.log('closing Watcher', this.webContentsId)
console.log('closing Watcher', this.webContentsId)
await this.removeFromOpenedFolders(this.workingDir)
if (this.watcher) this.watcher.close()
}
async openFolder(): Promise<void> {
const dirs = dialog.showOpenDialogSync(this.window, {
properties: ['openDirectory', 'createDirectory', "showHiddenFiles"]
})
if (dirs && dirs.length > 0) {
this.workingDir = dirs[0]
this.emit('workingDirChanged', dirs[0])
}
async updateRecentFolders(path: string): Promise<void> {
const config = await this.call('electronconfig' as any, 'readConfig')
config.recentFolders = config.recentFolders || []
config.recentFolders = config.recentFolders.filter((p: string) => p !== path)
config.recentFolders.push(path)
writeConfig(config)
}
async updateOpenedFolders(path: string): Promise<void> {
const config = await this.call('electronconfig' as any, 'readConfig')
config.openedFolders = config.openedFolders || []
config.openedFolders = config.openedFolders.filter((p: string) => p !== path)
config.openedFolders.push(path)
writeConfig(config)
}
async removeFromOpenedFolders(path: string): Promise<void> {
console.log('removeFromOpenedFolders', path)
const config = await this.call('electronconfig' as any, 'readConfig')
config.openedFolders = config.openedFolders || []
config.openedFolders = config.openedFolders.filter((p: string) => p !== path)
console.log('removeFromOpenedFolders', config)
writeConfig(config)
}
async getRecentFolders(): Promise<string[]> {
const config = await this.call('electronconfig' as any, 'readConfig')
return config.recentFolders || []
}
async openFolder(path?: string): Promise<void> {
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
this.workingDir = path
await this.updateRecentFolders(path)
await this.updateOpenedFolders(path)
this.window.setTitle(this.workingDir)
this.emit('workingDirChanged', path)
}
async setWorkingDir(path: string): Promise<void> {
console.log('setWorkingDir', path)
this.workingDir = path
this.emit('workingDirChanged', path)
console.log('setWorkingDir', path)
this.workingDir = path
await this.updateRecentFolders(path)
await this.updateOpenedFolders(path)
this.window.setTitle(this.workingDir)
this.emit('workingDirChanged', path)
}
fixPath(path: string): string {
if (this.workingDir === '') throw new Error('workingDir is not set')
if (path) {
if (path.startsWith('/')) {
path = path.slice(1)
}
}
if (!this.workingDir.endsWith('/')) this.workingDir = this.workingDir + '/'
path = this.workingDir + path
path = this.workingDir + (!this.workingDir.endsWith('/') ? '/' : '') + path
return path
}

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

@ -4,6 +4,8 @@ import path from 'path'
const cacheDir = path.join(os.homedir(), '.cache_remix_ide')
console.log('cacheDir', cacheDir)
try {
if (!fs.existsSync(cacheDir)) {
fs.mkdirSync(cacheDir)

@ -57,7 +57,7 @@ const RemixUIMainPanel = (props: RemixUIMainPanelProps) => {
{Object.values(plugins).map((pluginRecord, i) => {
return (
<React.Fragment key={`mainView${i}`}>
{(pluginRecord.profile.name === 'terminal') ? <DragBar key='dragbar-terminal' hidden={pluginRecord.minimized || false} setHideStatus={showTerminal} refObject={terminalRef}></DragBar> : null}
{(pluginRecord.profile.name === 'terminal') ? null : null}
<RemixUIPanelPlugin
ref={refs[i]}
key={pluginRecord.profile.name}

@ -13,6 +13,7 @@ const RemixUIPanelPlugin = (props: panelPLuginProps, panelRef: any) => {
const ref:any = panelRef || localRef
if (ref.current) {
console.log('ref.current', props.pluginRecord)
if (props.pluginRecord.view) {
if (React.isValidElement(props.pluginRecord.view)) {
setView(props.pluginRecord.view)

@ -122,6 +122,7 @@ export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.
console.log('isElectron initWorkspace')
plugin.call('notification', 'toast', `connecting to electron...`)
if(params.opendir){
params.opendir = decodeURIComponent(params.opendir)
plugin.call('notification', 'toast', `opening ${params.opendir}...`)
plugin.call('fs', 'setWorkingDir', params.opendir)
}

@ -292,3 +292,10 @@ export const setGitConfig = (config: {username: string, token: string, email: st
payload: config
}
}
export const setElectronRecentFolders = (folders: string[]) => {
return {
type: 'SET_ELECTRON_RECENT_FOLDERS',
payload: folders
}
}

@ -2,7 +2,7 @@ import React from 'react'
import { bufferToHex } from '@ethereumjs/util'
import { hash } from '@remix-project/remix-lib'
import axios, { AxiosResponse } from 'axios'
import { addInputFieldSuccess, cloneRepositoryFailed, cloneRepositoryRequest, cloneRepositorySuccess, createWorkspaceError, createWorkspaceRequest, createWorkspaceSuccess, displayNotification, displayPopUp, fetchWorkspaceDirectoryError, fetchWorkspaceDirectoryRequest, fetchWorkspaceDirectorySuccess, hideNotification, setCurrentWorkspace, setCurrentWorkspaceBranches, setCurrentWorkspaceCurrentBranch, setDeleteWorkspace, setMode, setReadOnlyMode, setRenameWorkspace, setCurrentWorkspaceIsGitRepo, setGitConfig } from './payload'
import { addInputFieldSuccess, cloneRepositoryFailed, cloneRepositoryRequest, cloneRepositorySuccess, createWorkspaceError, createWorkspaceRequest, createWorkspaceSuccess, displayNotification, displayPopUp, fetchWorkspaceDirectoryError, fetchWorkspaceDirectoryRequest, fetchWorkspaceDirectorySuccess, hideNotification, setCurrentWorkspace, setCurrentWorkspaceBranches, setCurrentWorkspaceCurrentBranch, setDeleteWorkspace, setMode, setReadOnlyMode, setRenameWorkspace, setCurrentWorkspaceIsGitRepo, setGitConfig, setElectronRecentFolders } from './payload'
import { addSlash, checkSlash, checkSpecialChars } from '@remix-ui/helper'
import { JSONStandardInput, WorkspaceTemplate } from '../types'
@ -272,9 +272,12 @@ export const fetchWorkspaceDirectory = async (path: string) => {
if (!path) return
const provider = plugin.fileManager.currentFileProvider()
console.log('fetchWorkspaceDirectory', path, provider)
const promise = new Promise((resolve) => {
const promise = new Promise((resolve, reject) => {
provider.resolveDirectory(path, (error, fileTree) => {
if (error) console.error(error)
if (error) {
console.error(error)
return reject(error)
}
console.log('fetchWorkspaceDirectory', fileTree)
resolve(fileTree)
})
@ -747,8 +750,14 @@ export const checkoutRemoteBranch = async (branch: string, remote: string) => {
}
}
export const openElectronFolder = async () => {
await plugin.call('fs', 'openFolder')
export const openElectronFolder = async (path: string) => {
await plugin.call('fs', 'openFolder', path)
}
export const getElectronRecentFolders = async () => {
const folders = await plugin.call('fs', 'getRecentFolders')
dispatch(setElectronRecentFolders(folders))
return folders
}
export const hasLocalChanges = async () => {

@ -0,0 +1,64 @@
import React, { MouseEventHandler, useContext, useEffect, useState } from "react"
import { FileSystemContext } from "../contexts"
import isElectron from 'is-electron'
import { FormattedMessage } from "react-intl"
import '../css/electron-menu.css'
export const ElectronMenu = () => {
const global = useContext(FileSystemContext)
useEffect(() => {
if (isElectron()) {
global.dispatchGetElectronRecentFolders()
}
}, [])
useEffect(() => {
if (isElectron()) {
console.log('global.fs.browser.recentFolders', global.fs.browser.recentFolders)
}
}, [global.fs.browser.recentFolders])
const openFolderElectron = async (path: string) => {
console.log('open folder electron', path)
global.dispatchOpenElectronFolder(path)
}
const lastFolderName = (path: string) => {
const pathArray = path.split('/')
return pathArray[pathArray.length - 1]
}
return (
(isElectron() && global.fs.browser.isSuccessfulWorkspace ? null :
<>
<div onClick={async()=>{await openFolderElectron(null)}} className='btn btn-primary'><FormattedMessage id="electron.openFolder" /></div>
{global.fs.browser.recentFolders.length > 0 ?
<>
<label className="py-2 pt-3 align-self-center m-0" style={{ fontSize: "1.2rem" }}>
<FormattedMessage id="electron.recentFolders" />
</label>
<ul>
{global.fs.browser.recentFolders.map((folder, index) => {
return <li key={index}>
<div className="recentfolder pb-1">
<span onClick={async()=>{await openFolderElectron(folder)}} className="pl-2 recentfolder_name pr-2">{lastFolderName(folder)}</span>
<span onClick={async()=>{await openFolderElectron(folder)}} data-id={{folder}} className="recentfolder_path pr-2">{folder}</span>
<i
onClick={() => {
}}
className="fas fa-times recentfolder_delete pr-2"
>
</i>
</div>
</li>
})}
</ul>
</>
: null}
</>
)
)
}

@ -46,7 +46,8 @@ export const FileSystemContext = createContext<{
dispatchCreateTsSolGithubAction: () => Promise<void>,
dispatchCreateSlitherGithubAction: () => Promise<void>
dispatchCreateHelperScripts: (script: string) => Promise<void>
dispatchOpenElectronFolder: () => Promise<void>
dispatchOpenElectronFolder: (path: string) => Promise<void>
dispatchGetElectronRecentFolders: () => Promise<void>
}>(null)

@ -0,0 +1,27 @@
.recentfolder {
display: flex;
min-width: 0;
cursor: pointer;
}
.recentfolder_path {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.recentfolder_name {
flex-shrink: 0;
color: var(--text);
}
.recentfolder_name:hover {
color: var(--primary);
text-decoration: underline;
}
.recentfolder_delete {
flex-shrink: 0;
margin-left: auto;
color: var(--text);
}

@ -8,7 +8,7 @@ import { browserReducer, browserInitialState } from '../reducers/workspace'
import { initWorkspace, fetchDirectory, removeInputField, deleteWorkspace, deleteAllWorkspaces, clearPopUp, publishToGist, createNewFile, setFocusElement, createNewFolder,
deletePath, renamePath, downloadPath, copyFile, copyFolder, runScript, emitContextMenuEvent, handleClickFile, handleExpandPath, addInputField, createWorkspace,
fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile, uploadFolder, handleDownloadWorkspace, handleDownloadFiles, restoreBackupZip, cloneRepository, moveFile, moveFolder,
showAllBranches, switchBranch, createNewBranch, checkoutRemoteBranch, createSolidityGithubAction, createTsSolGithubAction, createSlitherGithubAction, createHelperScripts, openElectronFolder
showAllBranches, switchBranch, createNewBranch, checkoutRemoteBranch, createSolidityGithubAction, createTsSolGithubAction, createSlitherGithubAction, createHelperScripts, openElectronFolder, getElectronRecentFolders
} from '../actions'
import { Modal, WorkspaceProps, WorkspaceTemplate } from '../types'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ -187,9 +187,14 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
await createHelperScripts(script)
}
const dispatchOpenElectronFolder = async () => {
const dispatchOpenElectronFolder = async (path: string) => {
console.log('open electron folder')
await openElectronFolder()
await openElectronFolder(path)
}
const dispatchGetElectronRecentFolders = async () => {
console.log('get electron recent folders')
await getElectronRecentFolders()
}
@ -311,7 +316,8 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
dispatchCreateTsSolGithubAction,
dispatchCreateSlitherGithubAction,
dispatchCreateHelperScripts,
dispatchOpenElectronFolder
dispatchOpenElectronFolder,
dispatchGetElectronRecentFolders
}
return (
<FileSystemContext.Provider value={value}>

@ -34,6 +34,7 @@ export interface BrowserState {
error: string
},
fileState: fileDecoration[]
recentFolders: string[]
},
localhost: {
sharedFolder: string,
@ -86,7 +87,8 @@ export const browserInitialState: BrowserState = {
removedMenuItems: [],
error: null
},
fileState: []
fileState: [],
recentFolders: []
},
localhost: {
sharedFolder: '',
@ -728,6 +730,18 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
}
case 'SET_ELECTRON_RECENT_FOLDERS': {
const payload: string[] = action.payload
return {
...state,
browser: {
...state.browser,
recentFolders: payload
}
}
}
default:
throw new Error()
}

@ -13,6 +13,7 @@ import { contextMenuActions } from './utils'
import FileExplorerContextMenu from './components/file-explorer-context-menu'
import { customAction } from '@remixproject/plugin-api'
import isElectron from 'is-electron'
import { ElectronMenu } from './components/electron-menu'
const _paq = window._paq = window._paq || []
@ -492,11 +493,6 @@ export function Workspace() {
global.dispatchPublishToGist(path, type)
}
const openFolderElectron = async () => {
global.dispatchOpenElectronFolder()
}
const editModeOn = (path: string, type: string, isNew = false) => {
if (global.fs.readonly) return global.toast('Cannot write/modify file system in read only mode.')
setState(prevState => {
@ -796,14 +792,12 @@ export function Workspace() {
</div>
</header>
</div>
{isElectron() && global.fs.browser.isSuccessfulDirectory ? null :
<div onClick={openFolderElectron} className='btn btn-primary'>Open Folder</div>
}
<ElectronMenu></ElectronMenu>
<div className='h-100 remixui_fileExplorerTree' onFocus={() => { toggleDropdown(false) }}>
<div className='h-100'>
{(global.fs.browser.isRequestingWorkspace || global.fs.browser.isRequestingCloning) && <div className="text-center py-5"><i className="fas fa-spinner fa-pulse fa-2x"></i></div>}
{!(global.fs.browser.isRequestingWorkspace || global.fs.browser.isRequestingCloning) &&
(global.fs.mode === 'browser') && (currentWorkspace !== NO_WORKSPACE) &&
(global.fs.mode === 'browser') && (currentWorkspace !== NO_WORKSPACE) && (!isElectron() || global.fs.browser.isSuccessfulWorkspace) &&
<div className='h-100 remixui_treeview' data-id='filePanelFileExplorerTree'>
<FileExplorer
fileState={global.fs.browser.fileState}

Loading…
Cancel
Save