const baseUrl = '';
(window as any).baseUrl = baseUrl;
+
+jest.mock('../../src/main/js/helpers/l10n', () => ({
+ ...jest.requireActual('../../src/main/js/helpers/l10n'),
+ hasMessage: () => true,
+ translate: (...keys: string[]) => keys.join('.'),
+ translateWithParameters: (messageKey: string, ...parameters: Array<string | number>) =>
+ [messageKey, ...parameters].join('.')
+}));
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { get, getJSON, parseError, post, postJSON } from '../helpers/request';
import {
AzureProject,
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { get, getJSON, HttpStatus, parseError, parseJSON, post } from '../helpers/request';
import {
AlmSettingsBindingDefinitions,
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON } from '../helpers/request';
import { Application, ApplicationPeriod } from '../types/application';
import { Visibility } from '../types/component';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post } from '../helpers/request';
import { Branch, PullRequest } from '../types/branch-like';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, RequestData } from '../helpers/request';
import { IndexationStatus } from '../types/indexation';
import { Task, TaskWarning } from '../types/tasks';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post } from '../helpers/request';
import { getBaseUrl } from '../helpers/system';
import { ComponentReportStatus } from '../types/component-report';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON, RequestData } from '../helpers/request';
import { BranchParameters } from '../types/branch-like';
import { ComponentQualifier, TreeComponent, TreeComponentWithPath } from '../types/component';
--- /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 { License } from '../types/editions';
+
+export function isValidLicense(): Promise<{ isValidLicense: boolean }> {
+ return getJSON('/api/editions/is_valid_license');
+}
+
+export function showLicense(): Promise<License> {
+ return getJSON('/api/editions/show_license').catch((response: Response) => {
+ if (response && response.status === 404) {
+ return undefined;
+ }
+ return throwGlobalError(response);
+ });
+}
* 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 '../app/utils/throwGlobalError';
import getCoverageStatus from '../components/SourceViewer/helpers/getCoverageStatus';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON, RequestData } from '../helpers/request';
import { IssueResponse, RawIssuesResponse } from '../types/issues';
import { Dict, FacetValue, IssueChangelog, SnippetsByComponent, SourceLine } from '../types/types';
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { getJSON } from '../helpers/request';
-import { L10nBundleRequestParams, L10nBundleRequestResponse } from '../types/l10n';
+import { L10nBundleRequestParams, L10nBundleRequestResponse } from '../types/l10nBundle';
export function fetchL10nBundle(
params: L10nBundleRequestParams
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON } from '../helpers/request';
import { Language } from '../types/languages';
+++ /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 '../app/utils/throwGlobalError';
-import { getJSON } from '../helpers/request';
-
-export interface License {
- contactEmail: string;
- edition: string;
- expiresAt: string;
- isExpired: boolean;
- isOfficialDistribution: boolean;
- isSupported: boolean;
- isValidEdition: boolean;
- isValidServerId: boolean;
- loc: number;
- maxLoc: number;
- plugins: string[];
- remainingLocThreshold: number;
- serverId: string;
- type: string;
-}
-
-export function isValidLicense(): Promise<{ isValidLicense: boolean }> {
- return getJSON('/api/editions/is_valid_license');
-}
-
-export function showLicense(): Promise<License> {
- return getJSON('/api/editions/show_license').catch((response: Response) => {
- if (response && response.status === 404) {
- return undefined;
- }
- return throwGlobalError(response);
- });
-}
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON } from '../helpers/request';
import { BranchParameters } from '../types/branch-like';
import {
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON } from '../helpers/request';
import { Metric } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON } from '../helpers/request';
import { BranchParameters } from '../types/branch-like';
import { Component, Extension } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post } from '../helpers/request';
import { NewCodePeriod, NewCodePeriodBranch, NewCodePeriodSettingType } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post } from '../helpers/request';
import { Notification } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON, RequestData } from '../helpers/request';
import {
Paging,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { findLastIndex } from 'lodash';
-import throwGlobalError from '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post } from '../helpers/request';
import { isDefined } from '../helpers/types';
import {
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, postJSON } from '../helpers/request';
export function getProjectBadgesToken(project: string) {
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post } from '../helpers/request';
import { DumpStatus } from '../types/project-dump';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON, RequestData } from '../helpers/request';
import { BranchParameters } from '../types/branch-like';
import { Analysis, Paging } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON } from '../helpers/request';
import { ProjectLink } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON } from '../helpers/request';
import { BranchParameters } from '../types/branch-like';
import {
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { map } from 'lodash';
-import throwGlobalError from '../app/utils/throwGlobalError';
import { Exporter, ProfileChangelogEvent } from '../apps/quality-profiles/types';
import { csvEscape } from '../helpers/csv';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON, RequestData } from '../helpers/request';
import { Dict, Paging, ProfileInheritanceDetails, UserSelected } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON } from '../helpers/request';
import { GetRulesAppResponse, SearchRulesResponse } from '../types/coding-rules';
import { SearchRulesQuery } from '../types/rules';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post } from '../helpers/request';
import { BranchParameters } from '../types/branch-like';
import {
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { omitBy } from 'lodash';
-import throwGlobalError from '../app/utils/throwGlobalError';
import { isCategoryDefinition } from '../apps/settings/utils';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON, RequestData } from '../helpers/request';
import { BranchParameters } from '../types/branch-like';
import {
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON, requestTryAndRepeatUntil } from '../helpers/request';
import { SystemUpgrade } from '../types/system';
import { SysInfoCluster, SysInfoStandalone, SysStatus } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON } from '../helpers/request';
import { BranchParameters } from '../types/branch-like';
import { Paging } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON } from '../helpers/request';
import { NewUserToken, UserToken } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON } from '../helpers/request';
import { Group, Paging, UserSelected } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON } from '../helpers/request';
import { IdentityProvider, Paging } from '../types/types';
import { CurrentUser, HomePage, User } from '../types/users';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON } from '../helpers/request';
import { WebApi } from '../types/types';
* 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 '../app/utils/throwGlobalError';
+import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON } from '../helpers/request';
import { Paging, Webhook, WebhookDelivery } from '../types/types';
*/
import { differenceInDays } from 'date-fns';
import * as React from 'react';
-import { showLicense } from '../../api/marketplace';
+import { showLicense } from '../../api/editions';
import { Location, Router, withRouter } from '../../components/hoc/withRouter';
import { lazyLoadComponent } from '../../components/lazyLoadComponent';
import { parseDate, toShortNotSoISOString } from '../../helpers/dates';
import { differenceInDays } from 'date-fns';
import { shallow, ShallowWrapper } from 'enzyme';
import * as React from 'react';
-import { showLicense } from '../../../api/marketplace';
+import { showLicense } from '../../../api/editions';
import { toShortNotSoISOString } from '../../../helpers/dates';
import { hasMessage } from '../../../helpers/l10n';
import { get, save } from '../../../helpers/storage';
import { LoggedInUser } from '../../../types/users';
import { StartupModal } from '../StartupModal';
-jest.mock('../../../api/marketplace', () => ({
+jest.mock('../../../api/editions', () => ({
showLicense: jest.fn().mockResolvedValue(undefined)
}));
import { connect } from 'react-redux';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
import { getExtensionStart } from '../../../helpers/extensions';
-import { getCurrentL10nBundle, translate } from '../../../helpers/l10n';
+import { translate } from '../../../helpers/l10n';
+import { getCurrentL10nBundle } from '../../../helpers/l10nBundle';
import { getBaseUrl } from '../../../helpers/system';
import { addGlobalErrorMessage } from '../../../store/globalMessages';
import { AppState } from '../../../types/appstate';
isPullRequest,
sortBranches
} from '../../../helpers/branch-like';
+import { throwGlobalError } from '../../../helpers/error';
import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import * as measures from '../../../helpers/measures';
getRulesUrl
} from '../../../helpers/urls';
import addGlobalSuccessMessage from '../../utils/addGlobalSuccessMessage';
-import throwGlobalError from '../../utils/throwGlobalError';
import A11ySkipTarget from '../a11y/A11ySkipTarget';
import Suggestions from '../embed-docs-modal/Suggestions';
*/
import * as React from 'react';
import { Link } from 'react-router';
-import { isValidLicense } from '../../../../api/marketplace';
+import { isValidLicense } from '../../../../api/editions';
import { Alert } from '../../../../components/ui/Alert';
import { translate, translateWithParameters } from '../../../../helpers/l10n';
import { AppState } from '../../../../types/appstate';
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { isValidLicense } from '../../../../../api/marketplace';
+import { isValidLicense } from '../../../../../api/editions';
import { mockTask } from '../../../../../helpers/mocks/tasks';
import { mockAppState } from '../../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../../helpers/testUtils';
hasMessage: jest.fn().mockReturnValue(true)
}));
-jest.mock('../../../../../api/marketplace', () => ({
+jest.mock('../../../../../api/editions', () => ({
isValidLicense: jest.fn().mockResolvedValue({ isValidLicense: false })
}));
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { installExtensionsHandler, installWebAnalyticsHandler } from '../helpers/extensionsHandler';
-import { loadL10nBundle } from '../helpers/l10n';
+import { loadL10nBundle } from '../helpers/l10nBundle';
import { parseJSON, request } from '../helpers/request';
import { getBaseUrl, getSystemStatus } from '../helpers/system';
import { AppState } from '../types/appstate';
+++ /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 getStore from '../getStore';
-import throwGlobalError from '../throwGlobalError';
-
-beforeAll(() => {
- jest.useFakeTimers();
-});
-
-afterAll(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-it('should put the error message in the store', async () => {
- const response = new Response();
- response.json = jest.fn().mockResolvedValue({ errors: [{ msg: 'error 1' }] });
-
- // We need to catch because throwGlobalError rethrows after displaying the message
- await throwGlobalError(response)
- .then(() => fail('Should throw'))
- .catch(() => {});
-
- expect(getStore().getState().globalMessages[0]).toMatchObject({
- level: 'ERROR',
- message: 'error 1'
- });
-});
-
-it('should put a default error messsage in the store', async () => {
- const response = new Response();
- response.json = jest.fn().mockResolvedValue({});
-
- // We need to catch because throwGlobalError rethrows after displaying the message
- await throwGlobalError(response)
- .then(() => fail('Should throw'))
- .catch(() => {});
-
- expect(getStore().getState().globalMessages[0]).toMatchObject({
- level: 'ERROR',
- message: 'default_error_message'
- });
-});
-
-it('should handle weird response types', () => {
- const response = { weird: 'response type' };
-
- return throwGlobalError(response)
- .then(() => fail('Should throw'))
- .catch(error => {
- expect(error).toBe(response);
- });
-});
-
-it('should unwrap response if necessary', async () => {
- const response = new Response();
- response.json = jest.fn().mockResolvedValue({});
-
- /* eslint-disable-next-line no-console */
- console.warn = jest.fn();
-
- // We need to catch because throwGlobalError rethrows after displaying the message
- await throwGlobalError({ response })
- .then(() => fail('Should throw'))
- .catch(() => {});
-
- /* eslint-disable-next-line no-console */
- expect(console.warn).toHaveBeenCalled();
-});
--- /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 * as EmotionReact from '@emotion/react';
+import EmotionStyled from '@emotion/styled';
+import * as DateFns from 'date-fns';
+import Lodash from 'lodash';
+import React from 'react';
+import * as ReactDom from 'react-dom';
+import * as ReactIntl from 'react-intl';
+import ReactModal from 'react-modal';
+import * as ReactRouter from 'react-router';
+
+/*
+ * Expose dependencies to extensions
+ */
+export default function exportModulesAsGlobals() {
+ const w = (window as unknown) as any;
+ w.EmotionReact = EmotionReact;
+ w.EmotionStyled = EmotionStyled;
+ w.DateFns = DateFns;
+ w.Lodash = Lodash;
+ w.React = React;
+ w.ReactDOM = ReactDom;
+ w.ReactIntl = ReactIntl;
+ w.ReactModal = ReactModal;
+ w.ReactRouter = ReactRouter;
+}
import { Location } from 'history';
import { pick } from 'lodash';
import * as React from 'react';
-import ReactDom, { render } from 'react-dom';
+import { render } from 'react-dom';
import { HelmetProvider } from 'react-helmet-async';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import { PageContext } from '../components/indexation/PageUnavailableDueToIndexation';
import MigrationContainer from '../components/MigrationContainer';
import NonAdminPagesContainer from '../components/NonAdminPagesContainer';
+import exportModulesAsGlobals from './exportModulesAsGlobals';
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 (query.types === 'SECURITY_HOTSPOT') {
replace({
pathname: '/security_hotspots',
- query: { ...pick(query, ['id', 'branch', 'pullRequest']), assignedToMe: false }
+ query: {
+ ...pick(query, ['id', 'branch', 'pullRequest']),
+ assignedToMe: false
+ }
});
} else {
query.types = query.types
}
export default function startReactApp(lang: string, appState: AppState, currentUser?: CurrentUser) {
- attachToGlobal();
+ exportModulesAsGlobals();
const el = document.getElementById('content');
+++ /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 { parseError } from '../../helpers/request';
-import { addGlobalErrorMessage } from '../../store/globalMessages';
-import getStore from './getStore';
-
-export default function throwGlobalError(param: Response | any): Promise<Response | any> {
- const store = getStore();
-
- if (param.response instanceof Response) {
- /* eslint-disable-next-line no-console */
- console.warn('DEPRECATED: response should not be wrapped, pass it directly.');
- param = param.response;
- }
-
- if (param instanceof Response) {
- return parseError(param)
- .then(
- message => {
- store.dispatch(addGlobalErrorMessage(message));
- },
- () => {}
- )
- .then(() => Promise.reject(param));
- }
-
- return Promise.reject(param);
-}
property="Reliability"
>
<FacetHeader
+ helper="component_measures.domain_facets.Reliability.help"
name="Reliability"
onClick={[Function]}
open={true}
property="Reliability"
>
<FacetHeader
+ helper="component_measures.domain_facets.Reliability.help"
name="Reliability"
onClick={[Function]}
open={true}
property="Reliability"
>
<FacetHeader
+ helper="component_measures.domain_facets.Reliability.help"
name="Reliability"
onClick={[Function]}
open={true}
property="Reliability"
>
<FacetHeader
+ helper="component_measures.domain_facets.Reliability.help"
name="Reliability"
onClick={[Function]}
open={true}
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { bulkChangeIssues, searchIssueTags } from '../../../api/issues';
-import throwGlobalError from '../../../app/utils/throwGlobalError';
import FormattingTips from '../../../components/common/FormattingTips';
import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import Checkbox from '../../../components/controls/Checkbox';
import SeverityHelper from '../../../components/shared/SeverityHelper';
import { Alert } from '../../../components/ui/Alert';
import Avatar from '../../../components/ui/Avatar';
+import { throwGlobalError } from '../../../helpers/error';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Component, Dict, Issue, IssueType, Paging } from '../../../types/types';
import { CurrentUser, isLoggedIn, isUserActive } from '../../../types/users';
import * as React from 'react';
import { getDuplications } from '../../../api/components';
import { getIssueFlowSnippets } from '../../../api/issues';
-import throwGlobalError from '../../../app/utils/throwGlobalError';
import DuplicationPopup from '../../../components/SourceViewer/components/DuplicationPopup';
import {
filterDuplicationBlocksByLine,
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
import { WorkspaceContext } from '../../../components/workspace/context';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
+import { throwGlobalError } from '../../../helpers/error';
import { translate } from '../../../helpers/l10n';
import { BranchLike } from '../../../types/branch-like';
import {
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { resetMessages } from '../../../helpers/l10n';
import { isSonarCloud } from '../../../helpers/system';
import { convertToPermissionDefinitions } from '../utils';
jest.mock('../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
-afterEach(() => {
- resetMessages({});
-});
+jest.mock('../../../helpers/l10nBundle', () => ({
+ getMessages: jest.fn().mockReturnValue({})
+}));
describe('convertToPermissionDefinitions', () => {
it('should convert and translate a permission definition', () => {
(isSonarCloud as jest.Mock).mockImplementation(() => false);
- resetMessages({
- 'global_permissions.admin': 'Administer System'
- });
-
const data = convertToPermissionDefinitions(['admin'], 'global_permissions');
const expected = [
- { description: 'global_permissions.admin.desc', key: 'admin', name: 'Administer System' }
+ {
+ description: 'global_permissions.admin.desc',
+ key: 'admin',
+ name: 'global_permissions.admin'
+ }
];
expect(data).toEqual(expected);
it('should convert and translate a permission definition for SonarCloud', () => {
(isSonarCloud as jest.Mock).mockImplementation(() => true);
- resetMessages({
- 'global_permissions.admin': 'Administer System',
- 'global_permissions.admin.sonarcloud': 'Administer Organization'
- });
-
const data = convertToPermissionDefinitions(['admin'], 'global_permissions');
const expected = [
{
- description: 'global_permissions.admin.desc',
+ description: 'global_permissions.admin.desc.sonarcloud',
key: 'admin',
- name: 'Administer Organization'
+ name: 'global_permissions.admin.sonarcloud'
}
];
it('should fallback to basic message when SonarCloud version does not exist', () => {
(isSonarCloud as jest.Mock).mockImplementation(() => true);
- resetMessages({
- 'global_permissions.admin': 'Administer System'
- });
-
const data = convertToPermissionDefinitions(['admin'], 'global_permissions');
const expected = [
- { description: 'global_permissions.admin.desc', key: 'admin', name: 'Administer System' }
+ {
+ description: 'global_permissions.admin.desc.sonarcloud',
+ key: 'admin',
+ name: 'global_permissions.admin.sonarcloud'
+ }
];
expect(data).toEqual(expected);
import { getActivity } from '../../api/ce';
import { getStatus } from '../../api/project-dump';
import withAppStateContext from '../../app/components/app-state/withAppStateContext';
-import throwGlobalError from '../../app/utils/throwGlobalError';
+import { throwGlobalError } from '../../helpers/error';
import { translate } from '../../helpers/l10n';
import { AppState } from '../../types/appstate';
import { DumpStatus, DumpTask } from '../../types/project-dump';
>
<IndexLink
className=""
- title="general"
+ title="property.category.general"
to={
Object {
"pathname": "/admin/settings",
}
}
>
- general
+ property.category.general
</IndexLink>
</li>
</ul>
>
<IndexLink
className=""
- title="general"
+ title="property.category.general"
to={
Object {
"pathname": "/admin/settings",
}
}
>
- general
+ property.category.general
</IndexLink>
</li>
</ul>
>
<IndexLink
className=""
- title="general"
+ title="property.category.general"
to={
Object {
"pathname": "/project/settings",
}
}
>
- general
+ property.category.general
</IndexLink>
</li>
</ul>
>
<IndexLink
className=""
- title="general"
+ title="property.category.general"
to={
Object {
"pathname": "/admin/settings",
}
}
>
- general
+ property.category.general
</IndexLink>
</li>
</ul>
>
<h3
className="settings-definition-name"
+ title="property.foo.name"
+ >
+ property.foo.name
+ </h3>
+ <div
+ className="markdown small spacer-top"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "property.foo.description",
+ }
+ }
/>
<div
className="settings-definition-key note little-spacer-top"
>
<h3
className="settings-definition-name"
+ title="property.foo.name"
+ >
+ property.foo.name
+ </h3>
+ <div
+ className="markdown small spacer-top"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "property.foo.description",
+ }
+ }
/>
<div
className="settings-definition-key note little-spacer-top"
>
<h3
className="settings-definition-name"
+ title="property.foo.name"
+ >
+ property.foo.name
+ </h3>
+ <div
+ className="markdown small spacer-top"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "property.foo.description",
+ }
+ }
/>
<div
className="settings-definition-key note little-spacer-top"
>
<h3
className="settings-definition-name"
+ title="property.foo.name"
+ >
+ property.foo.name
+ </h3>
+ <div
+ className="markdown small spacer-top"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "property.foo.description",
+ }
+ }
/>
<div
className="settings-definition-key note little-spacer-top"
>
<h3
className="settings-definition-name"
+ title="property.foo.name"
+ >
+ property.foo.name
+ </h3>
+ <div
+ className="markdown small spacer-top"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "property.foo.description",
+ }
+ }
/>
<div
className="settings-definition-key note little-spacer-top"
>
<h3
className="settings-definition-name"
- />
+ title="property.foo.name"
+ >
+ property.foo.name
+ </h3>
<div
className="markdown small spacer-top"
dangerouslySetInnerHTML={
Object {
- "__html": "description",
+ "__html": "property.foo.description",
}
}
/>
options={
Array [
Object {
- "label": "Java",
+ "label": "property.category.Java",
"originalValue": "Java",
"value": "java",
},
Object {
- "label": "JavaScript",
+ "label": "property.category.JavaScript",
"originalValue": "JavaScript",
"value": "javascript",
},
Object {
- "label": "COBOL",
+ "label": "property.category.COBOL",
"originalValue": "COBOL",
"value": "cobol",
},
options={
Array [
Object {
- "label": "Java",
+ "label": "property.category.Java",
"originalValue": "Java",
"value": "java",
},
Object {
- "label": "JavaScript",
+ "label": "property.category.JavaScript",
"originalValue": "JavaScript",
"value": "javascript",
},
Object {
- "label": "COBOL",
+ "label": "property.category.COBOL",
"originalValue": "COBOL",
"value": "cobol",
},
className="settings-sub-category-name"
data-key="email"
>
- email
+ property.category.general.email
</h2>
+ <div
+ className="settings-sub-category-description markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "property.category.general.email.description",
+ }
+ }
+ />
<DefinitionsList
scrollToDefinition={[Function]}
settings={
className="settings-sub-category-name"
data-key="qg"
>
- qg
+ property.category.general.qg
</h2>
+ <div
+ className="settings-sub-category-description markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "property.category.general.qg.description",
+ }
+ }
+ />
<DefinitionsList
scrollToDefinition={[Function]}
settings={
className="settings-sub-category-name"
data-key="qg"
>
- qg
+ property.category.general.qg
</h2>
+ <div
+ className="settings-sub-category-description markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "property.category.general.qg.description",
+ }
+ }
+ />
<DefinitionsList
scrollToDefinition={[Function]}
settings={
validateProjectAlmBinding
} from '../../../../api/alm-settings';
import withCurrentUserContext from '../../../../app/components/current-user/withCurrentUserContext';
-import throwGlobalError from '../../../../app/utils/throwGlobalError';
+import { throwGlobalError } from '../../../../helpers/error';
import { HttpStatus } from '../../../../helpers/request';
import { hasGlobalPermission } from '../../../../helpers/users';
import {
import * as React from 'react';
import { changePassword } from '../../../api/users';
import addGlobalSuccessMessage from '../../../app/utils/addGlobalSuccessMessage';
-import throwGlobalError from '../../../app/utils/throwGlobalError';
import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import Modal from '../../../components/controls/Modal';
import { Alert } from '../../../components/ui/Alert';
import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
+import { throwGlobalError } from '../../../helpers/error';
import { translate } from '../../../helpers/l10n';
import { parseError } from '../../../helpers/request';
import { User } from '../../../types/users';
import { uniq } from 'lodash';
import * as React from 'react';
import { createUser, updateUser } from '../../../api/users';
-import throwGlobalError from '../../../app/utils/throwGlobalError';
import { Button, ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import SimpleModal from '../../../components/controls/SimpleModal';
import { Alert } from '../../../components/ui/Alert';
import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
+import { throwGlobalError } from '../../../helpers/error';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { parseError } from '../../../helpers/request';
import { User } from '../../../types/users';
* 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 '../../../app/utils/throwGlobalError';
+import { throwGlobalError } from '../../../helpers/error';
import { parseIssueFromResponse } from '../../../helpers/issues';
import { mockComponent } from '../../../helpers/mocks/component';
import { mockIssue } from '../../../helpers/testMocks';
import { updateIssue } from '../actions';
-jest.mock('../../../app/utils/throwGlobalError', () => jest.fn());
+jest.mock('../../../helpers/error', () => ({ throwGlobalError: jest.fn() }));
jest.mock('../../../helpers/issues', () => ({
parseIssueFromResponse: jest.fn()
* 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 '../../app/utils/throwGlobalError';
+import { throwGlobalError } from '../../helpers/error';
import { parseIssueFromResponse } from '../../helpers/issues';
import { IssueResponse } from '../../types/issues';
import { Issue } from '../../types/types';
--- /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 getStore from '../../app/utils/getStore';
+import { throwGlobalError } from '../error';
+
+beforeAll(() => {
+ jest.useFakeTimers();
+});
+
+afterAll(() => {
+ jest.runOnlyPendingTimers();
+ jest.useRealTimers();
+});
+
+it('should put the error message in the store', async () => {
+ const response = new Response();
+ response.json = jest.fn().mockResolvedValue({ errors: [{ msg: 'error 1' }] });
+
+ // We need to catch because throwGlobalError rethrows after displaying the message
+ await throwGlobalError(response)
+ .then(() => {
+ throw new Error('Should throw');
+ })
+ .catch(() => {});
+
+ expect(getStore().getState().globalMessages[0]).toMatchObject({
+ level: 'ERROR',
+ message: 'error 1'
+ });
+});
+
+it('should put a default error messsage in the store', async () => {
+ const response = new Response();
+ response.json = jest.fn().mockResolvedValue({});
+
+ // We need to catch because throwGlobalError rethrows after displaying the message
+ await throwGlobalError(response)
+ .then(() => {
+ throw new Error('Should throw');
+ })
+ .catch(() => {});
+
+ expect(getStore().getState().globalMessages[0]).toMatchObject({
+ level: 'ERROR',
+ message: 'default_error_message'
+ });
+});
+
+it('should handle weird response types', () => {
+ const response = { weird: 'response type' };
+
+ return throwGlobalError(response)
+ .then(() => {
+ throw new Error('Should throw');
+ })
+ .catch(error => {
+ expect(error).toBe(response);
+ });
+});
+
+it('should unwrap response if necessary', async () => {
+ const response = new Response();
+ response.json = jest.fn().mockResolvedValue({});
+
+ /* eslint-disable-next-line no-console */
+ console.warn = jest.fn();
+
+ // We need to catch because throwGlobalError rethrows after displaying the message
+ await throwGlobalError({ response })
+ .then(() => {
+ throw new Error('Should throw');
+ })
+ .catch(() => {});
+
+ /* eslint-disable-next-line no-console */
+ expect(console.warn).toHaveBeenCalled();
+});
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { fetchL10nBundle } from '../../api/l10n';
+import { Dict } from '../../types/types';
import {
getLocalizedCategoryMetricName,
getLocalizedMetricDomain,
getLocalizedMetricName,
- getMessages,
getShortMonthName,
getShortWeekDayName,
getWeekDayName,
hasMessage,
- loadL10nBundle,
- resetMessages,
translate,
translateWithParameters
} from '../l10n';
-import { get } from '../storage';
+import { getMessages } from '../l10nBundle';
-beforeEach(() => {
- jest.clearAllMocks();
- jest.spyOn(window.navigator, 'languages', 'get').mockReturnValue(['de']);
-});
+const MSG = 'my_message';
-jest.mock('../../api/l10n', () => ({
- fetchL10nBundle: jest
- .fn()
- .mockResolvedValue({ effectiveLocale: 'de', messages: { test_message: 'test' } })
-}));
+jest.unmock('../l10n');
-jest.mock('../../helpers/storage', () => ({
- get: jest.fn(),
- save: jest.fn()
+jest.mock('../l10nBundle', () => ({
+ getMessages: jest.fn().mockReturnValue({})
}));
-describe('#loadL10nBundle', () => {
- it('should fetch bundle without any timestamp', async () => {
- await loadL10nBundle();
-
- expect(fetchL10nBundle).toHaveBeenCalledWith({ locale: 'de', ts: undefined });
- });
-
- it('should ftech bundle without local storage timestamp if locales are different', async () => {
- const cachedBundle = { timestamp: 'timestamp', locale: 'fr', messages: { cache: 'cache' } };
- (get as jest.Mock).mockReturnValueOnce(JSON.stringify(cachedBundle));
-
- await loadL10nBundle();
-
- expect(fetchL10nBundle).toHaveBeenCalledWith({ locale: 'de', ts: undefined });
- });
-
- it('should fetch bundle with cached bundle timestamp and browser locale', async () => {
- const cachedBundle = { timestamp: 'timestamp', locale: 'de', messages: { cache: 'cache' } };
- (get as jest.Mock).mockReturnValueOnce(JSON.stringify(cachedBundle));
+const resetMessages = (messages: Dict<string>) =>
+ (getMessages as jest.Mock).mockReturnValue(messages);
- await loadL10nBundle();
+beforeEach(() => {
+ resetMessages({});
+});
- expect(fetchL10nBundle).toHaveBeenCalledWith({ locale: 'de', ts: cachedBundle.timestamp });
+describe('hasMessage', () => {
+ it('should return that the message exists', () => {
+ resetMessages({
+ foo: 'foo',
+ 'foo.bar': 'foobar'
+ });
+ expect(hasMessage('foo')).toBe(true);
+ expect(hasMessage('foo', 'bar')).toBe(true);
});
- it('should fallback to cached bundle if the server respond with 304', async () => {
- const cachedBundle = { timestamp: 'timestamp', locale: 'fr', messages: { cache: 'cache' } };
- (fetchL10nBundle as jest.Mock).mockRejectedValueOnce({ status: 304 });
- (get as jest.Mock).mockReturnValueOnce(JSON.stringify(cachedBundle));
-
- const bundle = await loadL10nBundle();
-
- expect(bundle).toEqual(
- expect.objectContaining({ locale: cachedBundle.locale, messages: cachedBundle.messages })
- );
+ it('should return that the message is missing', () => {
+ expect(hasMessage('foo')).toBe(false);
+ expect(hasMessage('foo', 'bar')).toBe(false);
});
});
-const originalMessages = getMessages();
-const MSG = 'my_message';
-
-afterEach(() => {
- resetMessages(originalMessages);
-});
-
describe('translate', () => {
it('should translate simple message', () => {
resetMessages({ my_key: MSG });
});
});
-describe('hasMessage', () => {
- it('should return that the message exists', () => {
- resetMessages({ foo: 'Foo', 'foo.bar': 'Foo Bar' });
- expect(hasMessage('foo')).toBe(true);
- expect(hasMessage('foo', 'bar')).toBe(true);
- });
-
- it('should return that the message is missing', () => {
- expect(hasMessage('foo')).toBe(false);
- expect(hasMessage('foo', 'bar')).toBe(false);
- });
-});
-
describe('getLocalizedMetricName', () => {
const metric = { key: 'new_code', name: 'new_code_metric_name' };
--- /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 { fetchL10nBundle } from '../../api/l10n';
+import { loadL10nBundle } from '../l10nBundle';
+
+beforeEach(() => {
+ jest.clearAllMocks();
+ jest.spyOn(window.navigator, 'languages', 'get').mockReturnValue(['de']);
+});
+
+jest.mock('../../api/l10n', () => ({
+ fetchL10nBundle: jest.fn().mockResolvedValue({
+ effectiveLocale: 'de',
+ messages: { foo: 'Foo', 'foo.bar': 'Foo Bar' }
+ })
+}));
+
+describe('#loadL10nBundle', () => {
+ it('should fetch bundle without any timestamp', async () => {
+ await loadL10nBundle();
+
+ expect(fetchL10nBundle).toHaveBeenCalledWith({ locale: 'de', ts: undefined });
+ });
+
+ it('should ftech bundle without local storage timestamp if locales are different', async () => {
+ const cachedBundle = { timestamp: 'timestamp', locale: 'fr', messages: { cache: 'cache' } };
+ ((window as unknown) as any).sonarQubeL10nBundle = cachedBundle;
+
+ await loadL10nBundle();
+
+ expect(fetchL10nBundle).toHaveBeenCalledWith({ locale: 'de', ts: undefined });
+ });
+
+ it('should fetch bundle with cached bundle timestamp and browser locale', async () => {
+ const cachedBundle = { timestamp: 'timestamp', locale: 'de', messages: { cache: 'cache' } };
+ ((window as unknown) as any).sonarQubeL10nBundle = cachedBundle;
+
+ await loadL10nBundle();
+
+ expect(fetchL10nBundle).toHaveBeenCalledWith({ locale: 'de', ts: cachedBundle.timestamp });
+ });
+
+ it('should fallback to cached bundle if the server respond with 304', async () => {
+ const cachedBundle = { timestamp: 'timestamp', locale: 'fr', messages: { cache: 'cache' } };
+ (fetchL10nBundle as jest.Mock).mockRejectedValueOnce({ status: 304 });
+ ((window as unknown) as any).sonarQubeL10nBundle = cachedBundle;
+
+ const bundle = await loadL10nBundle();
+
+ expect(bundle).toEqual(
+ expect.objectContaining({ locale: cachedBundle.locale, messages: cachedBundle.messages })
+ );
+ });
+});
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { resetMessages } from '../l10n';
+
+import { Dict } from '../../types/types';
+import { getMessages } from '../l10nBundle';
import {
enhanceConditionWithMeasure,
formatMeasure,
import { mockQualityGateStatusCondition } from '../mocks/quality-gates';
import { mockMeasureEnhanced, mockMetric } from '../testMocks';
+jest.unmock('../l10n');
+
+jest.mock('../l10nBundle', () => ({
+ getCurrentLocale: jest.fn().mockReturnValue('us'),
+ getMessages: jest.fn().mockReturnValue({})
+}));
+
+const resetMessages = (messages: Dict<string>) =>
+ (getMessages as jest.Mock).mockReturnValue(messages);
+
+beforeAll(() => {
+ resetMessages({
+ 'work_duration.x_days': '{0}d',
+ 'work_duration.x_hours': '{0}h',
+ 'work_duration.x_minutes': '{0}min',
+ 'work_duration.about': '~ {0}',
+ 'metric.level.ERROR': 'Error',
+ 'metric.level.WARN': 'Warning',
+ 'metric.level.OK': 'Ok',
+ 'short_number_suffix.g': 'G',
+ 'short_number_suffix.k': 'k',
+ 'short_number_suffix.m': 'M'
+ });
+});
+
+const HOURS_IN_DAY = 8;
+const ONE_MINUTE = 1;
+const ONE_HOUR = ONE_MINUTE * 60;
+const ONE_DAY = HOURS_IN_DAY * ONE_HOUR;
+
describe('enhanceConditionWithMeasure', () => {
it('should correctly map enhance conditions with measure data', () => {
const measures = [
});
});
-const HOURS_IN_DAY = 8;
-const ONE_MINUTE = 1;
-const ONE_HOUR = ONE_MINUTE * 60;
-const ONE_DAY = HOURS_IN_DAY * ONE_HOUR;
-
-beforeAll(() => {
- resetMessages({
- 'work_duration.x_days': '{0}d',
- 'work_duration.x_hours': '{0}h',
- 'work_duration.x_minutes': '{0}min',
- 'work_duration.about': '~ {0}',
- 'metric.level.ERROR': 'Error',
- 'metric.level.WARN': 'Warning',
- 'metric.level.OK': 'Ok',
- 'short_number_suffix.g': 'G',
- 'short_number_suffix.k': 'k',
- 'short_number_suffix.m': 'M'
- });
-});
-
-afterAll(() => {
- resetMessages({});
-});
-
describe('#formatMeasure()', () => {
it('should format INT', () => {
expect(formatMeasure(0, 'INT')).toBe('0');
--- /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 getStore from '../app/utils/getStore';
+import { addGlobalErrorMessage } from '../store/globalMessages';
+import { parseError } from './request';
+
+export function throwGlobalError(param: Response | any): Promise<Response | any> {
+ const store = getStore();
+
+ if (param.response instanceof Response) {
+ /* eslint-disable-next-line no-console */
+ console.warn('DEPRECATED: response should not be wrapped, pass it directly.');
+ param = param.response;
+ }
+
+ if (param instanceof Response) {
+ return parseError(param)
+ .then(
+ message => {
+ store.dispatch(addGlobalErrorMessage(message));
+ },
+ () => {}
+ )
+ .then(() => Promise.reject(param));
+ }
+
+ return Promise.reject(param);
+}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { fetchL10nBundle } from '../api/l10n';
-import { L10nBundle, L10nBundleRequestParams } from '../types/l10n';
-import { Dict } from '../types/types';
-import { toNotSoISOString } from './dates';
-import { get as loadFromLocalStorage, save as saveInLocalStorage } from './storage';
-export type Messages = Dict<string>;
+import { getMessages } from './l10nBundle';
-export const DEFAULT_LOCALE = 'en';
-export const DEFAULT_MESSAGES = {
- // eslint-disable-next-line camelcase
- default_error_message: 'The request cannot be processed. Try again later.'
-};
-
-let allMessages: Messages = {};
-let locale: string | undefined;
+export function hasMessage(...keys: string[]): boolean {
+ const messageKey = keys.join('.');
+ return getMessages()[messageKey] != null;
+}
export function translate(...keys: string[]): string {
const messageKey = keys.join('.');
return `${messageKey}.${parameters.join('.')}`;
}
-export function hasMessage(...keys: string[]): boolean {
- const messageKey = keys.join('.');
- return getMessages()[messageKey] != null;
-}
-
-export function getMessages() {
- if (typeof allMessages === 'undefined') {
- logWarning('L10n messages are not initialized. Use default messages.');
- return DEFAULT_MESSAGES;
- }
- return allMessages;
-}
-
-export function resetMessages(newMessages: Messages) {
- allMessages = newMessages;
-}
-
export function getLocalizedMetricName(
metric: { key: string; name?: string },
short = false
return hasMessage(bundleKey) ? translate(bundleKey) : domainName;
}
-export function getCurrentLocale() {
- return locale;
-}
-
-export function resetCurrentLocale(newLocale: string) {
- locale = newLocale;
-}
-
export function getShortMonthName(index: number) {
const months = [
'Jan',
const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
return weekdays[index] ? translate(weekdays[index]) : '';
}
-
-const L10N_BUNDLE_LS_KEY = 'l10n.bundle';
-
-export async function loadL10nBundle() {
- const bundle = await getLatestL10nBundle().catch(() => ({
- locale: DEFAULT_LOCALE,
- messages: {}
- }));
-
- resetCurrentLocale(bundle.locale);
- resetMessages(bundle.messages);
-
- return bundle;
-}
-
-export async function getLatestL10nBundle() {
- const browserLocale = getPreferredLanguage();
- const cachedBundle = loadL10nBundleFromLocalStorage();
-
- const params: L10nBundleRequestParams = {};
-
- if (browserLocale) {
- params.locale = browserLocale;
-
- if (
- cachedBundle.locale &&
- browserLocale.startsWith(cachedBundle.locale) &&
- cachedBundle.timestamp &&
- cachedBundle.messages
- ) {
- params.ts = cachedBundle.timestamp;
- }
- }
-
- const { effectiveLocale, messages } = await fetchL10nBundle(params).catch(response => {
- if (response && response.status === 304) {
- return {
- effectiveLocale: cachedBundle.locale || browserLocale || DEFAULT_LOCALE,
- messages: cachedBundle.messages ?? {}
- };
- }
- throw new Error(`Unexpected status code: ${response.status}`);
- });
-
- const bundle = {
- timestamp: toNotSoISOString(new Date()),
- locale: effectiveLocale,
- messages
- };
-
- saveL10nBundleToLocalStorage(bundle);
-
- return bundle;
-}
-
-export function getCurrentL10nBundle() {
- return loadL10nBundleFromLocalStorage();
-}
-
-function getPreferredLanguage() {
- return window.navigator.languages ? window.navigator.languages[0] : window.navigator.language;
-}
-
-function loadL10nBundleFromLocalStorage() {
- let bundle: L10nBundle;
-
- try {
- bundle = JSON.parse(loadFromLocalStorage(L10N_BUNDLE_LS_KEY) ?? '{}');
- } catch {
- bundle = {};
- }
-
- return bundle;
-}
-
-function saveL10nBundleToLocalStorage(bundle: L10nBundle) {
- saveInLocalStorage(L10N_BUNDLE_LS_KEY, JSON.stringify(bundle));
-}
-
-function logWarning(message: string) {
- if (process.env.NODE_ENV !== 'production') {
- // eslint-disable-next-line no-console
- console.warn(message);
- }
-}
--- /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 { fetchL10nBundle } from '../api/l10n';
+import { L10nBundle, L10nBundleRequestParams } from '../types/l10nBundle';
+import { toNotSoISOString } from './dates';
+
+const DEFAULT_LOCALE = 'en';
+const DEFAULT_MESSAGES = {
+ // eslint-disable-next-line camelcase
+ default_error_message: 'The request cannot be processed. Try again later.'
+};
+
+export function getMessages() {
+ return getL10nBundleFromCache().messages ?? DEFAULT_MESSAGES;
+}
+
+export function getCurrentLocale() {
+ return getL10nBundleFromCache().locale;
+}
+
+export function getCurrentL10nBundle() {
+ return getL10nBundleFromCache();
+}
+
+export async function loadL10nBundle() {
+ const browserLocale = getPreferredLanguage();
+ const cachedBundle = getL10nBundleFromCache();
+
+ const params: L10nBundleRequestParams = {};
+
+ if (browserLocale) {
+ params.locale = browserLocale;
+
+ if (
+ cachedBundle.locale &&
+ browserLocale.startsWith(cachedBundle.locale) &&
+ cachedBundle.timestamp &&
+ cachedBundle.messages
+ ) {
+ params.ts = cachedBundle.timestamp;
+ }
+ }
+
+ const { effectiveLocale, messages } = await fetchL10nBundle(params).catch(response => {
+ if (response && response.status === 304) {
+ return {
+ effectiveLocale: cachedBundle.locale || browserLocale || DEFAULT_LOCALE,
+ messages: cachedBundle.messages ?? {}
+ };
+ }
+ throw new Error(`Unexpected status code: ${response.status}`);
+ });
+
+ const bundle = {
+ timestamp: toNotSoISOString(new Date()),
+ locale: effectiveLocale,
+ messages
+ };
+
+ persistL10nBundleInCache(bundle);
+
+ return bundle;
+}
+
+function getPreferredLanguage() {
+ return window.navigator.languages ? window.navigator.languages[0] : window.navigator.language;
+}
+
+function getL10nBundleFromCache() {
+ return ((window as unknown) as any).sonarQubeL10nBundle ?? {};
+}
+
+function persistL10nBundleInCache(bundle: L10nBundle) {
+ ((window as unknown) as any).sonarQubeL10nBundle = bundle;
+}
QualityGateStatusConditionEnhanced
} from '../types/quality-gates';
import { Dict, Measure, MeasureEnhanced, Metric } from '../types/types';
-import { getCurrentLocale, translate, translateWithParameters } from './l10n';
+import { translate, translateWithParameters } from './l10n';
+import { getCurrentLocale } from './l10nBundle';
import { isDefined } from './types';
export function enhanceMeasuresWithMetrics(
--- /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 { License } from '../../types/editions';
+
+export function mockLicense(override?: Partial<License>) {
+ return {
+ contactEmail: 'contact@sonarsource.com',
+ edition: 'Developer Edition',
+ expiresAt: '2018-05-18',
+ isExpired: false,
+ isValidEdition: true,
+ isValidServerId: true,
+ isOfficialDistribution: true,
+ isSupported: false,
+ loc: 120085,
+ maxLoc: 500000,
+ plugins: ['Branches', 'PLI language'],
+ remainingLocThreshold: 490000,
+ serverId: 'AU-TpxcA-iU5OvuD2FL0',
+ type: 'production',
+ ...override
+ };
+}
instance: InstanceType;
official: boolean;
- registerExtension: (key: string, start: ExtensionStartMethod) => void;
+ registerExtension: (key: string, start: ExtensionStartMethod, providesCSSFile?: boolean) => void;
setWebAnalyticsPageChangeHandler: (pageHandler: (pathname: string) => void) => void;
}
key: EditionKey;
name: string;
}
+
+export interface License {
+ contactEmail: string;
+ edition: string;
+ expiresAt: string;
+ isExpired: boolean;
+ isOfficialDistribution: boolean;
+ isSupported: boolean;
+ isValidEdition: boolean;
+ isValidServerId: boolean;
+ loc: number;
+ maxLoc: number;
+ plugins: string[];
+ remainingLocThreshold: number;
+ serverId: string;
+ type: string;
+}
import { Location, Router } from '../components/hoc/withRouter';
import { Store } from '../store/rootReducer';
import { AppState } from './appstate';
-import { L10nBundle } from './l10n';
+import { L10nBundle } from './l10nBundle';
import { Dict } from './types';
import { CurrentUser } from './users';
+++ /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 { Dict } from './types';
-
-export interface L10nBundleRequestParams {
- locale?: string;
- ts?: string;
-}
-
-export interface L10nBundleRequestResponse {
- effectiveLocale: string;
- messages: Dict<string>;
-}
-
-export interface L10nBundle {
- timestamp?: string;
- locale?: string;
- messages?: Dict<string>;
-}
--- /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 { Dict } from './types';
+
+export interface L10nBundleRequestParams {
+ locale?: string;
+ ts?: string;
+}
+
+export interface L10nBundleRequestResponse {
+ effectiveLocale: string;
+ messages: Dict<string>;
+}
+
+export interface L10nBundle {
+ timestamp?: string;
+ locale?: string;
+ messages?: Dict<string>;
+}
DaysBeforeDeletingInactiveBranchesAndPRs = 'sonar.dbcleaner.daysBeforeDeletingInactiveBranchesAndPRs',
DefaultProjectVisibility = 'projects.default.visibility',
ServerBaseUrl = 'sonar.core.serverBaseURL',
- PluginRiskConsent = 'sonar.plugins.risk.consent'
+ PluginRiskConsent = 'sonar.plugins.risk.consent',
+ LicenceRemainingLocNotificationThreshold = 'sonar.license.notifications.remainingLocThreshold'
}
export enum GlobalSettingKeys {