From 5e3e9b2b1a73a48d4094a227553d05a16f0e72d0 Mon Sep 17 00:00:00 2001 From: Jalil Date: Wed, 5 Aug 2026 09:19:13 +0200 Subject: [PATCH 1/2] fix(den-web): contain and dismiss workspace switcher --- .../_components/org-dashboard-shell.tsx | 42 +++++++++++++++++-- .../tests/org-dashboard-shell-layout.test.ts | 9 ++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx b/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx index f8a389df38..4ba6fc51d5 100644 --- a/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx +++ b/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { usePathname } from "next/navigation"; -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { BarChart3, ChevronDown, @@ -321,6 +321,8 @@ export function OrgDashboardShell({ children }: { children: React.ReactNode }) { const [switcherOpen, setSwitcherOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false); const [profilePromptDismissed, setProfilePromptDismissed] = useState(false); + const switcherRef = useRef(null); + const switcherTriggerRef = useRef(null); const isSingleOrgMode = runtimeConfigLoaded && runtimeConfig.orgMode === "single_org"; const { query: switcherQuery, @@ -333,6 +335,29 @@ export function OrgDashboardShell({ children }: { children: React.ReactNode }) { showSearch: showSwitcherSearch, } = useOrgListWindow(orgDirectory, 20); + useEffect(() => { + if (!switcherOpen) return; + + function handlePointerDown(event: PointerEvent) { + if (event.target instanceof Node && !switcherRef.current?.contains(event.target)) { + setSwitcherOpen(false); + } + } + + function handleKeyDown(event: KeyboardEvent) { + if (event.key !== "Escape") return; + setSwitcherOpen(false); + switcherTriggerRef.current?.focus(); + } + + document.addEventListener("pointerdown", handlePointerDown); + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("pointerdown", handlePointerDown); + document.removeEventListener("keydown", handleKeyDown); + }; + }, [switcherOpen]); + if (orgSelectionRequired) { return ( ) : ( -
+
{switcherOpen ? ( -
-
+
+

{user?.email ?? "OpenWork user"}

diff --git a/ee/apps/den-web/tests/org-dashboard-shell-layout.test.ts b/ee/apps/den-web/tests/org-dashboard-shell-layout.test.ts index cb3c4e6e2b..ec42dc064a 100644 --- a/ee/apps/den-web/tests/org-dashboard-shell-layout.test.ts +++ b/ee/apps/den-web/tests/org-dashboard-shell-layout.test.ts @@ -13,4 +13,13 @@ describe("OrgDashboardShell layout", () => { expect(source).toMatch(/
/); expect(source).toMatch(/
/); }); + + test("bounds the workspace switcher and dismisses it from outside", () => { + const source = readFileSync(shellPath, "utf8"); + + expect(source).toContain("grid-cols-[minmax(0,1fr)]"); + expect(source).toContain("max-w-[calc(100vw-1.5rem)]"); + expect(source).toContain('document.addEventListener("pointerdown", handlePointerDown)'); + expect(source).toContain("!switcherRef.current?.contains(event.target)"); + }); }); From 5050383afeb49a107b90cc0dcd3413e5e82b7315 Mon Sep 17 00:00:00 2001 From: Jalil Date: Wed, 5 Aug 2026 16:20:09 +0200 Subject: [PATCH 2/2] fix(den-web): preserve workspace switcher interactions --- .../(den)/dashboard/_components/org-dashboard-shell.tsx | 8 +++++--- ee/apps/den-web/tests/org-dashboard-shell-layout.test.ts | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx b/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx index 4ba6fc51d5..b84aa3250a 100644 --- a/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx +++ b/ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx @@ -321,7 +321,6 @@ export function OrgDashboardShell({ children }: { children: React.ReactNode }) { const [switcherOpen, setSwitcherOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false); const [profilePromptDismissed, setProfilePromptDismissed] = useState(false); - const switcherRef = useRef(null); const switcherTriggerRef = useRef(null); const isSingleOrgMode = runtimeConfigLoaded && runtimeConfig.orgMode === "single_org"; const { @@ -339,7 +338,10 @@ export function OrgDashboardShell({ children }: { children: React.ReactNode }) { if (!switcherOpen) return; function handlePointerDown(event: PointerEvent) { - if (event.target instanceof Node && !switcherRef.current?.contains(event.target)) { + const clickedInsideSwitcher = event.composedPath().some( + (target) => target instanceof Element && target.hasAttribute("data-workspace-switcher-root"), + ); + if (!clickedInsideSwitcher) { setSwitcherOpen(false); } } @@ -526,7 +528,7 @@ export function OrgDashboardShell({ children }: { children: React.ReactNode }) {
) : ( -
+