+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.
- */
-import { throwGlobalError } from '../helpers/error';
-import { getJSON } from '../helpers/request';
-import { BranchParameters } from '../types/branch-like';
-import { Component, Extension } from '../types/types';
-
-type NavComponent = Omit<Component, 'alm' | 'qualifier' | 'leakPeriodDate' | 'path' | 'tags'>;
-
-export function getComponentNavigation(
- data: { component: string } & BranchParameters
-): Promise<NavComponent> {
- return getJSON('/api/navigation/component', data).catch(throwGlobalError);
-}
-
-export function getMarketplaceNavigation(): Promise<{ serverId: string; ncloc: number }> {
- return getJSON('/api/navigation/marketplace').catch(throwGlobalError);
-}
-
-export function getSettingsNavigation(): Promise<{
- extensions: Extension[];
- showUpdateCenter: boolean;
-}> {
- return getJSON('/api/navigation/settings').catch(throwGlobalError);
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.
+ */
+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';
+
+type NavComponent = Omit<Component, 'alm' | 'qualifier' | 'leakPeriodDate' | 'path' | 'tags'>;
+
+export function getComponentNavigation(
+ data: { component: string } & BranchParameters
+): Promise<NavComponent> {
+ return getJSON('/api/navigation/component', data).catch(throwGlobalError);
+}
+
+export function getMarketplaceNavigation(): Promise<{ serverId: string; ncloc: number }> {
+ return getJSON('/api/navigation/marketplace').catch(throwGlobalError);
+}
+
+export function getSettingsNavigation(): Promise<{
+ extensions: Extension[];
+ showUpdateCenter: boolean;
+}> {
+ return getJSON('/api/navigation/settings').catch(throwGlobalError);
+}
+
+export function getGlobalNavigation(): Promise<AppState> {
+ return getJSON('/api/navigation/global', undefined, true);
+}
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) {
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';
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,
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';
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'
import * as React from 'react';
import { AppState } from '../../../types/appstate';
-const defaultAppState = {
+export const DEFAULT_APP_STATE = {
authenticationError: false,
authorizationError: false,
edition: undefined,
settings: {},
version: ''
};
-export const AppStateContext = React.createContext<AppState>(defaultAppState);
+export const AppStateContext = React.createContext<AppState>(DEFAULT_APP_STATE);
* 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() {
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';
);
}
-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 />
* 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';
import { EditionKey } from '../../../types/editions';
import EditionBoxes from '../EditionBoxes';
-jest.mock('../../../api/nav', () => ({
+jest.mock('../../../api/navigation', () => ({
getMarketplaceNavigation: jest.fn().mockResolvedValue({})
}));
* 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';
*/
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';
import { ComponentQualifier } from '../../../../types/component';
import { ApplicationCreation, ApplicationCreationProps } from '../ApplicationCreation';
-jest.mock('../../../../api/nav', () => ({
+jest.mock('../../../../api/navigation', () => ({
getComponentNavigation: jest.fn().mockResolvedValue({})
}));
*/
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';
*/
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({})
}));