import {useState} from 'react'; import EventDataSection from 'sentry/components/events/eventDataSection'; import CrashActions from 'sentry/components/events/interfaces/crashHeader/crashActions'; import CrashTitle from 'sentry/components/events/interfaces/crashHeader/crashTitle'; import {t} from 'sentry/locale'; import {Event, Project, STACK_TYPE, STACK_VIEW, Thread} from 'sentry/types'; import {defined} from 'sentry/utils'; import {isStacktraceNewestFirst} from '../utils'; import findBestThread from './threadSelector/findBestThread'; import getThreadException from './threadSelector/getThreadException'; import getThreadStacktrace from './threadSelector/getThreadStacktrace'; import Content from './content'; import ThreadSelector from './threadSelector'; type Props = Pick< React.ComponentProps, 'groupingCurrentLevel' | 'hasHierarchicalGrouping' > & { data: { values?: Array; }; event: Event; projectId: Project['id']; type: string; hideGuide?: boolean; }; type State = { newestFirst: boolean; stackType: STACK_TYPE; activeThread?: Thread; stackView?: STACK_VIEW; }; function getIntendedStackView(thread: Thread, event: Event) { const exception = getThreadException(event, thread); if (exception) { return !!exception.values.find(value => !!value.stacktrace?.hasSystemFrames) ? STACK_VIEW.APP : STACK_VIEW.FULL; } const stacktrace = getThreadStacktrace(false, thread); return stacktrace?.hasSystemFrames ? STACK_VIEW.APP : STACK_VIEW.FULL; } function Threads({ data, event, projectId, type, hasHierarchicalGrouping, groupingCurrentLevel, hideGuide = false, }: Props) { const [state, setState] = useState(() => { const thread = defined(data.values) ? findBestThread(data.values) : undefined; return { activeThread: thread, stackView: thread ? getIntendedStackView(thread, event) : undefined, stackType: STACK_TYPE.ORIGINAL, newestFirst: isStacktraceNewestFirst(), }; }); if (!data.values) { return null; } function handleSelectNewThread(thread: Thread) { setState({ ...state, activeThread: thread, stackView: state.stackView !== STACK_VIEW.RAW ? getIntendedStackView(thread, event) : state.stackView, stackType: STACK_TYPE.ORIGINAL, }); } function handleChangeNewestFirst({newestFirst}: Pick) { setState({...state, newestFirst}); } function handleChangeStackView({ stackView, stackType, }: Partial>) { setState({ ...state, stackView: stackView ?? state.stackView, stackType: stackType ?? state.stackType, }); } const threads = data.values; const {stackView, stackType, newestFirst, activeThread} = state; const exception = getThreadException(event, activeThread); const stacktrace = !exception ? getThreadStacktrace(stackType !== STACK_TYPE.ORIGINAL, activeThread) : undefined; const stackTraceNotFound = !(exception || stacktrace); const hasMoreThanOneThread = threads.length > 1; return ( ) } /> ) : ( ) } actions={ !stackTraceNotFound && ( ) } showPermalink={!hasMoreThanOneThread} wrapTitle={false} > ); } export default Threads;