diff --git a/static/app/components/events/eventTags/eventTagsTreeRow.tsx b/static/app/components/events/eventTags/eventTagsTreeRow.tsx index 0995f0dea238..b696fd81d653 100644 --- a/static/app/components/events/eventTags/eventTagsTreeRow.tsx +++ b/static/app/components/events/eventTags/eventTagsTreeRow.tsx @@ -283,15 +283,7 @@ function EventTagsTreeRowDropdown({ visitExternalLinkAction(content.value), ]; - return ( - - ); + return ; } function EventTagsTreeValue({ diff --git a/static/app/components/keyValueTree/keyValueTreeRowActions.tsx b/static/app/components/keyValueTree/keyValueTreeRowActions.tsx index a05d1bbcb506..3c1f73dbe605 100644 --- a/static/app/components/keyValueTree/keyValueTreeRowActions.tsx +++ b/static/app/components/keyValueTree/keyValueTreeRowActions.tsx @@ -1,10 +1,12 @@ -import {useState} from 'react'; +import {useContext, useState} from 'react'; +import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import {IconEllipsis} from '@sentry/icons/ellipsis'; import {type MenuItemProps} from '@sentry/scraps/dropdownMenu'; import {OverlayTrigger} from '@sentry/scraps/overlayTrigger'; import {RevealOnHover} from '@sentry/scraps/revealOnHover'; +import {TooltipContext} from '@sentry/scraps/tooltip'; import {openNavigateToExternalLinkModal} from 'sentry/actionCreators/modal'; import {t} from 'sentry/locale'; @@ -28,18 +30,22 @@ export function visitExternalLinkAction(value: KeyValueTreeValue): MenuItemProps export function KeyValueTreeRowActions({ ariaLabel, items, - usePortal, }: { ariaLabel: string; items: MenuItemProps[]; - usePortal?: boolean; }) { + const theme = useTheme(); const [isMenuOpen, setIsMenuOpen] = useState(false); + const {container} = useContext(TooltipContext); return ( { } // jsdom does not evaluate :hover styles, so bypass the hidden action's pointer-events check. await userEvent.click(actionsButton, {pointerEventsCheck: 0}); - expect(await within(row).findByText('Visible Action')).toBeInTheDocument(); - expect(await within(row).findByText('Disabled Action')).toBeInTheDocument(); - expect(within(row).queryByText('Hidden Action')).not.toBeInTheDocument(); + expect(actionsButton).toHaveAttribute('aria-expanded', 'true'); + expect(within(row).queryByRole('menu')).not.toBeInTheDocument(); + expect(await screen.findByText('Visible Action')).toBeInTheDocument(); + expect(await screen.findByText('Disabled Action')).toBeInTheDocument(); + expect(screen.queryByText('Hidden Action')).not.toBeInTheDocument(); } }); @@ -418,4 +422,36 @@ describe('attributesTree', () => { screen.getByTestId('tree-key-sentry.logger.name') ); }); + + it('renders the actions menu in the surrounding overlay container when one is provided', async () => { + function OverlayContainer({children}: {children: React.ReactNode}) { + const [container, setContainer] = useState(null); + + return ( +
+ {children} +
+ ); + } + + render( + + + + ); + + await userEvent.click(screen.getByRole('button', {name: 'Attribute Actions Menu'}), { + pointerEventsCheck: 0, + }); + + expect( + await within(screen.getByTestId('overlay-container')).findByRole('menu') + ).toBeInTheDocument(); + expect( + within(screen.getByTestId('attribute-tree-row')).queryByRole('menu') + ).not.toBeInTheDocument(); + }); }); diff --git a/static/packages/scraps/src/dropdownMenu/dropdownMenu.tsx b/static/packages/scraps/src/dropdownMenu/dropdownMenu.tsx index 3260a9f24af1..9828ddb641fb 100644 --- a/static/packages/scraps/src/dropdownMenu/dropdownMenu.tsx +++ b/static/packages/scraps/src/dropdownMenu/dropdownMenu.tsx @@ -63,7 +63,7 @@ interface BaseDropdownMenuProps /** * Reference to the container element that the portal should be rendered into. */ - portalContainerRef?: React.RefObject; + portalContainerRef?: React.RefObject; /** * Tag name for the outer wrap, defaults to `div` */