import styled from '@emotion/styled'; import {STACKTRACE_PREVIEW_TOOLTIP_DELAY} from 'sentry/components/stacktracePreview'; import Tooltip from 'sentry/components/tooltip'; import {IconFilter} from 'sentry/icons'; import {t} from 'sentry/locale'; import space from 'sentry/styles/space'; import {Theme} from 'sentry/utils/theme'; import {formatAddress, parseAddress} from '../utils'; type Props = { address: string; isAbsolute: boolean; isFoundByStackScanning: boolean; isInlineFrame: boolean; startingAddress: string | null; className?: string; /** * Is the stack trace being previewed in a hovercard? */ isHoverPreviewed?: boolean; onToggle?: (event: React.MouseEvent) => void; relativeAddressMaxlength?: number; }; function TogglableAddress({ startingAddress, address, relativeAddressMaxlength, isInlineFrame, isFoundByStackScanning, isAbsolute, onToggle, isHoverPreviewed, className, }: Props) { const convertAbsoluteAddressToRelative = () => { if (!startingAddress) { return ''; } const relativeAddress = formatAddress( parseAddress(address) - parseAddress(startingAddress), relativeAddressMaxlength ); return `+${relativeAddress}`; }; const getAddressTooltip = () => { if (isInlineFrame && isFoundByStackScanning) { return t('Inline frame, found by stack scanning'); } if (isInlineFrame) { return t('Inline frame'); } if (isFoundByStackScanning) { return t('Found by stack scanning'); } return undefined; }; const relativeAddress = convertAbsoluteAddressToRelative(); const canBeConverted = !!relativeAddress; const formattedAddress = !relativeAddress || isAbsolute ? address : relativeAddress; const tooltipTitle = getAddressTooltip(); const tooltipDelay = isHoverPreviewed ? STACKTRACE_PREVIEW_TOOLTIP_DELAY : undefined; return ( {onToggle && canBeConverted && ( )}
{formattedAddress}
); } const AddressIconTooltip = styled(Tooltip)` align-items: center; margin-right: ${space(0.75)}; `; const AddressToggleIcon = styled(IconFilter)` cursor: pointer; visibility: hidden; display: none; @media (min-width: ${p => p.theme.breakpoints.small}) { display: block; } `; const getAddresstextBorderBottom = ( p: Pick, 'isFoundByStackScanning' | 'isInlineFrame'> & {theme: Theme} ) => { if (p.isFoundByStackScanning) { return `1px dashed ${p.theme.red300}`; } if (p.isInlineFrame) { return `1px dashed ${p.theme.blue300}`; } return 'none'; }; const Address = styled('span') & {canBeConverted: boolean}>` border-bottom: ${getAddresstextBorderBottom}; white-space: nowrap; @media (min-width: ${p => p.theme.breakpoints.small}) { padding-left: ${p => (p.canBeConverted ? null : '18px')}; } `; const Wrapper = styled('span')` font-family: ${p => p.theme.text.familyMono}; font-size: ${p => p.theme.fontSizeExtraSmall}; color: ${p => p.theme.textColor}; letter-spacing: -0.25px; width: 100%; flex-grow: 0; flex-shrink: 0; display: inline-flex; align-items: center; padding: 0 ${space(0.5)} 0 0; order: 1; @media (min-width: ${props => props.theme.breakpoints.small}) { padding: 0 ${space(0.5)}; order: 0; } `; export default TogglableAddress; export {AddressToggleIcon};