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} 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 App from 'sentry/views/app'; import AuthLayout from 'sentry/views/auth/layout'; import IssueListContainer from 'sentry/views/issueList/container'; import IssueListOverview from 'sentry/views/issueList/overview'; import OrganizationContextContainer from 'sentry/views/organizationContextContainer'; import OrganizationDetails from 'sentry/views/organizationDetails'; import {Tab} from 'sentry/views/organizationGroupDetails/types'; 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 = { componentPromise?: () => Promise; name?: string; }; /** * We add some additional props to our routes */ const Route = BaseRoute as React.ComponentClass; const IndexRoute = BaseIndexRoute as React.ComponentClass; /** * Use react-router to lazy load a route. Use this for codesplitting containers * (e.g. SettingsLayout) * * The typical method for lazy loading a route leaf node is using the * component + `componentPromise` * * For wrapper / layout views react-router handles the route tree better by * using getComponent with this lazyLoad helper. If we just use it * will end up having to re-render more components than necessary. */ const lazyLoad = (load: () => Promise): RouteProps['getComponent'] => (_loc, cb) => load().then(module => cb(null, module.default)); const hook = (name: HookName) => HookStore.get(name).map(cb => cb()); const SafeLazyLoad = errorHandler(LazyLoad); 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. // // * The `lazyLoad` function // // This function is to be used with `getComponent`. It is used for // container component routes for performances reasons. See the // documentation on the function for more details. // // // ## 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. // // 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')} component={SafeLazyLoad} /> ) : null; const rootRoutes = ( import('sentry/views/app/root')} component={SafeLazyLoad} /> import('sentry/views/acceptOrganizationInvite')} component={SafeLazyLoad} /> import('sentry/views/acceptProjectTransfer')} component={SafeLazyLoad} /> import('sentry/views/integrationOrganizationLink')} component={SafeLazyLoad} /> import('sentry/views/integrationOrganizationLink'))} /> import('sentry/views/sentryAppExternalInstallation')} component={SafeLazyLoad} /> import('sentry/views/sharedGroupDetails')} component={SafeLazyLoad} /> import('sentry/views/organizationCreate')} component={SafeLazyLoad} /> import('sentry/views/dataExport/dataDownload')} component={SafeLazyLoad} /> import('sentry/views/disabledMember')} component={SafeLazyLoad} /> import('sentry/views/organizationJoinRequest')} component={SafeLazyLoad} /> import('sentry/views/onboarding/onboardingController')} component={SafeLazyLoad} /> ); const accountSettingsRoutes = ( import('sentry/views/settings/account/accountSettingsLayout') )} > import('sentry/views/settings/account/accountDetails')} component={SafeLazyLoad} /> import('sentry/views/settings/account/notifications/notificationSettings') } component={SafeLazyLoad} /> import('sentry/views/settings/account/accountNotificationFineTuning') } component={SafeLazyLoad} /> import('sentry/views/settings/account/accountEmails')} component={SafeLazyLoad} /> import('sentry/views/settings/account/accountAuthorizations') } component={SafeLazyLoad} /> import('sentry/views/settings/account/accountSecurity/accountSecurityWrapper') } component={SafeLazyLoad} > import('sentry/views/settings/account/accountSecurity') } component={SafeLazyLoad} /> import('sentry/views/settings/account/accountSecurity/sessionHistory') } component={SafeLazyLoad} /> import( 'sentry/views/settings/account/accountSecurity/accountSecurityDetails' ) } component={SafeLazyLoad} /> import('sentry/views/settings/account/accountSecurity/accountSecurityEnroll') } component={SafeLazyLoad} /> import('sentry/views/settings/account/accountSubscriptions') } component={SafeLazyLoad} /> import('sentry/views/settings/account/accountIdentities')} component={SafeLazyLoad} /> import('sentry/views/settings/account/apiTokens')} component={SafeLazyLoad} /> import('sentry/views/settings/account/apiNewToken')} component={SafeLazyLoad} /> import('sentry/views/settings/account/apiApplications') } component={SafeLazyLoad} /> import('sentry/views/settings/account/apiApplications/details') } component={SafeLazyLoad} /> {hook('routes:api')} import('sentry/views/settings/account/accountClose')} component={SafeLazyLoad} /> ); const projectSettingsRoutes = ( import('sentry/views/settings/project/projectSettingsLayout') )} > import('sentry/views/settings/projectGeneralSettings')} component={SafeLazyLoad} /> import('sentry/views/settings/project/projectTeams')} component={SafeLazyLoad} /> import('sentry/views/settings/projectAlerts')} > import('sentry/views/settings/projectAlerts/settings')} /> import('sentry/views/settings/project/projectEnvironments') } component={SafeLazyLoad} > import('sentry/views/settings/projectTags')} component={SafeLazyLoad} /> import('sentry/views/settings/project/projectReleaseTracking') } component={SafeLazyLoad} /> import('sentry/views/settings/project/projectOwnership')} component={SafeLazyLoad} /> import('sentry/views/settings/projectDataForwarding')} component={SafeLazyLoad} /> import('sentry/views/settings/projectSecurityAndPrivacy')} /> import('sentry/views/settings/projectDebugFiles')} component={SafeLazyLoad} /> import('sentry/views/settings/projectProguard')} component={SafeLazyLoad} /> import('sentry/views/settings/projectPerformance')} component={SafeLazyLoad} /> import('sentry/views/settings/projectSourceMaps')} component={SafeLazyLoad} > import('sentry/views/settings/projectSourceMaps/list')} component={SafeLazyLoad} /> import('sentry/views/settings/projectSourceMaps/detail') } component={SafeLazyLoad} /> import('sentry/views/settings/project/projectProcessingIssues') } component={SafeLazyLoad} /> import('sentry/views/settings/project/projectFilters')} component={SafeLazyLoad} > import('sentry/views/settings/project/filtersAndSampling') } component={SafeLazyLoad} /> import('sentry/views/settings/projectIssueGrouping')} component={SafeLazyLoad} /> import('sentry/views/settings/project/projectServiceHooks') } component={SafeLazyLoad} /> import('sentry/views/settings/project/projectCreateServiceHook') } component={SafeLazyLoad} /> import('sentry/views/settings/project/projectServiceHookDetails') } component={SafeLazyLoad} /> import('sentry/views/settings/project/projectKeys/list') } component={SafeLazyLoad} /> import('sentry/views/settings/project/projectKeys/details') } component={SafeLazyLoad} /> import('sentry/views/settings/project/projectUserFeedback') } component={SafeLazyLoad} /> import('sentry/views/settings/projectSecurityHeaders')} component={SafeLazyLoad} /> import('sentry/views/settings/projectSecurityHeaders/csp') } component={SafeLazyLoad} /> import('sentry/views/settings/projectSecurityHeaders/expectCt') } component={SafeLazyLoad} /> import('sentry/views/settings/projectSecurityHeaders/hpkp') } component={SafeLazyLoad} /> import('sentry/views/settings/projectPlugins')} component={SafeLazyLoad} /> import('sentry/views/settings/projectPlugins/details')} component={SafeLazyLoad} /> import('sentry/views/projectInstall/overview')} component={SafeLazyLoad} /> import('sentry/views/projectInstall/platformOrIntegration') } component={SafeLazyLoad} /> ); const orgSettingsRoutes = ( import('sentry/views/settings/organization/organizationSettingsLayout') )} > {hook('routes:organization')} import('sentry/views/settings/organizationGeneralSettings') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationProjects')} component={SafeLazyLoad} /> import('sentry/views/settings/organizationApiKeys')} component={SafeLazyLoad} /> import('sentry/views/settings/organizationApiKeys/organizationApiKeyDetails') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationAuditLog')} component={SafeLazyLoad} /> import('sentry/views/settings/organizationAuth')} component={SafeLazyLoad} /> import('sentry/views/settings/organizationMembers/organizationMembersWrapper') } component={SafeLazyLoad} > import('sentry/views/settings/organizationMembers/organizationMembersList') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationMembers/organizationMemberDetail') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationRateLimits')} component={SafeLazyLoad} /> import('sentry/views/settings/organizationRelay')} component={SafeLazyLoad} /> import('sentry/views/settings/organizationRepositories')} component={SafeLazyLoad} /> import('sentry/views/settings/organizationGeneralSettings') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationSecurityAndPrivacy') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationTeams')} component={SafeLazyLoad} /> import('sentry/views/settings/organizationTeams/teamDetails') } component={SafeLazyLoad} > import('sentry/views/settings/organizationTeams/teamMembers') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationTeams/teamNotifications') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationTeams/teamProjects') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationTeams/teamSettings') } component={SafeLazyLoad} /> import('sentry/views/organizationIntegrations/pluginDetailedView') } component={SafeLazyLoad} /> import('sentry/views/organizationIntegrations/sentryAppDetailedView') } component={SafeLazyLoad} /> import('sentry/views/organizationIntegrations/docIntegrationDetailedView') } component={SafeLazyLoad} /> import('sentry/views/organizationIntegrations/integrationListDirectory') } component={SafeLazyLoad} /> import('sentry/views/organizationIntegrations/integrationDetailedView') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationIntegrations/configureIntegration') } component={SafeLazyLoad} /> import('sentry/views/settings/organizationDeveloperSettings') } component={SafeLazyLoad} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryApplicationDetails' ) } component={SafeLazyLoad} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryApplicationDetails' ) } component={SafeLazyLoad} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryApplicationDetails' ) } component={SafeLazyLoad} /> import( 'sentry/views/settings/organizationDeveloperSettings/sentryApplicationDashboard' ) } component={SafeLazyLoad} /> ); const legacySettingsRedirects = ( ); const settingsRoutes = ( import('sentry/views/settings/settingsIndex'))} /> {accountSettingsRoutes} {orgSettingsRoutes} {projectSettingsRoutes} {legacySettingsRedirects} ); const projectsRoutes = ( import('sentry/views/projectsDashboard')} component={SafeLazyLoad} /> import('sentry/views/projectInstall/newProject')} component={SafeLazyLoad} /> import('sentry/views/projectInstall/gettingStarted')} component={SafeLazyLoad} > import('sentry/views/projectInstall/overview')} component={SafeLazyLoad} /> import('sentry/views/projectInstall/platformOrIntegration') } component={SafeLazyLoad} /> import('sentry/views/projectDetail')} component={SafeLazyLoad} /> ); const dashboardRoutes = ( import('sentry/views/dashboardsV2')} component={SafeLazyLoad} > import('sentry/views/dashboardsV2/manage')} component={SafeLazyLoad} /> import('sentry/views/dashboardsV2/create')} component={SafeLazyLoad} > import('sentry/views/dashboardsV2/widgetBuilder')} component={SafeLazyLoad} /> import('sentry/views/dashboardsV2/widgetBuilder')} component={SafeLazyLoad} /> import('sentry/views/dashboardsV2/create')} component={SafeLazyLoad} > import('sentry/views/dashboardsV2/create')} component={SafeLazyLoad} /> import('sentry/views/dashboardsV2/view')} component={SafeLazyLoad} > import('sentry/views/dashboardsV2/widgetBuilder')} component={SafeLazyLoad} /> import('sentry/views/dashboardsV2/widgetBuilder')} component={SafeLazyLoad} /> import('sentry/views/dashboardsV2/view')} component={SafeLazyLoad} /> ); const alertRoutes = ( import('sentry/views/alerts')} component={SafeLazyLoad} > import('sentry/views/alerts/list')} component={SafeLazyLoad} /> import('sentry/views/alerts/rules')} /> import('sentry/views/alerts/rules/details')} /> import('sentry/views/alerts/builder/projectProvider')} component={SafeLazyLoad} > import('sentry/views/alerts/edit')} component={SafeLazyLoad} /> import('sentry/views/alerts/details')} component={SafeLazyLoad} > import('sentry/views/alerts/details/ruleDetails')} /> import('sentry/views/alerts/builder/projectProvider')} component={SafeLazyLoad} > import('sentry/views/alerts/edit')} component={SafeLazyLoad} /> import('sentry/views/alerts/incidentRedirect')} component={SafeLazyLoad} /> import('sentry/views/alerts/builder/projectProvider')} component={SafeLazyLoad} > import('sentry/views/alerts/create')} /> import('sentry/views/alerts/wizard')} /> ); const monitorsRoutes = ( import('sentry/views/monitors')} component={SafeLazyLoad} > import('sentry/views/monitors/monitors')} component={SafeLazyLoad} /> import('sentry/views/monitors/create')} component={SafeLazyLoad} /> import('sentry/views/monitors/details')} component={SafeLazyLoad} /> import('sentry/views/monitors/edit')} component={SafeLazyLoad} /> ); const replayRoutes = ( import('sentry/views/replays')} component={SafeLazyLoad} > import('sentry/views/replays/replays')} component={SafeLazyLoad} /> import('sentry/views/replays/details')} component={SafeLazyLoad} /> ); const releasesRoutes = ( import('sentry/views/releases/list')} component={SafeLazyLoad} /> import('sentry/views/releases/detail')} component={SafeLazyLoad} > import('sentry/views/releases/detail/overview')} component={SafeLazyLoad} /> import('sentry/views/releases/detail/commitsAndFiles/commits') } component={SafeLazyLoad} /> import('sentry/views/releases/detail/commitsAndFiles/filesChanged') } component={SafeLazyLoad} /> ); const activityRoutes = ( import('sentry/views/organizationActivity')} component={SafeLazyLoad} /> ); const statsRoutes = ( import('sentry/views/organizationStats')} component={SafeLazyLoad} /> import('sentry/views/organizationStats/teamInsights')} component={SafeLazyLoad} > import('sentry/views/organizationStats/teamInsights/issues') } component={SafeLazyLoad} /> import('sentry/views/organizationStats/teamInsights')} component={SafeLazyLoad} > import('sentry/views/organizationStats/teamInsights/health') } component={SafeLazyLoad} /> ); // 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 discoverRoutes = ( import('sentry/views/eventsV2')} component={SafeLazyLoad} > import('sentry/views/eventsV2/landing')} component={SafeLazyLoad} /> import('sentry/views/eventsV2/results')} component={SafeLazyLoad} /> import('sentry/views/eventsV2/eventDetails')} component={SafeLazyLoad} /> ); const performanceRoutes = ( import('sentry/views/performance')} component={SafeLazyLoad} > import('sentry/views/performance/content')} component={SafeLazyLoad} /> import('sentry/views/performance/trends')} component={SafeLazyLoad} /> import('sentry/views/performance/transactionSummary/transactionOverview') } component={SafeLazyLoad} /> import('sentry/views/performance/transactionSummary/transactionVitals') } component={SafeLazyLoad} /> import('sentry/views/performance/transactionSummary/transactionTags') } component={SafeLazyLoad} /> import('sentry/views/performance/transactionSummary/transactionEvents') } component={SafeLazyLoad} /> import('sentry/views/performance/transactionSummary/transactionAnomalies') } component={SafeLazyLoad} /> import('sentry/views/performance/transactionSummary/transactionSpans') } component={SafeLazyLoad} /> import( 'sentry/views/performance/transactionSummary/transactionSpans/spanDetails' ) } component={SafeLazyLoad} /> import('sentry/views/performance/vitalDetail')} component={SafeLazyLoad} /> import('sentry/views/performance/traceDetails')} component={SafeLazyLoad} /> import('sentry/views/performance/transactionDetails')} component={SafeLazyLoad} /> ); const userFeedbackRoutes = ( import('sentry/views/userFeedback')} component={SafeLazyLoad} /> ); const issueListRoutes = ( ); // Once org issues is complete, these routes can be nested under // /organizations/:orgId/issues const groupDetailsRoutes = ( import('sentry/views/organizationGroupDetails')} component={SafeLazyLoad} > import('sentry/views/organizationGroupDetails/groupEventDetails') } component={SafeLazyLoad} props={{ currentTab: Tab.DETAILS, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/groupActivity') } component={SafeLazyLoad} props={{ currentTab: Tab.ACTIVITY, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/groupEvents') } component={SafeLazyLoad} props={{ currentTab: Tab.EVENTS, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/groupTags')} component={SafeLazyLoad} props={{ currentTab: Tab.TAGS, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/groupTagValues') } component={SafeLazyLoad} props={{ currentTab: Tab.TAGS, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/groupUserFeedback') } component={SafeLazyLoad} props={{ currentTab: Tab.USER_FEEDBACK, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/groupEventAttachments') } component={SafeLazyLoad} props={{ currentTab: Tab.ATTACHMENTS, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/groupSimilarIssues') } component={SafeLazyLoad} props={{ currentTab: Tab.SIMILAR_ISSUES, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/groupMerged') } component={SafeLazyLoad} props={{ currentTab: Tab.MERGED, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/grouping')} component={SafeLazyLoad} props={{ currentTab: Tab.GROUPING, isEventRoute: false, }} /> import('sentry/views/organizationGroupDetails/groupEventDetails') } component={SafeLazyLoad} props={{ currentTab: Tab.DETAILS, isEventRoute: true, }} /> import('sentry/views/organizationGroupDetails/groupActivity') } component={SafeLazyLoad} props={{ currentTab: Tab.ACTIVITY, isEventRoute: true, }} /> import('sentry/views/organizationGroupDetails/groupEvents') } component={SafeLazyLoad} props={{ currentTab: Tab.EVENTS, isEventRoute: true, }} /> import('sentry/views/organizationGroupDetails/groupSimilarIssues') } component={SafeLazyLoad} props={{ currentTab: Tab.SIMILAR_ISSUES, isEventRoute: true, }} /> import('sentry/views/organizationGroupDetails/groupTags') } component={SafeLazyLoad} props={{ currentTab: Tab.TAGS, isEventRoute: true, }} /> import('sentry/views/organizationGroupDetails/groupTagValues') } component={SafeLazyLoad} props={{ currentTab: Tab.TAGS, isEventRoute: true, }} /> import('sentry/views/organizationGroupDetails/groupUserFeedback') } component={SafeLazyLoad} props={{ currentTab: Tab.USER_FEEDBACK, isEventRoute: true, }} /> import('sentry/views/organizationGroupDetails/groupEventAttachments') } component={SafeLazyLoad} props={{ currentTab: Tab.ATTACHMENTS, isEventRoute: true, }} /> import('sentry/views/organizationGroupDetails/groupMerged') } component={SafeLazyLoad} props={{ currentTab: Tab.MERGED, isEventRoute: true, }} /> import('sentry/views/organizationGroupDetails/grouping') } component={SafeLazyLoad} props={{ currentTab: Tab.GROUPING, isEventRoute: 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')} component={SafeLazyLoad} > import('sentry/views/admin/adminOverview')} component={SafeLazyLoad} /> import('sentry/views/admin/adminBuffer')} component={SafeLazyLoad} /> import('sentry/views/admin/adminRelays')} component={SafeLazyLoad} /> import('sentry/views/admin/adminOrganizations')} component={SafeLazyLoad} /> import('sentry/views/admin/adminProjects')} component={SafeLazyLoad} /> import('sentry/views/admin/adminQueue')} component={SafeLazyLoad} /> import('sentry/views/admin/adminQuotas')} component={SafeLazyLoad} /> import('sentry/views/admin/adminSettings')} component={SafeLazyLoad} /> import('sentry/views/admin/adminUsers')} component={SafeLazyLoad} /> import('sentry/views/admin/adminUserEdit')} component={SafeLazyLoad} /> import('sentry/views/admin/adminMail')} component={SafeLazyLoad} /> import('sentry/views/admin/adminEnvironment')} component={SafeLazyLoad} /> import('sentry/views/admin/adminPackages')} component={SafeLazyLoad} /> import('sentry/views/admin/adminWarnings')} component={SafeLazyLoad} /> {hook('routes:admin')} ); // XXX(epurkhiser): This should probably go away. It's not totally clear to // me why we need the OrganizationRoot root container. const legacyOrganizationRootRoutes = ( import('sentry/views/teamCreate')} component={SafeLazyLoad} /> {hook('routes:organization')} ); // XXX(epurkhiser): These also exist in the legacyOrganizationRootRoutes. Not // sure which one here is more correct. const legacyGettingStartedRoutes = ( import('sentry/views/projectInstall/gettingStarted')} component={SafeLazyLoad} > import('sentry/views/projectInstall/overview')} component={SafeLazyLoad} /> import('sentry/views/projectInstall/platformOrIntegration') } component={SafeLazyLoad} /> ); // 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 profilingRoutes = ( import('sentry/views/profiling')} component={SafeLazyLoad} > import('sentry/views/profiling/content')} component={SafeLazyLoad} /> import('sentry/views/profiling/flamegraph')} /> ); const organizationRoutes = ( {settingsRoutes} {projectsRoutes} {dashboardRoutes} {userFeedbackRoutes} {issueListRoutes} {groupDetailsRoutes} {alertRoutes} {monitorsRoutes} {replayRoutes} {releasesRoutes} {activityRoutes} {statsRoutes} {discoverRoutes} {performanceRoutes} {profilingRoutes} {adminManageRoutes} {legacyOrganizationRootRoutes} {legacyGettingStartedRoutes} {legacyOrgRedirects} ); const legacyRedirectRoutes = ( ); const appRoutes = ( {experimentalSpaRoutes} {rootRoutes} {organizationRoutes} {legacyRedirectRoutes} {hook('routes')} ); return appRoutes; } // We load routes both when initlaizing the SDK (for routing integrations) and // when the app renders Main. Memoize to avoid rebuilding the route tree. const routes = memoize(buildRoutes); export default routes;