diff options
author | Philippe Perrin <philippe.perrin@sonarsource.com> | 2022-07-19 10:46:34 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-07-21 20:03:05 +0000 |
commit | 35ee1a94e9adcb757b656478523edd2df315f05f (patch) | |
tree | 3b2f16e9172b2e41a9628e4146a85bd45a0a4c0c | |
parent | 54df07c9f9c1e586c2931d2ca10e7759fc1ec61b (diff) | |
download | sonarqube-35ee1a94e9adcb757b656478523edd2df315f05f.tar.gz sonarqube-35ee1a94e9adcb757b656478523edd2df315f05f.zip |
[NO-JIRA] Simplify application initialization
14 files changed, 41 insertions, 119 deletions
diff --git a/server/sonar-web/src/main/js/api/nav.ts b/server/sonar-web/src/main/js/api/navigation.ts index bca04cabf98..69111204f41 100644 --- a/server/sonar-web/src/main/js/api/nav.ts +++ b/server/sonar-web/src/main/js/api/navigation.ts @@ -19,6 +19,7 @@ */ import { throwGlobalError } from '../helpers/error'; import { getJSON } from '../helpers/request'; +import { AppState } from '../types/appstate'; import { BranchParameters } from '../types/branch-like'; import { Component, Extension } from '../types/types'; @@ -40,3 +41,7 @@ export function getSettingsNavigation(): Promise<{ }> { return getJSON('/api/navigation/settings').catch(throwGlobalError); } + +export function getGlobalNavigation(): Promise<AppState> { + return getJSON('/api/navigation/global', undefined, true); +} diff --git a/server/sonar-web/src/main/js/api/users.ts b/server/sonar-web/src/main/js/api/users.ts index e512718770e..dae13297e64 100644 --- a/server/sonar-web/src/main/js/api/users.ts +++ b/server/sonar-web/src/main/js/api/users.ts @@ -23,7 +23,7 @@ import { IdentityProvider, Paging } from '../types/types'; import { CurrentUser, HomePage, NoticeType, User } from '../types/users'; export function getCurrentUser(): Promise<CurrentUser> { - return getJSON('/api/users/current'); + return getJSON('/api/users/current', undefined, true); } export function dismissNotification(notice: NoticeType) { diff --git a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx b/server/sonar-web/src/main/js/app/components/AdminContainer.tsx index de4a84124e4..0b5bcc72ab9 100644 --- a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/AdminContainer.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { Helmet } from 'react-helmet-async'; import { Outlet } from 'react-router-dom'; -import { getSettingsNavigation } from '../../api/nav'; +import { getSettingsNavigation } from '../../api/navigation'; import { getPendingPlugins } from '../../api/plugins'; import { getSystemStatus, waitSystemUPStatus } from '../../api/system'; import handleRequiredAuthorization from '../../app/utils/handleRequiredAuthorization'; diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx index 4d6d2f3fac0..2220ec14d6c 100644 --- a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx @@ -24,7 +24,7 @@ import { getProjectAlmBinding, validateProjectAlmBinding } from '../../api/alm-s import { getBranches, getPullRequests } from '../../api/branches'; import { getAnalysisStatus, getTasksForComponent } from '../../api/ce'; import { getComponentData } from '../../api/components'; -import { getComponentNavigation } from '../../api/nav'; +import { getComponentNavigation } from '../../api/navigation'; import { Location, Router, withRouter } from '../../components/hoc/withRouter'; import { getBranchLikeQuery, diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx index 88f82cbab52..e7822a0a90c 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx @@ -23,7 +23,7 @@ import { getProjectAlmBinding, validateProjectAlmBinding } from '../../../api/al import { getBranches, getPullRequests } from '../../../api/branches'; import { getAnalysisStatus, getTasksForComponent } from '../../../api/ce'; import { getComponentData } from '../../../api/components'; -import { getComponentNavigation } from '../../../api/nav'; +import { getComponentNavigation } from '../../../api/navigation'; import { mockProjectAlmBindingConfigurationErrors } from '../../../helpers/mocks/alm-settings'; import { mockBranch, mockMainBranch, mockPullRequest } from '../../../helpers/mocks/branch-like'; import { mockComponent } from '../../../helpers/mocks/component'; @@ -65,7 +65,7 @@ jest.mock('../../../api/components', () => ({ getComponentData: jest.fn().mockResolvedValue({ component: { analysisDate: '2018-07-30' } }) })); -jest.mock('../../../api/nav', () => ({ +jest.mock('../../../api/navigation', () => ({ getComponentNavigation: jest.fn().mockResolvedValue({ breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }], key: 'portfolioKey' diff --git a/server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx b/server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx index a8e130c84d2..d327bfb3aa1 100644 --- a/server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx +++ b/server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { AppState } from '../../../types/appstate'; -const defaultAppState = { +export const DEFAULT_APP_STATE = { authenticationError: false, authorizationError: false, edition: undefined, @@ -30,4 +30,4 @@ const defaultAppState = { settings: {}, version: '' }; -export const AppStateContext = React.createContext<AppState>(defaultAppState); +export const AppStateContext = React.createContext<AppState>(DEFAULT_APP_STATE); diff --git a/server/sonar-web/src/main/js/app/index.ts b/server/sonar-web/src/main/js/app/index.ts index a665c02f376..86c72242783 100644 --- a/server/sonar-web/src/main/js/app/index.ts +++ b/server/sonar-web/src/main/js/app/index.ts @@ -17,118 +17,30 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { getGlobalNavigation } from '../api/navigation'; +import { getCurrentUser } from '../api/users'; import { installExtensionsHandler, installWebAnalyticsHandler } from '../helpers/extensionsHandler'; import { loadL10nBundle } from '../helpers/l10nBundle'; -import { HttpStatus, parseJSON, request } from '../helpers/request'; import { getBaseUrl, getSystemStatus } from '../helpers/system'; -import { AppState } from '../types/appstate'; -import { L10nBundle } from '../types/l10nBundle'; -import { CurrentUser } from '../types/users'; import './styles/sonar.ts'; installWebAnalyticsHandler(); +installExtensionsHandler(); +initApplication(); -if (isMainApp()) { - installExtensionsHandler(); - - loadAll(loadAppState, loadUser).then( - ([l10nBundle, user, appState, startReactApp]) => { - startReactApp(l10nBundle.locale, appState, user); - }, - error => { - if (isResponse(error) && error.status === HttpStatus.Unauthorized) { - redirectToLogin(); - } else { - logError(error); - } - } - ); -} else { - // login, maintenance or setup pages - - const appStateLoader = () => - loadAppState().catch(() => { - return { - edition: undefined, - productionDatabase: true, - qualifiers: [], - settings: {}, - version: '' - }; - }); - - loadAll(appStateLoader).then( - ([l10nBundle, _user, appState, startReactApp]) => { - startReactApp(l10nBundle.locale, appState); - }, - error => { - logError(error); - } - ); -} - -async function loadAll( - appStateLoader: () => Promise<AppState>, - userLoader?: () => Promise<CurrentUser | undefined> -): Promise< - [ - Required<L10nBundle>, - CurrentUser | undefined, - AppState, - (lang: string, appState: AppState, currentUser?: CurrentUser) => void - ] -> { - const [l10nBundle, user, appState] = await Promise.all([ +async function initApplication() { + const [l10nBundle, currentUser, appState] = await Promise.all([ loadL10nBundle(), - userLoader ? userLoader() : undefined, - appStateLoader() - ]); - - const startReactApp = await loadApp(); - - return [l10nBundle, user, appState, startReactApp]; -} - -function loadUser() { - return request('/api/users/current') - .submit() - .then(checkStatus) - .then(parseJSON); -} - -function loadAppState() { - return request('/api/navigation/global') - .submit() - .then(checkStatus) - .then(parseJSON); -} - -function loadApp() { - return import(/* webpackChunkName: 'app' */ './utils/startReactApp').then(i => i.default); -} - -function checkStatus(response: Response) { - return new Promise((resolve, reject) => { - if (response.status >= 200 && response.status < 300) { - resolve(response); - } else { - reject(response); - } + isMainApp() ? getCurrentUser() : undefined, + isMainApp() ? getGlobalNavigation() : undefined + ]).catch(error => { + // eslint-disable-next-line no-console + console.error('Application failed to start', error); + throw error; }); -} - -function isResponse(error: any): error is Response { - return typeof error.status === 'number'; -} - -function redirectToLogin() { - const returnTo = window.location.pathname + window.location.search + window.location.hash; - window.location.href = `${getBaseUrl()}/sessions/new?return_to=${encodeURIComponent(returnTo)}`; -} -function logError(error: any) { - // eslint-disable-next-line no-console - console.error('Application failed to start!', error); + const startReactApp = await import('./utils/startReactApp').then(i => i.default); + startReactApp(l10nBundle.locale, currentUser, appState); } function isMainApp() { diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx index b5387cfa9ec..3bd41cee3be 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx @@ -64,6 +64,7 @@ import { AppState } from '../../types/appstate'; import { CurrentUser } from '../../types/users'; import AdminContainer from '../components/AdminContainer'; import App from '../components/App'; +import { DEFAULT_APP_STATE } from '../components/app-state/AppStateContext'; import AppStateContextProvider from '../components/app-state/AppStateContextProvider'; import ComponentContainer from '../components/ComponentContainer'; import CurrentUserContextProvider from '../components/current-user/CurrentUserContextProvider'; @@ -223,14 +224,18 @@ function renderAdminRoutes() { ); } -export default function startReactApp(lang: string, appState: AppState, currentUser?: CurrentUser) { +export default function startReactApp( + lang: string, + currentUser?: CurrentUser, + appState?: AppState +) { exportModulesAsGlobals(); const el = document.getElementById('content'); render( <HelmetProvider> - <AppStateContextProvider appState={appState}> + <AppStateContextProvider appState={appState ?? DEFAULT_APP_STATE}> <CurrentUserContextProvider currentUser={currentUser}> <IntlProvider defaultLocale={lang} locale={lang}> <GlobalMessagesContainer /> diff --git a/server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx b/server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx index 6270c9faecb..f4c18553a1e 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { getMarketplaceNavigation } from '../../api/nav'; +import { getMarketplaceNavigation } from '../../api/navigation'; import { getAllEditionsAbove } from '../../helpers/editions'; import { EditionKey } from '../../types/editions'; import EditionBox from './components/EditionBox'; diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/EditionBoxes-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/EditionBoxes-test.tsx index 7bc48dbcaa8..b1568cb8b73 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/EditionBoxes-test.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/__tests__/EditionBoxes-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import { EditionKey } from '../../../types/editions'; import EditionBoxes from '../EditionBoxes'; -jest.mock('../../../api/nav', () => ({ +jest.mock('../../../api/navigation', () => ({ getMarketplaceNavigation: jest.fn().mockResolvedValue({}) })); diff --git a/server/sonar-web/src/main/js/apps/projects/components/ApplicationCreation.tsx b/server/sonar-web/src/main/js/apps/projects/components/ApplicationCreation.tsx index f58be34596e..11bf1c33434 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ApplicationCreation.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ApplicationCreation.tsx @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { getComponentNavigation } from '../../../api/nav'; +import { getComponentNavigation } from '../../../api/navigation'; import withAppStateContext from '../../../app/components/app-state/withAppStateContext'; import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import CreateApplicationForm from '../../../app/components/extensions/CreateApplicationForm'; diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ApplicationCreation-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ApplicationCreation-test.tsx index ecdfa1b29fe..163991f0357 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ApplicationCreation-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ApplicationCreation-test.tsx @@ -19,7 +19,7 @@ */ import { shallow, ShallowWrapper } from 'enzyme'; import * as React from 'react'; -import { getComponentNavigation } from '../../../../api/nav'; +import { getComponentNavigation } from '../../../../api/navigation'; import CreateApplicationForm from '../../../../app/components/extensions/CreateApplicationForm'; import { Button } from '../../../../components/controls/buttons'; import { mockAppState, mockLoggedInUser, mockRouter } from '../../../../helpers/testMocks'; @@ -27,7 +27,7 @@ import { queryToSearch } from '../../../../helpers/urls'; import { ComponentQualifier } from '../../../../types/component'; import { ApplicationCreation, ApplicationCreationProps } from '../ApplicationCreation'; -jest.mock('../../../../api/nav', () => ({ +jest.mock('../../../../api/navigation', () => ({ getComponentNavigation: jest.fn().mockResolvedValue({}) })); diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx index 6a592edf6d9..64f0274f234 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import { Project } from '../../api/components'; -import { getComponentNavigation } from '../../api/nav'; +import { getComponentNavigation } from '../../api/navigation'; import ActionsDropdown, { ActionsDropdownItem } from '../../components/controls/ActionsDropdown'; import DeferredSpinner from '../../components/ui/DeferredSpinner'; import { translate } from '../../helpers/l10n'; diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectRowActions-test.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectRowActions-test.tsx index 95182dc9f18..8a8b3f2e706 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectRowActions-test.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectRowActions-test.tsx @@ -19,12 +19,12 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { getComponentNavigation } from '../../../api/nav'; +import { getComponentNavigation } from '../../../api/navigation'; import { mockLoggedInUser } from '../../../helpers/testMocks'; import { click, waitAndUpdate } from '../../../helpers/testUtils'; import ProjectRowActions, { Props } from '../ProjectRowActions'; -jest.mock('../../../api/nav', () => ({ +jest.mock('../../../api/navigation', () => ({ getComponentNavigation: jest.fn().mockResolvedValue({}) })); |