index.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import {useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import classNames from 'classnames';
  4. import ListItem from 'sentry/components/list/listItem';
  5. import StrictClick from 'sentry/components/strictClick';
  6. import {PlatformType, SentryAppComponent} from 'sentry/types';
  7. import {Event} from 'sentry/types/event';
  8. import withSentryAppComponents from 'sentry/utils/withSentryAppComponents';
  9. import Context from '../context';
  10. import {PackageStatusIcon} from '../packageStatus';
  11. import {FunctionNameToggleIcon} from '../symbol';
  12. import {AddressToggleIcon} from '../togglableAddress';
  13. import {
  14. getPlatform,
  15. hasAssembly,
  16. hasContextRegisters,
  17. hasContextSource,
  18. hasContextVars,
  19. isExpandable,
  20. } from '../utils';
  21. import Default from './default';
  22. import {Native} from './native';
  23. type Props = Omit<
  24. React.ComponentProps<typeof Native>,
  25. 'onToggleContext' | 'isExpandable' | 'leadsToApp' | 'hasGroupingBadge'
  26. > &
  27. Omit<
  28. React.ComponentProps<typeof Default>,
  29. 'onToggleContext' | 'isExpandable' | 'leadsToApp' | 'hasGroupingBadge'
  30. > & {
  31. components: Array<SentryAppComponent>;
  32. event: Event;
  33. registers: Record<string, string>;
  34. emptySourceNotation?: boolean;
  35. frameMeta?: Record<string, any>;
  36. isOnlyFrame?: boolean;
  37. registersMeta?: Record<string, any>;
  38. };
  39. function Line({
  40. frame,
  41. debugFrames,
  42. nextFrame,
  43. prevFrame,
  44. timesRepeated,
  45. includeSystemFrames,
  46. isFrameAfterLastNonApp,
  47. isUsedForGrouping,
  48. maxLengthOfRelativeAddress,
  49. image,
  50. registers,
  51. isOnlyFrame,
  52. event,
  53. components,
  54. frameMeta,
  55. registersMeta,
  56. emptySourceNotation = false,
  57. /**
  58. * Is the stack trace being previewed in a hovercard?
  59. */
  60. isHoverPreviewed = false,
  61. ...props
  62. }: Props) {
  63. // Prioritize the frame platform but fall back to the platform
  64. // of the stack trace / exception
  65. const platform = getPlatform(frame.platform, props.platform ?? 'other') as PlatformType;
  66. const leadsToApp = !frame.inApp && ((nextFrame && nextFrame.inApp) || !nextFrame);
  67. const expandable =
  68. !leadsToApp || includeSystemFrames
  69. ? isExpandable({
  70. frame,
  71. registers,
  72. platform,
  73. emptySourceNotation,
  74. isOnlyFrame,
  75. })
  76. : false;
  77. const [isExpanded, setIsExpanded] = useState(
  78. expandable ? props.isExpanded ?? false : false
  79. );
  80. function toggleContext(evt: React.MouseEvent) {
  81. evt.preventDefault();
  82. setIsExpanded(!isExpanded);
  83. }
  84. function renderLine() {
  85. switch (platform) {
  86. case 'objc':
  87. case 'cocoa':
  88. case 'native':
  89. return (
  90. <Native
  91. event={event}
  92. leadsToApp={leadsToApp}
  93. frame={frame}
  94. prevFrame={prevFrame}
  95. nextFrame={nextFrame}
  96. isHoverPreviewed={isHoverPreviewed}
  97. platform={platform}
  98. isExpanded={isExpanded}
  99. isExpandable={expandable}
  100. includeSystemFrames={includeSystemFrames}
  101. isFrameAfterLastNonApp={isFrameAfterLastNonApp}
  102. onToggleContext={toggleContext}
  103. image={image}
  104. maxLengthOfRelativeAddress={maxLengthOfRelativeAddress}
  105. isUsedForGrouping={isUsedForGrouping}
  106. />
  107. );
  108. default:
  109. return (
  110. <Default
  111. event={event}
  112. leadsToApp={leadsToApp}
  113. frame={frame}
  114. nextFrame={nextFrame}
  115. timesRepeated={timesRepeated}
  116. isHoverPreviewed={isHoverPreviewed}
  117. platform={platform}
  118. isExpanded={isExpanded}
  119. isExpandable={expandable}
  120. onToggleContext={toggleContext}
  121. isUsedForGrouping={isUsedForGrouping}
  122. frameMeta={frameMeta}
  123. debugFrames={debugFrames}
  124. />
  125. );
  126. }
  127. }
  128. const className = classNames({
  129. frame: true,
  130. 'is-expandable': expandable,
  131. expanded: isExpanded,
  132. collapsed: !isExpanded,
  133. 'system-frame': !frame.inApp,
  134. 'frame-errors': !!(frame.errors ?? []).length,
  135. 'leads-to-app': leadsToApp,
  136. });
  137. return (
  138. <StyleListItem className={className} data-test-id="stack-trace-frame">
  139. <StrictClick onClick={expandable ? toggleContext : undefined}>
  140. {renderLine()}
  141. </StrictClick>
  142. <Context
  143. frame={frame}
  144. event={event}
  145. registers={registers}
  146. components={components}
  147. hasContextSource={hasContextSource(frame)}
  148. hasContextVars={hasContextVars(frame)}
  149. hasContextRegisters={hasContextRegisters(registers)}
  150. emptySourceNotation={emptySourceNotation}
  151. hasAssembly={hasAssembly(frame, platform)}
  152. expandable={expandable}
  153. isExpanded={isExpanded}
  154. registersMeta={registersMeta}
  155. frameMeta={frameMeta}
  156. />
  157. </StyleListItem>
  158. );
  159. }
  160. export default withSentryAppComponents(Line, {componentType: 'stacktrace-link'});
  161. const StyleListItem = styled(ListItem)`
  162. overflow: hidden;
  163. :first-child {
  164. border-top: none;
  165. }
  166. ${PackageStatusIcon} {
  167. flex-shrink: 0;
  168. }
  169. :hover {
  170. ${PackageStatusIcon} {
  171. visibility: visible;
  172. }
  173. ${AddressToggleIcon} {
  174. visibility: visible;
  175. }
  176. ${FunctionNameToggleIcon} {
  177. visibility: visible;
  178. }
  179. }
  180. `;