eventOrGroupTitle.tsx 3.7 KB

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