index.tsx 5.8 KB

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