fix(app): unmount hidden session panes (#35628)

This commit is contained in:
Luke Parker
2026-07-09 09:44:02 +10:00
committed by GitHub
parent aa52d30d7f
commit d8a57ee15c
4 changed files with 291 additions and 311 deletions
@@ -168,8 +168,8 @@ test("keeps the review tree and terminal sized when both panels are open", async
await expectTree(page, 2_773, "action.yml") await expectTree(page, 2_773, "action.yml")
await page.getByRole("button", { name: "Toggle file tree" }).click() await page.getByRole("button", { name: "Toggle file tree" }).click()
await expect(page.locator('[data-slot="session-review-v2-sidebar"]')).toHaveAttribute("aria-hidden", "true") await expect(page.locator('[data-slot="session-review-v2-sidebar"]')).toHaveCount(0)
await expect(page.locator('#review-panel [data-component="file-tree-v2"]')).toHaveCount(1) await expect(page.locator('#review-panel [data-component="file-tree-v2"]')).toHaveCount(0)
await page.getByRole("button", { name: "Toggle file tree" }).click() await page.getByRole("button", { name: "Toggle file tree" }).click()
await expectTree(page, 2_773, "action.yml") await expectTree(page, 2_773, "action.yml")
@@ -181,8 +181,7 @@ test("keeps the review tree and terminal sized when both panels are open", async
await expectTree(page, 2_773, "action.yml") await expectTree(page, 2_773, "action.yml")
await page.getByRole("button", { name: "Toggle review" }).click() await page.getByRole("button", { name: "Toggle review" }).click()
await expect(page.locator("#review-panel")).toHaveAttribute("aria-hidden", "true") await expect(page.locator("#review-panel")).toHaveCount(0)
await expect(page.locator('#review-panel [data-component="file-tree-v2"]')).toHaveCount(1)
await page.getByRole("button", { name: "Toggle review" }).click() await page.getByRole("button", { name: "Toggle review" }).click()
await expectTree(page, 2_773, "action.yml") await expectTree(page, 2_773, "action.yml")
await page.setViewportSize({ width: 1_000, height: 700 }) await page.setViewportSize({ width: 1_000, height: 700 })
+3 -8
View File
@@ -2198,7 +2198,7 @@ export default function Page() {
</Show> </Show>
</div> </div>
<Show when={!newSessionDesign()}> <Show when={!newSessionDesign() && desktopSidePanelOpen()}>
<SessionSidePanel <SessionSidePanel
canReview={canReview} canReview={canReview}
diffs={reviewDiffs} diffs={reviewDiffs}
@@ -2217,13 +2217,8 @@ export default function Page() {
<Show when={newSessionDesign()}> <Show when={newSessionDesign()}>
<Show when={isDesktop() ? desktopV2PanelLayout().visible : terminalOpen()}> <Show when={isDesktop() ? desktopV2PanelLayout().visible : terminalOpen()}>
<div class="min-w-0 h-full flex flex-1 flex-col"> <div class="min-w-0 h-full flex flex-1 flex-col">
<Show when={isDesktop()}> <Show when={isDesktop() && (desktopV2ReviewOpen() || desktopFileTreeOpen())}>
<div <div class="min-h-0 flex-1">
classList={{
"min-h-0 flex-1": desktopV2ReviewOpen() || desktopFileTreeOpen(),
"size-0 shrink-0 overflow-hidden": !(desktopV2ReviewOpen() || desktopFileTreeOpen()),
}}
>
<SessionSidePanel <SessionSidePanel
canReview={canReview} canReview={canReview}
diffs={reviewDiffs} diffs={reviewDiffs}
@@ -81,7 +81,6 @@ export function SessionSidePanel(props: {
}), }),
) )
const open = createMemo(() => reviewOpen() || fileOpen()) const open = createMemo(() => reviewOpen() || fileOpen())
const rendered = createMemo<boolean>((previous) => previous || open(), false)
const reviewTab = createMemo(() => isDesktop()) const reviewTab = createMemo(() => isDesktop())
const panelWidth = createMemo(() => { const panelWidth = createMemo(() => {
if (!open()) return "0px" if (!open()) return "0px"
@@ -164,10 +163,6 @@ export function SessionSidePanel(props: {
const openedTabs = tabState.openedTabs const openedTabs = tabState.openedTabs
const activeTab = tabState.activeTab const activeTab = tabState.activeTab
const activeFileTab = tabState.activeFileTab const activeFileTab = tabState.activeFileTab
const reviewContentRendered = createMemo<boolean>(
(previous) => previous || (reviewOpen() && activeTab() === "review"),
false,
)
const fileTreeTab = () => layout.fileTree.tab() const fileTreeTab = () => layout.fileTree.tab()
@@ -272,21 +267,15 @@ export function SessionSidePanel(props: {
}} }}
style={{ width: panelWidth() }} style={{ width: panelWidth() }}
> >
<Show when={rendered()}> <Show when={open()}>
<div <div
class="size-full flex" class="size-full flex"
classList={{ classList={{
"border-l border-border-weaker-base": !settings.general.newLayoutDesigns(), "border-l border-border-weaker-base": !settings.general.newLayoutDesigns(),
}} }}
> >
<div <Show when={reviewOpen()}>
aria-hidden={!reviewOpen()} <div class="relative min-w-0 h-full flex-1 overflow-hidden bg-background-base">
inert={!reviewOpen()}
class="relative min-w-0 h-full flex-1 overflow-hidden bg-background-base"
classList={{
"pointer-events-none": !reviewOpen(),
}}
>
<div class="size-full min-w-0 h-full bg-background-base"> <div class="size-full min-w-0 h-full bg-background-base">
<DragDropProvider <DragDropProvider
onDragStart={handleDragStart} onDragStart={handleDragStart}
@@ -417,24 +406,21 @@ export function SessionSidePanel(props: {
</Tabs.List> </Tabs.List>
</div> </div>
<Show when={reviewTab() && props.canReview() && reviewContentRendered()}> <Show when={reviewTab() && props.canReview() && activeTab() === "review"}>
<div <div
id={reviewTabPanelID} id={reviewTabPanelID}
role="tabpanel" role="tabpanel"
aria-labelledby={reviewTabID} aria-labelledby={reviewTabID}
aria-hidden={activeTab() !== "review"}
inert={activeTab() !== "review"}
tabIndex={props.reviewHasFocusableContent() ? undefined : 0} tabIndex={props.reviewHasFocusableContent() ? undefined : 0}
data-slot="tabs-content" data-slot="tabs-content"
class="flex flex-col h-full overflow-hidden contain-strict" class="flex flex-col h-full overflow-hidden contain-strict"
classList={{ hidden: activeTab() !== "review" }}
> >
{props.reviewPanel()} {props.reviewPanel()}
</div> </div>
</Show> </Show>
<Tabs.Content value="empty" class="flex flex-col h-full overflow-hidden contain-strict">
<Show when={activeTab() === "empty"}> <Show when={activeTab() === "empty"}>
<Tabs.Content value="empty" class="flex flex-col h-full overflow-hidden contain-strict">
<div class="relative pt-2 flex-1 min-h-0 overflow-hidden"> <div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
<div class="h-full px-6 pb-42 -mt-4 flex flex-col items-center justify-center text-center gap-6"> <div class="h-full px-6 pb-42 -mt-4 flex flex-col items-center justify-center text-center gap-6">
<Mark class="w-14 opacity-10" /> <Mark class="w-14 opacity-10" />
@@ -443,16 +429,14 @@ export function SessionSidePanel(props: {
</div> </div>
</div> </div>
</div> </div>
</Show>
</Tabs.Content> </Tabs.Content>
</Show>
<Show when={contextOpen()}>
<Tabs.Content value="context" class="flex flex-col h-full overflow-hidden contain-strict">
<Show when={activeTab() === "context"}> <Show when={activeTab() === "context"}>
<Tabs.Content value="context" class="flex flex-col h-full overflow-hidden contain-strict">
<div class="relative pt-2 flex-1 min-h-0 overflow-hidden"> <div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
<SessionContextTab /> <SessionContextTab />
</div> </div>
</Show>
</Tabs.Content> </Tabs.Content>
</Show> </Show>
@@ -490,15 +474,13 @@ export function SessionSidePanel(props: {
</DragDropProvider> </DragDropProvider>
</div> </div>
</div> </div>
</Show>
<Show when={shown()}> <Show when={fileOpen()}>
<div <div
id="file-tree-panel" id="file-tree-panel"
aria-hidden={!fileOpen()}
inert={!fileOpen()}
class="relative min-w-0 h-full shrink-0 overflow-hidden" class="relative min-w-0 h-full shrink-0 overflow-hidden"
classList={{ classList={{
"pointer-events-none": !fileOpen(),
"transition-[width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none": "transition-[width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none":
!props.size.active(), !props.size.active(),
}} }}
@@ -526,6 +508,7 @@ export function SessionSidePanel(props: {
{language.t("session.files.all")} {language.t("session.files.all")}
</Tabs.Trigger> </Tabs.Trigger>
</Tabs.List> </Tabs.List>
<Show when={fileTreeTab() === "changes"}>
<Tabs.Content value="changes" class="bg-background-stronger px-3 py-0"> <Tabs.Content value="changes" class="bg-background-stronger px-3 py-0">
<Switch> <Switch>
<Match when={props.hasReview() || !props.diffsReady()}> <Match when={props.hasReview() || !props.diffsReady()}>
@@ -551,6 +534,8 @@ export function SessionSidePanel(props: {
</Match> </Match>
</Switch> </Switch>
</Tabs.Content> </Tabs.Content>
</Show>
<Show when={fileTreeTab() === "all"}>
<Tabs.Content value="all" class="bg-background-stronger px-3 py-0"> <Tabs.Content value="all" class="bg-background-stronger px-3 py-0">
<Switch> <Switch>
<Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match> <Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match>
@@ -565,6 +550,7 @@ export function SessionSidePanel(props: {
</Match> </Match>
</Switch> </Switch>
</Tabs.Content> </Tabs.Content>
</Show>
</Tabs> </Tabs>
</div> </div>
<Show when={fileOpen()}> <Show when={fileOpen()}>
@@ -74,12 +74,11 @@ export function SessionReviewV2Sidebar(props: SessionReviewV2SidebarProps) {
return ( return (
<div data-component="session-review-v2-sidebar-root"> <div data-component="session-review-v2-sidebar-root">
<Show when={props.open}>
<aside <aside
data-slot="session-review-v2-sidebar" data-slot="session-review-v2-sidebar"
data-resizing={resizing() ? "" : undefined} data-resizing={resizing() ? "" : undefined}
aria-hidden={!props.open} style={{ width: `${width()}px` }}
inert={!props.open}
style={{ width: props.open ? `${width()}px` : "0px" }}
> >
<div data-slot="session-review-v2-sidebar-header"> <div data-slot="session-review-v2-sidebar-header">
<div data-slot="session-review-v2-sidebar-title">{props.title}</div> <div data-slot="session-review-v2-sidebar-title">{props.title}</div>
@@ -130,6 +129,7 @@ export function SessionReviewV2Sidebar(props: SessionReviewV2SidebarProps) {
{props.children} {props.children}
</ScrollView> </ScrollView>
</aside> </aside>
</Show>
<Show when={props.open && props.onWidthChange}> <Show when={props.open && props.onWidthChange}>
<div data-slot="session-review-v2-sidebar-resize" onPointerDown={() => setResizing(true)}> <div data-slot="session-review-v2-sidebar-resize" onPointerDown={() => setResizing(true)}>
<ResizeHandle <ResizeHandle