context.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import styled from '@emotion/styled';
  2. import ClippedBox from 'sentry/components/clippedBox';
  3. import ErrorBoundary from 'sentry/components/errorBoundary';
  4. import {
  5. isMobileLanguage,
  6. StacktraceLink,
  7. } from 'sentry/components/events/interfaces/frame/stacktraceLink';
  8. import {IconFlag} from 'sentry/icons';
  9. import {t} from 'sentry/locale';
  10. import space from 'sentry/styles/space';
  11. import {Frame, Organization, SentryAppComponent} from 'sentry/types';
  12. import {Event} from 'sentry/types/event';
  13. import {defined} from 'sentry/utils';
  14. import withOrganization from 'sentry/utils/withOrganization';
  15. import {parseAssembly} from '../utils';
  16. import {Assembly} from './assembly';
  17. import ContextLine from './contextLine';
  18. import {FrameRegisters} from './frameRegisters';
  19. import {FrameVariables} from './frameVariables';
  20. import {OpenInContextLine} from './openInContextLine';
  21. type Props = {
  22. components: Array<SentryAppComponent>;
  23. event: Event;
  24. frame: Frame;
  25. registers: {[key: string]: string};
  26. className?: string;
  27. emptySourceNotation?: boolean;
  28. expandable?: boolean;
  29. frameMeta?: Record<any, any>;
  30. hasAssembly?: boolean;
  31. hasContextRegisters?: boolean;
  32. hasContextSource?: boolean;
  33. hasContextVars?: boolean;
  34. isExpanded?: boolean;
  35. organization?: Organization;
  36. registersMeta?: Record<any, any>;
  37. };
  38. const Context = ({
  39. hasContextVars = false,
  40. hasContextSource = false,
  41. hasContextRegisters = false,
  42. isExpanded = false,
  43. hasAssembly = false,
  44. expandable = false,
  45. emptySourceNotation = false,
  46. registers,
  47. components,
  48. frame,
  49. event,
  50. organization,
  51. className,
  52. frameMeta,
  53. registersMeta,
  54. }: Props) => {
  55. const isMobile = isMobileLanguage(event);
  56. if (
  57. !hasContextSource &&
  58. !hasContextVars &&
  59. !hasContextRegisters &&
  60. !hasAssembly &&
  61. !isMobile
  62. ) {
  63. return emptySourceNotation ? (
  64. <div className="empty-context">
  65. <StyledIconFlag size="xs" />
  66. <p>{t('No additional details are available for this frame.')}</p>
  67. </div>
  68. ) : null;
  69. }
  70. // Temporarily allow mobile platforms to make API call and "show" stacktrace link
  71. if (isMobile) {
  72. if (
  73. event.platform !== 'java' ||
  74. (event.platform === 'java' && frame?.module?.startsWith('com.'))
  75. ) {
  76. return (
  77. <ErrorBoundary customComponent={null}>
  78. <StacktraceLink
  79. line={frame.function ? frame.function : ''}
  80. frame={frame}
  81. event={event}
  82. />
  83. </ErrorBoundary>
  84. );
  85. }
  86. }
  87. const contextLines = isExpanded
  88. ? frame.context
  89. : frame.context.filter(l => l[0] === frame.lineNo);
  90. const startLineNo = hasContextSource ? frame.context[0][0] : undefined;
  91. const hasStacktraceLink =
  92. frame.inApp &&
  93. !!frame.filename &&
  94. isExpanded &&
  95. organization?.features.includes('integrations-stacktrace-link');
  96. return (
  97. <Wrapper
  98. start={startLineNo}
  99. className={`${className} context ${isExpanded ? 'expanded' : ''}`}
  100. >
  101. {defined(frame.errors) && (
  102. <li className={expandable ? 'expandable error' : 'error'} key="errors">
  103. {frame.errors.join(', ')}
  104. </li>
  105. )}
  106. {frame.context &&
  107. contextLines.map((line, index) => {
  108. const isActive = frame.lineNo === line[0];
  109. const hasComponents = isActive && components.length > 0;
  110. const showStacktraceLink = hasStacktraceLink && isActive;
  111. return (
  112. <StyledContextLine key={index} line={line} isActive={isActive}>
  113. {hasComponents && (
  114. <ErrorBoundary mini>
  115. <OpenInContextLine
  116. key={index}
  117. lineNo={line[0]}
  118. filename={frame.filename || ''}
  119. components={components}
  120. />
  121. </ErrorBoundary>
  122. )}
  123. {showStacktraceLink && (
  124. <ErrorBoundary customComponent={null}>
  125. <StacktraceLink
  126. key={index}
  127. line={line[1]}
  128. frame={frame}
  129. event={event}
  130. />
  131. </ErrorBoundary>
  132. )}
  133. </StyledContextLine>
  134. );
  135. })}
  136. {hasContextVars && (
  137. <StyledClippedBox clipHeight={100}>
  138. <FrameVariables data={frame.vars ?? {}} meta={frameMeta?.vars} />
  139. </StyledClippedBox>
  140. )}
  141. {hasContextRegisters && (
  142. <FrameRegisters
  143. registers={registers}
  144. meta={registersMeta}
  145. deviceArch={event.contexts?.device?.arch}
  146. />
  147. )}
  148. {hasAssembly && (
  149. <Assembly {...parseAssembly(frame.package)} filePath={frame.absPath} />
  150. )}
  151. </Wrapper>
  152. );
  153. };
  154. export default withOrganization(Context);
  155. const StyledClippedBox = styled(ClippedBox)`
  156. padding: 0;
  157. `;
  158. const StyledIconFlag = styled(IconFlag)`
  159. margin-right: ${space(1)};
  160. `;
  161. const StyledContextLine = styled(ContextLine)`
  162. background: inherit;
  163. padding: 0;
  164. text-indent: 20px;
  165. z-index: 1000;
  166. `;
  167. const Wrapper = styled('ol')`
  168. && {
  169. border-radius: 0;
  170. }
  171. `;