diff --git a/apps/reactotron-app/src/main/menu.ts b/apps/reactotron-app/src/main/menu.ts index 258e350fe..deca7b4b2 100644 --- a/apps/reactotron-app/src/main/menu.ts +++ b/apps/reactotron-app/src/main/menu.ts @@ -1,5 +1,6 @@ import { Menu, app, shell } from "electron" import Store from "electron-store" +import { setupActiveConnectionsMenuIpcCommands } from "./utils" const configStore = new Store() @@ -88,6 +89,12 @@ function buildViewMenu(window: Electron.BrowserWindow, isDevelopment: boolean) { window.setFullScreen(!window.isFullScreen()) }, }, + { + id: "activeConnectionsMenu", + label: "Active Connections", + submenu: [], + }, + { type: "separator" }, { label: "Toggle Developer Tools", accelerator: "Alt+Command+I", @@ -166,5 +173,9 @@ export default function createMenu(window: Electron.BrowserWindow, isDevelopment ] const menu = Menu.buildFromTemplate(template.filter((t) => !!t) as any) + + //ipc for adding and removing connection from active connections menu as they connect/drop + setupActiveConnectionsMenuIpcCommands(window, template) + Menu.setApplicationMenu(menu) } diff --git a/apps/reactotron-app/src/main/utils.ts b/apps/reactotron-app/src/main/utils.ts index b5d853983..6c9867481 100644 --- a/apps/reactotron-app/src/main/utils.ts +++ b/apps/reactotron-app/src/main/utils.ts @@ -1,5 +1,49 @@ import childProcess from "child_process" -import { type BrowserWindow, dialog, ipcMain } from "electron" +import { type BrowserWindow, dialog, ipcMain, Menu, MenuItem } from "electron" +import { ReactotronConnection } from "src/renderer/contexts/Standalone/useStandalone" + +interface menuTemplateModel { + label: string + submenu: any[] +} + +export const setupActiveConnectionsMenuIpcCommands = ( + window: BrowserWindow, + menuTemplate: menuTemplateModel[] +) => { + ipcMain.on( + "remove-connection-from-connection-menu", + (_event, connection: ReactotronConnection) => { + const menu = Menu.getApplicationMenu() + const activeConnectionsMenu = menu.getMenuItemById("activeConnectionsMenu") + + //menuTemplate[2] => view menu + //menuTemplate[2].submenu[1] => connections menu + if (menuTemplate[2]?.submenu[1]?.submenu && activeConnectionsMenu) { + //remove the disconnected connection from active connections menu + menuTemplate[2].submenu[1].submenu = activeConnectionsMenu.submenu.items.filter( + (item) => item.id !== connection.clientId + ) + } + + const updatedMenu = Menu.buildFromTemplate(menuTemplate.filter((t) => !!t)) + Menu.setApplicationMenu(updatedMenu) + } + ) + + ipcMain.on("add-connection-to-connection-menu", (_event, connection: ReactotronConnection) => { + const menu = Menu.getApplicationMenu() + const fileSubMenu = menu.getMenuItemById("activeConnectionsMenu") + + fileSubMenu.submenu.append( + new MenuItem({ + label: connection.name, + id: connection.clientId, + click: () => window.webContents.send("select-connection-from-menu", connection.clientId), + }) + ) + }) +} // This function sets up numerous IPC commands for communicating with android devices. // It also watches for android devices being plugged in and unplugged. diff --git a/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.ts b/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.ts index 96c6d5b2e..42abee093 100644 --- a/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.ts +++ b/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.ts @@ -1,5 +1,6 @@ -import { useCallback, useReducer } from "react" +import { useCallback, useEffect, useReducer } from "react" import { produce } from "immer" +import { ipcRenderer } from "electron" export enum ActionTypes { ServerStarted = "SERVER_STARTED", @@ -186,6 +187,13 @@ function useStandalone() { commandListeners: [], }) + useEffect(() => { + //change active connection when connection is selected from active connection menu + ipcRenderer.on("select-connection-from-menu", (_event, connectionClientId) => { + selectConnection(connectionClientId) + }) + }, []) + // Called when the server successfully starts const serverStarted = useCallback(() => { dispatch({ type: ActionTypes.ServerStarted, payload: undefined }) @@ -198,6 +206,8 @@ function useStandalone() { // Called when we have client details. NOTE: Commands can start flying in before this gets called! const connectionEstablished = useCallback((connection: ReactotronConnection) => { + ipcRenderer.send("add-connection-to-connection-menu", connection) + dispatch({ type: ActionTypes.AddConnection, payload: connection, @@ -211,6 +221,8 @@ function useStandalone() { // Called when a client disconnects. NOTE: They could be coming back. This could happen with a reload of the simulator! const connectionDisconnected = useCallback((connection: ReactotronConnection) => { + ipcRenderer.send("remove-connection-from-connection-menu", connection) + dispatch({ type: ActionTypes.RemoveConnection, payload: connection }) }, [])