diff options
author | Philippe Perrin <philippe.perrin@sonarsource.com> | 2022-01-28 17:39:50 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-03-29 20:03:37 +0000 |
commit | b345bbc09eb8e0bd04951e1db88f56666f5f4c6a (patch) | |
tree | d61378aa709f81a1c6a9729b6c792e404700dfcf /server/sonar-web | |
parent | c1ea1e9df27db899c07948ce50e6aa9cceab348a (diff) | |
download | sonarqube-b345bbc09eb8e0bd04951e1db88f56666f5f4c6a.tar.gz sonarqube-b345bbc09eb8e0bd04951e1db88f56666f5f4c6a.zip |
SONAR-15938 Improve code sharing with the license extension
Diffstat (limited to 'server/sonar-web')
72 files changed, 541 insertions, 351 deletions
diff --git a/server/sonar-web/config/jest/SetupTestEnvironment.ts b/server/sonar-web/config/jest/SetupTestEnvironment.ts index b590a82fc67..d4ce2e93c3c 100644 --- a/server/sonar-web/config/jest/SetupTestEnvironment.ts +++ b/server/sonar-web/config/jest/SetupTestEnvironment.ts @@ -23,3 +23,11 @@ document.documentElement.appendChild(content); 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('.') +})); diff --git a/server/sonar-web/src/main/js/api/alm-integrations.ts b/server/sonar-web/src/main/js/api/alm-integrations.ts index 32186b51d98..1cd48a9e80a 100644 --- a/server/sonar-web/src/main/js/api/alm-integrations.ts +++ b/server/sonar-web/src/main/js/api/alm-integrations.ts @@ -17,7 +17,7 @@ * 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, diff --git a/server/sonar-web/src/main/js/api/alm-settings.ts b/server/sonar-web/src/main/js/api/alm-settings.ts index 218ca9de03b..d4d4e3f4c38 100644 --- a/server/sonar-web/src/main/js/api/alm-settings.ts +++ b/server/sonar-web/src/main/js/api/alm-settings.ts @@ -17,7 +17,7 @@ * 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, diff --git a/server/sonar-web/src/main/js/api/application.ts b/server/sonar-web/src/main/js/api/application.ts index 5e5ca222d55..99bd71ef4a9 100644 --- a/server/sonar-web/src/main/js/api/application.ts +++ b/server/sonar-web/src/main/js/api/application.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/branches.ts b/server/sonar-web/src/main/js/api/branches.ts index 8be0209fcad..baf8f9d9d72 100644 --- a/server/sonar-web/src/main/js/api/branches.ts +++ b/server/sonar-web/src/main/js/api/branches.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/ce.ts b/server/sonar-web/src/main/js/api/ce.ts index eea8235f8f6..b91be651a4d 100644 --- a/server/sonar-web/src/main/js/api/ce.ts +++ b/server/sonar-web/src/main/js/api/ce.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/component-report.ts b/server/sonar-web/src/main/js/api/component-report.ts index 9bc734f2308..a3133b80adb 100644 --- a/server/sonar-web/src/main/js/api/component-report.ts +++ b/server/sonar-web/src/main/js/api/component-report.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/components.ts b/server/sonar-web/src/main/js/api/components.ts index 3ebc6070a00..eebd23b059f 100644 --- a/server/sonar-web/src/main/js/api/components.ts +++ b/server/sonar-web/src/main/js/api/components.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/marketplace.ts b/server/sonar-web/src/main/js/api/editions.ts index 6c376b36eec..7a9d871af71 100644 --- a/server/sonar-web/src/main/js/api/marketplace.ts +++ b/server/sonar-web/src/main/js/api/editions.ts @@ -17,25 +17,9 @@ * 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'; - -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 { License } from '../types/editions'; export function isValidLicense(): Promise<{ isValidLicense: boolean }> { return getJSON('/api/editions/is_valid_license'); diff --git a/server/sonar-web/src/main/js/api/issues.ts b/server/sonar-web/src/main/js/api/issues.ts index 60fd262dbb5..b4e6509c10c 100644 --- a/server/sonar-web/src/main/js/api/issues.ts +++ b/server/sonar-web/src/main/js/api/issues.ts @@ -17,8 +17,8 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/l10n.ts b/server/sonar-web/src/main/js/api/l10n.ts index 4144301f796..f6c39df6559 100644 --- a/server/sonar-web/src/main/js/api/l10n.ts +++ b/server/sonar-web/src/main/js/api/l10n.ts @@ -18,7 +18,7 @@ * 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 diff --git a/server/sonar-web/src/main/js/api/languages.ts b/server/sonar-web/src/main/js/api/languages.ts index 941c2c4c7ba..45d891d9486 100644 --- a/server/sonar-web/src/main/js/api/languages.ts +++ b/server/sonar-web/src/main/js/api/languages.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/measures.ts b/server/sonar-web/src/main/js/api/measures.ts index 0387baf9f37..de681a61a49 100644 --- a/server/sonar-web/src/main/js/api/measures.ts +++ b/server/sonar-web/src/main/js/api/measures.ts @@ -17,7 +17,7 @@ * 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 { diff --git a/server/sonar-web/src/main/js/api/metrics.ts b/server/sonar-web/src/main/js/api/metrics.ts index d2d5996b891..c3d684d774a 100644 --- a/server/sonar-web/src/main/js/api/metrics.ts +++ b/server/sonar-web/src/main/js/api/metrics.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/nav.ts b/server/sonar-web/src/main/js/api/nav.ts index 974fb5fc1b3..bca04cabf98 100644 --- a/server/sonar-web/src/main/js/api/nav.ts +++ b/server/sonar-web/src/main/js/api/nav.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/newCodePeriod.ts b/server/sonar-web/src/main/js/api/newCodePeriod.ts index e33b3d297a4..6e570e338aa 100644 --- a/server/sonar-web/src/main/js/api/newCodePeriod.ts +++ b/server/sonar-web/src/main/js/api/newCodePeriod.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/notifications.ts b/server/sonar-web/src/main/js/api/notifications.ts index 27f0a2ad6a0..79f51757d06 100644 --- a/server/sonar-web/src/main/js/api/notifications.ts +++ b/server/sonar-web/src/main/js/api/notifications.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/permissions.ts b/server/sonar-web/src/main/js/api/permissions.ts index cb274e2e591..295ccc7f274 100644 --- a/server/sonar-web/src/main/js/api/permissions.ts +++ b/server/sonar-web/src/main/js/api/permissions.ts @@ -17,7 +17,7 @@ * 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, diff --git a/server/sonar-web/src/main/js/api/plugins.ts b/server/sonar-web/src/main/js/api/plugins.ts index abffaad12b6..64510fd49e9 100644 --- a/server/sonar-web/src/main/js/api/plugins.ts +++ b/server/sonar-web/src/main/js/api/plugins.ts @@ -18,7 +18,7 @@ * 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 { diff --git a/server/sonar-web/src/main/js/api/project-badges.ts b/server/sonar-web/src/main/js/api/project-badges.ts index aa5110861b4..44c9e94f34d 100644 --- a/server/sonar-web/src/main/js/api/project-badges.ts +++ b/server/sonar-web/src/main/js/api/project-badges.ts @@ -17,7 +17,7 @@ * 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) { diff --git a/server/sonar-web/src/main/js/api/project-dump.ts b/server/sonar-web/src/main/js/api/project-dump.ts index 9e027dc9c47..34e9271c7d4 100644 --- a/server/sonar-web/src/main/js/api/project-dump.ts +++ b/server/sonar-web/src/main/js/api/project-dump.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/projectActivity.ts b/server/sonar-web/src/main/js/api/projectActivity.ts index cc773eea128..9fde41ead19 100644 --- a/server/sonar-web/src/main/js/api/projectActivity.ts +++ b/server/sonar-web/src/main/js/api/projectActivity.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/projectLinks.ts b/server/sonar-web/src/main/js/api/projectLinks.ts index 7c7307d510b..6af46e1adc5 100644 --- a/server/sonar-web/src/main/js/api/projectLinks.ts +++ b/server/sonar-web/src/main/js/api/projectLinks.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/quality-gates.ts b/server/sonar-web/src/main/js/api/quality-gates.ts index e28492899cd..dbc478b3b60 100644 --- a/server/sonar-web/src/main/js/api/quality-gates.ts +++ b/server/sonar-web/src/main/js/api/quality-gates.ts @@ -17,7 +17,7 @@ * 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 { diff --git a/server/sonar-web/src/main/js/api/quality-profiles.ts b/server/sonar-web/src/main/js/api/quality-profiles.ts index ae130bb6373..283f0c52d2a 100644 --- a/server/sonar-web/src/main/js/api/quality-profiles.ts +++ b/server/sonar-web/src/main/js/api/quality-profiles.ts @@ -18,9 +18,9 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/rules.ts b/server/sonar-web/src/main/js/api/rules.ts index 419e7ed7eef..6a39950ed35 100644 --- a/server/sonar-web/src/main/js/api/rules.ts +++ b/server/sonar-web/src/main/js/api/rules.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/security-hotspots.ts b/server/sonar-web/src/main/js/api/security-hotspots.ts index 2f2608b2b3b..b4d4d01dba0 100644 --- a/server/sonar-web/src/main/js/api/security-hotspots.ts +++ b/server/sonar-web/src/main/js/api/security-hotspots.ts @@ -17,7 +17,7 @@ * 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 { diff --git a/server/sonar-web/src/main/js/api/settings.ts b/server/sonar-web/src/main/js/api/settings.ts index e621314c27e..e322511bce8 100644 --- a/server/sonar-web/src/main/js/api/settings.ts +++ b/server/sonar-web/src/main/js/api/settings.ts @@ -18,8 +18,8 @@ * 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 { diff --git a/server/sonar-web/src/main/js/api/system.ts b/server/sonar-web/src/main/js/api/system.ts index 40b03839a31..fa0721eb9b8 100644 --- a/server/sonar-web/src/main/js/api/system.ts +++ b/server/sonar-web/src/main/js/api/system.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/time-machine.ts b/server/sonar-web/src/main/js/api/time-machine.ts index 720e562738c..f6e7ee3da68 100644 --- a/server/sonar-web/src/main/js/api/time-machine.ts +++ b/server/sonar-web/src/main/js/api/time-machine.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/user-tokens.ts b/server/sonar-web/src/main/js/api/user-tokens.ts index adcc9215475..53daaf04b4b 100644 --- a/server/sonar-web/src/main/js/api/user-tokens.ts +++ b/server/sonar-web/src/main/js/api/user-tokens.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/user_groups.ts b/server/sonar-web/src/main/js/api/user_groups.ts index 9b78402d12d..5949d53c70d 100644 --- a/server/sonar-web/src/main/js/api/user_groups.ts +++ b/server/sonar-web/src/main/js/api/user_groups.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/users.ts b/server/sonar-web/src/main/js/api/users.ts index 272c2c73295..9b94961ebc8 100644 --- a/server/sonar-web/src/main/js/api/users.ts +++ b/server/sonar-web/src/main/js/api/users.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/web-api.ts b/server/sonar-web/src/main/js/api/web-api.ts index b9d7119dde6..31b3770d7ac 100644 --- a/server/sonar-web/src/main/js/api/web-api.ts +++ b/server/sonar-web/src/main/js/api/web-api.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/api/webhooks.ts b/server/sonar-web/src/main/js/api/webhooks.ts index e178cc4dc02..3c9fe1300ef 100644 --- a/server/sonar-web/src/main/js/api/webhooks.ts +++ b/server/sonar-web/src/main/js/api/webhooks.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/app/components/StartupModal.tsx b/server/sonar-web/src/main/js/app/components/StartupModal.tsx index ebbdebed587..8bf0201d3b4 100644 --- a/server/sonar-web/src/main/js/app/components/StartupModal.tsx +++ b/server/sonar-web/src/main/js/app/components/StartupModal.tsx @@ -19,7 +19,7 @@ */ 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'; diff --git a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx index 0813389c9ba..c6d82ab38e9 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx @@ -20,7 +20,7 @@ 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'; @@ -30,7 +30,7 @@ import { EditionKey } from '../../../types/editions'; import { LoggedInUser } from '../../../types/users'; import { StartupModal } from '../StartupModal'; -jest.mock('../../../api/marketplace', () => ({ +jest.mock('../../../api/editions', () => ({ showLicense: jest.fn().mockResolvedValue(undefined) })); diff --git a/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx b/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx index 695cd5f3efc..1220526fb6a 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx +++ b/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx @@ -23,7 +23,8 @@ import { injectIntl, WrappedComponentProps } from 'react-intl'; 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'; diff --git a/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts b/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts index 243356b07ee..ab9847c117b 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts +++ b/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts @@ -87,6 +87,7 @@ import { 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'; @@ -119,7 +120,6 @@ import { 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'; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavLicenseNotif.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavLicenseNotif.tsx index 7c9e217e1ab..7ada2c4db56 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavLicenseNotif.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavLicenseNotif.tsx @@ -19,7 +19,7 @@ */ 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'; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavLicenseNotif-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavLicenseNotif-test.tsx index 354a592c179..292790dfdce 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavLicenseNotif-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavLicenseNotif-test.tsx @@ -19,7 +19,7 @@ */ 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'; @@ -31,7 +31,7 @@ jest.mock('../../../../../helpers/l10n', () => ({ hasMessage: jest.fn().mockReturnValue(true) })); -jest.mock('../../../../../api/marketplace', () => ({ +jest.mock('../../../../../api/editions', () => ({ isValidLicense: jest.fn().mockResolvedValue({ isValidLicense: false }) })); diff --git a/server/sonar-web/src/main/js/app/index.ts b/server/sonar-web/src/main/js/app/index.ts index f63328930f4..85532d23a70 100644 --- a/server/sonar-web/src/main/js/app/index.ts +++ b/server/sonar-web/src/main/js/app/index.ts @@ -18,7 +18,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/app/utils/exportModulesAsGlobals.ts b/server/sonar-web/src/main/js/app/utils/exportModulesAsGlobals.ts new file mode 100644 index 00000000000..f9351d9ef26 --- /dev/null +++ b/server/sonar-web/src/main/js/app/utils/exportModulesAsGlobals.ts @@ -0,0 +1,45 @@ +/* + * 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; +} 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 0c8dc2ab1d5..fc17431e3fa 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx @@ -21,7 +21,7 @@ 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'; @@ -69,16 +69,9 @@ import GlobalContainer from '../components/GlobalContainer'; 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; @@ -202,7 +195,10 @@ function renderComponentRoutes() { 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 @@ -282,7 +278,7 @@ function renderAdminRoutes() { } export default function startReactApp(lang: string, appState: AppState, currentUser?: CurrentUser) { - attachToGlobal(); + exportModulesAsGlobals(); const el = document.getElementById('content'); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.tsx.snap index 11dab834f4b..7fe3dc6a978 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.tsx.snap @@ -5,6 +5,7 @@ exports[`should display facet item list 1`] = ` property="Reliability" > <FacetHeader + helper="component_measures.domain_facets.Reliability.help" name="Reliability" onClick={[Function]} open={true} @@ -141,6 +142,7 @@ exports[`should display facet item list with bugs selected 1`] = ` property="Reliability" > <FacetHeader + helper="component_measures.domain_facets.Reliability.help" name="Reliability" onClick={[Function]} open={true} @@ -281,6 +283,7 @@ exports[`should not display subtitles of new measures if there is none 1`] = ` property="Reliability" > <FacetHeader + helper="component_measures.domain_facets.Reliability.help" name="Reliability" onClick={[Function]} open={true} @@ -363,6 +366,7 @@ exports[`should not display subtitles of new measures if there is none, even on property="Reliability" > <FacetHeader + helper="component_measures.domain_facets.Reliability.help" name="Reliability" onClick={[Function]} open={true} diff --git a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx index fe751666118..0690a1223a9 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx @@ -21,7 +21,6 @@ import { pickBy, sortBy } from 'lodash'; 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'; @@ -35,6 +34,7 @@ import IssueTypeIcon from '../../../components/icons/IssueTypeIcon'; 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'; diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx index ed64d641e5f..2bd9406c410 100644 --- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx +++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx @@ -21,7 +21,6 @@ import { findLastIndex } from 'lodash'; 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, @@ -37,6 +36,7 @@ import { Alert } from '../../../components/ui/Alert'; 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 { diff --git a/server/sonar-web/src/main/js/apps/permissions/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/permissions/__tests__/utils-test.ts index a7a8493f2cd..72e28f5ac38 100644 --- a/server/sonar-web/src/main/js/apps/permissions/__tests__/utils-test.ts +++ b/server/sonar-web/src/main/js/apps/permissions/__tests__/utils-test.ts @@ -17,27 +17,26 @@ * 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); @@ -46,17 +45,12 @@ describe('convertToPermissionDefinitions', () => { 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' } ]; @@ -66,13 +60,13 @@ describe('convertToPermissionDefinitions', () => { 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); diff --git a/server/sonar-web/src/main/js/apps/projectDump/ProjectDumpApp.tsx b/server/sonar-web/src/main/js/apps/projectDump/ProjectDumpApp.tsx index 29043ef9a85..43c17531ec2 100644 --- a/server/sonar-web/src/main/js/apps/projectDump/ProjectDumpApp.tsx +++ b/server/sonar-web/src/main/js/apps/projectDump/ProjectDumpApp.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; 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'; diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AllCategoriesList-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AllCategoriesList-test.tsx.snap index bc199c6498d..1b46b821b3f 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AllCategoriesList-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AllCategoriesList-test.tsx.snap @@ -27,7 +27,7 @@ exports[`should render correctly: branches disabled 1`] = ` > <IndexLink className="" - title="general" + title="property.category.general" to={ Object { "pathname": "/admin/settings", @@ -37,7 +37,7 @@ exports[`should render correctly: branches disabled 1`] = ` } } > - general + property.category.general </IndexLink> </li> </ul> @@ -88,7 +88,7 @@ exports[`should render correctly: global mode 1`] = ` > <IndexLink className="" - title="general" + title="property.category.general" to={ Object { "pathname": "/admin/settings", @@ -98,7 +98,7 @@ exports[`should render correctly: global mode 1`] = ` } } > - general + property.category.general </IndexLink> </li> </ul> @@ -151,7 +151,7 @@ exports[`should render correctly: project mode 1`] = ` > <IndexLink className="" - title="general" + title="property.category.general" to={ Object { "pathname": "/project/settings", @@ -162,7 +162,7 @@ exports[`should render correctly: project mode 1`] = ` } } > - general + property.category.general </IndexLink> </li> </ul> @@ -213,7 +213,7 @@ exports[`should render correctly: selected category 1`] = ` > <IndexLink className="" - title="general" + title="property.category.general" to={ Object { "pathname": "/admin/settings", @@ -223,7 +223,7 @@ exports[`should render correctly: selected category 1`] = ` } } > - general + property.category.general </IndexLink> </li> </ul> diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionRenderer-test.tsx.snap index 25ae668483f..4dd0f528a50 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionRenderer-test.tsx.snap @@ -10,6 +10,17 @@ exports[`should render correctly: changed value 1`] = ` > <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" @@ -83,6 +94,17 @@ exports[`should render correctly: in error 1`] = ` > <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" @@ -165,6 +187,17 @@ exports[`should render correctly: loading 1`] = ` > <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" @@ -245,6 +278,17 @@ exports[`should render correctly: original value 1`] = ` > <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" @@ -319,6 +363,17 @@ exports[`should render correctly: success 1`] = ` > <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" @@ -399,12 +454,15 @@ exports[`should render correctly: with description 1`] = ` > <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", } } /> diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Languages-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Languages-test.tsx.snap index 71ac56dcb64..0659334976a 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Languages-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Languages-test.tsx.snap @@ -16,17 +16,17 @@ exports[`should render correctly 1`] = ` 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", }, @@ -63,17 +63,17 @@ exports[`should render correctly with an unknow language 1`] = ` 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", }, diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SubCategoryDefinitionsList-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SubCategoryDefinitionsList-test.tsx.snap index ff66d64f6a4..d4699f7f8e2 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SubCategoryDefinitionsList-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SubCategoryDefinitionsList-test.tsx.snap @@ -11,8 +11,16 @@ exports[`should render correctly 1`] = ` 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={ @@ -45,8 +53,16 @@ exports[`should render correctly 1`] = ` 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={ @@ -83,8 +99,16 @@ exports[`should render correctly: subcategory 1`] = ` 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={ diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx index dcd43858157..5d307e589cc 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx @@ -30,7 +30,7 @@ import { 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 { diff --git a/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx b/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx index b4b0d24b776..86f9416a7fe 100644 --- a/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx @@ -20,12 +20,12 @@ 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'; diff --git a/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx b/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx index e0d954293d6..3bd0a8cc0e9 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx @@ -20,12 +20,12 @@ 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'; diff --git a/server/sonar-web/src/main/js/components/issue/__tests__/actions-test.ts b/server/sonar-web/src/main/js/components/issue/__tests__/actions-test.ts index 93d18d556ff..fb0a525465b 100644 --- a/server/sonar-web/src/main/js/components/issue/__tests__/actions-test.ts +++ b/server/sonar-web/src/main/js/components/issue/__tests__/actions-test.ts @@ -17,13 +17,13 @@ * 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() diff --git a/server/sonar-web/src/main/js/components/issue/actions.ts b/server/sonar-web/src/main/js/components/issue/actions.ts index c074dc0c952..e84b3a5fcd7 100644 --- a/server/sonar-web/src/main/js/components/issue/actions.ts +++ b/server/sonar-web/src/main/js/components/issue/actions.ts @@ -17,7 +17,7 @@ * 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'; diff --git a/server/sonar-web/src/main/js/app/utils/__tests__/throwGlobalError-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/error-test.ts index 13c5f9f85b4..ca6f81a60e9 100644 --- a/server/sonar-web/src/main/js/app/utils/__tests__/throwGlobalError-test.ts +++ b/server/sonar-web/src/main/js/helpers/__tests__/error-test.ts @@ -17,8 +17,8 @@ * 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'; +import getStore from '../../app/utils/getStore'; +import { throwGlobalError } from '../error'; beforeAll(() => { jest.useFakeTimers(); @@ -35,7 +35,9 @@ it('should put the error message in the store', async () => { // We need to catch because throwGlobalError rethrows after displaying the message await throwGlobalError(response) - .then(() => fail('Should throw')) + .then(() => { + throw new Error('Should throw'); + }) .catch(() => {}); expect(getStore().getState().globalMessages[0]).toMatchObject({ @@ -50,7 +52,9 @@ it('should put a default error messsage in the store', async () => { // We need to catch because throwGlobalError rethrows after displaying the message await throwGlobalError(response) - .then(() => fail('Should throw')) + .then(() => { + throw new Error('Should throw'); + }) .catch(() => {}); expect(getStore().getState().globalMessages[0]).toMatchObject({ @@ -63,7 +67,9 @@ it('should handle weird response types', () => { const response = { weird: 'response type' }; return throwGlobalError(response) - .then(() => fail('Should throw')) + .then(() => { + throw new Error('Should throw'); + }) .catch(error => { expect(error).toBe(response); }); @@ -78,7 +84,9 @@ it('should unwrap response if necessary', async () => { // We need to catch because throwGlobalError rethrows after displaying the message await throwGlobalError({ response }) - .then(() => fail('Should throw')) + .then(() => { + throw new Error('Should throw'); + }) .catch(() => {}); /* eslint-disable-next-line no-console */ diff --git a/server/sonar-web/src/main/js/helpers/__tests__/l10n-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/l10n-test.ts index 58d2f94461d..346d097dce8 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/l10n-test.ts +++ b/server/sonar-web/src/main/js/helpers/__tests__/l10n-test.ts @@ -17,84 +17,51 @@ * 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 }); @@ -153,19 +120,6 @@ describe('translateWithParameters', () => { }); }); -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' }; diff --git a/server/sonar-web/src/main/js/helpers/__tests__/l10nBundle-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/l10nBundle-test.ts new file mode 100644 index 00000000000..58c1e603b51 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/__tests__/l10nBundle-test.ts @@ -0,0 +1,71 @@ +/* + * 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 }) + ); + }); +}); diff --git a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts index 04a0bfa2ffa..3a301c9b9b6 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts +++ b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts @@ -17,7 +17,9 @@ * 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, @@ -27,6 +29,36 @@ import { 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 = [ @@ -71,30 +103,6 @@ describe('isPeriodBestValue', () => { }); }); -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'); diff --git a/server/sonar-web/src/main/js/app/utils/throwGlobalError.ts b/server/sonar-web/src/main/js/helpers/error.ts index dbb9ee45771..78f2fa12d9a 100644 --- a/server/sonar-web/src/main/js/app/utils/throwGlobalError.ts +++ b/server/sonar-web/src/main/js/helpers/error.ts @@ -17,11 +17,11 @@ * 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'; +import getStore from '../app/utils/getStore'; +import { addGlobalErrorMessage } from '../store/globalMessages'; +import { parseError } from './request'; -export default function throwGlobalError(param: Response | any): Promise<Response | any> { +export function throwGlobalError(param: Response | any): Promise<Response | any> { const store = getStore(); if (param.response instanceof Response) { diff --git a/server/sonar-web/src/main/js/helpers/l10n.ts b/server/sonar-web/src/main/js/helpers/l10n.ts index 9b8fafa258e..149955f2844 100644 --- a/server/sonar-web/src/main/js/helpers/l10n.ts +++ b/server/sonar-web/src/main/js/helpers/l10n.ts @@ -17,22 +17,13 @@ * 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('.'); @@ -61,23 +52,6 @@ export function translateWithParameters( 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 @@ -101,14 +75,6 @@ export function getLocalizedMetricDomain(domainName: string) { 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', @@ -136,88 +102,3 @@ export function getShortWeekDayName(index: number) { 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); - } -} diff --git a/server/sonar-web/src/main/js/helpers/l10nBundle.ts b/server/sonar-web/src/main/js/helpers/l10nBundle.ts new file mode 100644 index 00000000000..fc1a4414d57 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/l10nBundle.ts @@ -0,0 +1,93 @@ +/* + * 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; +} diff --git a/server/sonar-web/src/main/js/helpers/measures.ts b/server/sonar-web/src/main/js/helpers/measures.ts index cedf304914a..31aca41f983 100644 --- a/server/sonar-web/src/main/js/helpers/measures.ts +++ b/server/sonar-web/src/main/js/helpers/measures.ts @@ -23,7 +23,8 @@ import { 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( diff --git a/server/sonar-web/src/main/js/helpers/mocks/editions.ts b/server/sonar-web/src/main/js/helpers/mocks/editions.ts new file mode 100644 index 00000000000..58fb0b759cb --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/mocks/editions.ts @@ -0,0 +1,41 @@ +/* + * 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 + }; +} diff --git a/server/sonar-web/src/main/js/types/browser.ts b/server/sonar-web/src/main/js/types/browser.ts index de6f688b8cc..b2adcb34d6d 100644 --- a/server/sonar-web/src/main/js/types/browser.ts +++ b/server/sonar-web/src/main/js/types/browser.ts @@ -27,6 +27,6 @@ export interface EnhancedWindow extends Window { instance: InstanceType; official: boolean; - registerExtension: (key: string, start: ExtensionStartMethod) => void; + registerExtension: (key: string, start: ExtensionStartMethod, providesCSSFile?: boolean) => void; setWebAnalyticsPageChangeHandler: (pageHandler: (pathname: string) => void) => void; } diff --git a/server/sonar-web/src/main/js/types/editions.ts b/server/sonar-web/src/main/js/types/editions.ts index eb86835624c..82098ba4429 100644 --- a/server/sonar-web/src/main/js/types/editions.ts +++ b/server/sonar-web/src/main/js/types/editions.ts @@ -32,3 +32,20 @@ export interface Edition { 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; +} diff --git a/server/sonar-web/src/main/js/types/extension.ts b/server/sonar-web/src/main/js/types/extension.ts index 5ec01bd71f0..73324b6ce66 100644 --- a/server/sonar-web/src/main/js/types/extension.ts +++ b/server/sonar-web/src/main/js/types/extension.ts @@ -22,7 +22,7 @@ import { Store as ReduxStore } from 'redux'; 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'; diff --git a/server/sonar-web/src/main/js/types/l10n.ts b/server/sonar-web/src/main/js/types/l10nBundle.ts index dec56e5d81b..0fcc3cee01e 100644 --- a/server/sonar-web/src/main/js/types/l10n.ts +++ b/server/sonar-web/src/main/js/types/l10nBundle.ts @@ -17,6 +17,7 @@ * 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 { diff --git a/server/sonar-web/src/main/js/types/settings.ts b/server/sonar-web/src/main/js/types/settings.ts index bf95ca0336b..a9b9b5f610a 100644 --- a/server/sonar-web/src/main/js/types/settings.ts +++ b/server/sonar-web/src/main/js/types/settings.ts @@ -24,7 +24,8 @@ export const enum SettingsKey { 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 { |