/* * SonarQube * Copyright (C) 2009-2021 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* eslint-disable react/jsx-sort-props */ import { Location } from 'history'; import { pick } from 'lodash'; import * as React from 'react'; import ReactDom, { render } from 'react-dom'; import { HelmetProvider } from 'react-helmet-async'; import { IntlProvider } from 'react-intl'; import { Provider } from 'react-redux'; import { IndexRoute, Redirect, Route, RouteConfig, RouteProps, Router } from 'react-router'; import accountRoutes from '../../apps/account/routes'; import applicationConsoleRoutes from '../../apps/application-console/routes'; import applicationSettingsRoutes from '../../apps/application-settings/routes'; import auditLogsRoutes from '../../apps/audit-logs/routes'; import backgroundTasksRoutes from '../../apps/background-tasks/routes'; import codeRoutes from '../../apps/code/routes'; import codingRulesRoutes from '../../apps/coding-rules/routes'; import componentMeasuresRoutes from '../../apps/component-measures/routes'; import documentationRoutes from '../../apps/documentation/routes'; import groupsRoutes from '../../apps/groups/routes'; import Issues from '../../apps/issues/components/AppContainer'; import { maintenanceRoutes, setupRoutes } from '../../apps/maintenance/routes'; import marketplaceRoutes from '../../apps/marketplace/routes'; import overviewRoutes from '../../apps/overview/routes'; import permissionTemplatesRoutes from '../../apps/permission-templates/routes'; import { globalPermissionsRoutes, projectPermissionsRoutes } from '../../apps/permissions/routes'; import portfolioRoutes from '../../apps/portfolio/routes'; import projectActivityRoutes from '../../apps/projectActivity/routes'; import projectBaselineRoutes from '../../apps/projectBaseline/routes'; import projectBranchesRoutes from '../../apps/projectBranches/routes'; import projectDumpRoutes from '../../apps/projectDump/routes'; import projectQualityGateRoutes from '../../apps/projectQualityGate/routes'; import projectQualityProfilesRoutes from '../../apps/projectQualityProfiles/routes'; import projectsRoutes from '../../apps/projects/routes'; import projectsManagementRoutes from '../../apps/projectsManagement/routes'; import qualityGatesRoutes from '../../apps/quality-gates/routes'; import qualityProfilesRoutes from '../../apps/quality-profiles/routes'; import sessionsRoutes from '../../apps/sessions/routes'; import settingsRoutes from '../../apps/settings/routes'; import systemRoutes from '../../apps/system/routes'; import tutorialsRoutes from '../../apps/tutorials/routes'; import usersRoutes from '../../apps/users/routes'; import webAPIRoutes from '../../apps/web-api/routes'; import webhooksRoutes from '../../apps/webhooks/routes'; import withIndexationGuard from '../../components/hoc/withIndexationGuard'; import { lazyLoadComponent } from '../../components/lazyLoadComponent'; import getHistory from '../../helpers/getHistory'; import App from '../components/App'; import GlobalContainer from '../components/GlobalContainer'; import { PageContext } from '../components/indexation/PageUnavailableDueToIndexation'; import MigrationContainer from '../components/MigrationContainer'; import getStore from './getStore'; /* * Expose dependencies to extensions */ function attachToGlobal() { window.React = React; window.ReactDOM = ReactDom; } function handleUpdate(this: { state: { location: Location } }) { const { action } = this.state.location; if (action === 'PUSH') { window.scrollTo(0, 0); } } // this is not an official api const RouteWithChildRoutes = Route as React.ComponentClass< RouteProps & { childRoutes: RouteConfig } >; function renderRedirects() { return ( <> <Route path="/account/issues" onEnter={(_, replace) => { replace({ pathname: '/issues', query: { myIssues: 'true', resolved: 'false' } }); }} /> <Route path="/codingrules" onEnter={(_, replace) => { replace(`/coding_rules${window.location.hash}`); }} /> <Route path="/dashboard/index/:key" onEnter={(nextState, replace) => { replace({ pathname: '/dashboard', query: { id: nextState.params.key } }); }} /> <Route path="/issues/search" onEnter={(_, replace) => { replace(`/issues${window.location.hash}`); }} /> <Redirect from="/admin" to="/admin/settings" /> <Redirect from="/background_tasks" to="/admin/background_tasks" /> <Redirect from="/component/index" to="/component" /> <Redirect from="/component_issues" to="/project/issues" /> <Redirect from="/dashboard/index" to="/dashboard" /> <Redirect from="/documentation/analysis/languages/vb" to="/documentation/analysis/languages/vbnet/" /> <Redirect from="/governance" to="/portfolio" /> <Redirect from="/groups" to="/admin/groups" /> <Redirect from="/extension/governance/portfolios" to="/portfolios" /> <Redirect from="/permission_templates" to="/admin/permission_templates" /> <Redirect from="/profiles/index" to="/profiles" /> <Redirect from="/projects_admin" to="/admin/projects_management" /> <Redirect from="/quality_gates/index" to="/quality_gates" /> <Redirect from="/roles/global" to="/admin/permissions" /> <Redirect from="/admin/roles/global" to="/admin/permissions" /> <Redirect from="/settings" to="/admin/settings" /> <Redirect from="/settings/encryption" to="/admin/settings/encryption" /> <Redirect from="/settings/index" to="/admin/settings" /> <Redirect from="/sessions/login" to="/sessions/new" /> <Redirect from="/system" to="/admin/system" /> <Redirect from="/system/index" to="/admin/system" /> <Redirect from="/view" to="/portfolio" /> <Redirect from="/users" to="/admin/users" /> <Redirect from="/onboarding" to="/projects/create" /> <Redirect from="markdown/help" to="formatting/help" /> </> ); } function renderComponentRoutes() { return ( <Route component={lazyLoadComponent(() => import('../components/ComponentContainer'))}> <RouteWithChildRoutes path="code" childRoutes={codeRoutes} /> <RouteWithChildRoutes path="component_measures" childRoutes={componentMeasuresRoutes} /> <RouteWithChildRoutes path="dashboard" childRoutes={overviewRoutes} /> <RouteWithChildRoutes path="portfolio" childRoutes={portfolioRoutes} /> <RouteWithChildRoutes path="project/activity" childRoutes={projectActivityRoutes} /> <Route path="project/extension/:pluginKey/:extensionKey" component={lazyLoadComponent(() => import('../components/extensions/ProjectPageExtension'))} /> <Route path="project/issues" component={Issues} onEnter={({ location: { query } }, replace) => { if (query.types) { if (query.types === 'SECURITY_HOTSPOT') { replace({ pathname: '/security_hotspots', query: { ...pick(query, ['id', 'branch', 'pullRequest']), assignedToMe: false } }); } else { query.types = query.types .split(',') .filter((type: string) => type !== 'SECURITY_HOTSPOT') .join(','); } } }} /> <Route path="security_hotspots" component={lazyLoadComponent(() => import('../../apps/security-hotspots/SecurityHotspotsApp') )} /> <RouteWithChildRoutes path="project/quality_gate" childRoutes={projectQualityGateRoutes} /> <RouteWithChildRoutes path="project/quality_profiles" childRoutes={projectQualityProfilesRoutes} /> <RouteWithChildRoutes path="tutorials" childRoutes={tutorialsRoutes} /> <Route component={lazyLoadComponent(() => import('../components/ProjectAdminContainer'))}> <Route path="project/admin/extension/:pluginKey/:extensionKey" component={lazyLoadComponent(() => import('../components/extensions/ProjectAdminPageExtension') )} /> <RouteWithChildRoutes path="project/background_tasks" childRoutes={backgroundTasksRoutes} /> <RouteWithChildRoutes path="project/baseline" childRoutes={projectBaselineRoutes} /> <RouteWithChildRoutes path="project/branches" childRoutes={projectBranchesRoutes} /> <RouteWithChildRoutes path="project/import_export" childRoutes={projectDumpRoutes} /> <RouteWithChildRoutes path="project/settings" childRoutes={settingsRoutes} /> <RouteWithChildRoutes path="project_roles" childRoutes={projectPermissionsRoutes} /> <RouteWithChildRoutes path="application/console" childRoutes={applicationConsoleRoutes} /> <RouteWithChildRoutes path="application/settings" childRoutes={applicationSettingsRoutes} /> <RouteWithChildRoutes path="project/webhooks" childRoutes={webhooksRoutes} /> <Route path="project/deletion" component={lazyLoadComponent(() => import('../../apps/projectDeletion/App'))} /> <Route path="project/links" component={lazyLoadComponent(() => import('../../apps/projectLinks/App'))} /> <Route path="project/key" component={lazyLoadComponent(() => import('../../apps/projectKey/Key'))} /> </Route> </Route> ); } function renderAdminRoutes() { return ( <Route component={lazyLoadComponent(() => import('../components/AdminContainer'))} path="admin"> <Route path="extension/:pluginKey/:extensionKey" component={lazyLoadComponent(() => import('../components/extensions/GlobalAdminPageExtension') )} /> <RouteWithChildRoutes path="audit" childRoutes={auditLogsRoutes} /> <RouteWithChildRoutes path="background_tasks" childRoutes={backgroundTasksRoutes} /> <RouteWithChildRoutes path="groups" childRoutes={groupsRoutes} /> <RouteWithChildRoutes path="permission_templates" childRoutes={permissionTemplatesRoutes} /> <RouteWithChildRoutes path="permissions" childRoutes={globalPermissionsRoutes} /> <RouteWithChildRoutes path="projects_management" childRoutes={projectsManagementRoutes} /> <RouteWithChildRoutes path="settings" childRoutes={settingsRoutes} /> <RouteWithChildRoutes path="system" childRoutes={systemRoutes} /> <RouteWithChildRoutes path="marketplace" childRoutes={marketplaceRoutes} /> <RouteWithChildRoutes path="users" childRoutes={usersRoutes} /> <RouteWithChildRoutes path="webhooks" childRoutes={webhooksRoutes} /> </Route> ); } export default function startReactApp( lang: string, currentUser?: T.CurrentUser, appState?: T.AppState ) { attachToGlobal(); const el = document.getElementById('content'); const history = getHistory(); const store = getStore(currentUser, appState); render( <HelmetProvider> <Provider store={store}> <IntlProvider defaultLocale={lang} locale={lang}> <Router history={history} onUpdate={handleUpdate}> {renderRedirects()} <Route path="formatting/help" component={lazyLoadComponent(() => import('../components/FormattingHelp'))} /> <Route component={lazyLoadComponent(() => import('../components/SimpleContainer'))}> <Route path="maintenance">{maintenanceRoutes}</Route> <Route path="setup">{setupRoutes}</Route> </Route> <Route component={MigrationContainer}> <Route component={lazyLoadComponent(() => import('../components/SimpleSessionsContainer') )}> <RouteWithChildRoutes path="/sessions" childRoutes={sessionsRoutes} /> </Route> <Route path="/" component={App}> <IndexRoute component={lazyLoadComponent(() => import('../components/Landing'))} /> <Route component={GlobalContainer}> <RouteWithChildRoutes path="account" childRoutes={accountRoutes} /> <RouteWithChildRoutes path="coding_rules" childRoutes={codingRulesRoutes} /> <RouteWithChildRoutes path="documentation" childRoutes={documentationRoutes} /> <Route path="extension/:pluginKey/:extensionKey" component={lazyLoadComponent(() => import('../components/extensions/GlobalPageExtension') )} /> <Route path="issues" component={withIndexationGuard(Issues, PageContext.Issues)} /> <RouteWithChildRoutes path="projects" childRoutes={projectsRoutes} /> <RouteWithChildRoutes path="quality_gates" childRoutes={qualityGatesRoutes} /> <Route path="portfolios" component={lazyLoadComponent(() => import('../components/extensions/PortfoliosPage') )} /> <RouteWithChildRoutes path="profiles" childRoutes={qualityProfilesRoutes} /> <RouteWithChildRoutes path="web_api" childRoutes={webAPIRoutes} /> {renderComponentRoutes()} {renderAdminRoutes()} </Route> <Route // We don't want this route to have any menu. // That is why we can not have it under the accountRoutes path="account/reset_password" component={lazyLoadComponent(() => import('../components/ResetPassword'))} /> <Route // We don't want this route to have any menu. This is why we define it here // rather than under the admin routes. path="admin/change_admin_password" component={lazyLoadComponent(() => import('../../apps/change-admin-password/ChangeAdminPasswordApp') )} /> <Route // We don't want this route to have any menu. This is why we define it here // rather than under the admin routes. path="admin/plugin_risk_consent" component={lazyLoadComponent(() => import('../components/PluginRiskConsent'))} /> <Route path="not_found" component={lazyLoadComponent(() => import('../components/NotFound'))} /> <Route path="*" component={lazyLoadComponent(() => import('../components/NotFound'))} /> </Route> </Route> </Router> </IntlProvider> </Provider> </HelmetProvider>, el ); }