index.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import {useState} from 'react';
  2. import EventDataSection from 'sentry/components/events/eventDataSection';
  3. import CrashActions from 'sentry/components/events/interfaces/crashHeader/crashActions';
  4. import CrashTitle from 'sentry/components/events/interfaces/crashHeader/crashTitle';
  5. import {t} from 'sentry/locale';
  6. import {Event, Project, STACK_TYPE, STACK_VIEW, Thread} from 'sentry/types';
  7. import {defined} from 'sentry/utils';
  8. import {isStacktraceNewestFirst} from '../utils';
  9. import findBestThread from './threadSelector/findBestThread';
  10. import getThreadException from './threadSelector/getThreadException';
  11. import getThreadStacktrace from './threadSelector/getThreadStacktrace';
  12. import Content from './content';
  13. import ThreadSelector from './threadSelector';
  14. type Props = Pick<
  15. React.ComponentProps<typeof Content>,
  16. 'groupingCurrentLevel' | 'hasHierarchicalGrouping'
  17. > & {
  18. data: {
  19. values?: Array<Thread>;
  20. };
  21. event: Event;
  22. projectId: Project['id'];
  23. type: string;
  24. hideGuide?: boolean;
  25. };
  26. type State = {
  27. newestFirst: boolean;
  28. stackType: STACK_TYPE;
  29. activeThread?: Thread;
  30. stackView?: STACK_VIEW;
  31. };
  32. function getIntendedStackView(thread: Thread, event: Event) {
  33. const exception = getThreadException(event, thread);
  34. if (exception) {
  35. return !!exception.values.find(value => !!value.stacktrace?.hasSystemFrames)
  36. ? STACK_VIEW.APP
  37. : STACK_VIEW.FULL;
  38. }
  39. const stacktrace = getThreadStacktrace(false, thread);
  40. return stacktrace?.hasSystemFrames ? STACK_VIEW.APP : STACK_VIEW.FULL;
  41. }
  42. function Threads({
  43. data,
  44. event,
  45. projectId,
  46. type,
  47. hasHierarchicalGrouping,
  48. groupingCurrentLevel,
  49. hideGuide = false,
  50. }: Props) {
  51. const [state, setState] = useState<State>(() => {
  52. const thread = defined(data.values) ? findBestThread(data.values) : undefined;
  53. return {
  54. activeThread: thread,
  55. stackView: thread ? getIntendedStackView(thread, event) : undefined,
  56. stackType: STACK_TYPE.ORIGINAL,
  57. newestFirst: isStacktraceNewestFirst(),
  58. };
  59. });
  60. if (!data.values) {
  61. return null;
  62. }
  63. function handleSelectNewThread(thread: Thread) {
  64. setState({
  65. ...state,
  66. activeThread: thread,
  67. stackView:
  68. state.stackView !== STACK_VIEW.RAW
  69. ? getIntendedStackView(thread, event)
  70. : state.stackView,
  71. stackType: STACK_TYPE.ORIGINAL,
  72. });
  73. }
  74. function handleChangeNewestFirst({newestFirst}: Pick<State, 'newestFirst'>) {
  75. setState({...state, newestFirst});
  76. }
  77. function handleChangeStackView({
  78. stackView,
  79. stackType,
  80. }: Partial<Pick<State, 'stackType' | 'stackView'>>) {
  81. setState({
  82. ...state,
  83. stackView: stackView ?? state.stackView,
  84. stackType: stackType ?? state.stackType,
  85. });
  86. }
  87. const threads = data.values;
  88. const {stackView, stackType, newestFirst, activeThread} = state;
  89. const exception = getThreadException(event, activeThread);
  90. const stacktrace = !exception
  91. ? getThreadStacktrace(stackType !== STACK_TYPE.ORIGINAL, activeThread)
  92. : undefined;
  93. const stackTraceNotFound = !(exception || stacktrace);
  94. const hasMoreThanOneThread = threads.length > 1;
  95. return (
  96. <EventDataSection
  97. type={type}
  98. title={
  99. hasMoreThanOneThread ? (
  100. <CrashTitle
  101. title=""
  102. newestFirst={newestFirst}
  103. hideGuide={hideGuide}
  104. onChange={handleChangeNewestFirst}
  105. beforeTitle={
  106. activeThread && (
  107. <ThreadSelector
  108. threads={threads}
  109. activeThread={activeThread}
  110. event={event}
  111. onChange={handleSelectNewThread}
  112. exception={exception}
  113. />
  114. )
  115. }
  116. />
  117. ) : (
  118. <CrashTitle
  119. title={t('Stack Trace')}
  120. newestFirst={newestFirst}
  121. hideGuide={hideGuide}
  122. onChange={!stackTraceNotFound ? handleChangeNewestFirst : undefined}
  123. />
  124. )
  125. }
  126. actions={
  127. !stackTraceNotFound && (
  128. <CrashActions
  129. stackView={stackView}
  130. platform={event.platform}
  131. stacktrace={stacktrace}
  132. stackType={stackType}
  133. thread={hasMoreThanOneThread ? activeThread : undefined}
  134. exception={exception}
  135. onChange={handleChangeStackView}
  136. hasHierarchicalGrouping={hasHierarchicalGrouping}
  137. />
  138. )
  139. }
  140. showPermalink={!hasMoreThanOneThread}
  141. wrapTitle={false}
  142. >
  143. <Content
  144. data={activeThread}
  145. exception={exception}
  146. stackView={stackView}
  147. stackType={stackType}
  148. stacktrace={stacktrace}
  149. event={event}
  150. newestFirst={newestFirst}
  151. projectId={projectId}
  152. groupingCurrentLevel={groupingCurrentLevel}
  153. stackTraceNotFound={stackTraceNotFound}
  154. hasHierarchicalGrouping={hasHierarchicalGrouping}
  155. />
  156. </EventDataSection>
  157. );
  158. }
  159. export default Threads;