groupEventDetailsContent.tsx 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. import {Fragment, lazy, useMemo, useRef} from 'react';
  2. import styled from '@emotion/styled';
  3. import {usePrompt} from 'sentry/actionCreators/prompts';
  4. import {Button} from 'sentry/components/button';
  5. import {CommitRow} from 'sentry/components/commitRow';
  6. import ErrorBoundary from 'sentry/components/errorBoundary';
  7. import BreadcrumbsDataSection from 'sentry/components/events/breadcrumbs/breadcrumbsDataSection';
  8. import {EventContexts} from 'sentry/components/events/contexts';
  9. import {EventDevice} from 'sentry/components/events/device';
  10. import {EventAttachments} from 'sentry/components/events/eventAttachments';
  11. import {EventDataSection} from 'sentry/components/events/eventDataSection';
  12. import {EventEvidence} from 'sentry/components/events/eventEvidence';
  13. import {EventExtraData} from 'sentry/components/events/eventExtraData';
  14. import EventHydrationDiff from 'sentry/components/events/eventHydrationDiff';
  15. import {EventProcessingErrors} from 'sentry/components/events/eventProcessingErrors';
  16. import EventReplay from 'sentry/components/events/eventReplay';
  17. import {EventSdk} from 'sentry/components/events/eventSdk';
  18. import AggregateSpanDiff from 'sentry/components/events/eventStatisticalDetector/aggregateSpanDiff';
  19. import EventBreakpointChart from 'sentry/components/events/eventStatisticalDetector/breakpointChart';
  20. import {EventAffectedTransactions} from 'sentry/components/events/eventStatisticalDetector/eventAffectedTransactions';
  21. import EventComparison from 'sentry/components/events/eventStatisticalDetector/eventComparison';
  22. import {EventDifferentialFlamegraph} from 'sentry/components/events/eventStatisticalDetector/eventDifferentialFlamegraph';
  23. import {EventFunctionComparisonList} from 'sentry/components/events/eventStatisticalDetector/eventFunctionComparisonList';
  24. import {EventRegressionSummary} from 'sentry/components/events/eventStatisticalDetector/eventRegressionSummary';
  25. import {EventFunctionBreakpointChart} from 'sentry/components/events/eventStatisticalDetector/functionBreakpointChart';
  26. import {TransactionsDeltaProvider} from 'sentry/components/events/eventStatisticalDetector/transactionsDeltaProvider';
  27. import {EventTagsAndScreenshot} from 'sentry/components/events/eventTagsAndScreenshot';
  28. import {ScreenshotDataSection} from 'sentry/components/events/eventTagsAndScreenshot/screenshot/screenshotDataSection';
  29. import EventTagsDataSection from 'sentry/components/events/eventTagsAndScreenshot/tags';
  30. import {EventViewHierarchy} from 'sentry/components/events/eventViewHierarchy';
  31. import {EventGroupingInfo} from 'sentry/components/events/groupingInfo';
  32. import HighlightsDataSection from 'sentry/components/events/highlights/highlightsDataSection';
  33. import {HighlightsIconSummary} from 'sentry/components/events/highlights/highlightsIconSummary';
  34. import {Breadcrumbs} from 'sentry/components/events/interfaces/breadcrumbs';
  35. import {ActionableItems} from 'sentry/components/events/interfaces/crashContent/exception/actionableItems';
  36. import {actionableItemsEnabled} from 'sentry/components/events/interfaces/crashContent/exception/useActionableItems';
  37. import {CronTimelineSection} from 'sentry/components/events/interfaces/crons/cronTimelineSection';
  38. import {Csp} from 'sentry/components/events/interfaces/csp';
  39. import {DebugMeta} from 'sentry/components/events/interfaces/debugMeta';
  40. import {Exception} from 'sentry/components/events/interfaces/exception';
  41. import {Generic} from 'sentry/components/events/interfaces/generic';
  42. import {Message} from 'sentry/components/events/interfaces/message';
  43. import {AnrRootCause} from 'sentry/components/events/interfaces/performance/anrRootCause';
  44. import {SpanEvidenceSection} from 'sentry/components/events/interfaces/performance/spanEvidence';
  45. import {Request} from 'sentry/components/events/interfaces/request';
  46. import {StackTrace} from 'sentry/components/events/interfaces/stackTrace';
  47. import {Template} from 'sentry/components/events/interfaces/template';
  48. import {Threads} from 'sentry/components/events/interfaces/threads';
  49. import {UptimeDataSection} from 'sentry/components/events/interfaces/uptime/uptimeDataSection';
  50. import {EventPackageData} from 'sentry/components/events/packageData';
  51. import {EventRRWebIntegration} from 'sentry/components/events/rrwebIntegration';
  52. import {DataSection} from 'sentry/components/events/styles';
  53. import {SuspectCommits} from 'sentry/components/events/suspectCommits';
  54. import {EventUserFeedback} from 'sentry/components/events/userFeedback';
  55. import LazyLoad from 'sentry/components/lazyLoad';
  56. import Placeholder from 'sentry/components/placeholder';
  57. import {useHasNewTimelineUI} from 'sentry/components/timeline/utils';
  58. import {IconChevron} from 'sentry/icons';
  59. import {t} from 'sentry/locale';
  60. import {space} from 'sentry/styles/space';
  61. import type {Entry, EntryException, Event, EventTransaction} from 'sentry/types/event';
  62. import {EntryType, EventOrGroupType} from 'sentry/types/event';
  63. import type {Group} from 'sentry/types/group';
  64. import {IssueCategory, IssueType} from 'sentry/types/group';
  65. import type {Project} from 'sentry/types/project';
  66. import {defined} from 'sentry/utils';
  67. import {
  68. getConfigForIssueType,
  69. shouldShowCustomErrorResourceConfig,
  70. } from 'sentry/utils/issueTypeConfig';
  71. import {QuickTraceContext} from 'sentry/utils/performance/quickTrace/quickTraceContext';
  72. import QuickTraceQuery from 'sentry/utils/performance/quickTrace/quickTraceQuery';
  73. import {getReplayIdFromEvent} from 'sentry/utils/replays/getReplayIdFromEvent';
  74. import {useLocation} from 'sentry/utils/useLocation';
  75. import useOrganization from 'sentry/utils/useOrganization';
  76. import {ResourcesAndPossibleSolutions} from 'sentry/views/issueDetails/resourcesAndPossibleSolutions';
  77. import {SectionKey} from 'sentry/views/issueDetails/streamline/context';
  78. import {EventDetails} from 'sentry/views/issueDetails/streamline/eventDetails';
  79. import {InterimSection} from 'sentry/views/issueDetails/streamline/interimSection';
  80. import {TraceDataSection} from 'sentry/views/issueDetails/traceDataSection';
  81. import {useHasStreamlinedUI} from 'sentry/views/issueDetails/utils';
  82. const LLMMonitoringSection = lazy(
  83. () => import('sentry/components/events/interfaces/llm-monitoring/llmMonitoringSection')
  84. );
  85. export interface EventDetailsContentProps {
  86. group: Group;
  87. project: Project;
  88. event?: Event;
  89. }
  90. export function EventDetailsContent({
  91. group,
  92. event,
  93. project,
  94. }: Required<EventDetailsContentProps>) {
  95. const organization = useOrganization();
  96. const location = useLocation();
  97. const hasNewTimelineUI = useHasNewTimelineUI();
  98. const hasStreamlinedUI = useHasStreamlinedUI();
  99. const tagsRef = useRef<HTMLDivElement>(null);
  100. const eventEntries = useMemo(() => {
  101. const {entries = []} = event;
  102. return entries.reduce<{[key in EntryType]?: Entry}>((entryMap, entry) => {
  103. entryMap[entry.type] = entry;
  104. return entryMap;
  105. }, {});
  106. }, [event]);
  107. const projectSlug = project.slug;
  108. const hasReplay = Boolean(getReplayIdFromEvent(event));
  109. const mechanism = event.tags?.find(({key}) => key === 'mechanism')?.value;
  110. const isANR = mechanism === 'ANR' || mechanism === 'AppExitInfo';
  111. const showPossibleSolutionsHigher = shouldShowCustomErrorResourceConfig(group, project);
  112. const hasHierarchicalGrouping =
  113. !!organization.features?.includes('grouping-stacktrace-ui') &&
  114. !!(event.metadata.current_tree_label || event.metadata.finest_tree_label);
  115. const groupingCurrentLevel = group?.metadata?.current_level;
  116. const hasActionableItems = actionableItemsEnabled({
  117. eventId: event.id,
  118. organization,
  119. projectSlug,
  120. });
  121. const {
  122. isLoading: promptLoading,
  123. isError: promptError,
  124. isPromptDismissed,
  125. dismissPrompt,
  126. showPrompt,
  127. } = usePrompt({
  128. feature: 'issue_feedback_hidden',
  129. organization,
  130. projectId: project.id,
  131. });
  132. // default to show on error or isPromptDismissed === undefined
  133. const showFeedback = !isPromptDismissed || promptError || hasStreamlinedUI;
  134. const issueTypeConfig = getConfigForIssueType(group, group.project);
  135. return (
  136. <Fragment>
  137. {hasStreamlinedUI && <HighlightsIconSummary event={event} />}
  138. {hasActionableItems && !hasStreamlinedUI && (
  139. <ActionableItems event={event} project={project} isShare={false} />
  140. )}
  141. {hasStreamlinedUI && <TraceDataSection event={event} />}
  142. <StyledDataSection>
  143. {!hasStreamlinedUI && <TraceDataSection event={event} />}
  144. {!hasStreamlinedUI && (
  145. <SuspectCommits
  146. project={project}
  147. eventId={event.id}
  148. group={group}
  149. commitRow={CommitRow}
  150. />
  151. )}
  152. </StyledDataSection>
  153. {event.userReport && (
  154. <InterimSection
  155. title={t('User Feedback')}
  156. type={SectionKey.USER_FEEDBACK}
  157. actions={
  158. hasStreamlinedUI ? null : (
  159. <ErrorBoundary mini>
  160. <Button
  161. size="xs"
  162. icon={<IconChevron direction={showFeedback ? 'up' : 'down'} />}
  163. onClick={showFeedback ? dismissPrompt : showPrompt}
  164. title={
  165. showFeedback
  166. ? t('Hide feedback on all issue details')
  167. : t('Unhide feedback on all issue details')
  168. }
  169. disabled={promptError}
  170. busy={promptLoading}
  171. >
  172. {showFeedback ? t('Hide') : t('Show')}
  173. </Button>
  174. </ErrorBoundary>
  175. )
  176. }
  177. >
  178. {promptLoading ? (
  179. <Placeholder />
  180. ) : showFeedback ? (
  181. <EventUserFeedback
  182. report={event.userReport}
  183. orgSlug={organization.slug}
  184. issueId={group.id}
  185. showEventLink={false}
  186. />
  187. ) : null}
  188. </InterimSection>
  189. )}
  190. {event.type === EventOrGroupType.ERROR &&
  191. organization.features.includes('insights-addon-modules') &&
  192. event?.entries
  193. ?.filter((x): x is EntryException => x.type === EntryType.EXCEPTION)
  194. .flatMap(x => x.data.values ?? [])
  195. .some(({value}) => {
  196. const lowerText = value?.toLowerCase();
  197. return (
  198. lowerText &&
  199. (lowerText.includes('api key') || lowerText.includes('429')) &&
  200. (lowerText.includes('openai') ||
  201. lowerText.includes('anthropic') ||
  202. lowerText.includes('cohere') ||
  203. lowerText.includes('langchain'))
  204. );
  205. }) ? (
  206. <LazyLoad
  207. LazyComponent={LLMMonitoringSection}
  208. event={event}
  209. organization={organization}
  210. />
  211. ) : null}
  212. {group.issueCategory === IssueCategory.UPTIME && (
  213. <UptimeDataSection group={group} />
  214. )}
  215. {group.issueCategory === IssueCategory.CRON && (
  216. <CronTimelineSection
  217. event={event}
  218. organization={organization}
  219. project={project}
  220. />
  221. )}
  222. <HighlightsDataSection event={event} project={project} viewAllRef={tagsRef} />
  223. {showPossibleSolutionsHigher && (
  224. <ResourcesAndPossibleSolutionsIssueDetailsContent
  225. event={event}
  226. project={project}
  227. group={group}
  228. />
  229. )}
  230. <EventEvidence event={event} group={group} project={project} />
  231. {defined(eventEntries[EntryType.MESSAGE]) && (
  232. <EntryErrorBoundary type={EntryType.MESSAGE}>
  233. <Message event={event} data={eventEntries[EntryType.MESSAGE].data} />
  234. </EntryErrorBoundary>
  235. )}
  236. {defined(eventEntries[EntryType.EXCEPTION]) && (
  237. <EntryErrorBoundary type={EntryType.EXCEPTION}>
  238. <Exception
  239. event={event}
  240. data={eventEntries[EntryType.EXCEPTION].data}
  241. projectSlug={projectSlug}
  242. groupingCurrentLevel={groupingCurrentLevel}
  243. hasHierarchicalGrouping={hasHierarchicalGrouping}
  244. />
  245. </EntryErrorBoundary>
  246. )}
  247. {defined(eventEntries[EntryType.STACKTRACE]) && (
  248. <EntryErrorBoundary type={EntryType.STACKTRACE}>
  249. <StackTrace
  250. event={event}
  251. data={eventEntries[EntryType.STACKTRACE].data}
  252. projectSlug={projectSlug}
  253. groupingCurrentLevel={groupingCurrentLevel}
  254. hasHierarchicalGrouping={hasHierarchicalGrouping}
  255. />
  256. </EntryErrorBoundary>
  257. )}
  258. {defined(eventEntries[EntryType.THREADS]) && (
  259. <EntryErrorBoundary type={EntryType.THREADS}>
  260. <Threads
  261. event={event}
  262. data={eventEntries[EntryType.THREADS].data}
  263. projectSlug={projectSlug}
  264. groupingCurrentLevel={groupingCurrentLevel}
  265. hasHierarchicalGrouping={hasHierarchicalGrouping}
  266. />
  267. </EntryErrorBoundary>
  268. )}
  269. {isANR && (
  270. <QuickTraceQuery
  271. event={event}
  272. location={location}
  273. orgSlug={organization.slug}
  274. type={'spans'}
  275. skipLight
  276. >
  277. {results => {
  278. return (
  279. <QuickTraceContext.Provider value={results}>
  280. <AnrRootCause event={event} organization={organization} />
  281. </QuickTraceContext.Provider>
  282. );
  283. }}
  284. </QuickTraceQuery>
  285. )}
  286. {group.issueCategory === IssueCategory.PERFORMANCE && (
  287. <SpanEvidenceSection
  288. event={event as EventTransaction}
  289. organization={organization}
  290. projectSlug={project.slug}
  291. />
  292. )}
  293. <EventHydrationDiff event={event} group={group} />
  294. {issueTypeConfig.replays.enabled && (
  295. <EventReplay event={event} group={group} projectSlug={project.slug} />
  296. )}
  297. {defined(eventEntries[EntryType.HPKP]) && (
  298. <EntryErrorBoundary type={EntryType.HPKP}>
  299. <Generic
  300. type={EntryType.HPKP}
  301. data={eventEntries[EntryType.HPKP].data}
  302. meta={event._meta?.hpkp ?? {}}
  303. />
  304. </EntryErrorBoundary>
  305. )}
  306. {defined(eventEntries[EntryType.CSP]) && (
  307. <EntryErrorBoundary type={EntryType.CSP}>
  308. <Csp event={event} data={eventEntries[EntryType.CSP].data} />
  309. </EntryErrorBoundary>
  310. )}
  311. {defined(eventEntries[EntryType.EXPECTCT]) && (
  312. <EntryErrorBoundary type={EntryType.EXPECTCT}>
  313. <Generic
  314. type={EntryType.EXPECTCT}
  315. data={eventEntries[EntryType.EXPECTCT].data}
  316. />
  317. </EntryErrorBoundary>
  318. )}
  319. {defined(eventEntries[EntryType.EXPECTSTAPLE]) && (
  320. <EntryErrorBoundary type={EntryType.EXPECTSTAPLE}>
  321. <Generic
  322. type={EntryType.EXPECTSTAPLE}
  323. data={eventEntries[EntryType.EXPECTSTAPLE].data}
  324. />
  325. </EntryErrorBoundary>
  326. )}
  327. {defined(eventEntries[EntryType.TEMPLATE]) && (
  328. <EntryErrorBoundary type={EntryType.TEMPLATE}>
  329. <Template event={event} data={eventEntries[EntryType.TEMPLATE].data} />
  330. </EntryErrorBoundary>
  331. )}
  332. {hasNewTimelineUI ? (
  333. <BreadcrumbsDataSection event={event} group={group} project={project} />
  334. ) : defined(eventEntries[EntryType.BREADCRUMBS]) ? (
  335. <EntryErrorBoundary type={EntryType.BREADCRUMBS}>
  336. <Breadcrumbs
  337. data={eventEntries[EntryType.BREADCRUMBS].data}
  338. organization={organization}
  339. event={event}
  340. />
  341. </EntryErrorBoundary>
  342. ) : null}
  343. {!showPossibleSolutionsHigher && (
  344. <ResourcesAndPossibleSolutionsIssueDetailsContent
  345. event={event}
  346. project={project}
  347. group={group}
  348. />
  349. )}
  350. {defined(eventEntries[EntryType.DEBUGMETA]) && (
  351. <EntryErrorBoundary type={EntryType.DEBUGMETA}>
  352. <DebugMeta
  353. event={event}
  354. projectSlug={projectSlug}
  355. groupId={group?.id}
  356. data={eventEntries[EntryType.DEBUGMETA].data}
  357. />
  358. </EntryErrorBoundary>
  359. )}
  360. {defined(eventEntries[EntryType.REQUEST]) && (
  361. <EntryErrorBoundary type={EntryType.REQUEST}>
  362. <Request event={event} data={eventEntries[EntryType.REQUEST].data} />
  363. </EntryErrorBoundary>
  364. )}
  365. {hasStreamlinedUI ? (
  366. <EventTagsDataSection event={event} projectSlug={project.slug} ref={tagsRef} />
  367. ) : (
  368. <div ref={tagsRef}>
  369. <EventTagsAndScreenshot event={event} projectSlug={project.slug} />
  370. </div>
  371. )}
  372. <EventContexts group={group} event={event} />
  373. <EventExtraData event={event} />
  374. <EventPackageData event={event} />
  375. <EventDevice event={event} />
  376. <EventViewHierarchy event={event} project={project} />
  377. {hasStreamlinedUI && (
  378. <ScreenshotDataSection event={event} projectSlug={project.slug} />
  379. )}
  380. <EventAttachments event={event} projectSlug={project.slug} />
  381. <EventSdk sdk={event.sdk} meta={event._meta?.sdk} />
  382. {hasStreamlinedUI && (
  383. <EventProcessingErrors event={event} project={project} isShare={false} />
  384. )}
  385. {event.groupID && (
  386. <EventGroupingInfo
  387. projectSlug={project.slug}
  388. event={event}
  389. showGroupingConfig={
  390. organization.features.includes('set-grouping-config') &&
  391. 'groupingConfig' in event
  392. }
  393. group={group}
  394. />
  395. )}
  396. {!hasReplay && (
  397. <EventRRWebIntegration
  398. event={event}
  399. orgId={organization.slug}
  400. projectSlug={project.slug}
  401. />
  402. )}
  403. </Fragment>
  404. );
  405. }
  406. function ResourcesAndPossibleSolutionsIssueDetailsContent({
  407. event,
  408. project,
  409. group,
  410. }: Required<EventDetailsContentProps>) {
  411. return (
  412. <ErrorBoundary mini>
  413. <ResourcesAndPossibleSolutions event={event} project={project} group={group} />
  414. </ErrorBoundary>
  415. );
  416. }
  417. function PerformanceDurationRegressionIssueDetailsContent({
  418. group,
  419. event,
  420. project,
  421. }: Required<EventDetailsContentProps>) {
  422. return (
  423. <Fragment>
  424. <ErrorBoundary mini>
  425. <EventRegressionSummary event={event} group={group} />
  426. </ErrorBoundary>
  427. <ErrorBoundary mini>
  428. <EventBreakpointChart event={event} />
  429. </ErrorBoundary>
  430. <ErrorBoundary mini>
  431. <AggregateSpanDiff event={event} project={project} />
  432. </ErrorBoundary>
  433. <ErrorBoundary mini>
  434. <EventComparison event={event} project={project} />
  435. </ErrorBoundary>
  436. </Fragment>
  437. );
  438. }
  439. function ProfilingDurationRegressionIssueDetailsContent({
  440. group,
  441. event,
  442. project,
  443. }: Required<EventDetailsContentProps>) {
  444. const organization = useOrganization();
  445. return (
  446. <TransactionsDeltaProvider event={event} project={project}>
  447. <Fragment>
  448. <ErrorBoundary mini>
  449. <EventRegressionSummary event={event} group={group} />
  450. </ErrorBoundary>
  451. <ErrorBoundary mini>
  452. <EventFunctionBreakpointChart event={event} />
  453. </ErrorBoundary>
  454. {!organization.features.includes('continuous-profiling-compat') && (
  455. <ErrorBoundary mini>
  456. <EventAffectedTransactions event={event} group={group} project={project} />
  457. </ErrorBoundary>
  458. )}
  459. <ErrorBoundary mini>
  460. <DataSection>
  461. <b>{t('Largest Changes in Call Stack Frequency')}</b>
  462. <p>
  463. {t(`See which functions changed the most before and after the regression. The
  464. frame with the largest increase in call stack population likely
  465. contributed to the cause for the duration regression.`)}
  466. </p>
  467. h
  468. <EventDifferentialFlamegraph event={event} />
  469. </DataSection>
  470. </ErrorBoundary>
  471. <ErrorBoundary mini>
  472. <EventFunctionComparisonList event={event} group={group} project={project} />
  473. </ErrorBoundary>
  474. </Fragment>
  475. </TransactionsDeltaProvider>
  476. );
  477. }
  478. export default function GroupEventDetailsContent({
  479. group,
  480. event,
  481. project,
  482. }: EventDetailsContentProps) {
  483. const hasStreamlinedUI = useHasStreamlinedUI();
  484. if (!event) {
  485. return (
  486. <NotFoundMessage>
  487. <h3>{t('Latest event not available')}</h3>
  488. </NotFoundMessage>
  489. );
  490. }
  491. switch (group.issueType) {
  492. case IssueType.PERFORMANCE_DURATION_REGRESSION:
  493. case IssueType.PERFORMANCE_ENDPOINT_REGRESSION: {
  494. return (
  495. <PerformanceDurationRegressionIssueDetailsContent
  496. group={group}
  497. event={event}
  498. project={project}
  499. />
  500. );
  501. }
  502. case IssueType.PROFILE_FUNCTION_REGRESSION_EXPERIMENTAL:
  503. case IssueType.PROFILE_FUNCTION_REGRESSION: {
  504. return (
  505. <ProfilingDurationRegressionIssueDetailsContent
  506. group={group}
  507. event={event}
  508. project={project}
  509. />
  510. );
  511. }
  512. default: {
  513. return hasStreamlinedUI ? (
  514. <EventDetails event={event} group={group} project={project} />
  515. ) : (
  516. <EventDetailsContent group={group} event={event} project={project} />
  517. );
  518. }
  519. }
  520. }
  521. /**
  522. * This component is only necessary while the streamlined UI is not in place.
  523. * The FoldSection by default wraps its children with an ErrorBoundary, preventing content
  524. * from crashing the whole page if an error occurs, but EventDataSection does not do this.
  525. */
  526. function EntryErrorBoundary({
  527. children,
  528. type,
  529. }: {
  530. children: React.ReactNode;
  531. type: EntryType;
  532. }) {
  533. return (
  534. <ErrorBoundary
  535. customComponent={
  536. <EventDataSection type={type} title={type}>
  537. <p>{t('There was an error rendering this data.')}</p>
  538. </EventDataSection>
  539. }
  540. >
  541. {children}
  542. </ErrorBoundary>
  543. );
  544. }
  545. const NotFoundMessage = styled('div')`
  546. padding: ${space(2)} ${space(4)};
  547. `;
  548. const StyledDataSection = styled(DataSection)`
  549. padding: ${space(0.5)} ${space(2)};
  550. @media (min-width: ${p => p.theme.breakpoints.medium}) {
  551. padding: ${space(1)} ${space(4)};
  552. }
  553. &:empty {
  554. display: none;
  555. }
  556. `;