error.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import {useMemo} from 'react';
  2. import {useTheme} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import {LinkButton} from 'sentry/components/button';
  5. import {
  6. getStacktrace,
  7. StackTracePreviewContent,
  8. } from 'sentry/components/groupPreviewTooltip/stackTracePreview';
  9. import LoadingIndicator from 'sentry/components/loadingIndicator';
  10. import {generateIssueEventTarget} from 'sentry/components/quickTrace/utils';
  11. import {t} from 'sentry/locale';
  12. import type {EventError} from 'sentry/types/event';
  13. import {useApiQuery} from 'sentry/utils/queryClient';
  14. import type {TraceTreeNodeDetailsProps} from '../../traceDrawer/tabs/traceTreeNodeDetails';
  15. import {TraceIcons} from '../../traceIcons';
  16. import {TraceTree} from '../../traceModels/traceTree';
  17. import type {TraceTreeNode} from '../../traceModels/traceTreeNode';
  18. import {makeTraceNodeBarColor} from '../../traceRow/traceBar';
  19. import {getTraceTabTitle} from '../../traceState/traceTabs';
  20. import {IssueList} from './issues/issues';
  21. import {type SectionCardKeyValueList, TraceDrawerComponents} from './styles';
  22. export function ErrorNodeDetails({
  23. node,
  24. organization,
  25. onTabScrollToNode,
  26. onParentClick,
  27. }: TraceTreeNodeDetailsProps<TraceTreeNode<TraceTree.TraceError>>) {
  28. const issues = useMemo(() => {
  29. return [...node.errors];
  30. }, [node.errors]);
  31. const {isPending, data} = useApiQuery<EventError>(
  32. [
  33. `/organizations/${organization.slug}/events/${node.value.project_slug}:${node.value.event_id}/`,
  34. ],
  35. {
  36. staleTime: 2 * 60 * 1000,
  37. }
  38. );
  39. const stackTrace = useMemo(() => {
  40. if (data) {
  41. return getStacktrace(data);
  42. }
  43. return null;
  44. }, [data]);
  45. const theme = useTheme();
  46. const parentTransaction = TraceTree.ParentTransaction(node);
  47. const items: SectionCardKeyValueList = [
  48. {
  49. key: 'title',
  50. subject: t('Title'),
  51. value: <TraceDrawerComponents.CopyableCardValueWithLink value={node.value.title} />,
  52. },
  53. ];
  54. if (parentTransaction) {
  55. items.push({
  56. key: 'parent_transaction',
  57. subject: t('Parent Transaction'),
  58. value: (
  59. <a onClick={() => onParentClick(parentTransaction)}>
  60. {getTraceTabTitle(parentTransaction)}
  61. </a>
  62. ),
  63. });
  64. }
  65. return isPending ? (
  66. <LoadingIndicator />
  67. ) : data ? (
  68. <TraceDrawerComponents.DetailContainer>
  69. <TraceDrawerComponents.LegacyHeaderContainer>
  70. <TraceDrawerComponents.Title>
  71. <TraceDrawerComponents.IconBorder
  72. backgroundColor={makeTraceNodeBarColor(theme, node)}
  73. >
  74. <TraceIcons.Icon event={node.value} />
  75. </TraceDrawerComponents.IconBorder>
  76. <TraceDrawerComponents.LegacyTitleText>
  77. <div>{node.value.level ?? t('error')}</div>
  78. <TraceDrawerComponents.TitleOp
  79. text={node.value.message ?? node.value.title ?? 'Error'}
  80. />
  81. </TraceDrawerComponents.LegacyTitleText>
  82. </TraceDrawerComponents.Title>
  83. <TraceDrawerComponents.Actions>
  84. <TraceDrawerComponents.NodeActions
  85. node={node}
  86. organization={organization}
  87. onTabScrollToNode={onTabScrollToNode}
  88. />
  89. <LinkButton size="xs" to={generateIssueEventTarget(node.value, organization)}>
  90. {t('Go to Issue')}
  91. </LinkButton>
  92. </TraceDrawerComponents.Actions>
  93. </TraceDrawerComponents.LegacyHeaderContainer>
  94. <IssueList issues={issues} node={node} organization={organization} />
  95. <TraceDrawerComponents.SectionCard
  96. items={[
  97. {
  98. key: 'stack_trace',
  99. subject: t('Stack Trace'),
  100. subjectNode: null,
  101. value:
  102. stackTrace && data ? (
  103. <StackTraceWrapper>
  104. <StackTracePreviewContent event={data} stacktrace={stackTrace} />
  105. </StackTraceWrapper>
  106. ) : (
  107. t('No stack trace has been reported with this error')
  108. ),
  109. },
  110. ]}
  111. title={t('Stack Trace')}
  112. />
  113. <TraceDrawerComponents.SectionCard items={items} title={t('General')} />
  114. <TraceDrawerComponents.EventTags
  115. projectSlug={node.value.project_slug}
  116. event={data}
  117. />
  118. </TraceDrawerComponents.DetailContainer>
  119. ) : null;
  120. }
  121. const StackTraceWrapper = styled('div')`
  122. .traceback {
  123. margin-bottom: 0;
  124. border: 0;
  125. }
  126. `;