eventOrGroupTitle.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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. hasGuideAnchor?: boolean;
  16. withStackTracePreview?: boolean;
  17. guideAnchorName?: string;
  18. /* is issue breakdown? */
  19. grouping?: boolean;
  20. className?: string;
  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. <StyledStacktracePreview
  46. organization={organization}
  47. issueId={groupID ? groupID : id}
  48. groupingCurrentLevel={groupingCurrentLevel}
  49. // we need eventId and projectSlug only when hovering over Event, not Group
  50. // (different API call is made to get the stack trace then)
  51. eventId={eventID}
  52. projectSlug={eventID ? ProjectsStore.getById(projectID)?.slug : undefined}
  53. disablePreview={!withStackTracePreview}
  54. hasGroupingStacktraceUI={hasGroupingStacktraceUI}
  55. >
  56. {treeLabel ? <EventTitleTreeLabel treeLabel={treeLabel} /> : title}
  57. </StyledStacktracePreview>
  58. </GuideAnchor>
  59. {subtitle && (
  60. <Fragment>
  61. <Spacer />
  62. <Subtitle title={subtitle}>{subtitle}</Subtitle>
  63. <br />
  64. </Fragment>
  65. )}
  66. </Wrapper>
  67. );
  68. }
  69. export default withOrganization(EventOrGroupTitle);
  70. /**
  71. * &nbsp; is used instead of margin/padding to split title and subtitle
  72. * into 2 separate text nodes on the HTML AST. This allows the
  73. * title to be highlighted without spilling over to the subtitle.
  74. */
  75. const Spacer = () => <span style={{display: 'inline-block', width: 10}}>&nbsp;</span>;
  76. const Subtitle = styled('em')`
  77. color: ${p => p.theme.gray300};
  78. font-style: normal;
  79. `;
  80. const StyledStacktracePreview = styled(StacktracePreview)<{
  81. hasGroupingStacktraceUI: boolean;
  82. }>`
  83. ${p =>
  84. p.hasGroupingStacktraceUI &&
  85. `
  86. display: inline-flex;
  87. overflow: hidden;
  88. > span:first-child {
  89. ${overflowEllipsis}
  90. }
  91. `}
  92. `;
  93. const Wrapper = styled('span')<{hasGroupingTreeUI: boolean}>`
  94. ${p =>
  95. p.hasGroupingTreeUI &&
  96. `
  97. display: inline-grid;
  98. grid-template-columns: auto max-content 1fr max-content;
  99. align-items: flex-end;
  100. line-height: 100%;
  101. ${Subtitle} {
  102. ${overflowEllipsis};
  103. display: inline-block;
  104. }
  105. `}
  106. `;