diff --git a/backend/ipc.js b/backend/ipc.js index 12f2127..ab06335 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -1,5 +1,6 @@ const fs = require('fs') const registerMenu = require('./menu.js') +const serial = require('./serial/serial.js').sharedInstance const { openFolderDialog, @@ -9,6 +10,8 @@ const { } = require('./helpers.js') module.exports = function registerIPCHandlers(win, ipcMain, app, dialog) { + serial.win = win // Required to send callback messages to renderer + ipcMain.handle('open-folder', async (event) => { console.log('ipcMain', 'open-folder') const folder = await openFolderDialog(win) @@ -141,8 +144,8 @@ module.exports = function registerIPCHandlers(win, ipcMain, app, dialog) { win.webContents.send('check-before-close') }) - // handle disconnection before reload - ipcMain.handle('prepare-reload', async (event) => { - return win.webContents.send('before-reload') + ipcMain.handle('serial', (event, command, ...args) => { + console.debug('Handling IPC serial command:', command, ...args) + return serial[command](...args) }) } diff --git a/backend/menu.js b/backend/menu.js index eb7810e..6db8023 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -1,5 +1,6 @@ const { app, Menu } = require('electron') const path = require('path') +const serial = require('./serial/serial.js').sharedInstance const openAboutWindow = require('about-window').default const shortcuts = require('./shortcuts.js') const { type } = require('os') @@ -127,10 +128,8 @@ module.exports = function registerMenu(win, state = {}) { accelerator: '', click: async () => { try { - win.webContents.send('cleanup-before-reload') - setTimeout(() => { - win.reload() - }, 500) + await serial.disconnect() + win.reload() } catch(e) { console.error('Reload from menu failed:', e) } diff --git a/backend/serial/serial-bridge.js b/backend/serial/serial-bridge.js new file mode 100644 index 0000000..715d21a --- /dev/null +++ b/backend/serial/serial-bridge.js @@ -0,0 +1,97 @@ +const { ipcRenderer } = require('electron') +const path = require('path') + +const SerialBridge = { + loadPorts: async () => { + return await ipcRenderer.invoke('serial', 'loadPorts') + }, + connect: async (path) => { + return await ipcRenderer.invoke('serial', 'connect', path) + }, + disconnect: async () => { + return await ipcRenderer.invoke('serial', 'disconnect') + }, + run: async (code) => { + return await ipcRenderer.invoke('serial', 'run', code) + }, + execFile: async (path) => { + return await ipcRenderer.invoke('serial', 'execFile', path) + }, + getPrompt: async () => { + return await ipcRenderer.invoke('serial', 'getPrompt') + }, + keyboardInterrupt: async () => { + await ipcRenderer.invoke('serial', 'keyboardInterrupt') + return Promise.resolve() + }, + reset: async () => { + await ipcRenderer.invoke('serial', 'reset') + return Promise.resolve() + }, + eval: (d) => { + return ipcRenderer.invoke('serial', 'eval', d) + }, + onData: (callback) => { + // Remove all previous listeners + if (ipcRenderer.listeners("serial-on-data").length > 0) { + ipcRenderer.removeAllListeners("serial-on-data") + } + ipcRenderer.on('serial-on-data', (event, data) => { + callback(data) + }) + }, + listFiles: async (folder) => { + return await ipcRenderer.invoke('serial', 'listFiles', folder) + }, + ilistFiles: async (folder) => { + return await ipcRenderer.invoke('serial', 'ilistFiles', folder) + }, + loadFile: async (file) => { + return await ipcRenderer.invoke('serial', 'loadFile', file) + }, + removeFile: async (file) => { + return await ipcRenderer.invoke('serial', 'removeFile', file) + }, + saveFileContent: async (filename, content, dataConsumer) => { + return await ipcRenderer.invoke('serial', 'saveFileContent', filename, content, dataConsumer) + }, + uploadFile: async (src, dest, dataConsumer) => { + return await ipcRenderer.invoke('serial', 'uploadFile', src, dest, dataConsumer) + }, + downloadFile: async (src, dest) => { + let contents = await ipcRenderer.invoke('serial', 'loadFile', src) + return ipcRenderer.invoke('save-file', dest, contents) + }, + renameFile: async (oldName, newName) => { + return await ipcRenderer.invoke('serial', 'renameFile', oldName, newName) + }, + onConnectionClosed: async (callback) => { + // Remove all previous listeners + if (ipcRenderer.listeners("serial-on-connection-closed").length > 0) { + ipcRenderer.removeAllListeners("serial-on-connection-closed") + } + ipcRenderer.on('serial-on-connection-closed', (event) => { + callback() + }) + }, + createFolder: async (folder) => { + return await ipcRenderer.invoke('serial', 'createFolder', folder) + }, + removeFolder: async (folder) => { + return await ipcRenderer.invoke('serial', 'removeFolder', folder) + }, + getNavigationPath: (navigation, target) => { + return path.posix.join(navigation, target) + }, + getFullPath: (root, navigation, file) => { + return path.posix.join(root, navigation, file) + }, + getParentPath: (navigation) => { + return path.posix.dirname(navigation) + }, + fileExists: async (filePath) => { + return await ipcRenderer.invoke('serial', 'fileExists', filePath) + } +} + +module.exports = SerialBridge \ No newline at end of file diff --git a/backend/serial/serial.js b/backend/serial/serial.js new file mode 100644 index 0000000..e702b17 --- /dev/null +++ b/backend/serial/serial.js @@ -0,0 +1,117 @@ +const MicroPython = require('micropython.js') + +class Serial { + constructor(win = null) { + this.win = win + this.board = new MicroPython() + this.board.chunk_size = 192 + this.board.chunk_sleep = 200 + } + + async loadPorts() { + let ports = await this.board.list_ports() + return ports.filter(p => p.vendorId && p.productId) + } + + async connect(path) { + await this.board.open(path) + this.registerCallbacks() + } + + async disconnect() { + return await this.board.close() + } + + async run(code) { + return await this.board.run(code) + } + + async execFile(path) { + return await this.board.execfile(path) + } + + async getPrompt() { + return await this.board.get_prompt() + } + + async keyboardInterrupt() { + await this.board.stop() + return Promise.resolve() + } + + async reset() { + await this.board.stop() + await this.board.exit_raw_repl() + await this.board.reset() + return Promise.resolve() + } + + async eval(d) { + return await this.board.eval(d) + } + + registerCallbacks() { + this.board.serial.on('data', (data) => { + this.win.webContents.send('serial-on-data', data) + }) + + this.board.serial.on('close', () => { + this.board.serial.removeAllListeners("data") + this.board.serial.removeAllListeners("close") + this.win.webContents.send('serial-on-connection-closed') + }) + } + + async listFiles(folder) { + return await this.board.fs_ls(folder) + } + + async ilistFiles(folder) { + return await this.board.fs_ils(folder) + } + + async loadFile(file) { + const output = await this.board.fs_cat_binary(file) + return output || '' + } + + async removeFile(file) { + return await this.board.fs_rm(file) + } + + async saveFileContent(filename, content, dataConsumer) { + return await this.board.fs_save(content || ' ', filename, dataConsumer) + } + + async uploadFile(src, dest, dataConsumer) { + return await this.board.fs_put(src, dest.replaceAll(path.win32.sep, path.posix.sep), dataConsumer) + } + + async renameFile(oldName, newName) { + return await this.board.fs_rename(oldName, newName) + } + + async createFolder(folder) { + return await this.board.fs_mkdir(folder) + } + + async removeFolder(folder) { + return await this.board.fs_rmdir(folder) + } + + async fileExists(filePath) { + const output = await this.board.run(` +import os +try: + os.stat("${filePath}") + print(0) +except OSError: + print(1) +`) + return output[2] === '0' + } +} + +const sharedInstance = new Serial() + +module.exports = {sharedInstance, Serial} \ No newline at end of file diff --git a/index.js b/index.js index aa5d989..a6fcc04 100644 --- a/index.js +++ b/index.js @@ -50,24 +50,6 @@ function createWindow () { win.show() }) - win.webContents.on('before-reload', async (event) => { - // Prevent the default reload behavior - event.preventDefault() - - try { - // Tell renderer to do cleanup - win.webContents.send('cleanup-before-reload') - - // Wait for cleanup then reload - setTimeout(() => { - // This will trigger a page reload, but won't trigger 'before-reload' again - win.reload() - }, 500) - } catch(e) { - console.error('Reload preparation failed:', e) - } - }) - const initialMenuState = { isConnected: false, view: 'editor' diff --git a/preload.js b/preload.js index dd4f28f..f67d43c 100644 --- a/preload.js +++ b/preload.js @@ -2,107 +2,8 @@ console.log('preload') const { contextBridge, ipcRenderer } = require('electron') const path = require('path') const shortcuts = require('./backend/shortcuts.js').global -const MicroPython = require('micropython.js') const { emit, platform } = require('process') - -const board = new MicroPython() -board.chunk_size = 192 -board.chunk_sleep = 200 - -const Serial = { - loadPorts: async () => { - let ports = await board.list_ports() - return ports.filter(p => p.vendorId && p.productId) - }, - connect: async (path) => { - return board.open(path) - }, - disconnect: async () => { - return board.close() - }, - run: async (code) => { - return board.run(code) - }, - execFile: async (path) => { - return board.execfile(path) - }, - getPrompt: async () => { - return board.get_prompt() - }, - keyboardInterrupt: async () => { - await board.stop() - return Promise.resolve() - }, - reset: async () => { - await board.stop() - await board.exit_raw_repl() - await board.reset() - return Promise.resolve() - }, - eval: (d) => { - return board.eval(d) - }, - onData: (fn) => { - board.serial.on('data', fn) - }, - listFiles: async (folder) => { - return board.fs_ls(folder) - }, - ilistFiles: async (folder) => { - return board.fs_ils(folder) - }, - loadFile: async (file) => { - const output = await board.fs_cat_binary(file) - return output || '' - }, - removeFile: async (file) => { - return board.fs_rm(file) - }, - saveFileContent: async (filename, content, dataConsumer) => { - return board.fs_save(content || ' ', filename, dataConsumer) - }, - uploadFile: async (src, dest, dataConsumer) => { - return board.fs_put(src, dest.replaceAll(path.win32.sep, path.posix.sep), dataConsumer) - }, - downloadFile: async (src, dest) => { - let contents = await Serial.loadFile(src) - return ipcRenderer.invoke('save-file', dest, contents) - }, - renameFile: async (oldName, newName) => { - return board.fs_rename(oldName, newName) - }, - onDisconnect: async (fn) => { - board.serial.on('close', fn) - }, - createFolder: async (folder) => { - return await board.fs_mkdir(folder) - }, - removeFolder: async (folder) => { - return await board.fs_rmdir(folder) - }, - getNavigationPath: (navigation, target) => { - return path.posix.join(navigation, target) - }, - getFullPath: (root, navigation, file) => { - return path.posix.join(root, navigation, file) - }, - getParentPath: (navigation) => { - return path.posix.dirname(navigation) - }, - fileExists: async (filePath) => { - // !!!: Fix this on micropython.js level - // ???: Check if file exists is not part of mpremote specs - const output = await board.run(` -import os -try: - os.stat("${filePath}") - print(0) -except OSError: - print(1) -`) - return output[2] === '0' - } -} +const SerialBridge = require('./backend/serial/serial-bridge.js') const Disk = { openFolder: async () => { @@ -163,16 +64,6 @@ const Window = { }) }, - onBeforeReload: (callback) => { - ipcRenderer.on('cleanup-before-reload', async () => { - try { - await callback() - } catch(e) { - console.error('Cleanup before reload failed:', e) - } - }) - }, - beforeClose: (callback) => ipcRenderer.on('check-before-close', callback), confirmClose: () => ipcRenderer.invoke('confirm-close'), isPackaged: () => ipcRenderer.invoke('is-packaged'), @@ -189,6 +80,6 @@ const Window = { getShortcuts: () => shortcuts } -contextBridge.exposeInMainWorld('BridgeSerial', Serial) +contextBridge.exposeInMainWorld('BridgeSerial', SerialBridge) contextBridge.exposeInMainWorld('BridgeDisk', Disk) -contextBridge.exposeInMainWorld('BridgeWindow', Window) +contextBridge.exposeInMainWorld('BridgeWindow', Window) \ No newline at end of file diff --git a/ui/arduino/store.js b/ui/arduino/store.js index c4de3ab..09a373e 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1,5 +1,5 @@ const log = console.log -const serial = window.BridgeSerial +const serialBridge = window.BridgeSerial const disk = window.BridgeDisk const win = window.BridgeWindow @@ -114,7 +114,8 @@ async function store(state, emitter) { // CONNECTION DIALOG emitter.on('open-connection-dialog', async () => { log('open-connection-dialog') - emitter.emit('disconnect') + // UI should be in disconnected state, no need to update + await serialBridge.disconnect() state.availablePorts = await getAvailablePorts() state.isConnectionDialogOpen = true emitter.emit('render') @@ -148,14 +149,14 @@ async function store(state, emitter) { emitter.emit('connection-timeout') }, 3500) try { - await serial.connect(path) + await serialBridge.connect(path) } catch(e) { console.error(e) } // Stop whatever is going on // Recover from getting stuck in raw repl - await serial.getPrompt() + await serialBridge.getPrompt() clearTimeout(timeout_id) // Connected and ready state.isConnecting = false @@ -171,23 +172,25 @@ async function store(state, emitter) { if (!state.isTerminalBound) { state.isTerminalBound = true term.onData((data) => { - serial.eval(data) + serialBridge.eval(data) term.scrollToBottom() }) - serial.eval('\x02') + serialBridge.eval('\x02') // Send Ctrl+B to enter normal repl mode } - serial.onData((data) => { + serialBridge.onData((data) => { term.write(data) term.scrollToBottom() }) - serial.onDisconnect(() => emitter.emit('disconnect')) + + // Update the UI when the conncetion is closed + // This may happen when unplugging the board + serialBridge.onConnectionClosed(() => emitter.emit('disconnected')) emitter.emit('close-connection-dialog') emitter.emit('refresh-files') emitter.emit('render') }) - emitter.on('disconnect', async () => { - await serial.disconnect() + emitter.on('disconnected', () => { state.isConnected = false state.panelHeight = PANEL_CLOSED state.boardFiles = [] @@ -196,6 +199,9 @@ async function store(state, emitter) { emitter.emit('render') updateMenu() }) + emitter.on('disconnect', async () => { + await serialBridge.disconnect() + }) emitter.on('connection-timeout', async () => { state.isConnected = false state.isConnecting = false @@ -228,8 +234,8 @@ async function store(state, emitter) { emitter.emit('open-panel') emitter.emit('render') try { - await serial.getPrompt() - await serial.run(code) + await serialBridge.getPrompt() + await serialBridge.run(code) } catch(e) { log('error', e) } @@ -241,7 +247,7 @@ async function store(state, emitter) { } emitter.emit('open-panel') emitter.emit('render') - await serial.getPrompt() + await serialBridge.getPrompt() }) emitter.on('reset', async () => { log('reset') @@ -250,7 +256,7 @@ async function store(state, emitter) { } emitter.emit('open-panel') emitter.emit('render') - await serial.reset() + await serialBridge.reset() emitter.emit('update-files') emitter.emit('render') }) @@ -326,9 +332,9 @@ async function store(state, emitter) { // Check if the current full path exists let fullPathExists = false if (openFile.source == 'board') { - await serial.getPrompt() - fullPathExists = await serial.fileExists( - serial.getFullPath( + await serialBridge.getPrompt() + fullPathExists = await serialBridge.fileExists( + serialBridge.getFullPath( state.boardNavigationRoot, openFile.parentFolder, openFile.fileName @@ -349,9 +355,9 @@ async function store(state, emitter) { if (openFile.source == 'board') { openFile.parentFolder = state.boardNavigationPath // Check for overwrite - await serial.getPrompt() - willOverwrite = await serial.fileExists( - serial.getFullPath( + await serialBridge.getPrompt() + willOverwrite = await serialBridge.fileExists( + serialBridge.getFullPath( state.boardNavigationRoot, openFile.parentFolder, openFile.fileName @@ -384,9 +390,9 @@ async function store(state, emitter) { const contents = openFile.editor.editor.state.doc.toString() try { if (openFile.source == 'board') { - await serial.getPrompt() - await serial.saveFileContent( - serial.getFullPath( + await serialBridge.getPrompt() + await serialBridge.saveFileContent( + serialBridge.getFullPath( state.boardNavigationRoot, openFile.parentFolder, openFile.fileName @@ -462,7 +468,7 @@ async function store(state, emitter) { if (state.isConnected) { try { state.boardFiles = await getBoardFiles( - serial.getFullPath( + serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, '' @@ -540,8 +546,8 @@ async function store(state, emitter) { } // TODO: Remove existing file } - await serial.saveFileContent( - serial.getFullPath( + await serialBridge.saveFileContent( + serialBridge.getFullPath( '/', state.boardNavigationPath, value @@ -611,15 +617,15 @@ async function store(state, emitter) { } // Remove existing folder await removeBoardFolder( - serial.getFullPath( + serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, value ) ) } - await serial.createFolder( - serial.getFullPath( + await serialBridge.createFolder( + serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, value @@ -701,7 +707,7 @@ async function store(state, emitter) { if (file.type == 'folder') { if (file.source === 'board') { await removeBoardFolder( - serial.getFullPath( + serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, file.fileName @@ -718,8 +724,8 @@ async function store(state, emitter) { } } else { if (file.source === 'board') { - await serial.removeFile( - serial.getFullPath( + await serialBridge.removeFile( + serialBridge.getFullPath( '/', state.boardNavigationPath, file.fileName @@ -787,15 +793,15 @@ async function store(state, emitter) { if (file.type == 'folder') { await removeBoardFolder( - serial.getFullPath( + serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, value ) ) } else if (file.type == 'file') { - await serial.removeFile( - serial.getFullPath( + await serialBridge.removeFile( + serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, value @@ -847,13 +853,13 @@ async function store(state, emitter) { try { if (state.renamingFile == 'board') { - await serial.renameFile( - serial.getFullPath( + await serialBridge.renameFile( + serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, file.fileName ), - serial.getFullPath( + serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, value @@ -924,8 +930,8 @@ async function store(state, emitter) { if (!isNewFile) { // Check if full path exists if (openFile.source == 'board') { - fullPathExists = await serial.fileExists( - serial.getFullPath( + fullPathExists = await serialBridge.fileExists( + serialBridge.getFullPath( state.boardNavigationRoot, openFile.parentFolder, oldName @@ -953,8 +959,8 @@ async function store(state, emitter) { // Check if it will overwrite let willOverwrite = false if (openFile.source == 'board') { - willOverwrite = await serial.fileExists( - serial.getFullPath( + willOverwrite = await serialBridge.fileExists( + serialBridge.getFullPath( state.boardNavigationRoot, openFile.parentFolder, openFile.fileName @@ -986,9 +992,9 @@ async function store(state, emitter) { const contents = openFile.editor.editor.state.doc.toString() try { if (openFile.source == 'board') { - await serial.getPrompt() - await serial.saveFileContent( - serial.getFullPath( + await serialBridge.getPrompt() + await serialBridge.saveFileContent( + serialBridge.getFullPath( state.boardNavigationRoot, openFile.parentFolder, oldName @@ -1015,13 +1021,13 @@ async function store(state, emitter) { // RENAME FILE try { if (openFile.source == 'board') { - await serial.renameFile( - serial.getFullPath( + await serialBridge.renameFile( + serialBridge.getFullPath( state.boardNavigationRoot, openFile.parentFolder, oldName ), - serial.getFullPath( + serialBridge.getFullPath( state.boardNavigationRoot, openFile.parentFolder, openFile.fileName @@ -1049,9 +1055,9 @@ async function store(state, emitter) { const contents = openFile.editor.editor.state.doc.toString() try { if (openFile.source == 'board') { - await serial.getPrompt() - await serial.saveFileContent( - serial.getFullPath( + await serialBridge.getPrompt() + await serialBridge.saveFileContent( + serialBridge.getFullPath( state.boardNavigationRoot, openFile.parentFolder, openFile.fileName @@ -1141,8 +1147,8 @@ async function store(state, emitter) { // load content and append it to the list of files to open let file = null if (selectedFile.source == 'board') { - const fileContent = await serial.loadFile( - serial.getFullPath( + const fileContent = await serialBridge.loadFile( + serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, selectedFile.fileName @@ -1222,7 +1228,7 @@ async function store(state, emitter) { const willOverwrite = await checkOverwrite({ source: 'board', fileNames: state.selectedFiles.map(f => f.fileName), - parentPath: serial.getFullPath( + parentPath: serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, '' @@ -1249,7 +1255,7 @@ async function store(state, emitter) { state.diskNavigationPath, file.fileName ) - const destPath = serial.getFullPath( + const destPath = serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, file.fileName @@ -1263,7 +1269,7 @@ async function store(state, emitter) { } ) } else { - await serial.uploadFile( + await serialBridge.uploadFile( srcPath, destPath, (progress) => { state.transferringProgress = `${file.fileName}: ${progress}` @@ -1309,7 +1315,7 @@ async function store(state, emitter) { for (let i in state.selectedFiles) { const file = state.selectedFiles[i] - const srcPath = serial.getFullPath( + const srcPath = serialBridge.getFullPath( state.boardNavigationRoot, state.boardNavigationPath, file.fileName @@ -1328,7 +1334,7 @@ async function store(state, emitter) { } ) } else { - await serial.downloadFile( + await serialBridge.downloadFile( srcPath, destPath, (e) => { state.transferringProgress = e @@ -1347,7 +1353,7 @@ async function store(state, emitter) { // NAVIGATION emitter.on('navigate-board-folder', (folder) => { log('navigate-board-folder', folder) - state.boardNavigationPath = serial.getNavigationPath( + state.boardNavigationPath = serialBridge.getNavigationPath( state.boardNavigationPath, folder ) @@ -1356,7 +1362,7 @@ async function store(state, emitter) { }) emitter.on('navigate-board-parent', () => { log('navigate-board-parent') - state.boardNavigationPath = serial.getNavigationPath( + state.boardNavigationPath = serialBridge.getNavigationPath( state.boardNavigationPath, '..' ) @@ -1383,18 +1389,6 @@ async function store(state, emitter) { emitter.emit('render') }) - win.onBeforeReload(async () => { - // Perform any cleanup needed - if (state.isConnected) { - await serial.disconnect() - state.isConnected = false - state.panelHeight = PANEL_CLOSED - state.boardFiles = [] - state.boardNavigationPath = '/' - } - // Any other cleanup needed - }) - win.beforeClose(async () => { const hasChanges = !!state.openFiles.find(f => f.hasChanges) if (hasChanges) { @@ -1553,12 +1547,12 @@ function generateHash() { } async function getAvailablePorts() { - return await serial.loadPorts() + return await serialBridge.loadPorts() } async function getBoardFiles(path) { - await serial.getPrompt() - let files = await serial.ilistFiles(path) + await serialBridge.getPrompt() + let files = await serialBridge.ilistFiles(path) files = files.map(f => ({ fileName: f[0], type: f[1] === 0x4000 ? 'folder' : 'file' @@ -1576,9 +1570,9 @@ function checkDiskFile({ root, parentFolder, fileName }) { async function checkBoardFile({ root, parentFolder, fileName }) { if (root == null || parentFolder == null || fileName == null) return false - await serial.getPrompt() - return serial.fileExists( - serial.getFullPath(root, parentFolder, fileName) + await serialBridge.getPrompt() + return serialBridge.fileExists( + serialBridge.getFullPath(root, parentFolder, fileName) ) } @@ -1643,29 +1637,29 @@ function canEdit({ selectedFiles }) { async function removeBoardFolder(fullPath) { // TODO: Replace with getting the file tree from the board and deleting one by one - let output = await serial.execFile(await getHelperFullPath()) - await serial.run(`delete_folder('${fullPath}')`) + let output = await serialBridge.execFile(await getHelperFullPath()) + await serialBridge.run(`delete_folder('${fullPath}')`) } async function uploadFolder(srcPath, destPath, dataConsumer) { dataConsumer = dataConsumer || function() {} - await serial.createFolder(destPath) + await serialBridge.createFolder(destPath) let allFiles = await disk.ilistAllFiles(srcPath) for (let i in allFiles) { const file = allFiles[i] const relativePath = file.path.substring(srcPath.length) if (file.type === 'folder') { - await serial.createFolder( - serial.getFullPath( + await serialBridge.createFolder( + serialBridge.getFullPath( destPath, relativePath, '' ) ) } else { - await serial.uploadFile( + await serialBridge.uploadFile( disk.getFullPath(srcPath, relativePath, ''), - serial.getFullPath(destPath, relativePath, ''), + serialBridge.getFullPath(destPath, relativePath, ''), (progress) => { dataConsumer(progress, relativePath) } @@ -1677,8 +1671,8 @@ async function uploadFolder(srcPath, destPath, dataConsumer) { async function downloadFolder(srcPath, destPath, dataConsumer) { dataConsumer = dataConsumer || function() {} await disk.createFolder(destPath) - let output = await serial.execFile(await getHelperFullPath()) - output = await serial.run(`ilist_all('${srcPath}')`) + let output = await serialBridge.execFile(await getHelperFullPath()) + output = await serialBridge.run(`ilist_all('${srcPath}')`) let files = [] try { // Extracting the json output from serial response @@ -1698,9 +1692,9 @@ async function downloadFolder(srcPath, destPath, dataConsumer) { disk.getFullPath( destPath, relativePath, '') ) } else { - await serial.downloadFile( - serial.getFullPath(srcPath, relativePath, ''), - serial.getFullPath(destPath, relativePath, '') + await serialBridge.downloadFile( + serialBridge.getFullPath(srcPath, relativePath, ''), + serialBridge.getFullPath(destPath, relativePath, '') ) } } diff --git a/ui/arduino/views/components/toolbar.js b/ui/arduino/views/components/toolbar.js index 0e3d497..70982b0 100644 --- a/ui/arduino/views/components/toolbar.js +++ b/ui/arduino/views/components/toolbar.js @@ -16,7 +16,7 @@ function Toolbar(state, emit) { ${Button({ icon: state.isConnected ? 'connect.svg' : 'disconnect.svg', tooltip: state.isConnected ? `Disconnect (${metaKeyString}+Shift+D)` : `Connect (${metaKeyString}+Shift+C)`, - onClick: () => emit('open-connection-dialog'), + onClick: () => state.isConnected ? emit('disconnect') : emit('open-connection-dialog'), active: state.isConnected })} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy