sidebar.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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 {DetectorSection} from 'sentry/views/issueDetails/streamline/sidebar/detectorSection';
  16. import {ExternalIssueList} from 'sentry/views/issueDetails/streamline/sidebar/externalIssueList';
  17. import FirstLastSeenSection from 'sentry/views/issueDetails/streamline/sidebar/firstLastSeenSection';
  18. import {MergedIssuesSidebarSection} from 'sentry/views/issueDetails/streamline/sidebar/mergedSidebarSection';
  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. return (
  44. <Side>
  45. <GuideAnchor target="issue_sidebar_releases" position="left">
  46. <FirstLastSeenSection group={group} />
  47. </GuideAnchor>
  48. <StyledBreak />
  49. {((organization.features.includes('gen-ai-features') &&
  50. issueTypeConfig.issueSummary.enabled &&
  51. !organization.hideAiFeatures) ||
  52. issueTypeConfig.resources) && (
  53. <SolutionsSection group={group} project={project} event={event} />
  54. )}
  55. {event && (
  56. <ErrorBoundary mini>
  57. <ExternalIssueList group={group} event={event} project={project} />
  58. <StyledBreak style={{marginBottom: space(0.5)}} />
  59. </ErrorBoundary>
  60. )}
  61. <StreamlinedActivitySection group={group} />
  62. {showPeopleSection && (
  63. <Fragment>
  64. <StyledBreak />
  65. <PeopleSection
  66. userParticipants={userParticipants}
  67. teamParticipants={teamParticipants}
  68. viewers={viewers}
  69. />
  70. </Fragment>
  71. )}
  72. {issueTypeConfig.similarIssues.enabled && (
  73. <Fragment>
  74. <StyledBreak />
  75. <SimilarIssuesSidebarSection />
  76. </Fragment>
  77. )}
  78. {issueTypeConfig.mergedIssues.enabled && (
  79. <Fragment>
  80. <StyledBreak />
  81. <MergedIssuesSidebarSection />
  82. </Fragment>
  83. )}
  84. {/* Currently, we require events for displaying detector details */}
  85. {event && issueTypeConfig.detector.enabled && (
  86. <Fragment>
  87. <StyledBreak />
  88. <DetectorSection event={event} group={group} project={project} />
  89. </Fragment>
  90. )}
  91. </Side>
  92. );
  93. }
  94. const StyledBreak = styled('hr')`
  95. margin-top: ${space(1.5)};
  96. margin-bottom: ${space(1.5)};
  97. border-color: ${p => p.theme.border};
  98. `;
  99. export const SidebarSectionTitle = styled(SidebarSection.Title)`
  100. margin-bottom: ${space(1)};
  101. color: ${p => p.theme.headingColor};
  102. `;
  103. const Side = styled(Layout.Side)`
  104. position: relative;
  105. padding: ${space(1.5)} ${space(2)};
  106. @media (max-width: ${p => p.theme.breakpoints.large}) {
  107. border-top: 1px solid ${p => p.theme.border};
  108. }
  109. `;