mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(desktop): stop Leave-channel dialog from freezing the app (#1482)
Signed-off-by: Mathieu Balez <mbalez@squareup.com>
This commit is contained in:
@@ -387,7 +387,11 @@ export function ChannelGroupSection({
|
||||
items.length > 0 ? (
|
||||
<SidebarMenu data-testid={listTestId}>
|
||||
{items.map((channel) => (
|
||||
<ContextMenu key={channel.id}>
|
||||
// modal={false}: menu items (e.g. Leave channel) open a modal
|
||||
// AlertDialog. A modal ContextMenu would leave `pointer-events: none`
|
||||
// stuck on <body> when it closes as the dialog mounts, freezing the
|
||||
// whole app. Non-modal avoids installing that body guard entirely.
|
||||
<ContextMenu key={channel.id} modal={false}>
|
||||
<ContextMenuTrigger asChild>
|
||||
<SidebarMenuItem className="content-visibility-auto-row">
|
||||
{draggable ? (
|
||||
@@ -572,7 +576,10 @@ export function CustomChannelSection({
|
||||
isDragging && "opacity-30",
|
||||
)}
|
||||
>
|
||||
<ContextMenu>
|
||||
{/* modal={false}: Rename/Delete section open a modal dialog;
|
||||
a modal ContextMenu would leave `pointer-events: none` stuck on
|
||||
<body> after it closes, freezing the app. */}
|
||||
<ContextMenu modal={false}>
|
||||
<ContextMenuTrigger asChild>
|
||||
<div className="relative" {...dragHandleProps}>
|
||||
<SidebarGroupLabel asChild>
|
||||
@@ -673,7 +680,10 @@ export function CustomChannelSection({
|
||||
{channels.length > 0 ? (
|
||||
<SidebarMenu>
|
||||
{channels.map((channel) => (
|
||||
<ContextMenu key={channel.id}>
|
||||
// modal={false}: see note on the other channel ContextMenu
|
||||
// above — avoids the pointer-events lockup when Leave
|
||||
// channel's AlertDialog opens.
|
||||
<ContextMenu key={channel.id} modal={false}>
|
||||
<ContextMenuTrigger asChild>
|
||||
<SidebarMenuItem>
|
||||
<DraggableChannelRow channelId={channel.id}>
|
||||
|
||||
@@ -22,6 +22,20 @@ async function storedSidebarWidth(page: Page) {
|
||||
);
|
||||
}
|
||||
|
||||
// Regression guard for the "Leave channel" lockup: opening a modal AlertDialog
|
||||
// from a modal Radix ContextMenu leaves `pointer-events: none` stuck on <body>
|
||||
// after the dialog closes, freezing the whole app. The fix makes the sidebar
|
||||
// context menus non-modal. This asserts the app is still interactive.
|
||||
async function expectAppClickable(page: Page) {
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(() => getComputedStyle(document.body).pointerEvents),
|
||||
)
|
||||
.not.toBe("none");
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
}
|
||||
|
||||
async function dragSidebarRail(page: Page, deltaX: number) {
|
||||
const sidebarRail = page.locator('[data-sidebar="rail"]');
|
||||
await expect(sidebarRail).toBeVisible();
|
||||
@@ -41,6 +55,29 @@ async function dragSidebarRail(page: Page, deltaX: number) {
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
test("leaving a channel from the context menu never freezes the app", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/");
|
||||
await expect(page.getByTestId("app-sidebar")).toBeVisible();
|
||||
|
||||
// Cancel path: dialog opens from the context menu, then is dismissed.
|
||||
await page.getByTestId("channel-random").click({ button: "right" });
|
||||
await page.getByRole("menuitem", { name: "Leave channel" }).click();
|
||||
await expect(page.getByRole("alertdialog")).toBeVisible();
|
||||
await page.getByRole("button", { name: "Cancel" }).click();
|
||||
await expect(page.getByRole("alertdialog")).toHaveCount(0);
|
||||
await expectAppClickable(page);
|
||||
|
||||
// Confirm path: same overlay lifecycle, plus the leave mutation.
|
||||
await page.getByTestId("channel-random").click({ button: "right" });
|
||||
await page.getByRole("menuitem", { name: "Leave channel" }).click();
|
||||
await expect(page.getByRole("alertdialog")).toBeVisible();
|
||||
await page.getByRole("button", { name: "Leave" }).click();
|
||||
await expect(page.getByRole("alertdialog")).toHaveCount(0);
|
||||
await expectAppClickable(page);
|
||||
});
|
||||
|
||||
test("fades the pinned sidebar chrome edges", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user