Connection manager in its own native window, modal to main
Single window centered over the main app. Electrobun has no native modality, so it's approximated: bun bounces the main window's focus back to the manager, the main webview shows a click-swallowing overlay, and main-targeted menu/keyboard actions are dropped while open. Editor windows stay fully usable. Connect/open-stack execute in the main window via the existing connect: action channel; store edits push a connectionsChanged refresh. Trigger moved from the panel dropdown to a tab-bar button. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+37
-4
@@ -6,6 +6,7 @@ import { PanelContextMenu } from "./context-menu";
|
||||
import { EditManager } from "./edits";
|
||||
import { EditorWindows } from "./editor-windows";
|
||||
import { SessionRegistry } from "./fs/registry";
|
||||
import { ManagerWindow } from "./manager-window";
|
||||
import { applyApplicationMenu } from "./menu";
|
||||
import { createAppRPC } from "./rpc-handlers";
|
||||
import { ConnectionStore } from "./store/connections";
|
||||
@@ -49,6 +50,7 @@ const events = {
|
||||
connectionsChanged: () => {},
|
||||
openEditor: (_ctx: EditorOpenContext) => {},
|
||||
settingsChanged: (_settings: AppSettings) => {},
|
||||
openConnectionManager: () => {},
|
||||
};
|
||||
const rpc = createAppRPC({ registry, engine, store, settings, edits, contextMenu, events });
|
||||
const url = await getMainViewUrl();
|
||||
@@ -83,17 +85,42 @@ const editors = new EditorWindows({
|
||||
mainFrame: () => win.getFrame(),
|
||||
notifyMain: { pathRefresh: (info) => rpc.send.pathRefresh(info) },
|
||||
});
|
||||
const manager = new ManagerWindow({
|
||||
store,
|
||||
settings,
|
||||
url,
|
||||
mainFrame: () => win.getFrame(),
|
||||
notifyMain: {
|
||||
managerState: (info) => rpc.send.managerState(info),
|
||||
connectionsChanged: () => rpc.send.connectionsChanged({}),
|
||||
menuAction: (info) => rpc.send.menuAction(info),
|
||||
},
|
||||
rebuildMenu: () => void applyApplicationMenu(store),
|
||||
});
|
||||
|
||||
events.openEditor = (ctx) => editors.open(ctx);
|
||||
events.settingsChanged = (s) => editors.broadcastSettings(s);
|
||||
// clean editors close with the main window; dirty ones get to ask first
|
||||
win.on("close", () => editors.closeAllForAppExit());
|
||||
events.settingsChanged = (s) => {
|
||||
editors.broadcastSettings(s);
|
||||
manager.broadcastSettings(s);
|
||||
};
|
||||
events.openConnectionManager = () => manager.open();
|
||||
// clean editors close with the main window; dirty ones get to ask first,
|
||||
// and the modal manager has nothing to guard
|
||||
win.on("close", () => {
|
||||
manager.close();
|
||||
editors.closeAllForAppExit();
|
||||
});
|
||||
|
||||
new AppTray(win);
|
||||
contextMenu.onAction = (action) => rpc.send.menuAction({ action });
|
||||
|
||||
// notify on finished transfers while the window is in the background
|
||||
let windowFocused = true;
|
||||
win.on("focus", () => (windowFocused = true));
|
||||
win.on("focus", () => {
|
||||
windowFocused = true;
|
||||
// modal bounce: the main window can't take focus while the manager is open
|
||||
if (manager.isOpen()) manager.activate();
|
||||
});
|
||||
win.on("blur", () => (windowFocused = false));
|
||||
const notifiedStates = new Map<string, string>();
|
||||
|
||||
@@ -173,6 +200,12 @@ ApplicationMenu.on("application-menu-clicked", (event) => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (action === "manage-connections") {
|
||||
manager.open();
|
||||
return;
|
||||
}
|
||||
// the manager is modal to the main window — don't drive main behind it
|
||||
if (manager.isOpen()) return;
|
||||
rpc.send.menuAction({ action });
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user