symbol.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import styled from '@emotion/styled';
  2. import {Tooltip} from 'sentry/components/tooltip';
  3. import {SLOW_TOOLTIP_DELAY} from 'sentry/constants';
  4. import {IconFilter} from 'sentry/icons';
  5. import {t} from 'sentry/locale';
  6. import {space} from 'sentry/styles/space';
  7. import {Frame} from 'sentry/types';
  8. import {defined} from 'sentry/utils';
  9. import {FunctionName} from './functionName';
  10. import GroupingIndicator from './groupingIndicator';
  11. import {getFrameHint} from './utils';
  12. type Props = {
  13. frame: Frame;
  14. absoluteFilePaths?: boolean;
  15. className?: string;
  16. /**
  17. * Is the stack trace being previewed in a hovercard?
  18. */
  19. isHoverPreviewed?: boolean;
  20. isUsedForGrouping?: boolean;
  21. onFunctionNameToggle?: (event: React.MouseEvent<SVGElement>) => void;
  22. showCompleteFunctionName?: boolean;
  23. };
  24. function Symbol({
  25. frame,
  26. absoluteFilePaths,
  27. onFunctionNameToggle,
  28. showCompleteFunctionName,
  29. isHoverPreviewed,
  30. isUsedForGrouping,
  31. className,
  32. }: Props) {
  33. const hasFunctionNameHiddenDetails =
  34. defined(frame.rawFunction) &&
  35. defined(frame.function) &&
  36. frame.function !== frame.rawFunction;
  37. const getFunctionNameTooltipTitle = () => {
  38. if (!hasFunctionNameHiddenDetails) {
  39. return undefined;
  40. }
  41. if (!showCompleteFunctionName) {
  42. return t('Expand function details');
  43. }
  44. return t('Hide function details');
  45. };
  46. const [hint, hintIcon] = getFrameHint(frame);
  47. const functionNameTooltipTitle = getFunctionNameTooltipTitle();
  48. const tooltipDelay = isHoverPreviewed ? SLOW_TOOLTIP_DELAY : undefined;
  49. return (
  50. <Wrapper className={className}>
  51. {onFunctionNameToggle && (
  52. <FunctionNameToggleTooltip
  53. title={functionNameTooltipTitle}
  54. containerDisplayMode="inline-flex"
  55. delay={tooltipDelay}
  56. >
  57. <FunctionNameToggleIcon
  58. hasFunctionNameHiddenDetails={hasFunctionNameHiddenDetails}
  59. onClick={hasFunctionNameHiddenDetails ? onFunctionNameToggle : undefined}
  60. size="xs"
  61. color="purple300"
  62. />
  63. </FunctionNameToggleTooltip>
  64. )}
  65. <Data>
  66. <StyledFunctionName
  67. frame={frame}
  68. showCompleteFunctionName={showCompleteFunctionName}
  69. hasHiddenDetails={hasFunctionNameHiddenDetails}
  70. />
  71. {hint && (
  72. <HintStatus>
  73. <Tooltip title={hint} delay={tooltipDelay}>
  74. {hintIcon}
  75. </Tooltip>
  76. </HintStatus>
  77. )}
  78. {frame.filename && (
  79. <Filename>
  80. {'('}
  81. {absoluteFilePaths ? frame.absPath : frame.filename}
  82. {frame.lineNo && `:${frame.lineNo}`}
  83. {')'}
  84. </Filename>
  85. )}
  86. {isUsedForGrouping && <GroupingIndicator />}
  87. </Data>
  88. </Wrapper>
  89. );
  90. }
  91. const Wrapper = styled('div')`
  92. text-align: left;
  93. grid-column-start: 1;
  94. grid-column-end: -1;
  95. order: 3;
  96. flex: 1;
  97. display: flex;
  98. code {
  99. background: transparent;
  100. color: ${p => p.theme.textColor};
  101. padding-right: ${space(0.5)};
  102. }
  103. @media (min-width: ${props => props.theme.breakpoints.small}) {
  104. order: 0;
  105. grid-column-start: auto;
  106. grid-column-end: auto;
  107. }
  108. `;
  109. const StyledFunctionName = styled(FunctionName)`
  110. margin-right: ${space(0.75)};
  111. `;
  112. const Data = styled('div')`
  113. max-width: 100%;
  114. display: flex;
  115. flex-wrap: wrap;
  116. align-items: center;
  117. `;
  118. const HintStatus = styled('span')`
  119. position: relative;
  120. top: ${space(0.25)};
  121. margin: 0 ${space(0.75)} 0 -${space(0.25)};
  122. `;
  123. const Filename = styled('span')`
  124. color: ${p => p.theme.activeText};
  125. `;
  126. export const FunctionNameToggleIcon = styled(IconFilter, {
  127. shouldForwardProp: prop => prop !== 'hasFunctionNameHiddenDetails',
  128. })<{
  129. hasFunctionNameHiddenDetails: boolean;
  130. }>`
  131. cursor: pointer;
  132. visibility: hidden;
  133. display: none;
  134. @media (min-width: ${p => p.theme.breakpoints.small}) {
  135. display: block;
  136. }
  137. ${p => !p.hasFunctionNameHiddenDetails && 'opacity: 0; cursor: inherit;'};
  138. `;
  139. const FunctionNameToggleTooltip = styled(Tooltip)`
  140. height: 16px;
  141. align-items: center;
  142. margin-right: ${space(0.75)};
  143. @media (max-width: ${p => p.theme.breakpoints.small}) {
  144. display: none;
  145. }
  146. `;
  147. export default Symbol;