From bc49be33e2987058c1417b39cc45999a4c4abd94 Mon Sep 17 00:00:00 2001 From: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e Date: Mon, 13 Jul 2026 18:49:08 -0700 Subject: [PATCH] Address review feedback round 6 Keep permission-loading rows stable for the open menu, treat query failures as resolved, and make the cold-cache assertion deterministic. Co-authored-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e Signed-off-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e --- .../sidebar/ui/ChannelContextMenu.tsx | 23 ++++++++++++------- desktop/tests/e2e/channels.spec.ts | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/desktop/src/features/sidebar/ui/ChannelContextMenu.tsx b/desktop/src/features/sidebar/ui/ChannelContextMenu.tsx index 8467f09c97..00664ebdb2 100644 --- a/desktop/src/features/sidebar/ui/ChannelContextMenu.tsx +++ b/desktop/src/features/sidebar/ui/ChannelContextMenu.tsx @@ -1,3 +1,5 @@ +import * as React from "react"; + import { Archive, Bell, @@ -229,17 +231,22 @@ export function ChannelContextMenuItems({ selfMember?.role === "owner" || selfMember?.role === "admin" || canManageOwnedAgentChannel; - const hasResolvedMembers = membersQuery.data !== undefined; + const hasResolvedMembers = + membersQuery.data !== undefined || membersQuery.isError; const hasResolvedOwnerProfiles = - ownerPubkeys.length === 0 || ownerProfilesQuery.data !== undefined; + ownerPubkeys.length === 0 || + ownerProfilesQuery.data !== undefined || + ownerProfilesQuery.isError; const isManagementCandidate = channel.channelType !== "dm" && channel.archivedAt === null; - // Reserve disabled rows while capability queries resolve. This keeps the - // menu stable under the pointer without making owners close and reopen a - // cold-cache menu before the actions appear. - const showManagementActions = - isManagementCandidate && - (!hasResolvedMembers || !hasResolvedOwnerProfiles || canManageChannel); + // Context-menu content mounts per open session. Once these rows are reserved, + // keep them until close so permission resolution cannot move another action + // beneath the pointer; eligible rows transition from disabled to enabled. + const [showManagementActions] = React.useState( + () => + isManagementCandidate && + (!hasResolvedMembers || !hasResolvedOwnerProfiles || canManageChannel), + ); const disableManagementActions = !canManageChannel; const showStar = Boolean(onStarChannel && onUnstarChannel); const showReadToggle = hasUnread diff --git a/desktop/tests/e2e/channels.spec.ts b/desktop/tests/e2e/channels.spec.ts index a07378ce1c..f8516ab1e4 100644 --- a/desktop/tests/e2e/channels.spec.ts +++ b/desktop/tests/e2e/channels.spec.ts @@ -2335,7 +2335,7 @@ test("open channel management supports join and leave", async ({ page }) => { }); test("channel context menu edits a stream", async ({ page }) => { - await installMockBridge(page, { channelMembersDelayMs: 500 }); + await installMockBridge(page, { channelMembersDelayMs: 2_000 }); await page.goto("/"); await page.getByTestId("channel-agents").click({ button: "right" });