You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

startReactApp.tsx 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import { ThemeProvider } from '@emotion/react';
  21. import { QueryClientProvider } from '@tanstack/react-query';
  22. import { ToastMessageContainer, lightTheme } from 'design-system';
  23. import * as React from 'react';
  24. import { createRoot } from 'react-dom/client';
  25. import { Helmet, HelmetProvider } from 'react-helmet-async';
  26. import { IntlShape, RawIntlProvider } from 'react-intl';
  27. import {
  28. Route,
  29. RouterProvider,
  30. createBrowserRouter,
  31. createRoutesFromElements,
  32. } from 'react-router-dom';
  33. import accountRoutes from '../../apps/account/routes';
  34. import auditLogsRoutes from '../../apps/audit-logs/routes';
  35. import backgroundTasksRoutes from '../../apps/background-tasks/routes';
  36. import ChangeAdminPasswordApp from '../../apps/change-admin-password/ChangeAdminPasswordApp';
  37. import codeRoutes from '../../apps/code/routes';
  38. import codingRulesRoutes from '../../apps/coding-rules/routes';
  39. import componentMeasuresRoutes from '../../apps/component-measures/routes';
  40. import groupsRoutes from '../../apps/groups/routes';
  41. import { globalIssuesRoutes, projectIssuesRoutes } from '../../apps/issues/routes';
  42. import maintenanceRoutes from '../../apps/maintenance/routes';
  43. import marketplaceRoutes from '../../apps/marketplace/routes';
  44. import overviewRoutes from '../../apps/overview/routes';
  45. import permissionTemplatesRoutes from '../../apps/permission-templates/routes';
  46. import { globalPermissionsRoutes, projectPermissionsRoutes } from '../../apps/permissions/routes';
  47. import projectActivityRoutes from '../../apps/projectActivity/routes';
  48. import projectBranchesRoutes from '../../apps/projectBranches/routes';
  49. import ProjectDeletionApp from '../../apps/projectDeletion/App';
  50. import projectDumpRoutes from '../../apps/projectDump/routes';
  51. import projectInfoRoutes from '../../apps/projectInformation/routes';
  52. import ProjectKeyApp from '../../apps/projectKey/ProjectKeyApp';
  53. import ProjectLinksApp from '../../apps/projectLinks/ProjectLinksApp';
  54. import projectNewCodeDefinitionRoutes from '../../apps/projectNewCode/routes';
  55. import projectQualityGateRoutes from '../../apps/projectQualityGate/routes';
  56. import projectQualityProfilesRoutes from '../../apps/projectQualityProfiles/routes';
  57. import projectsRoutes from '../../apps/projects/routes';
  58. import projectsManagementRoutes from '../../apps/projectsManagement/routes';
  59. import qualityGatesRoutes from '../../apps/quality-gates/routes';
  60. import qualityProfilesRoutes from '../../apps/quality-profiles/routes';
  61. import SecurityHotspotsApp from '../../apps/security-hotspots/SecurityHotspotsApp';
  62. import sessionsRoutes from '../../apps/sessions/routes';
  63. import settingsRoutes from '../../apps/settings/routes';
  64. import systemRoutes from '../../apps/system/routes';
  65. import tutorialsRoutes from '../../apps/tutorials/routes';
  66. import usersRoutes from '../../apps/users/routes';
  67. import webAPIRoutesV2 from '../../apps/web-api-v2/routes';
  68. import webAPIRoutes from '../../apps/web-api/routes';
  69. import webhooksRoutes from '../../apps/webhooks/routes';
  70. import { translate } from '../../helpers/l10n';
  71. import { getBaseUrl } from '../../helpers/system';
  72. import { queryClient } from '../../queries/queryClient';
  73. import { AppState } from '../../types/appstate';
  74. import { Feature } from '../../types/features';
  75. import { CurrentUser } from '../../types/users';
  76. import AdminContainer from '../components/AdminContainer';
  77. import App from '../components/App';
  78. import ComponentContainer from '../components/ComponentContainer';
  79. import DocumentationRedirect from '../components/DocumentationRedirect';
  80. import FormattingHelp from '../components/FormattingHelp';
  81. import GlobalContainer from '../components/GlobalContainer';
  82. import Landing from '../components/Landing';
  83. import MigrationContainer from '../components/MigrationContainer';
  84. import NonAdminPagesContainer from '../components/NonAdminPagesContainer';
  85. import NotFound from '../components/NotFound';
  86. import PluginRiskConsent from '../components/PluginRiskConsent';
  87. import ProjectAdminContainer from '../components/ProjectAdminContainer';
  88. import ResetPassword from '../components/ResetPassword';
  89. import SimpleContainer from '../components/SimpleContainer';
  90. import SonarLintConnection from '../components/SonarLintConnection';
  91. import { DEFAULT_APP_STATE } from '../components/app-state/AppStateContext';
  92. import AppStateContextProvider from '../components/app-state/AppStateContextProvider';
  93. import {
  94. AvailableFeaturesContext,
  95. DEFAULT_AVAILABLE_FEATURES,
  96. } from '../components/available-features/AvailableFeaturesContext';
  97. import CurrentUserContextProvider from '../components/current-user/CurrentUserContextProvider';
  98. import GlobalAdminPageExtension from '../components/extensions/GlobalAdminPageExtension';
  99. import GlobalPageExtension from '../components/extensions/GlobalPageExtension';
  100. import PortfolioPage from '../components/extensions/PortfolioPage';
  101. import PortfoliosPage from '../components/extensions/PortfoliosPage';
  102. import ProjectAdminPageExtension from '../components/extensions/ProjectAdminPageExtension';
  103. import ProjectPageExtension from '../components/extensions/ProjectPageExtension';
  104. import { GlobalStyles } from '../styles/GlobalStyles';
  105. import exportModulesAsGlobals from './exportModulesAsGlobals';
  106. function renderComponentRoutes() {
  107. return (
  108. <Route element={<ComponentContainer />}>
  109. {/* This container is a catch-all for all non-admin pages */}
  110. <Route element={<NonAdminPagesContainer />}>
  111. {codeRoutes()}
  112. {componentMeasuresRoutes()}
  113. {overviewRoutes()}
  114. <Route path="portfolio" element={<PortfolioPage />} />
  115. {projectActivityRoutes()}
  116. <Route
  117. path="project/extension/:pluginKey/:extensionKey"
  118. element={<ProjectPageExtension />}
  119. />
  120. {projectIssuesRoutes()}
  121. <Route path="security_hotspots" element={<SecurityHotspotsApp />} />
  122. {projectQualityGateRoutes()}
  123. {projectQualityProfilesRoutes()}
  124. {projectInfoRoutes()}
  125. {tutorialsRoutes()}
  126. </Route>
  127. <Route element={<ProjectAdminContainer />}>
  128. <Route path="project">
  129. <Route
  130. path="admin/extension/:pluginKey/:extensionKey"
  131. element={<ProjectAdminPageExtension />}
  132. />
  133. {backgroundTasksRoutes()}
  134. {projectNewCodeDefinitionRoutes()}
  135. {projectBranchesRoutes()}
  136. {projectDumpRoutes()}
  137. {settingsRoutes()}
  138. {webhooksRoutes()}
  139. <Route path="deletion" element={<ProjectDeletionApp />} />
  140. <Route path="links" element={<ProjectLinksApp />} />
  141. <Route path="key" element={<ProjectKeyApp />} />
  142. </Route>
  143. {projectPermissionsRoutes()}
  144. </Route>
  145. </Route>
  146. );
  147. }
  148. function renderAdminRoutes() {
  149. return (
  150. <Route path="admin" element={<AdminContainer />}>
  151. <Route path="extension/:pluginKey/:extensionKey" element={<GlobalAdminPageExtension />} />
  152. {settingsRoutes()}
  153. {auditLogsRoutes()}
  154. {backgroundTasksRoutes()}
  155. {groupsRoutes()}
  156. {permissionTemplatesRoutes()}
  157. {globalPermissionsRoutes()}
  158. {projectsManagementRoutes()}
  159. {systemRoutes()}
  160. {marketplaceRoutes()}
  161. {usersRoutes()}
  162. {webhooksRoutes()}
  163. </Route>
  164. );
  165. }
  166. function renderRedirects() {
  167. return (
  168. <>
  169. {/*
  170. * This redirect enables analyzers and PDFs to link to the correct version of the
  171. * documentation without having to compute the direct links themselves (DRYer).
  172. */}
  173. <Route path="/documentation/*" element={<DocumentationRedirect />} />
  174. </>
  175. );
  176. }
  177. const router = createBrowserRouter(
  178. createRoutesFromElements(
  179. <>
  180. {renderRedirects()}
  181. <Route path="formatting/help" element={<FormattingHelp />} />
  182. <Route element={<SimpleContainer />}>{maintenanceRoutes()}</Route>
  183. <Route element={<MigrationContainer />}>
  184. {sessionsRoutes()}
  185. <Route path="/" element={<App />}>
  186. <Route index element={<Landing />} />
  187. <Route element={<GlobalContainer />}>
  188. {accountRoutes()}
  189. {codingRulesRoutes()}
  190. <Route path="extension/:pluginKey/:extensionKey" element={<GlobalPageExtension />} />
  191. {globalIssuesRoutes()}
  192. {projectsRoutes()}
  193. {qualityGatesRoutes()}
  194. {qualityProfilesRoutes()}
  195. <Route path="portfolios" element={<PortfoliosPage />} />
  196. <Route path="sonarlint/auth" element={<SonarLintConnection />} />
  197. {webAPIRoutes()}
  198. {webAPIRoutesV2()}
  199. {renderComponentRoutes()}
  200. {renderAdminRoutes()}
  201. </Route>
  202. <Route
  203. // We don't want this route to have any menu.
  204. // That is why we can not have it under the accountRoutes
  205. path="account/reset_password"
  206. element={<ResetPassword />}
  207. />
  208. <Route
  209. // We don't want this route to have any menu. This is why we define it here
  210. // rather than under the admin routes.
  211. path="admin/change_admin_password"
  212. element={<ChangeAdminPasswordApp />}
  213. />
  214. <Route
  215. // We don't want this route to have any menu. This is why we define it here
  216. // rather than under the admin routes.
  217. path="admin/plugin_risk_consent"
  218. element={<PluginRiskConsent />}
  219. />
  220. <Route element={<SimpleContainer />}>
  221. <Route path="not_found" element={<NotFound />} />
  222. <Route path="*" element={<NotFound />} />
  223. </Route>
  224. </Route>
  225. </Route>
  226. </>,
  227. ),
  228. { basename: getBaseUrl() },
  229. );
  230. export default function startReactApp(
  231. l10nBundle: IntlShape,
  232. currentUser?: CurrentUser,
  233. appState?: AppState,
  234. availableFeatures?: Feature[],
  235. ) {
  236. exportModulesAsGlobals();
  237. const el = document.getElementById('content');
  238. const root = createRoot(el as HTMLElement);
  239. root.render(
  240. <HelmetProvider>
  241. <AppStateContextProvider appState={appState ?? DEFAULT_APP_STATE}>
  242. <AvailableFeaturesContext.Provider value={availableFeatures ?? DEFAULT_AVAILABLE_FEATURES}>
  243. <CurrentUserContextProvider currentUser={currentUser}>
  244. <RawIntlProvider value={l10nBundle}>
  245. <ThemeProvider theme={lightTheme}>
  246. <QueryClientProvider client={queryClient}>
  247. <GlobalStyles />
  248. <ToastMessageContainer />
  249. <Helmet titleTemplate={translate('page_title.template.default')} />
  250. <RouterProvider router={router} />
  251. </QueryClientProvider>
  252. </ThemeProvider>
  253. </RawIntlProvider>
  254. </CurrentUserContextProvider>
  255. </AvailableFeaturesContext.Provider>
  256. </AppStateContextProvider>
  257. </HelmetProvider>,
  258. );
  259. }