context.tsx 4.4 KB

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