sidebar.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. </ErrorBoundary>
  59. )}
  60. <StreamlinedActivitySection group={group} />
  61. {showPeopleSection && (
  62. <Fragment>
  63. <StyledBreak />
  64. <PeopleSection
  65. userParticipants={userParticipants}
  66. teamParticipants={teamParticipants}
  67. viewers={viewers}
  68. />
  69. </Fragment>
  70. )}
  71. {issueTypeConfig.similarIssues.enabled && (
  72. <Fragment>
  73. <StyledBreak />
  74. <SimilarIssuesSidebarSection />
  75. </Fragment>
  76. )}
  77. {issueTypeConfig.mergedIssues.enabled && (
  78. <Fragment>
  79. <StyledBreak />
  80. <MergedIssuesSidebarSection />
  81. </Fragment>
  82. )}
  83. {issueTypeConfig.detector.enabled && (
  84. <Fragment>
  85. <StyledBreak />
  86. <DetectorSection group={group} project={project} />
  87. </Fragment>
  88. )}
  89. </Side>
  90. );
  91. }
  92. const StyledBreak = styled('hr')`
  93. margin-top: ${space(1.5)};
  94. margin-bottom: ${space(1.5)};
  95. border-color: ${p => p.theme.border};
  96. `;
  97. export const SidebarSectionTitle = styled(SidebarSection.Title)`
  98. margin-bottom: ${space(1)};
  99. color: ${p => p.theme.headingColor};
  100. `;
  101. const Side = styled(Layout.Side)`
  102. position: relative;
  103. padding: ${space(1.5)} ${space(2)};
  104. @media (max-width: ${p => p.theme.breakpoints.large}) {
  105. border-top: 1px solid ${p => p.theme.border};
  106. }
  107. `;