From 26a474bb3dbaa3914e1b6ddf9416a8a65c84918d Mon Sep 17 00:00:00 2001 From: LukeGus Date: Tue, 6 Oct 2026 14:30:49 -0500 Subject: [PATCH] fix: open plain settings from the profile button, navigation only from the rail menu --- src/ui/AppShell.tsx | 22 ++++++++++++++++++-- src/ui/sidebar/AppRail.tsx | 5 ++++- src/ui/tests/sidebar/AppRail.test.tsx | 29 +++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/ui/AppShell.tsx b/src/ui/AppShell.tsx index a3b6712a2..61a617316 100644 --- a/src/ui/AppShell.tsx +++ b/src/ui/AppShell.tsx @@ -238,7 +238,10 @@ import { setShellLayoutProvider, } from "@/plugin-host/shell-bridge"; import { PluginViewPlaceholder } from "@/plugin-host/PluginViewPlaceholder"; -import { OPEN_PLUGINS_EVENT } from "@/plugins/open-plugins"; +import { + OPEN_PLUGINS_EVENT, + OPEN_PLUGIN_SETTINGS_EVENT, +} from "@/plugins/open-plugins"; export { buildHostTree } from "@/sidebar/build-host-tree"; export { tabIcon, renderTabContent } from "@/shell/tabUtils"; @@ -1784,6 +1787,20 @@ export function AppShell({ return () => window.removeEventListener(OPEN_PLUGINS_EVENT, handler); }, []); + useEffect(() => { + const handler = (event: Event) => { + const pluginId = (event as CustomEvent).detail; + if (typeof pluginId !== "string") return; + openSingletonTabRef.current("settings", undefined, undefined, { + section: `plugin:${pluginId}`, + revealAt: Date.now(), + }); + }; + window.addEventListener(OPEN_PLUGIN_SETTINGS_EVENT, handler); + return () => + window.removeEventListener(OPEN_PLUGIN_SETTINGS_EVENT, handler); + }, []); + const getTabCloseLabel = useCallback((tab: Tab) => { return tab.customLabel || tab.label || tab.host?.name || String(tab.id); }, []); @@ -2969,7 +2986,8 @@ export function AppShell({ onRailClick={handleRailClick} onOpenTab={openSingletonTab} onOpenInRightDock={openInRightDock} - onOpenSettings={() => + onOpenSettings={() => openSingletonTab("settings")} + onOpenNavigationSettings={() => openSingletonTab("settings", undefined, undefined, { section: "appearance", reveal: "settings-navigation", diff --git a/src/ui/sidebar/AppRail.tsx b/src/ui/sidebar/AppRail.tsx index a2685989a..b1e6d2cdf 100644 --- a/src/ui/sidebar/AppRail.tsx +++ b/src/ui/sidebar/AppRail.tsx @@ -130,6 +130,7 @@ export function AppRail({ onOpenTab, onOpenInRightDock, onOpenSettings, + onOpenNavigationSettings, onOpenPalette, onLogout, }: { @@ -143,6 +144,8 @@ export function AppRail({ onOpenTab?: (type: TabType) => void; onOpenInRightDock?: (view: RailView) => void; onOpenSettings: () => void; + /** The rail menu's own entry, which jumps to the navigation settings. */ + onOpenNavigationSettings: () => void; onOpenPalette?: () => void; onLogout: (options?: { manual?: boolean }) => void; }) { @@ -543,7 +546,7 @@ export function AppRail({ } onClick={() => { - onOpenSettings(); + onOpenNavigationSettings(); setMenuPos(null); }} > diff --git a/src/ui/tests/sidebar/AppRail.test.tsx b/src/ui/tests/sidebar/AppRail.test.tsx index 9fa7161df..abdee43c5 100644 --- a/src/ui/tests/sidebar/AppRail.test.tsx +++ b/src/ui/tests/sidebar/AppRail.test.tsx @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { render, screen } from "@testing-library/react"; +import { fireEvent, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Bell, Boxes } from "lucide-react"; import { AppRail } from "../../sidebar/AppRail"; @@ -36,6 +36,7 @@ function renderRail(onRailClick = vi.fn()) { isAdmin={false} onRailClick={onRailClick} onOpenSettings={vi.fn()} + onOpenNavigationSettings={vi.fn()} onLogout={vi.fn()} />, ); @@ -117,8 +118,9 @@ describe("AppRail", () => { expect(await screen.findByTitle("nav.connections")).toBeTruthy(); }); - it("opens settings from the account button", async () => { + it("opens plain settings from the account button", async () => { const onOpenSettings = vi.fn(); + const onOpenNavigationSettings = vi.fn(); render( { isAdmin onRailClick={vi.fn()} onOpenSettings={onOpenSettings} + onOpenNavigationSettings={onOpenNavigationSettings} onLogout={vi.fn()} />, ); await userEvent.click(screen.getByLabelText("nav.openSettings")); expect(onOpenSettings).toHaveBeenCalled(); + expect(onOpenNavigationSettings).not.toHaveBeenCalled(); + }); + + it("opens the navigation settings from the rail menu", async () => { + const onOpenSettings = vi.fn(); + const onOpenNavigationSettings = vi.fn(); + render( + , + ); + fireEvent.contextMenu(screen.getByTitle("nav.connections")); + await userEvent.click(screen.getByText("nav.openSettings")); + expect(onOpenNavigationSettings).toHaveBeenCalled(); + expect(onOpenSettings).not.toHaveBeenCalled(); }); });