sidebar.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import {Fragment, useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import GuideAnchor from 'sentry/components/assistant/guideAnchor';
  4. import ErrorBoundary from 'sentry/components/errorBoundary';
  5. import * as Layout from 'sentry/components/layouts/thirds';
  6. import * as SidebarSection from 'sentry/components/sidebarSection';
  7. import {space} from 'sentry/styles/space';
  8. import type {Event} from 'sentry/types/event';
  9. import type {Group, TeamParticipant, UserParticipant} from 'sentry/types/group';
  10. import type {Project} from 'sentry/types/project';
  11. import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
  12. import useOrganization from 'sentry/utils/useOrganization';
  13. import {useUser} from 'sentry/utils/useUser';
  14. import StreamlinedActivitySection from 'sentry/views/issueDetails/streamline/sidebar/activitySection';
  15. import {ExternalIssueList} from 'sentry/views/issueDetails/streamline/sidebar/externalIssueList';
  16. import FirstLastSeenSection from 'sentry/views/issueDetails/streamline/sidebar/firstLastSeenSection';
  17. import {MergedIssuesSidebarSection} from 'sentry/views/issueDetails/streamline/sidebar/mergedSidebarSection';
  18. import {MetricIssueSidebarSection} from 'sentry/views/issueDetails/streamline/sidebar/metricIssueSidebarSection';
  19. import PeopleSection from 'sentry/views/issueDetails/streamline/sidebar/peopleSection';
  20. import {SimilarIssuesSidebarSection} from 'sentry/views/issueDetails/streamline/sidebar/similarIssuesSidebarSection';
  21. import SolutionsSection from 'sentry/views/issueDetails/streamline/sidebar/solutionsSection';
  22. type Props = {
  23. group: Group;
  24. project: Project;
  25. event?: Event;
  26. };
  27. export default function StreamlinedSidebar({group, event, project}: Props) {
  28. const activeUser = useUser();
  29. const organization = useOrganization();
  30. const {userParticipants, teamParticipants, viewers} = useMemo(() => {
  31. return {
  32. userParticipants: group.participants.filter(
  33. (p): p is UserParticipant => p.type === 'user'
  34. ),
  35. teamParticipants: group.participants.filter(
  36. (p): p is TeamParticipant => p.type === 'team'
  37. ),
  38. viewers: group.seenBy.filter(user => activeUser.id !== user.id),
  39. };
  40. }, [group, activeUser.id]);
  41. const showPeopleSection = group.participants.length > 0 || viewers.length > 0;
  42. const issueTypeConfig = getConfigForIssueType(group, group.project);
  43. const showMetricIssueSection = event?.contexts?.metric_alert?.alert_rule_id;
  44. return (
  45. <Side>
  46. <GuideAnchor target="issue_sidebar_releases" position="left">
  47. <FirstLastSeenSection group={group} />
  48. </GuideAnchor>
  49. <StyledBreak />
  50. {((organization.features.includes('gen-ai-features') &&
  51. issueTypeConfig.issueSummary.enabled &&
  52. !organization.hideAiFeatures) ||
  53. issueTypeConfig.resources) && (
  54. <ErrorBoundary mini>
  55. <SolutionsSection group={group} project={project} event={event} />
  56. <StyledBreak />
  57. </ErrorBoundary>
  58. )}
  59. {event && (
  60. <ErrorBoundary mini>
  61. <ExternalIssueList group={group} event={event} project={project} />
  62. <StyledBreak style={{marginBottom: space(0.5)}} />
  63. </ErrorBoundary>
  64. )}
  65. <StreamlinedActivitySection group={group} />
  66. {showPeopleSection && (
  67. <Fragment>
  68. <StyledBreak />
  69. <PeopleSection
  70. userParticipants={userParticipants}
  71. teamParticipants={teamParticipants}
  72. viewers={viewers}
  73. />
  74. </Fragment>
  75. )}
  76. {issueTypeConfig.similarIssues.enabled && (
  77. <Fragment>
  78. <StyledBreak />
  79. <SimilarIssuesSidebarSection />
  80. </Fragment>
  81. )}
  82. {issueTypeConfig.mergedIssues.enabled && (
  83. <Fragment>
  84. <StyledBreak />
  85. <MergedIssuesSidebarSection />
  86. </Fragment>
  87. )}
  88. {showMetricIssueSection && (
  89. <Fragment>
  90. <StyledBreak />
  91. <MetricIssueSidebarSection event={event} />
  92. </Fragment>
  93. )}
  94. </Side>
  95. );
  96. }
  97. const StyledBreak = styled('hr')`
  98. margin-top: ${space(1.5)};
  99. margin-bottom: ${space(1.5)};
  100. border-color: ${p => p.theme.border};
  101. `;
  102. export const SidebarSectionTitle = styled(SidebarSection.Title)`
  103. margin-bottom: ${space(1)};
  104. color: ${p => p.theme.headingColor};
  105. `;
  106. const Side = styled(Layout.Side)`
  107. position: relative;
  108. padding: ${space(1.5)} ${space(2)};
  109. @media (max-width: ${p => p.theme.breakpoints.large}) {
  110. border-top: 1px solid ${p => p.theme.border};
  111. }
  112. `;