error.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import {useMemo} from 'react';
  2. import {useTheme} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import {Button} from 'sentry/components/button';
  5. import {CopyToClipboardButton} from 'sentry/components/copyToClipboardButton';
  6. import {
  7. getStacktrace,
  8. StackTracePreviewContent,
  9. } from 'sentry/components/groupPreviewTooltip/stackTracePreview';
  10. import LoadingIndicator from 'sentry/components/loadingIndicator';
  11. import {generateIssueEventTarget} from 'sentry/components/quickTrace/utils';
  12. import {t} from 'sentry/locale';
  13. import type {EventError} from 'sentry/types';
  14. import {useApiQuery} from 'sentry/utils/queryClient';
  15. import {useLocation} from 'sentry/utils/useLocation';
  16. import {TraceIcons} from 'sentry/views/performance/newTraceDetails/icons';
  17. import type {TraceTreeNodeDetailsProps} from 'sentry/views/performance/newTraceDetails/traceDrawer/tabs/traceTreeNodeDetails';
  18. import {getTraceTabTitle} from 'sentry/views/performance/newTraceDetails/traceState/traceTabs';
  19. import {Row, Tags} from 'sentry/views/performance/traceDetails/styles';
  20. import {
  21. makeTraceNodeBarColor,
  22. type TraceTree,
  23. type TraceTreeNode,
  24. } from '../../traceModels/traceTree';
  25. import {IssueList} from './issues/issues';
  26. import {TraceDrawerComponents} from './styles';
  27. export function ErrorNodeDetails({
  28. node,
  29. organization,
  30. onTabScrollToNode,
  31. onParentClick,
  32. }: TraceTreeNodeDetailsProps<TraceTreeNode<TraceTree.TraceError>>) {
  33. const location = useLocation();
  34. const issues = useMemo(() => {
  35. return [...node.errors];
  36. }, [node.errors]);
  37. const {isLoading, data} = useApiQuery<EventError>(
  38. [
  39. `/organizations/${organization.slug}/events/${node.value.project_slug}:${node.value.event_id}/`,
  40. ],
  41. {
  42. staleTime: 2 * 60 * 1000,
  43. }
  44. );
  45. const stackTrace = useMemo(() => {
  46. if (data) {
  47. return getStacktrace(data);
  48. }
  49. return null;
  50. }, [data]);
  51. const theme = useTheme();
  52. const parentTransaction = node.parent_transaction;
  53. return isLoading ? (
  54. <LoadingIndicator />
  55. ) : data ? (
  56. <TraceDrawerComponents.DetailContainer>
  57. <TraceDrawerComponents.HeaderContainer>
  58. <TraceDrawerComponents.Title>
  59. <TraceDrawerComponents.IconBorder
  60. backgroundColor={makeTraceNodeBarColor(theme, node)}
  61. >
  62. <TraceIcons.Icon event={node.value} />
  63. </TraceDrawerComponents.IconBorder>
  64. <TraceDrawerComponents.TitleText>
  65. <div>{node.value.level ?? t('error')}</div>
  66. <TraceDrawerComponents.TitleOp>
  67. {' '}
  68. {node.value.title}
  69. </TraceDrawerComponents.TitleOp>
  70. </TraceDrawerComponents.TitleText>
  71. </TraceDrawerComponents.Title>
  72. <TraceDrawerComponents.Actions>
  73. <Button size="xs" onClick={_e => onTabScrollToNode(node)}>
  74. {t('Show in view')}
  75. </Button>
  76. <TraceDrawerComponents.EventDetailsLink
  77. node={node}
  78. organization={organization}
  79. />
  80. <Button size="xs" to={generateIssueEventTarget(node.value, organization)}>
  81. {t('Go to Issue')}
  82. </Button>
  83. </TraceDrawerComponents.Actions>
  84. </TraceDrawerComponents.HeaderContainer>
  85. <IssueList issues={issues} node={node} organization={organization} />
  86. <TraceDrawerComponents.Table className="table key-value">
  87. <tbody>
  88. {stackTrace ? (
  89. <tr>
  90. <StackTraceTitle>{t('Stack Trace')}</StackTraceTitle>
  91. <StackTraceWrapper>
  92. <StackTracePreviewContent event={data} stacktrace={stackTrace} />
  93. </StackTraceWrapper>
  94. </tr>
  95. ) : (
  96. <Row title={t('Stack Trace')}>
  97. {t('No stack trace has been reported with this error')}
  98. </Row>
  99. )}
  100. <Tags
  101. enableHiding
  102. location={location}
  103. organization={organization}
  104. event={node.value}
  105. tags={data.tags}
  106. />
  107. <Row
  108. title={t('Title')}
  109. extra={<CopyToClipboardButton size="xs" borderless text={node.value.title} />}
  110. >
  111. {node.value.title}
  112. </Row>
  113. {parentTransaction ? (
  114. <Row title="Parent Transaction">
  115. <td className="value">
  116. <a onClick={() => onParentClick(parentTransaction)}>
  117. {getTraceTabTitle(parentTransaction)}
  118. </a>
  119. </td>
  120. </Row>
  121. ) : null}
  122. </tbody>
  123. </TraceDrawerComponents.Table>
  124. </TraceDrawerComponents.DetailContainer>
  125. ) : null;
  126. }
  127. const StackTraceWrapper = styled('td')`
  128. .traceback {
  129. margin-bottom: 0;
  130. border: 0;
  131. }
  132. `;
  133. const StackTraceTitle = styled('td')`
  134. font-weight: 600;
  135. font-size: 13px;
  136. width: 175px;
  137. `;