groupDetailsLayout.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import * as Layout from 'sentry/components/layouts/thirds';
  4. import {space} from 'sentry/styles/space';
  5. import type {Event} from 'sentry/types/event';
  6. import type {Group} from 'sentry/types/group';
  7. import type {Project} from 'sentry/types/project';
  8. import theme from 'sentry/utils/theme';
  9. import useMedia from 'sentry/utils/useMedia';
  10. import {useSyncedLocalStorageState} from 'sentry/utils/useSyncedLocalStorageState';
  11. import {EventDetailsHeader} from 'sentry/views/issueDetails/streamline/eventDetailsHeader';
  12. import {IssueEventNavigation} from 'sentry/views/issueDetails/streamline/eventNavigation';
  13. import {useEventQuery} from 'sentry/views/issueDetails/streamline/eventSearch';
  14. import StreamlinedGroupHeader from 'sentry/views/issueDetails/streamline/header';
  15. import StreamlinedSidebar from 'sentry/views/issueDetails/streamline/sidebar';
  16. import type {ReprocessingStatus} from 'sentry/views/issueDetails/utils';
  17. interface GroupDetailsLayoutProps {
  18. children: React.ReactNode;
  19. event: Event | undefined;
  20. group: Group;
  21. groupReprocessingStatus: ReprocessingStatus;
  22. project: Project;
  23. }
  24. export function GroupDetailsLayout({
  25. group,
  26. event,
  27. project,
  28. groupReprocessingStatus,
  29. children,
  30. }: GroupDetailsLayoutProps) {
  31. const searchQuery = useEventQuery({group});
  32. const [sidebarOpen] = useSyncedLocalStorageState('issue-details-sidebar-open', true);
  33. const isScreenSmall = useMedia(`(max-width: ${theme.breakpoints.large})`);
  34. const shouldDisplaySidebar = sidebarOpen || isScreenSmall;
  35. return (
  36. <Fragment>
  37. <StreamlinedGroupHeader
  38. group={group}
  39. event={event ?? null}
  40. project={project}
  41. groupReprocessingStatus={groupReprocessingStatus}
  42. />
  43. <StyledLayoutBody data-test-id="group-event-details" sidebarOpen={sidebarOpen}>
  44. <div>
  45. <EventDetailsHeader event={event} group={group} />
  46. <GroupContent>
  47. <div>
  48. <IssueEventNavigation event={event} group={group} query={searchQuery} />
  49. {children}
  50. </div>
  51. </GroupContent>
  52. </div>
  53. {shouldDisplaySidebar ? (
  54. <StreamlinedSidebar group={group} event={event} project={project} />
  55. ) : null}
  56. </StyledLayoutBody>
  57. </Fragment>
  58. );
  59. }
  60. const StyledLayoutBody = styled(Layout.Body)<{
  61. sidebarOpen: boolean;
  62. }>`
  63. padding: 0 !important;
  64. gap: 0 !important;
  65. @media (min-width: ${p => p.theme.breakpoints.large}) {
  66. align-content: stretch;
  67. grid-template-columns: minmax(100px, auto) ${p => (p.sidebarOpen ? '325px' : '0px')};
  68. }
  69. `;
  70. const GroupContent = styled(Layout.Main)`
  71. background: ${p => p.theme.backgroundSecondary};
  72. min-height: 100vh;
  73. padding: 10px ${space(1.5)} ${space(1.5)};
  74. display: flex;
  75. flex-direction: column;
  76. @media (min-width: ${p => p.theme.breakpoints.large}) {
  77. border-right: 1px solid ${p => p.theme.translucentBorder};
  78. }
  79. @media (max-width: ${p => p.theme.breakpoints.large}) {
  80. border-bottom-width: 1px solid ${p => p.theme.translucentBorder};
  81. }
  82. `;