index.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import styled from '@emotion/styled';
  2. import Footer from 'sentry/components/footer';
  3. import HookOrDefault from 'sentry/components/hookOrDefault';
  4. import Nav from 'sentry/components/nav';
  5. import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
  6. import Sidebar from 'sentry/components/sidebar';
  7. import type {Organization} from 'sentry/types/organization';
  8. import useRouteAnalyticsHookSetup from 'sentry/utils/routeAnalytics/useRouteAnalyticsHookSetup';
  9. import useDevToolbar from 'sentry/utils/useDevToolbar';
  10. import {useIsSentryEmployee} from 'sentry/utils/useIsSentryEmployee';
  11. import useOrganization from 'sentry/utils/useOrganization';
  12. import OrganizationContainer from 'sentry/views/organizationContainer';
  13. import Body from './body';
  14. interface Props {
  15. children: React.ReactNode;
  16. }
  17. const OrganizationHeader = HookOrDefault({
  18. hookName: 'component:organization-header',
  19. });
  20. function DevToolInit() {
  21. const isEmployee = useIsSentryEmployee();
  22. const organization = useOrganization();
  23. const showDevToolbar = organization.features.includes('devtoolbar');
  24. useDevToolbar({enabled: showDevToolbar && isEmployee});
  25. return null;
  26. }
  27. function OrganizationLayout({children}: Props) {
  28. useRouteAnalyticsHookSetup();
  29. // XXX(epurkhiser): The OrganizationContainer is responsible for ensuring the
  30. // oganization is loaded before rendering children. Organization may not be
  31. // loaded yet when this first renders.
  32. const organization = useOrganization({allowNull: true});
  33. const hasNavigationV2 = organization?.features.includes('navigation-sidebar-v2');
  34. const App = hasNavigationV2 ? AppLayout : LegacyAppLayout;
  35. return (
  36. <SentryDocumentTitle noSuffix title={organization?.name ?? 'Sentry'}>
  37. <OrganizationContainer>
  38. <App organization={organization}>{children}</App>
  39. </OrganizationContainer>
  40. </SentryDocumentTitle>
  41. );
  42. }
  43. interface LayoutProps extends Props {
  44. organization: Organization | null;
  45. }
  46. function AppLayout({children, organization}: LayoutProps) {
  47. return (
  48. <AppContainer className="app">
  49. <Nav />
  50. {/* The `#main` selector is used to make the app content `inert` when an overlay is active */}
  51. <BodyContainer id="main">
  52. {organization && <OrganizationHeader organization={organization} />}
  53. {organization && <DevToolInit />}
  54. <Body>{children}</Body>
  55. <Footer />
  56. </BodyContainer>
  57. </AppContainer>
  58. );
  59. }
  60. function LegacyAppLayout({children, organization}: LayoutProps) {
  61. return (
  62. <div className="app">
  63. {organization && <OrganizationHeader organization={organization} />}
  64. {organization && <DevToolInit />}
  65. <Sidebar />
  66. <Body>{children}</Body>
  67. <Footer />
  68. </div>
  69. );
  70. }
  71. const AppContainer = styled('div')`
  72. display: flex;
  73. @media (min-width: ${p => p.theme.breakpoints.medium}) {
  74. flex-direction: row;
  75. }
  76. `;
  77. const BodyContainer = styled('div')`
  78. display: flex;
  79. flex-direction: column;
  80. flex: 1;
  81. `;
  82. export default OrganizationLayout;