eventOrGroupTitle.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import ProjectsStore from 'sentry/stores/projectsStore';
  4. import {BaseGroup, GroupTombstone, Organization} from 'sentry/types';
  5. import {Event} from 'sentry/types/event';
  6. import {getTitle} from 'sentry/utils/events';
  7. import withOrganization from 'sentry/utils/withOrganization';
  8. import EventTitleTreeLabel from './eventTitleTreeLabel';
  9. import {StackTracePreview} from './stacktracePreview';
  10. type Props = {
  11. data: Event | BaseGroup | GroupTombstone;
  12. organization: Organization;
  13. className?: string;
  14. /* is issue breakdown? */
  15. grouping?: boolean;
  16. hasGuideAnchor?: boolean;
  17. withStackTracePreview?: boolean;
  18. };
  19. function EventOrGroupTitle({
  20. organization,
  21. data,
  22. withStackTracePreview,
  23. grouping = false,
  24. className,
  25. }: Props) {
  26. const event = data as Event;
  27. const groupingCurrentLevel = (data as BaseGroup).metadata?.current_level;
  28. const hasGroupingTreeUI = !!organization?.features.includes('grouping-tree-ui');
  29. const hasGroupingStacktraceUI = !!organization?.features.includes(
  30. 'grouping-stacktrace-ui'
  31. );
  32. const {id, eventID, groupID, projectID} = event;
  33. const {title, subtitle, treeLabel} = getTitle(event, organization?.features, grouping);
  34. return (
  35. <Wrapper className={className} hasGroupingTreeUI={hasGroupingTreeUI}>
  36. {withStackTracePreview ? (
  37. <StyledStacktracePreview
  38. organization={organization}
  39. issueId={groupID ? groupID : id}
  40. groupingCurrentLevel={groupingCurrentLevel}
  41. // we need eventId and projectSlug only when hovering over Event, not Group
  42. // (different API call is made to get the stack trace then)
  43. eventId={eventID}
  44. projectSlug={eventID ? ProjectsStore.getById(projectID)?.slug : undefined}
  45. hasGroupingStacktraceUI={hasGroupingStacktraceUI}
  46. >
  47. {treeLabel ? <EventTitleTreeLabel treeLabel={treeLabel} /> : title}
  48. </StyledStacktracePreview>
  49. ) : treeLabel ? (
  50. <EventTitleTreeLabel treeLabel={treeLabel} />
  51. ) : (
  52. title
  53. )}
  54. {subtitle && (
  55. <Fragment>
  56. <Spacer />
  57. <Subtitle title={subtitle}>{subtitle}</Subtitle>
  58. <br />
  59. </Fragment>
  60. )}
  61. </Wrapper>
  62. );
  63. }
  64. export default withOrganization(EventOrGroupTitle);
  65. /**
  66. * &nbsp; is used instead of margin/padding to split title and subtitle
  67. * into 2 separate text nodes on the HTML AST. This allows the
  68. * title to be highlighted without spilling over to the subtitle.
  69. */
  70. const Spacer = () => <span style={{display: 'inline-block', width: 10}}>&nbsp;</span>;
  71. const Subtitle = styled('em')`
  72. color: ${p => p.theme.gray300};
  73. font-style: normal;
  74. `;
  75. const StyledStacktracePreview = styled(StackTracePreview)<{
  76. hasGroupingStacktraceUI: boolean;
  77. }>`
  78. ${p =>
  79. p.hasGroupingStacktraceUI &&
  80. `
  81. display: inline-flex;
  82. overflow: hidden;
  83. height: 100%;
  84. > span:first-child {
  85. ${p.theme.overflowEllipsis}
  86. }
  87. `}
  88. `;
  89. const Wrapper = styled('span')<{hasGroupingTreeUI: boolean}>`
  90. ${p =>
  91. p.hasGroupingTreeUI &&
  92. `
  93. display: inline-grid;
  94. grid-template-columns: auto max-content 1fr max-content;
  95. align-items: flex-end;
  96. line-height: 100%;
  97. ${Subtitle} {
  98. ${p.theme.overflowEllipsis};
  99. display: inline-block;
  100. height: 100%;
  101. }
  102. `}
  103. `;