import {Fragment} from 'react'; import { IndexRedirect, IndexRoute as BaseIndexRoute, IndexRouteProps, Redirect, Route as BaseRoute, RouteProps, } from 'react-router'; import memoize from 'lodash/memoize'; import LazyLoad from 'sentry/components/lazyLoad'; import {EXPERIMENTAL_SPA, usingCustomerDomain} from 'sentry/constants'; import {t} from 'sentry/locale'; import HookStore from 'sentry/stores/hookStore'; import {HookName} from 'sentry/types/hooks'; import errorHandler from 'sentry/utils/errorHandler'; import withDomainRedirect from 'sentry/utils/withDomainRedirect'; import withDomainRequired from 'sentry/utils/withDomainRequired'; import App from 'sentry/views/app'; import AuthLayout from 'sentry/views/auth/layout'; import {Tab, TabPaths} from 'sentry/views/issueDetails/types'; import IssueListContainer from 'sentry/views/issueList'; import IssueListOverview from 'sentry/views/issueList/overview'; import OrganizationContextContainer from 'sentry/views/organizationContextContainer'; import OrganizationDetails from 'sentry/views/organizationDetails'; import OrganizationRoot from 'sentry/views/organizationRoot'; import ProjectEventRedirect from 'sentry/views/projectEventRedirect'; import redirectDeprecatedProjectRoute from 'sentry/views/projects/redirectDeprecatedProjectRoute'; import RouteNotFound from 'sentry/views/routeNotFound'; import SettingsWrapper from 'sentry/views/settings/components/settingsWrapper'; type CustomProps = { name?: string; }; /** * We add some additional props to our routes */ const Route = BaseRoute as React.ComponentClass< React.PropsWithChildren >; const IndexRoute = BaseIndexRoute as React.ComponentClass; const hook = (name: HookName) => HookStore.get(name).map(cb => cb()); const SafeLazyLoad = errorHandler(LazyLoad); // NOTE: makeLazyloadComponent is exported for use in the sentry.io (getsentry) // pirvate routing tree. /** * Factory function to produce a component that will render the SafeLazyLoad * _with_ the required props. */ export function makeLazyloadComponent>( resolve: () => Promise<{default: C}> ) { // XXX: Assign the component to a variable so it has a displayname function RouteLazyLoad(props: React.ComponentProps) { // we can use this hook to set the organization as it's // a child of the organization context return ; } return RouteLazyLoad; } // Shorthand to avoid extra line wrapping const make = makeLazyloadComponent; function buildRoutes() { // Read this to understand where to add new routes, how / why the routing // tree is structured the way it is, and how the lazy-loading / // code-splitting works for pages. // // ## Formatting // // NOTE that there are intentionally NO blank lines within route tree blocks. // This helps make it easier to navigate within the file by using your // editors shortcuts to jump between 'paragraphs' of code. // // [!!] Do NOT add blank lines within route blocks to preserve this behavior! // // // ## Lazy loading // // * The `SafeLazyLoad` component // // Most routes are rendered as LazyLoad components (SafeLazyLoad is the // errorHandler wrapped version). This means the rendered component for the // route will only be loaded when the route is loaded. This helps us // "code-split" the app. // // ## Hooks // // There are a number of `hook()` routes placed within the routing tree to // allow for additional routes to be augmented into the application via the // hookStore mechanism. // // // ## The structure // // * `experimentalSpaRoutes` // // These routes are specifically for the experimental single-page-app mode, // where Sentry is run separate from Django. These are NOT part of the root // component. // // Right now these are mainly used for authentication pages. In the future // they would be used for other pages like registration. // // * `rootRoutes` // // These routes live directly under the container, and generally // are not specific to an organization. // // * `settingsRoutes` // // This is the route tree for all of `/settings/`. This route tree is // composed of a few different sub-trees. // // - `accountSettingsRoutes` User specific settings // - `orgSettingsRoutes` Specific to a organization // - `projectSettingsRoutes` Specific to a project // - `legacySettingsRedirects` Routes that used to exist in settings // // * `organizationRoutes` // // This is where a majority of the app routes live. This is wrapped with // the component, which provides the sidebar and // organization context. // // When adding new routes make sure you have both a route that starts // with `/organizations/:orgId` and also 'customer-domains' route that // does not include `/organizations/:orgId`. Often you'll only need to // worry about this for the container route for that section of the UI. // Child routes should access the current organization with `useOrganization()` // or `withOrganization()` methods. // // Within these routes are a variety of subroutes. They are not all // listed here as the subroutes will be added and removed, and most are // self explanatory. // // * `legacyRedirectRoutes` // // This route tree contains routes for many old legacy paths. // // You may also find 's collocated next to the feature routes // they have redirects for. A good rule here is to place 'helper' redirects // next to the routes they redirect to, and place 'legacy route' redirects // for routes that have completely changed in this tree. const experimentalSpaRoutes = EXPERIMENTAL_SPA ? ( import('sentry/views/auth/login'))} /> import('sentry/views/auth/login'))} /> ) : null; const rootRoutes = ( import('sentry/views/app/root'))} /> {hook('routes:root')} import('sentry/views/acceptOrganizationInvite'))} /> import('sentry/views/acceptOrganizationInvite'))} /> import('sentry/views/acceptProjectTransfer'))} /> import('sentry/views/integrationOrganizationLink'))} /> import('sentry/views/integrationOrganizationLink'))} /> import('sentry/views/sentryAppExternalInstallation'))} /> {/* TODO: remove share/issue orgless url */} import('sentry/views/sharedGroupDetails'))} /> import('sentry/views/sharedGroupDetails'))} /> import('sentry/views/organizationCreate'))} /> {usingCustomerDomain && ( import('sentry/views/dataExport/dataDownload')) )} key="orgless-data-export-route" /> )} import('sentry/views/dataExport/dataDownload')) )} key="org-data-export" /> {usingCustomerDomain && ( import('sentry/views/disabledMember')) )} key="orgless-disabled-member-route" /> )} import('sentry/views/disabledMember')))} key="org-disabled-member" /> {usingCustomerDomain && ( import('sentry/views/organizationJoinRequest')) )} key="orgless-join-request" /> )} import('sentry/views/organizationJoinRequest')) )} key="org-join-request" /> {usingCustomerDomain && ( import('sentry/views/onboarding'))} /> )} import('sentry/views/onboarding'))} /> ); const accountSettingsRoutes = ( import('sentry/views/settings/account/accountSettingsLayout') )} > import('sentry/views/settings/account/accountDetails'))} /> import( 'sentry/views/settings/account/notifications/notificationSettingsController' ) )} /> import( 'sentry/views/settings/account/accountNotificationFineTuningController' ) )} /> import('sentry/views/settings/account/accountEmails'))} /> import('sentry/views/settings/account/accountAuthorizations') )} /> import( 'sentry/views/settings/account/accountSecurity/accountSecurityWrapper' ) )} > import('sentry/views/settings/account/accountSecurity') )} /> import('sentry/views/settings/account/accountSecurity/sessionHistory') )} /> import( 'sentry/views/settings/account/accountSecurity/accountSecurityDetails' ) )} /> import( 'sentry/views/settings/account/accountSecurity/accountSecurityEnroll' ) )} /> import('sentry/views/settings/account/accountSubscriptions') )} /> import('sentry/views/settings/account/accountIdentities'))} /> import('sentry/views/settings/account/apiTokens'))} /> import('sentry/views/settings/account/apiNewToken'))} /> import('sentry/views/settings/account/apiApplications') )} /> import('sentry/views/settings/account/apiApplications/details') )} /> {hook('routes:api')} import('sentry/views/settings/account/accountClose'))} /> ); const projectSettingsRoutes = ( import('sentry/views/settings/project/projectSettingsLayout') )} > import('sentry/views/settings/projectGeneralSettings'))} /> import('sentry/views/settings/project/projectTeams'))} /> import('sentry/views/settings/projectAlerts'))} > import('sentry/views/settings/projectAlerts/settings'))} /> import('sentry/views/settings/project/projectEnvironments') )} > import('sentry/views/settings/projectTags'))} /> import('sentry/views/settings/project/projectReleaseTracking') )} /> import('sentry/views/settings/project/projectOwnership'))} /> import('sentry/views/settings/projectDataForwarding'))} /> import('sentry/views/settings/projectSecurityAndPrivacy') )} /> import('sentry/views/settings/projectSecurityAndPrivacy') )} /> import('sentry/views/settings/projectDebugFiles'))} /> import('sentry/views/settings/projectProguard'))} /> import('sentry/views/settings/projectPerformance'))} /> import('sentry/views/settings/projectSourceMaps'))} /> import('sentry/views/settings/projectSourceMaps'))} > import('sentry/views/settings/projectSourceMaps'))} /> import('sentry/views/settings/projectSourceMaps'))} > import('sentry/views/settings/projectSourceMaps'))} /> import('sentry/views/settings/project/projectProcessingIssues') )} /> import('sentry/views/settings/project/projectFilters'))} > import('sentry/views/settings/projectIssueGrouping'))} /> import('sentry/views/settings/project/projectServiceHooks') )} /> import('sentry/views/settings/project/projectCreateServiceHook') )} /> import('sentry/views/settings/project/projectServiceHookDetails') )} /> import('sentry/views/settings/project/projectKeys/list'))} /> import('sentry/views/settings/project/projectKeys/details') )} /> import('sentry/views/settings/project/loaderScript'))} /> import('sentry/views/settings/project/projectUserFeedback') )} /> import('sentry/views/settings/projectSecurityHeaders'))} /> import('sentry/views/settings/projectSecurityHeaders/csp') )} /> import('sentry/views/settings/projectSecurityHeaders/expectCt') )} /> import('sentry/views/settings/projectSecurityHeaders/hpkp') )} /> import('sentry/views/settings/projectPlugins'))} /> import('sentry/views/settings/projectPlugins/details'))} /> ); const orgSettingsRoutes = ( import('sentry/views/settings/organization/organizationSettingsLayout') )} > {hook('routes:organization')} {!usingCustomerDomain && ( import('sentry/views/settings/organizationGeneralSettings') )} /> )} {usingCustomerDomain && ( import('sentry/views/settings/organizationGeneralSettings') )} /> )} import('sentry/views/settings/organizationProjects'))} /> import('sentry/views/settings/organizationApiKeys'))} /> import( 'sentry/views/settings/organizationApiKeys/organizationApiKeyDetails' ) )} /> import('sentry/views/settings/organizationAuditLog'))} /> import('sentry/views/settings/organizationAuth'))} /> import( 'sentry/views/settings/organizationMembers/organizationMembersWrapper' ) )} > import( 'sentry/views/settings/organizationMembers/organizationMembersList' ) )} /> import('sentry/views/settings/organizationMembers/organizationMemberDetail') )} /> import('sentry/views/settings/organizationRateLimits'))} /> import('sentry/views/settings/organizationRelay'))} /> import('sentry/views/settings/organizationRepositories'))} /> import('sentry/views/settings/organizationGeneralSettings') )} /> import('sentry/views/settings/organizationSecurityAndPrivacy') )} /> import('sentry/views/settings/organizationSecurityAndPrivacy') )} /> import('sentry/views/settings/organizationTeams'))} /> import('sentry/views/settings/organizationTeams/teamDetails') )} > import('sentry/views/settings/organizationTeams/teamMembers') )} /> import('sentry/views/settings/organizationTeams/teamNotifications') )} /> import('sentry/views/settings/organizationTeams/teamProjects') )} /> import('sentry/views/settings/organizationTeams/teamSettings') )} /> import('sentry/views/settings/organizationIntegrations/pluginDetailedView') )} /> import( 'sentry/views/settings/organizationIntegrations/sentryAppDetailedView' ) )} /> import( 'sentry/views/settings/organizationIntegrations/docIntegrationDetailedView' ) )} /> import( 'sentry/views/settings/organizationIntegrations/integrationListDirectory' ) )} /> import( 'sentry/views/settings/organizationIntegrations/integrationDetailedView' ) )} /> import( 'sentry/views/settings/organizationIntegrations/configureIntegration' ) )} /> import('sentry/views/settings/organizationDeveloperSettings') )} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryApplicationDetails' ) )} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryApplicationDetails' ) )} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryApplicationDetails' ) )} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryApplicationDashboard' ) )} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryFunctionDetails' ) )} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryFunctionDetails' ) )} /> import('sentry/views/settings/organizationAuthTokens'))} /> import('sentry/views/settings/organizationAuthTokens/newAuthToken') )} /> import('sentry/views/settings/organizationAuthTokens/authTokenDetails') )} /> ); const legacySettingsRedirects = ( ); const settingsRoutes = ( import('sentry/views/settings/settingsIndex'))} /> {accountSettingsRoutes} {usingCustomerDomain && ( {orgSettingsRoutes} {projectSettingsRoutes} )} {orgSettingsRoutes} {projectSettingsRoutes} {legacySettingsRedirects} ); const projectsChildRoutes = ( import('sentry/views/projectsDashboard'))} /> import('sentry/views/projectInstall/newProject'))} /> import('sentry/views/projectDetail'))} /> import('sentry/views/projectInstall/platformOrIntegration') )} /> ); const projectsRoutes = ( {usingCustomerDomain && ( import('sentry/views/projects/'))} key="orgless-projects-route" > {projectsChildRoutes} )} import('sentry/views/projects/'))} key="org-projects" > {projectsChildRoutes} ); const dashboardWidgetRoutes = ( import('sentry/views/dashboards/widgetBuilder'))} /> import('sentry/views/dashboards/widgetBuilder'))} /> import('sentry/views/dashboards/view'))} /> ); const dashboardRoutes = ( {usingCustomerDomain && ( import('sentry/views/dashboards')))} key="orgless-dashboards-route" > import('sentry/views/dashboards/manage'))} /> )} import('sentry/views/dashboards')))} key="org-dashboards" > import('sentry/views/dashboards/manage'))} /> {usingCustomerDomain && ( import('sentry/views/dashboards/create')) )} key="orgless-dashboards-new-route" > import('sentry/views/dashboards/widgetBuilder'))} /> import('sentry/views/dashboards/widgetBuilder'))} /> )} import('sentry/views/dashboards/create')) )} key="org-dashboards-new" > import('sentry/views/dashboards/widgetBuilder'))} /> import('sentry/views/dashboards/widgetBuilder'))} /> {usingCustomerDomain && ( import('sentry/views/dashboards/create')) )} key="orgless-dashboards-new-template-route" > import('sentry/views/dashboards/create'))} /> )} import('sentry/views/dashboards/create')) )} key="org-dashboards-new-template" > import('sentry/views/dashboards/create'))} /> {usingCustomerDomain && ( )} {usingCustomerDomain && ( import('sentry/views/dashboards/view')) )} key="orgless-dashboards-dashboard-id-route" > {dashboardWidgetRoutes} )} import('sentry/views/dashboards/view')) )} key="org-dashboards-dashboard-id" > {dashboardWidgetRoutes} ); const alertChildRoutes = ({forCustomerDomain}: {forCustomerDomain: boolean}) => { return ( import('sentry/views/alerts/list/incidents'))} /> import('sentry/views/alerts/list/rules'))} /> import('sentry/views/alerts/rules/metric/details'))} /> import('sentry/views/alerts/builder/projectProvider'))} > import('sentry/views/alerts/edit'))} /> import('sentry/views/alerts/rules/issue/details/ruleDetails') )} /> import('sentry/views/alerts/builder/projectProvider'))} > import('sentry/views/alerts/edit'))} /> import('sentry/views/alerts/builder/projectProvider'))} > import('sentry/views/alerts/wizard'))} /> import('sentry/views/alerts/builder/projectProvider'))} > import('sentry/views/alerts/create'))} /> import('sentry/views/alerts/incidentRedirect'))} /> import('sentry/views/alerts/builder/projectProvider'))} > import('sentry/views/alerts/create'))} /> import('sentry/views/alerts/wizard'))} /> ); }; const alertRoutes = ( {usingCustomerDomain && ( import('sentry/views/alerts')))} key="orgless-alerts-route" > {alertChildRoutes({forCustomerDomain: true})} )} import('sentry/views/alerts')))} key="org-alerts" > {alertChildRoutes({forCustomerDomain: false})} ); const cronsChildRoutes = ({forCustomerDomain}: {forCustomerDomain: boolean}) => { return ( import('sentry/views/monitors/overview'))} /> import('sentry/views/monitors/create'))} key={forCustomerDomain ? 'orgless-monitors-create' : 'org-monitors-create'} /> import('sentry/views/monitors/details'))} key={ forCustomerDomain ? 'orgless-monitors-monitor-id' : 'org-monitors-monitor-id' } /> import('sentry/views/monitors/edit'))} key={forCustomerDomain ? 'orgless-monitors-edit' : 'org-monitors-edit'} /> ); }; const cronsRoutes = ( {usingCustomerDomain && ( import('sentry/views/monitors')))} key="orgless-monitors-route" > {cronsChildRoutes({forCustomerDomain: true})} )} import('sentry/views/monitors')))} key="org-monitors" > {cronsChildRoutes({forCustomerDomain: false})} ); const replayChildRoutes = ( import('sentry/views/replays/list'))} /> import('sentry/views/replays/details'))} /> ); const replayRoutes = ( {usingCustomerDomain && ( import('sentry/views/replays/index')))} key="orgless-replays-route" > {replayChildRoutes} )} import('sentry/views/replays/index')))} key="org-replays" > {replayChildRoutes} ); const releasesChildRoutes = ({forCustomerDomain}: {forCustomerDomain: boolean}) => { return ( import('sentry/views/releases/list'))} /> import('sentry/views/releases/detail'))} > import('sentry/views/releases/detail/overview'))} /> import('sentry/views/releases/detail/commitsAndFiles/commits') )} /> import('sentry/views/releases/detail/commitsAndFiles/filesChanged') )} /> {forCustomerDomain ? null : ( )} ); }; const releasesRoutes = ( {usingCustomerDomain && ( {releasesChildRoutes({forCustomerDomain: true})} )} {releasesChildRoutes({forCustomerDomain: false})} ); const activityRoutes = ( {usingCustomerDomain && ( import('sentry/views/organizationActivity')) )} key="orgless-activity-route" /> )} import('sentry/views/organizationActivity')) )} key="org-activity" /> ); const statsChildRoutes = ({forCustomerDomain}: {forCustomerDomain: boolean}) => { return ( import('sentry/views/organizationStats'))} /> import('sentry/views/organizationStats/teamInsights'))} > import('sentry/views/organizationStats/teamInsights/issues') )} /> import('sentry/views/organizationStats/teamInsights'))} > import('sentry/views/organizationStats/teamInsights/health') )} /> {forCustomerDomain ? null : ( )} ); }; const statsRoutes = ( {usingCustomerDomain && ( {statsChildRoutes({forCustomerDomain: true})} )} {statsChildRoutes({forCustomerDomain: false})} ); // TODO(mark) Long term this /queries route should go away and /discover // should be the canonical route for discover2. We have a redirect right now // as /discover was for discover 1 and most of the application is linking to // /discover/queries and not /discover const discoverChildRoutes = ( import('sentry/views/discover/homepage'))} /> import('sentry/views/discover/landing'))} /> import('sentry/views/discover/results'))} /> import('sentry/views/discover/eventDetails'))} /> ); const discoverRoutes = ( {usingCustomerDomain && ( import('sentry/views/discover')))} key="orgless-discover-route" > {discoverChildRoutes} )} import('sentry/views/discover')))} key="org-discover-route" > {discoverChildRoutes} ); const performanceChildRoutes = ( import('sentry/views/performance/content'))} /> import('sentry/views/performance/trends'))} /> import('sentry/views/performance/database/databaseLandingPage') )} /> import('sentry/views/performance/database/databaseSpanSummaryPage') )} /> import('sentry/views/performance/browser/interactionsLandingPage') )} /> import('sentry/views/performance/browser/interactionSummary/index') )} /> import('sentry/views/performance/transactionSummary/transactionOverview') )} /> import('sentry/views/performance/transactionSummary/transactionReplays') )} /> import('sentry/views/performance/transactionSummary/transactionVitals') )} /> import('sentry/views/performance/transactionSummary/transactionTags') )} /> import('sentry/views/performance/transactionSummary/transactionEvents') )} /> import('sentry/views/performance/transactionSummary/transactionAnomalies') )} /> import('sentry/views/performance/transactionSummary/transactionProfiles') )} /> import('sentry/views/performance/transactionSummary/transactionSpans') )} /> import( 'sentry/views/performance/transactionSummary/transactionSpans/spanDetails' ) )} /> import('sentry/views/performance/vitalDetail'))} /> import('sentry/views/performance/traceDetails'))} /> import('sentry/views/performance/transactionDetails'))} /> ); const performanceRoutes = ( {usingCustomerDomain && ( import('sentry/views/performance')))} key="orgless-performance-route" > {performanceChildRoutes} )} import('sentry/views/performance')))} key="org-performance" > {performanceChildRoutes} ); const starfishChildRoutes = ( import('sentry/views/starfish/views/webServiceView'))} /> import('sentry/views/starfish/views/webServiceView/endpointOverview') )} /> import('sentry/views/starfish/views/spanSummaryPage'))} /> import('sentry/views/starfish/modules/mobile/initialization') )} /> import('sentry/views/starfish/modules/mobile/pageload'))} /> import('sentry/views/starfish/modules/mobile/responsiveness') )} /> import('sentry/views/starfish/views/spans'))} /> import('sentry/views/starfish/views/spanSummaryPage'))} /> ); const starfishRoutes = ( {usingCustomerDomain && ( import('sentry/views/starfish')))} key="orgless-starfish-route" > {starfishChildRoutes} )} import('sentry/views/starfish/')))} key="org-starfish" > {starfishChildRoutes} ); const userFeedbackRoutes = ( {usingCustomerDomain && ( import('sentry/views/userFeedback')))} key="orgless-user-feedback-route" /> )} import('sentry/views/userFeedback')))} key="org-user-feedback" /> ); const feedbackChildRoutes = ( import('sentry/views/feedback/list'))} /> import('sentry/views/feedback/details'))} /> ); const feedbackv2Routes = ( {usingCustomerDomain && ( import('sentry/views/feedback/index')) )} key="orgless-feedback-list-route" > {feedbackChildRoutes} )} import('sentry/views/feedback/index')))} key="org-feedback-list-route" > {feedbackChildRoutes} ); const issueListRoutes = ( {usingCustomerDomain && ( )} ); // Once org issues is complete, these routes can be nested under // /organizations/:orgId/issues const issueTabs = ({forCustomerDomain}: {forCustomerDomain: boolean}) => { const hoc = forCustomerDomain ? withDomainRequired : x => x; return ( import('sentry/views/issueDetails/groupEventDetails')) )} /> import('sentry/views/issueDetails/groupReplays')))} /> import('sentry/views/issueDetails/groupActivity')))} /> import('sentry/views/issueDetails/groupEvents')))} /> import('sentry/views/issueDetails/groupTags')))} /> import('sentry/views/issueDetails/groupTagValues'))} /> import('sentry/views/issueDetails/groupUserFeedback')) )} /> import('sentry/views/issueDetails/groupEventAttachments')) )} /> import('sentry/views/issueDetails/groupSimilarIssues')) )} /> import('sentry/views/issueDetails/groupMerged')))} /> ); }; const issueDetailsChildRoutes = ({forCustomerDomain}: {forCustomerDomain: boolean}) => ( {issueTabs({forCustomerDomain})} {issueTabs({forCustomerDomain})} ); const issueDetailsRoutes = ( import('sentry/views/issueDetails')))} key="org-issues-group-id" > {issueDetailsChildRoutes({forCustomerDomain: false})} {usingCustomerDomain && ( import('sentry/views/issueDetails')))} key="orgless-issues-group-id-route" > {issueDetailsChildRoutes({forCustomerDomain: true})} )} ); // These are the "manage" pages. For sentry.io, these are _different_ from // the SaaS admin routes in getsentry. const adminManageRoutes = ( import('sentry/views/admin/adminLayout'))} > import('sentry/views/admin/adminOverview'))} /> import('sentry/views/admin/adminBuffer'))} /> import('sentry/views/admin/adminRelays'))} /> import('sentry/views/admin/adminOrganizations'))} /> import('sentry/views/admin/adminProjects'))} /> import('sentry/views/admin/adminQueue'))} /> import('sentry/views/admin/adminQuotas'))} /> import('sentry/views/admin/adminSettings'))} /> import('sentry/views/admin/adminUsers'))} /> import('sentry/views/admin/adminUserEdit'))} /> import('sentry/views/admin/adminMail'))} /> import('sentry/views/admin/adminEnvironment'))} /> import('sentry/views/admin/adminPackages'))} /> import('sentry/views/admin/adminWarnings'))} /> ); // XXX(epurkhiser): This should probably go away. It's not totally clear to // me why we need the OrganizationRoot root container. const legacyOrganizationRootRoutes = ( {hook('routes:organization')} ); const gettingStartedRoutes = ( {usingCustomerDomain && ( )} ); const profilingChildRoutes = ( import('sentry/views/profiling/content'))} /> import('sentry/views/profiling/profileSummary'))} /> import('sentry/views/profiling/profilesProvider'))} > {/* @TODO Remove flamechart route name */} import('sentry/views/profiling/profileFlamechart'))} /> import('sentry/views/profiling/profileFlamechart'))} /> ); const profilingRoutes = ( {usingCustomerDomain && ( import('sentry/views/profiling')))} key="orgless-profiling-route" > {profilingChildRoutes} )} import('sentry/views/profiling')))} key="org-profiling" > {profilingChildRoutes} ); // Support for deprecated URLs (pre-Sentry 10). We just redirect users to new // canonical URLs. // // XXX(epurkhiser): Can these be moved over to the legacyOrgRedirects routes, // or do these need to be nested into the OrganizationDetails tree? const legacyOrgRedirects = ( `/organizations/${orgId}/issues/?project=${projectId}` ) )} /> `/organizations/${orgId}/issues/?project=${projectId}` ) )} /> `/organizations/${orgId}/dashboards/?project=${projectId}` ) )} /> `/organizations/${orgId}/user-feedback/?project=${projectId}` ) )} /> `/organizations/${orgId}/releases/?project=${projectId}` ) )} /> `/organizations/${orgId}/releases/${router.params.version}/?project=${projectId}` ) )} /> `/organizations/${orgId}/releases/${router.params.version}/new-events/?project=${projectId}` ) )} /> `/organizations/${orgId}/releases/${router.params.version}/all-events/?project=${projectId}` ) )} /> `/organizations/${orgId}/releases/${router.params.version}/commits/?project=${projectId}` ) )} /> ); const organizationRoutes = ( {settingsRoutes} {projectsRoutes} {dashboardRoutes} {userFeedbackRoutes} {feedbackv2Routes} {issueListRoutes} {issueDetailsRoutes} {alertRoutes} {cronsRoutes} {replayRoutes} {releasesRoutes} {activityRoutes} {statsRoutes} {discoverRoutes} {performanceRoutes} {starfishRoutes} {profilingRoutes} {gettingStartedRoutes} {adminManageRoutes} {legacyOrganizationRootRoutes} {legacyOrgRedirects} ); const legacyRedirectRoutes = ( ); const appRoutes = ( {experimentalSpaRoutes} {rootRoutes} {organizationRoutes} {legacyRedirectRoutes} ); return appRoutes; } // We load routes both when initializing the SDK (for routing integrations) and // when the app renders Main. Memoize to avoid rebuilding the route tree. export const routes = memoize(buildRoutes); // Exported for use in tests. export {buildRoutes}; function NoOp(props: {children: React.ReactNode}) { return {props.children}; }