From: Stas Vilchik Date: Wed, 23 Aug 2017 07:38:42 +0000 (+0200) Subject: move some helpers to ts (#2399) X-Git-Tag: 6.6-RC1~548 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=c49ca3ba841ea7763148a76d9a84e1bf7f5698ad;p=sonarqube.git move some helpers to ts (#2399) --- diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx index cc7470d93ab..f79240d88a0 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx @@ -35,7 +35,7 @@ export default function ProfileRulesSonarWayComparison(props: Props) { const url = getRulesUrl( { qprofile: props.profile, - activation: false, + activation: 'false', compareToProfile: props.sonarway, languages: props.language }, diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts b/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts index b23906f430f..cc7140c0fd4 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts +++ b/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts @@ -69,15 +69,22 @@ export function isStagnant(profile: Profile) { return moment().diff(moment(profile.userUpdatedAt), 'years') >= 1; } -export const getProfilesPath = (organization: string | null) => +export const getProfilesPath = (organization: string | null | undefined) => organization ? `/organizations/${organization}/quality_profiles` : '/profiles'; -export const getProfilesForLanguagePath = (language: string, organization: string | null) => ({ +export const getProfilesForLanguagePath = ( + language: string, + organization: string | null | undefined +) => ({ pathname: getProfilesPath(organization), query: { language } }); -export const getProfilePath = (name: string, language: string, organization: string | null) => ({ +export const getProfilePath = ( + name: string, + language: string, + organization: string | null | undefined +) => ({ pathname: getProfilesPath(organization) + '/show', query: { name, language } }); @@ -85,7 +92,7 @@ export const getProfilePath = (name: string, language: string, organization: str export const getProfileComparePath = ( name: string, language: string, - organization: string | null, + organization: string | null | undefined, withKey?: string ) => { const query = { language, name }; @@ -101,7 +108,7 @@ export const getProfileComparePath = ( export const getProfileChangelogPath = ( name: string, language: string, - organization: string | null, + organization: string | null | undefined, filter?: { since?: string; to?: string } ) => { const query = { language, name }; diff --git a/server/sonar-web/src/main/js/helpers/__tests__/path-test.js b/server/sonar-web/src/main/js/helpers/__tests__/path-test.js deleted file mode 100644 index 3941b76b9b7..00000000000 --- a/server/sonar-web/src/main/js/helpers/__tests__/path-test.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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 { collapsedDirFromPath, fileFromPath } from '../path'; - -describe('#collapsedDirFromPath()', () => { - it('should return null when pass null', () => { - expect(collapsedDirFromPath(null)).toBeNull(); - }); - - it('should return "/" when pass "/"', () => { - expect(collapsedDirFromPath('/')).toBe('/'); - }); - - it('should not cut short path', () => { - expect(collapsedDirFromPath('src/main/js/components/state.js')).toBe('src/main/js/components/'); - }); - - it('should cut long path', () => { - expect(collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js')).toBe( - 'src/.../js/components/navigator/app/models/' - ); - }); - - it('should cut very long path', () => { - expect( - collapsedDirFromPath('src/main/another/js/components/navigator/app/models/state.js') - ).toBe('src/.../js/components/navigator/app/models/'); - }); -}); - -describe('#fileFromPath()', () => { - it('should return null when pass null', () => { - expect(fileFromPath(null)).toBeNull(); - }); - - it('should return empty string when pass "/"', () => { - expect(fileFromPath('/')).toBe(''); - }); - - it('should return file name when pass only file name', () => { - expect(fileFromPath('file.js')).toBe('file.js'); - }); - - it('should return file name when pass file path', () => { - expect(fileFromPath('src/main/js/file.js')).toBe('file.js'); - }); - - it('should return file name when pass file name without extension', () => { - expect(fileFromPath('src/main/file')).toBe('file'); - }); -}); diff --git a/server/sonar-web/src/main/js/helpers/__tests__/path-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/path-test.ts new file mode 100644 index 00000000000..3941b76b9b7 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/__tests__/path-test.ts @@ -0,0 +1,68 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 { collapsedDirFromPath, fileFromPath } from '../path'; + +describe('#collapsedDirFromPath()', () => { + it('should return null when pass null', () => { + expect(collapsedDirFromPath(null)).toBeNull(); + }); + + it('should return "/" when pass "/"', () => { + expect(collapsedDirFromPath('/')).toBe('/'); + }); + + it('should not cut short path', () => { + expect(collapsedDirFromPath('src/main/js/components/state.js')).toBe('src/main/js/components/'); + }); + + it('should cut long path', () => { + expect(collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js')).toBe( + 'src/.../js/components/navigator/app/models/' + ); + }); + + it('should cut very long path', () => { + expect( + collapsedDirFromPath('src/main/another/js/components/navigator/app/models/state.js') + ).toBe('src/.../js/components/navigator/app/models/'); + }); +}); + +describe('#fileFromPath()', () => { + it('should return null when pass null', () => { + expect(fileFromPath(null)).toBeNull(); + }); + + it('should return empty string when pass "/"', () => { + expect(fileFromPath('/')).toBe(''); + }); + + it('should return file name when pass only file name', () => { + expect(fileFromPath('file.js')).toBe('file.js'); + }); + + it('should return file name when pass file path', () => { + expect(fileFromPath('src/main/js/file.js')).toBe('file.js'); + }); + + it('should return file name when pass file name without extension', () => { + expect(fileFromPath('src/main/file')).toBe('file'); + }); +}); diff --git a/server/sonar-web/src/main/js/helpers/__tests__/urls-test.js b/server/sonar-web/src/main/js/helpers/__tests__/urls-test.js deleted file mode 100644 index 9321a56db18..00000000000 --- a/server/sonar-web/src/main/js/helpers/__tests__/urls-test.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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 { - getComponentUrl, - getComponentIssuesUrl, - getComponentDrilldownUrl, - getQualityGatesUrl, - getQualityGateUrl -} from '../urls'; - -const SIMPLE_COMPONENT_KEY = 'sonarqube'; -const COMPLEX_COMPONENT_KEY = 'org.sonarsource.sonarqube:sonarqube'; -const COMPLEX_COMPONENT_KEY_ENCODED = encodeURIComponent(COMPLEX_COMPONENT_KEY); -const METRIC = 'coverage'; - -let oldBaseUrl; - -beforeEach(() => { - oldBaseUrl = window.baseUrl; -}); - -afterEach(() => { - window.baseUrl = oldBaseUrl; -}); - -describe('#getComponentUrl', () => { - it('should return component url', () => { - expect(getComponentUrl(SIMPLE_COMPONENT_KEY)).toBe('/dashboard?id=' + SIMPLE_COMPONENT_KEY); - }); - - it('should encode component key', () => { - expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).toBe( - '/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED - ); - }); - - it('should take baseUrl into account', () => { - window.baseUrl = '/context'; - expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).toBe( - '/context/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED - ); - }); -}); - -describe('#getComponentIssuesUrl', () => { - it('should work without parameters', () => { - expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, {})).toEqual({ - pathname: '/project/issues', - query: { id: SIMPLE_COMPONENT_KEY } - }); - }); - - it('should work with parameters', () => { - expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, { resolved: 'false' })).toEqual({ - pathname: '/project/issues', - query: { id: SIMPLE_COMPONENT_KEY, resolved: 'false' } - }); - }); -}); - -describe('#getComponentDrilldownUrl', () => { - it('should return component drilldown url', () => { - expect(getComponentDrilldownUrl(SIMPLE_COMPONENT_KEY, METRIC)).toEqual({ - pathname: '/component_measures', - query: { id: SIMPLE_COMPONENT_KEY, metric: METRIC } - }); - }); - - it('should not encode component key', () => { - expect(getComponentDrilldownUrl(COMPLEX_COMPONENT_KEY, METRIC)).toEqual({ - pathname: '/component_measures', - query: { id: COMPLEX_COMPONENT_KEY, metric: METRIC } - }); - }); -}); - -describe('#getQualityGate(s)Url', () => { - it('should take organization key into account', () => { - expect(getQualityGatesUrl()).toEqual({ pathname: '/quality_gates' }); - expect(getQualityGatesUrl('foo')).toEqual({ pathname: '/organizations/foo/quality_gates' }); - expect(getQualityGateUrl('bar')).toEqual({ pathname: '/quality_gates/show/bar' }); - expect(getQualityGateUrl('bar', 'foo')).toEqual({ - pathname: '/organizations/foo/quality_gates/show/bar' - }); - }); - - it('should encode keys', () => { - expect(getQualityGatesUrl(COMPLEX_COMPONENT_KEY)).toEqual({ - pathname: '/organizations/' + COMPLEX_COMPONENT_KEY_ENCODED + '/quality_gates' - }); - expect(getQualityGateUrl(COMPLEX_COMPONENT_KEY)).toEqual({ - pathname: '/quality_gates/show/' + COMPLEX_COMPONENT_KEY_ENCODED - }); - }); -}); diff --git a/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts new file mode 100644 index 00000000000..90f0417fd6a --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts @@ -0,0 +1,112 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 { + getComponentUrl, + getComponentIssuesUrl, + getComponentDrilldownUrl, + getQualityGatesUrl, + getQualityGateUrl +} from '../urls'; + +const SIMPLE_COMPONENT_KEY = 'sonarqube'; +const COMPLEX_COMPONENT_KEY = 'org.sonarsource.sonarqube:sonarqube'; +const COMPLEX_COMPONENT_KEY_ENCODED = encodeURIComponent(COMPLEX_COMPONENT_KEY); +const METRIC = 'coverage'; + +let oldBaseUrl: string; + +beforeEach(() => { + oldBaseUrl = (window as any).baseUrl; +}); + +afterEach(() => { + (window as any).baseUrl = oldBaseUrl; +}); + +describe('#getComponentUrl', () => { + it('should return component url', () => { + expect(getComponentUrl(SIMPLE_COMPONENT_KEY)).toBe('/dashboard?id=' + SIMPLE_COMPONENT_KEY); + }); + + it('should encode component key', () => { + expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).toBe( + '/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED + ); + }); + + it('should take baseUrl into account', () => { + (window as any).baseUrl = '/context'; + expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).toBe( + '/context/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED + ); + }); +}); + +describe('#getComponentIssuesUrl', () => { + it('should work without parameters', () => { + expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, {})).toEqual({ + pathname: '/project/issues', + query: { id: SIMPLE_COMPONENT_KEY } + }); + }); + + it('should work with parameters', () => { + expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, { resolved: 'false' })).toEqual({ + pathname: '/project/issues', + query: { id: SIMPLE_COMPONENT_KEY, resolved: 'false' } + }); + }); +}); + +describe('#getComponentDrilldownUrl', () => { + it('should return component drilldown url', () => { + expect(getComponentDrilldownUrl(SIMPLE_COMPONENT_KEY, METRIC)).toEqual({ + pathname: '/component_measures', + query: { id: SIMPLE_COMPONENT_KEY, metric: METRIC } + }); + }); + + it('should not encode component key', () => { + expect(getComponentDrilldownUrl(COMPLEX_COMPONENT_KEY, METRIC)).toEqual({ + pathname: '/component_measures', + query: { id: COMPLEX_COMPONENT_KEY, metric: METRIC } + }); + }); +}); + +describe('#getQualityGate(s)Url', () => { + it('should take organization key into account', () => { + expect(getQualityGatesUrl()).toEqual({ pathname: '/quality_gates' }); + expect(getQualityGatesUrl('foo')).toEqual({ pathname: '/organizations/foo/quality_gates' }); + expect(getQualityGateUrl('bar')).toEqual({ pathname: '/quality_gates/show/bar' }); + expect(getQualityGateUrl('bar', 'foo')).toEqual({ + pathname: '/organizations/foo/quality_gates/show/bar' + }); + }); + + it('should encode keys', () => { + expect(getQualityGatesUrl(COMPLEX_COMPONENT_KEY)).toEqual({ + pathname: '/organizations/' + COMPLEX_COMPONENT_KEY_ENCODED + '/quality_gates' + }); + expect(getQualityGateUrl(COMPLEX_COMPONENT_KEY)).toEqual({ + pathname: '/quality_gates/show/' + COMPLEX_COMPONENT_KEY_ENCODED + }); + }); +}); diff --git a/server/sonar-web/src/main/js/helpers/constants.js b/server/sonar-web/src/main/js/helpers/constants.js deleted file mode 100644 index 8900b93777f..00000000000 --- a/server/sonar-web/src/main/js/helpers/constants.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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. - */ -export const SEVERITIES = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']; -export const STATUSES = ['OPEN', 'REOPENED', 'CONFIRMED', 'RESOLVED', 'CLOSED']; - -export const CHART_COLORS_RANGE_PERCENT = ['#00aa00', '#b0d513', '#eabe06', '#ed7d20', '#d4333f']; -export const CHART_REVERSED_COLORS_RANGE_PERCENT = [ - '#d4333f', - '#ed7d20', - '#eabe06', - '#b0d513', - '#00aa00' -]; - -export const RATING_COLORS = ['#00aa00', '#b0d513', '#eabe06', '#ed7d20', '#e00']; diff --git a/server/sonar-web/src/main/js/helpers/constants.ts b/server/sonar-web/src/main/js/helpers/constants.ts new file mode 100644 index 00000000000..8900b93777f --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/constants.ts @@ -0,0 +1,32 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +export const SEVERITIES = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']; +export const STATUSES = ['OPEN', 'REOPENED', 'CONFIRMED', 'RESOLVED', 'CLOSED']; + +export const CHART_COLORS_RANGE_PERCENT = ['#00aa00', '#b0d513', '#eabe06', '#ed7d20', '#d4333f']; +export const CHART_REVERSED_COLORS_RANGE_PERCENT = [ + '#d4333f', + '#ed7d20', + '#eabe06', + '#b0d513', + '#00aa00' +]; + +export const RATING_COLORS = ['#00aa00', '#b0d513', '#eabe06', '#ed7d20', '#e00']; diff --git a/server/sonar-web/src/main/js/helpers/cookies.js b/server/sonar-web/src/main/js/helpers/cookies.js deleted file mode 100644 index 8255c5924da..00000000000 --- a/server/sonar-web/src/main/js/helpers/cookies.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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. - */ -// @flow -let cookies; - -export function getCookie(name /*: string */) { - if (cookies) { - return cookies[name]; - } - - const rawCookies = document.cookie.split('; '); - cookies = {}; - - rawCookies.forEach(candidate => { - const [key, value] = candidate.split('='); - cookies[key] = value; - }); - - return cookies[name]; -} diff --git a/server/sonar-web/src/main/js/helpers/cookies.ts b/server/sonar-web/src/main/js/helpers/cookies.ts new file mode 100644 index 00000000000..b3442b76703 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/cookies.ts @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +let cookies: { [key: string]: string }; + +export function getCookie(name: string): string | undefined { + if (cookies) { + return cookies[name]; + } + + const rawCookies = document.cookie.split('; '); + cookies = {}; + + rawCookies.forEach(candidate => { + const [key, value] = candidate.split('='); + cookies[key] = value; + }); + + return cookies[name]; +} diff --git a/server/sonar-web/src/main/js/helpers/csv.js b/server/sonar-web/src/main/js/helpers/csv.js deleted file mode 100644 index cc49b2f3ec0..00000000000 --- a/server/sonar-web/src/main/js/helpers/csv.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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. - */ -// @flow -export function csvEscape(value /*: string */) /*: string */ { - const escaped = value.replace(/"/g, '\\"'); - return `"${escaped}"`; -} diff --git a/server/sonar-web/src/main/js/helpers/csv.ts b/server/sonar-web/src/main/js/helpers/csv.ts new file mode 100644 index 00000000000..6838ee14b40 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/csv.ts @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +export function csvEscape(value: string): string { + const escaped = value.replace(/"/g, '\\"'); + return `"${escaped}"`; +} diff --git a/server/sonar-web/src/main/js/helpers/latinize.js b/server/sonar-web/src/main/js/helpers/latinize.js deleted file mode 100644 index 18b5cfe8de1..00000000000 --- a/server/sonar-web/src/main/js/helpers/latinize.js +++ /dev/null @@ -1,411 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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. - */ -/* - * Latinize string by removing all diacritics - * From http://stackoverflow.com/questions/990904/javascript-remove-accents-in-strings - */ -/* eslint max-len: 0 */ -/* jscs:disable maximumLineLength */ -const defaultDiacriticsRemovalap = [ - { - base: 'A', - letters: - '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F' - }, - { - base: 'AA', - letters: '\uA732' - }, - { - base: 'AE', - letters: '\u00C6\u01FC\u01E2' - }, - { - base: 'AO', - letters: '\uA734' - }, - { - base: 'AU', - letters: '\uA736' - }, - { - base: 'AV', - letters: '\uA738\uA73A' - }, - { - base: 'AY', - letters: '\uA73C' - }, - { - base: 'B', - letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181' - }, - { - base: 'C', - letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E' - }, - { - base: 'D', - letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779' - }, - { - base: 'DZ', - letters: '\u01F1\u01C4' - }, - { - base: 'Dz', - letters: '\u01F2\u01C5' - }, - { - base: 'E', - letters: - '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E' - }, - { - base: 'F', - letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' - }, - { - base: 'G', - letters: - '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E' - }, - { - base: 'H', - letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D' - }, - { - base: 'I', - letters: - '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197' - }, - { - base: 'J', - letters: '\u004A\u24BF\uFF2A\u0134\u0248' - }, - { - base: 'K', - letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2' - }, - { - base: 'L', - letters: - '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780' - }, - { - base: 'LJ', - letters: '\u01C7' - }, - { - base: 'Lj', - letters: '\u01C8' - }, - { - base: 'M', - letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' - }, - { - base: 'N', - letters: - '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4' - }, - { - base: 'NJ', - letters: '\u01CA' - }, - { - base: 'Nj', - letters: '\u01CB' - }, - { - base: 'O', - letters: - '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C' - }, - { - base: 'OI', - letters: '\u01A2' - }, - { - base: 'OO', - letters: '\uA74E' - }, - { - base: 'OU', - letters: '\u0222' - }, - { - base: 'OE', - letters: '\u008C\u0152' - }, - { - base: 'oe', - letters: '\u009C\u0153' - }, - { - base: 'P', - letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754' - }, - { - base: 'Q', - letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' - }, - { - base: 'R', - letters: - '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782' - }, - { - base: 'S', - letters: - '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784' - }, - { - base: 'T', - letters: - '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786' - }, - { - base: 'TZ', - letters: '\uA728' - }, - { - base: 'U', - letters: - '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244' - }, - { - base: 'V', - letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' - }, - { - base: 'VY', - letters: '\uA760' - }, - { - base: 'W', - letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72' - }, - { - base: 'X', - letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' - }, - { - base: 'Y', - letters: - '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE' - }, - { - base: 'Z', - letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762' - }, - { - base: 'a', - letters: - '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250' - }, - { - base: 'aa', - letters: '\uA733' - }, - { - base: 'ae', - letters: '\u00E6\u01FD\u01E3' - }, - { - base: 'ao', - letters: '\uA735' - }, - { - base: 'au', - letters: '\uA737' - }, - { - base: 'av', - letters: '\uA739\uA73B' - }, - { - base: 'ay', - letters: '\uA73D' - }, - { - base: 'b', - letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253' - }, - { - base: 'c', - letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184' - }, - { - base: 'd', - letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A' - }, - { - base: 'dz', - letters: '\u01F3\u01C6' - }, - { - base: 'e', - letters: - '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD' - }, - { - base: 'f', - letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' - }, - { - base: 'g', - letters: - '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F' - }, - { - base: 'h', - letters: - '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265' - }, - { - base: 'hv', - letters: '\u0195' - }, - { - base: 'i', - letters: - '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131' - }, - { - base: 'j', - letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' - }, - { - base: 'k', - letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3' - }, - { - base: 'l', - letters: - '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747' - }, - { - base: 'lj', - letters: '\u01C9' - }, - { - base: 'm', - letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' - }, - { - base: 'n', - letters: - '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5' - }, - { - base: 'nj', - letters: '\u01CC' - }, - { - base: 'o', - letters: - '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275' - }, - { - base: 'oi', - letters: '\u01A3' - }, - { - base: 'ou', - letters: '\u0223' - }, - { - base: 'oo', - letters: '\uA74F' - }, - { - base: 'p', - letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755' - }, - { - base: 'q', - letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' - }, - { - base: 'r', - letters: - '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783' - }, - { - base: 's', - letters: - '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B' - }, - { - base: 't', - letters: - '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787' - }, - { - base: 'tz', - letters: '\uA729' - }, - { - base: 'u', - letters: - '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289' - }, - { - base: 'v', - letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' - }, - { - base: 'vy', - letters: '\uA761' - }, - { - base: 'w', - letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73' - }, - { - base: 'x', - letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' - }, - { - base: 'y', - letters: - '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF' - }, - { - base: 'z', - letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763' - } -]; - -const diacriticsMap = {}; -for (let i = 0; i < defaultDiacriticsRemovalap.length; i++) { - const letters = defaultDiacriticsRemovalap[i].letters.split(''); - for (let j = 0; j < letters.length; j++) { - diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base; - } -} - -// "what?" version ... http://jsperf.com/diacritics/12 -function removeDiacritics(str) { - return str.replace(/[^\u0000-\u007E]/g, a => diacriticsMap[a] || a); -} - -export default removeDiacritics; diff --git a/server/sonar-web/src/main/js/helpers/latinize.ts b/server/sonar-web/src/main/js/helpers/latinize.ts new file mode 100644 index 00000000000..1397450acfc --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/latinize.ts @@ -0,0 +1,407 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +/* + * Latinize string by removing all diacritics + * From http://stackoverflow.com/questions/990904/javascript-remove-accents-in-strings + */ +const defaultDiacriticsRemovalap = [ + { + base: 'A', + letters: + '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F' + }, + { + base: 'AA', + letters: '\uA732' + }, + { + base: 'AE', + letters: '\u00C6\u01FC\u01E2' + }, + { + base: 'AO', + letters: '\uA734' + }, + { + base: 'AU', + letters: '\uA736' + }, + { + base: 'AV', + letters: '\uA738\uA73A' + }, + { + base: 'AY', + letters: '\uA73C' + }, + { + base: 'B', + letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181' + }, + { + base: 'C', + letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E' + }, + { + base: 'D', + letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779' + }, + { + base: 'DZ', + letters: '\u01F1\u01C4' + }, + { + base: 'Dz', + letters: '\u01F2\u01C5' + }, + { + base: 'E', + letters: + '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E' + }, + { + base: 'F', + letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' + }, + { + base: 'G', + letters: + '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E' + }, + { + base: 'H', + letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D' + }, + { + base: 'I', + letters: + '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197' + }, + { + base: 'J', + letters: '\u004A\u24BF\uFF2A\u0134\u0248' + }, + { + base: 'K', + letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2' + }, + { + base: 'L', + letters: + '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780' + }, + { + base: 'LJ', + letters: '\u01C7' + }, + { + base: 'Lj', + letters: '\u01C8' + }, + { + base: 'M', + letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' + }, + { + base: 'N', + letters: + '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4' + }, + { + base: 'NJ', + letters: '\u01CA' + }, + { + base: 'Nj', + letters: '\u01CB' + }, + { + base: 'O', + letters: + '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C' + }, + { + base: 'OI', + letters: '\u01A2' + }, + { + base: 'OO', + letters: '\uA74E' + }, + { + base: 'OU', + letters: '\u0222' + }, + { + base: 'OE', + letters: '\u008C\u0152' + }, + { + base: 'oe', + letters: '\u009C\u0153' + }, + { + base: 'P', + letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754' + }, + { + base: 'Q', + letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' + }, + { + base: 'R', + letters: + '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782' + }, + { + base: 'S', + letters: + '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784' + }, + { + base: 'T', + letters: + '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786' + }, + { + base: 'TZ', + letters: '\uA728' + }, + { + base: 'U', + letters: + '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244' + }, + { + base: 'V', + letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' + }, + { + base: 'VY', + letters: '\uA760' + }, + { + base: 'W', + letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72' + }, + { + base: 'X', + letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' + }, + { + base: 'Y', + letters: + '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE' + }, + { + base: 'Z', + letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762' + }, + { + base: 'a', + letters: + '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250' + }, + { + base: 'aa', + letters: '\uA733' + }, + { + base: 'ae', + letters: '\u00E6\u01FD\u01E3' + }, + { + base: 'ao', + letters: '\uA735' + }, + { + base: 'au', + letters: '\uA737' + }, + { + base: 'av', + letters: '\uA739\uA73B' + }, + { + base: 'ay', + letters: '\uA73D' + }, + { + base: 'b', + letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253' + }, + { + base: 'c', + letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184' + }, + { + base: 'd', + letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A' + }, + { + base: 'dz', + letters: '\u01F3\u01C6' + }, + { + base: 'e', + letters: + '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD' + }, + { + base: 'f', + letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' + }, + { + base: 'g', + letters: + '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F' + }, + { + base: 'h', + letters: + '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265' + }, + { + base: 'hv', + letters: '\u0195' + }, + { + base: 'i', + letters: + '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131' + }, + { + base: 'j', + letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' + }, + { + base: 'k', + letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3' + }, + { + base: 'l', + letters: + '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747' + }, + { + base: 'lj', + letters: '\u01C9' + }, + { + base: 'm', + letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' + }, + { + base: 'n', + letters: + '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5' + }, + { + base: 'nj', + letters: '\u01CC' + }, + { + base: 'o', + letters: + '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275' + }, + { + base: 'oi', + letters: '\u01A3' + }, + { + base: 'ou', + letters: '\u0223' + }, + { + base: 'oo', + letters: '\uA74F' + }, + { + base: 'p', + letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755' + }, + { + base: 'q', + letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' + }, + { + base: 'r', + letters: + '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783' + }, + { + base: 's', + letters: + '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B' + }, + { + base: 't', + letters: + '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787' + }, + { + base: 'tz', + letters: '\uA729' + }, + { + base: 'u', + letters: + '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289' + }, + { + base: 'v', + letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' + }, + { + base: 'vy', + letters: '\uA761' + }, + { + base: 'w', + letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73' + }, + { + base: 'x', + letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' + }, + { + base: 'y', + letters: + '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF' + }, + { + base: 'z', + letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763' + } +]; + +const diacriticsMap: { [x: string]: string } = {}; +for (let i = 0; i < defaultDiacriticsRemovalap.length; i++) { + const letters = defaultDiacriticsRemovalap[i].letters.split(''); + for (let j = 0; j < letters.length; j++) { + diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base; + } +} + +// "what?" version ... http://jsperf.com/diacritics/12 +export default function removeDiacritics(str: string): string { + return str.replace(/[^\u0000-\u007E]/g, a => diacriticsMap[a] || a); +} diff --git a/server/sonar-web/src/main/js/helpers/path.js b/server/sonar-web/src/main/js/helpers/path.js deleted file mode 100644 index f1400210753..00000000000 --- a/server/sonar-web/src/main/js/helpers/path.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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. - */ -export function collapsePath(path, limit = 30) { - if (typeof path !== 'string') { - return ''; - } - - const tokens = path.split('/'); - - if (tokens.length <= 2) { - return path; - } - - const head = tokens[0]; - const tail = tokens[tokens.length - 1]; - const middle = tokens.slice(1, -1); - let cut = false; - - while (middle.join().length > limit && middle.length > 0) { - middle.shift(); - cut = true; - } - - const body = [].concat(head, cut ? ['...'] : [], middle, tail); - return body.join('/'); -} - -/** - * Return a collapsed path without a file name - * @example - * // returns 'src/.../js/components/navigator/app/models/' - * collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js') - * @param {string} path - * @returns {string|null} - */ -export function collapsedDirFromPath(path) { - const limit = 30; - if (typeof path === 'string') { - const tokens = path.split('/').slice(0, -1); - if (tokens.length > 2) { - const head = tokens[0]; - const tail = tokens[tokens.length - 1]; - const middle = tokens.slice(1, -1); - - let cut = false; - while (middle.join().length > limit && middle.length > 0) { - middle.shift(); - cut = true; - } - const body = [].concat(head, cut ? ['...'] : [], middle, tail); - return body.join('/') + '/'; - } else { - return tokens.join('/') + '/'; - } - } else { - return null; - } -} - -/** - * Return a file name for a given file path - * * @example - * // returns 'state.js' - * collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js') - * @param {string} path - * @returns {string|null} - */ -export function fileFromPath(path) { - if (typeof path === 'string') { - const tokens = path.split('/'); - return tokens[tokens.length - 1]; - } else { - return null; - } -} - -export function splitPath(path) { - if (typeof path === 'string') { - const tokens = path.split('/'); - return { - head: tokens.slice(0, -1).join('/'), - tail: tokens[tokens.length - 1] - }; - } else { - return null; - } -} - -export function limitComponentName(str, limit = 30) { - if (typeof str === 'string') { - return str.length > limit ? str.substr(0, limit) + '...' : str; - } else { - return ''; - } -} diff --git a/server/sonar-web/src/main/js/helpers/path.ts b/server/sonar-web/src/main/js/helpers/path.ts new file mode 100644 index 00000000000..2ea8d4f5963 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/path.ts @@ -0,0 +1,108 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +export function collapsePath(path: string, limit = 30): string { + if (typeof path !== 'string') { + return ''; + } + + const tokens = path.split('/'); + + if (tokens.length <= 2) { + return path; + } + + const head = tokens[0]; + const tail = tokens[tokens.length - 1]; + const middle = tokens.slice(1, -1); + let cut = false; + + while (middle.join().length > limit && middle.length > 0) { + middle.shift(); + cut = true; + } + + const body = [head, ...(cut ? ['...'] : []), ...middle, tail]; + return body.join('/'); +} + +/** + * Return a collapsed path without a file name + * @example + * // returns 'src/.../js/components/navigator/app/models/' + * collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js') + */ +export function collapsedDirFromPath(path: string | null): string | null { + const limit = 30; + if (typeof path === 'string') { + const tokens = path.split('/').slice(0, -1); + if (tokens.length > 2) { + const head = tokens[0]; + const tail = tokens[tokens.length - 1]; + const middle = tokens.slice(1, -1); + + let cut = false; + while (middle.join().length > limit && middle.length > 0) { + middle.shift(); + cut = true; + } + const body = [head, ...(cut ? ['...'] : []), ...middle, tail]; + return body.join('/') + '/'; + } else { + return tokens.join('/') + '/'; + } + } else { + return null; + } +} + +/** + * Return a file name for a given file path + * * @example + * // returns 'state.js' + * collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js') + */ +export function fileFromPath(path: string | null): string | null { + if (typeof path === 'string') { + const tokens = path.split('/'); + return tokens[tokens.length - 1]; + } else { + return null; + } +} + +export function splitPath(path: string): { head: string; tail: string } | null { + if (typeof path === 'string') { + const tokens = path.split('/'); + return { + head: tokens.slice(0, -1).join('/'), + tail: tokens[tokens.length - 1] + }; + } else { + return null; + } +} + +export function limitComponentName(str: string, limit = 30): string { + if (typeof str === 'string') { + return str.length > limit ? str.substr(0, limit) + '...' : str; + } else { + return ''; + } +} diff --git a/server/sonar-web/src/main/js/helpers/ratings.js b/server/sonar-web/src/main/js/helpers/ratings.js deleted file mode 100644 index 2bcce15b3df..00000000000 --- a/server/sonar-web/src/main/js/helpers/ratings.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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. - */ -const checkNumberRating = coverageRating => { - if (!(typeof coverageRating === 'number' && coverageRating > 0 && coverageRating < 6)) { - throw new Error(`Unknown number rating: "${coverageRating}"`); - } -}; - -export const getCoverageRatingLabel = rating => { - checkNumberRating(rating); - - const mapping = ['≥ 80%', '< 80%', '< 70%', '< 50%', '< 30%']; - return mapping[rating - 1]; -}; -export const getCoverageRatingAverageValue = rating => { - checkNumberRating(rating); - const mapping = [90, 75, 60, 40, 15]; - return mapping[rating - 1]; -}; -export const getDuplicationsRatingLabel = rating => { - checkNumberRating(rating); - const mapping = ['< 3%', '≥ 3%', '> 5%', '> 10%', '> 20%']; - return mapping[rating - 1]; -}; -export const getDuplicationsRatingAverageValue = rating => { - checkNumberRating(rating); - const mapping = [1.5, 4, 7.5, 15, 30]; - return mapping[rating - 1]; -}; -export const getSizeRatingLabel = rating => { - checkNumberRating(rating); - const mapping = ['< 1k', '≥ 1k', '> 10k', '> 100k', '> 500k']; - return mapping[rating - 1]; -}; -export const getSizeRatingAverageValue = rating => { - checkNumberRating(rating); - const mapping = [500, 5000, 50000, 250000, 750000]; - return mapping[rating - 1]; -}; diff --git a/server/sonar-web/src/main/js/helpers/ratings.ts b/server/sonar-web/src/main/js/helpers/ratings.ts new file mode 100644 index 00000000000..c1880e3aa4b --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/ratings.ts @@ -0,0 +1,60 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +function checkNumberRating(coverageRating: number): void { + if (!(typeof coverageRating === 'number' && coverageRating > 0 && coverageRating < 6)) { + throw new Error(`Unknown number rating: "${coverageRating}"`); + } +} + +export function getCoverageRatingLabel(rating: number): string { + checkNumberRating(rating); + const mapping = ['≥ 80%', '< 80%', '< 70%', '< 50%', '< 30%']; + return mapping[rating - 1]; +} + +export function getCoverageRatingAverageValue(rating: number): number { + checkNumberRating(rating); + const mapping = [90, 75, 60, 40, 15]; + return mapping[rating - 1]; +} + +export function getDuplicationsRatingLabel(rating: number): string { + checkNumberRating(rating); + const mapping = ['< 3%', '≥ 3%', '> 5%', '> 10%', '> 20%']; + return mapping[rating - 1]; +} + +export function getDuplicationsRatingAverageValue(rating: number): number { + checkNumberRating(rating); + const mapping = [1.5, 4, 7.5, 15, 30]; + return mapping[rating - 1]; +} + +export function getSizeRatingLabel(rating: number): string { + checkNumberRating(rating); + const mapping = ['< 1k', '≥ 1k', '> 10k', '> 100k', '> 500k']; + return mapping[rating - 1]; +} + +export function getSizeRatingAverageValue(rating: number): number { + checkNumberRating(rating); + const mapping = [500, 5000, 50000, 250000, 750000]; + return mapping[rating - 1]; +} diff --git a/server/sonar-web/src/main/js/helpers/scrolling.js b/server/sonar-web/src/main/js/helpers/scrolling.js deleted file mode 100644 index 7e1fd53c926..00000000000 --- a/server/sonar-web/src/main/js/helpers/scrolling.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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. - */ -// @flow -import { debounce } from 'lodash'; - -const SCROLLING_DURATION = 100; -const SCROLLING_INTERVAL = 10; -const SCROLLING_STEPS = SCROLLING_DURATION / SCROLLING_INTERVAL; - -function getScrollPosition(element /*: HTMLElement */) /*: number */ { - return element === window ? window.scrollY : element.scrollTop; -} - -function scrollElement(element /*: HTMLElement */, position /*: number */) { - if (element === window) { - window.scrollTo(0, position); - } else { - element.scrollTop = position; - } -} - -let smoothScrollTop = (y /*: number */, parent) => { - let scrollTop = getScrollPosition(parent); - const scrollingDown = y > scrollTop; - const step = Math.ceil(Math.abs(y - scrollTop) / SCROLLING_STEPS); - let stepsDone = 0; - - const interval = setInterval(() => { - if (scrollTop === y || SCROLLING_STEPS === stepsDone) { - clearInterval(interval); - } else { - let goal; - if (scrollingDown) { - goal = Math.min(y, scrollTop + step); - } else { - goal = Math.max(y, scrollTop - step); - } - stepsDone++; - scrollTop = goal; - scrollElement(parent, goal); - } - }, SCROLLING_INTERVAL); -}; - -smoothScrollTop = debounce(smoothScrollTop, SCROLLING_DURATION, { leading: true }); - -export const scrollToElement = ( - element /*: HTMLElement */, - options /*: { - topOffset?: number, - bottomOffset?: number, - parent?: HTMLElement, - smooth?: boolean - } */ -) => { - const opts = { topOffset: 0, bottomOffset: 0, parent: window, smooth: true, ...options }; - const { parent } = opts; - - const { top, bottom } = element.getBoundingClientRect(); - - const scrollTop = getScrollPosition(parent); - - const height /*: number */ = - parent === window ? window.innerHeight : parent.getBoundingClientRect().height; - - const parentTop = parent === window ? 0 : parent.getBoundingClientRect().top; - - if (top - parentTop < opts.topOffset) { - const goal = scrollTop - opts.topOffset + top - parentTop; - if (opts.smooth) { - smoothScrollTop(goal, parent); - } else { - scrollElement(parent, goal); - } - } - - if (bottom - parentTop > height - opts.bottomOffset) { - const goal = scrollTop + bottom - parentTop - height + opts.bottomOffset; - if (opts.smooth) { - smoothScrollTop(goal, parent); - } else { - scrollElement(parent, goal); - } - } -}; diff --git a/server/sonar-web/src/main/js/helpers/scrolling.ts b/server/sonar-web/src/main/js/helpers/scrolling.ts new file mode 100644 index 00000000000..a36c6ef0789 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/scrolling.ts @@ -0,0 +1,106 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 { debounce } from 'lodash'; + +const SCROLLING_DURATION = 100; +const SCROLLING_INTERVAL = 10; +const SCROLLING_STEPS = SCROLLING_DURATION / SCROLLING_INTERVAL; + +function isWindow(element: HTMLElement | Window): element is Window { + return element === window; +} + +function getScrollPosition(element: HTMLElement | Window): number { + return isWindow(element) ? window.scrollY : element.scrollTop; +} + +function scrollElement(element: HTMLElement | Window, position: number): void { + if (isWindow(element)) { + window.scrollTo(0, position); + } else { + element.scrollTop = position; + } +} + +let smoothScrollTop = (y: number, parent: HTMLElement | Window) => { + let scrollTop = getScrollPosition(parent); + const scrollingDown = y > scrollTop; + const step = Math.ceil(Math.abs(y - scrollTop) / SCROLLING_STEPS); + let stepsDone = 0; + + const interval = setInterval(() => { + if (scrollTop === y || SCROLLING_STEPS === stepsDone) { + clearInterval(interval); + } else { + let goal; + if (scrollingDown) { + goal = Math.min(y, scrollTop + step); + } else { + goal = Math.max(y, scrollTop - step); + } + stepsDone++; + scrollTop = goal; + scrollElement(parent, goal); + } + }, SCROLLING_INTERVAL); +}; + +smoothScrollTop = debounce(smoothScrollTop, SCROLLING_DURATION, { leading: true }); + +export function scrollToElement( + element: HTMLElement, + options: { + topOffset?: number; + bottomOffset?: number; + parent?: HTMLElement; + smooth?: boolean; + } +): void { + const opts = { topOffset: 0, bottomOffset: 0, parent: window, smooth: true, ...options }; + const { parent } = opts; + + const { top, bottom } = element.getBoundingClientRect(); + + const scrollTop = getScrollPosition(parent); + + const height: number = isWindow(parent) + ? window.innerHeight + : parent.getBoundingClientRect().height; + + const parentTop = isWindow(parent) ? 0 : parent.getBoundingClientRect().top; + + if (top - parentTop < opts.topOffset) { + const goal = scrollTop - opts.topOffset + top - parentTop; + if (opts.smooth) { + smoothScrollTop(goal, parent); + } else { + scrollElement(parent, goal); + } + } + + if (bottom - parentTop > height - opts.bottomOffset) { + const goal = scrollTop + bottom - parentTop - height + opts.bottomOffset; + if (opts.smooth) { + smoothScrollTop(goal, parent); + } else { + scrollElement(parent, goal); + } + } +} diff --git a/server/sonar-web/src/main/js/helpers/storage.js b/server/sonar-web/src/main/js/helpers/storage.js deleted file mode 100644 index 404daf59a67..00000000000 --- a/server/sonar-web/src/main/js/helpers/storage.js +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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. - */ -// @flow -const PROJECTS_DEFAULT_FILTER = 'sonarqube.projects.default'; -const PROJECTS_FAVORITE = 'favorite'; -const PROJECTS_ALL = 'all'; - -const PROJECTS_VIEW = 'sonarqube.projects.view'; -const PROJECTS_VISUALIZATION = 'sonarqube.projects.visualization'; -const PROJECTS_SORT = 'sonarqube.projects.sort'; - -const PROJECT_ACTIVITY_GRAPH = 'sonarqube.project_activity.graph'; -const PROJECT_ACTIVITY_GRAPH_CUSTOM = 'sonarqube.project_activity.graph.custom'; - -const save = (key /*: string */, value /*: ?string */) => { - try { - if (value) { - window.localStorage.setItem(key, value); - } else { - window.localStorage.removeItem(key); - } - } catch (e) { - // usually that means the storage is full - // just do nothing in this case - } -}; - -export function saveFavorite() { - save(PROJECTS_DEFAULT_FILTER, PROJECTS_FAVORITE); -} -export function isFavoriteSet() /*: boolean */ { - const setting = window.localStorage.getItem(PROJECTS_DEFAULT_FILTER); - return setting === PROJECTS_FAVORITE; -} - -export function saveAll() { - save(PROJECTS_DEFAULT_FILTER, PROJECTS_ALL); -} -export function isAllSet() /*: boolean */ { - const setting = window.localStorage.getItem(PROJECTS_DEFAULT_FILTER); - return setting === PROJECTS_ALL; -} - -export function saveView(view /*: ?string */) { - save(PROJECTS_VIEW, view); -} -export function getView() { - return window.localStorage.getItem(PROJECTS_VIEW); -} - -export function saveVisualization(visualization /*: ?string */) { - save(PROJECTS_VISUALIZATION, visualization); -} -export function getVisualization() { - window.localStorage.getItem(PROJECTS_VISUALIZATION); -} - -export function saveSort(sort /*: ?string */) { - save(PROJECTS_SORT, sort); -} -export function getSort() { - window.localStorage.getItem(PROJECTS_SORT); -} - -export function saveCustomGraph(metrics /*: ?Array */) { - save(PROJECT_ACTIVITY_GRAPH_CUSTOM, metrics ? metrics.join(',') : ''); -} -export function getCustomGraph() /*: Array */ { - const customGraphs = window.localStorage.getItem(PROJECT_ACTIVITY_GRAPH_CUSTOM); - return customGraphs ? customGraphs.split(',') : []; -} - -export function saveGraph(graph /*: ?string */) { - save(PROJECT_ACTIVITY_GRAPH, graph); -} -export function getGraph() /*: string */ { - return window.localStorage.getItem(PROJECT_ACTIVITY_GRAPH) || 'issues'; -} diff --git a/server/sonar-web/src/main/js/helpers/storage.ts b/server/sonar-web/src/main/js/helpers/storage.ts new file mode 100644 index 00000000000..783a7c5d580 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/storage.ts @@ -0,0 +1,101 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +const PROJECTS_DEFAULT_FILTER = 'sonarqube.projects.default'; +const PROJECTS_FAVORITE = 'favorite'; +const PROJECTS_ALL = 'all'; + +const PROJECTS_VIEW = 'sonarqube.projects.view'; +const PROJECTS_VISUALIZATION = 'sonarqube.projects.visualization'; +const PROJECTS_SORT = 'sonarqube.projects.sort'; + +const PROJECT_ACTIVITY_GRAPH = 'sonarqube.project_activity.graph'; +const PROJECT_ACTIVITY_GRAPH_CUSTOM = 'sonarqube.project_activity.graph.custom'; + +function save(key: string, value?: string): void { + try { + if (value) { + window.localStorage.setItem(key, value); + } else { + window.localStorage.removeItem(key); + } + } catch (e) { + // usually that means the storage is full + // just do nothing in this case + } +} + +export function saveFavorite(): void { + save(PROJECTS_DEFAULT_FILTER, PROJECTS_FAVORITE); +} + +export function isFavoriteSet(): boolean { + const setting = window.localStorage.getItem(PROJECTS_DEFAULT_FILTER); + return setting === PROJECTS_FAVORITE; +} + +export function saveAll(): void { + save(PROJECTS_DEFAULT_FILTER, PROJECTS_ALL); +} + +export function isAllSet(): boolean { + const setting = window.localStorage.getItem(PROJECTS_DEFAULT_FILTER); + return setting === PROJECTS_ALL; +} + +export function saveView(view?: string): void { + save(PROJECTS_VIEW, view); +} + +export function getView(): string | null { + return window.localStorage.getItem(PROJECTS_VIEW); +} + +export function saveVisualization(visualization?: string): void { + save(PROJECTS_VISUALIZATION, visualization); +} + +export function getVisualization(): string | null { + return window.localStorage.getItem(PROJECTS_VISUALIZATION); +} + +export function saveSort(sort?: string): void { + save(PROJECTS_SORT, sort); +} + +export function getSort(): string | null { + return window.localStorage.getItem(PROJECTS_SORT); +} + +export function saveCustomGraph(metrics?: string[]): void { + save(PROJECT_ACTIVITY_GRAPH_CUSTOM, metrics ? metrics.join(',') : ''); +} + +export function getCustomGraph(): string[] { + const customGraphs = window.localStorage.getItem(PROJECT_ACTIVITY_GRAPH_CUSTOM); + return customGraphs ? customGraphs.split(',') : []; +} + +export function saveGraph(graph?: string): void { + save(PROJECT_ACTIVITY_GRAPH, graph); +} + +export function getGraph(): string { + return window.localStorage.getItem(PROJECT_ACTIVITY_GRAPH) || 'issues'; +} diff --git a/server/sonar-web/src/main/js/helpers/testUtils.js b/server/sonar-web/src/main/js/helpers/testUtils.js deleted file mode 100644 index a69169ceeae..00000000000 --- a/server/sonar-web/src/main/js/helpers/testUtils.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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. - */ -export const mockEvent = { - target: { blur() {} }, - currentTarget: { blur() {} }, - preventDefault() {}, - stopPropagation() {} -}; - -export const click = (element, event = {}) => element.simulate('click', { ...mockEvent, ...event }); - -export const clickOutside = (event = {}) => { - const dispatchedEvent = new MouseEvent('click', event); - window.dispatchEvent(dispatchedEvent); -}; - -export const submit = element => - element.simulate('submit', { - preventDefault() {} - }); - -export const change = (element, value) => - element.simulate('change', { - target: { value }, - currentTarget: { value } - }); - -export const keydown = keyCode => { - const event = new KeyboardEvent('keydown', { keyCode }); - document.dispatchEvent(event); -}; - -export const elementKeydown = (element, keyCode) => { - element.simulate('keydown', { - currentTarget: { element }, - keyCode, - preventDefault() {} - }); -}; - -export const doAsync = fn => - new Promise(resolve => { - setTimeout(() => { - fn(); - resolve(); - }, 0); - }); diff --git a/server/sonar-web/src/main/js/helpers/testUtils.ts b/server/sonar-web/src/main/js/helpers/testUtils.ts new file mode 100644 index 00000000000..deed3501e74 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/testUtils.ts @@ -0,0 +1,71 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 { ShallowWrapper } from 'enzyme'; + +export const mockEvent = { + target: { blur() {} }, + currentTarget: { blur() {} }, + preventDefault() {}, + stopPropagation() {} +}; + +export function click(element: ShallowWrapper, event = {}): void { + element.simulate('click', { ...mockEvent, ...event }); +} + +export function clickOutside(event = {}): void { + const dispatchedEvent = new MouseEvent('click', event); + window.dispatchEvent(dispatchedEvent); +} + +export function submit(element: ShallowWrapper): void { + element.simulate('submit', { + preventDefault() {} + }); +} + +export function change(element: ShallowWrapper, value: string): void { + element.simulate('change', { + target: { value }, + currentTarget: { value } + }); +} + +export function keydown(keyCode: number): void { + const event = new KeyboardEvent('keydown', { keyCode } as KeyboardEventInit); + document.dispatchEvent(event); +} + +export function elementKeydown(element: ShallowWrapper, keyCode: number): void { + element.simulate('keydown', { + currentTarget: { element }, + keyCode, + preventDefault() {} + }); +} + +export function doAsync(fn: Function): Promise { + return new Promise(resolve => { + setTimeout(() => { + fn(); + resolve(); + }, 0); + }); +} diff --git a/server/sonar-web/src/main/js/helpers/urls.js b/server/sonar-web/src/main/js/helpers/urls.js deleted file mode 100644 index 52fe92dd365..00000000000 --- a/server/sonar-web/src/main/js/helpers/urls.js +++ /dev/null @@ -1,145 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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 { stringify } from 'querystring'; -import { getProfilePath } from '../apps/quality-profiles/utils'; - -/** - * Generate URL for a component's home page - * @param {string} componentKey - * @returns {string} - */ -export function getComponentUrl(componentKey) { - return window.baseUrl + '/dashboard?id=' + encodeURIComponent(componentKey); -} - -export function getProjectUrl(key) { - return { - pathname: '/dashboard', - query: { id: key } - }; -} - -/** - * Generate URL for a global issues page - */ -export function getIssuesUrl(query) { - return { pathname: '/issues', query }; -} - -/** - * Generate URL for a component's issues page - */ -export function getComponentIssuesUrl(componentKey, query) { - return { pathname: '/project/issues', query: { ...query, id: componentKey } }; -} - -export function getComponentIssuesUrlAsString(componentKey, query) { - const path = getComponentIssuesUrl(componentKey, query); - return `${window.baseUrl}${path.pathname}?${stringify(path.query)}`; -} - -/** - * Generate URL for a component's drilldown page - * @param {string} componentKey - * @param {string} metric - * @returns {Object} - */ -export function getComponentDrilldownUrl(componentKey, metric) { - return { pathname: '/component_measures', query: { id: componentKey, metric } }; -} - -/** - * Generate URL for a component's measure history - * @param {string} componentKey - * @param {string} metric - * @returns {Object} - */ -export function getComponentMeasureHistory(componentKey, metric) { - return { - pathname: '/project/activity', - query: { id: componentKey, graph: 'custom', custom_metrics: metric } - }; -} - -/** - * Generate URL for a component's permissions page - * @param {string} componentKey - * @returns {Object} - */ -export function getComponentPermissionsUrl(componentKey) { - return { - pathname: '/project_roles', - query: { id: componentKey } - }; -} - -/** - * Generate URL for a quality profile - */ -export function getQualityProfileUrl(name, language, organization) { - return getProfilePath(name, language, organization); -} - -export function getQualityGateUrl(key /*: string */, organization /*: ?string */) { - return { - pathname: getQualityGatesUrl(organization).pathname + '/show/' + encodeURIComponent(key) - }; -} - -export function getQualityGatesUrl(organization /*: ?string */) { - return { - pathname: - (organization ? '/organizations/' + encodeURIComponent(organization) : '') + '/quality_gates' - }; -} - -/** - * Generate URL for the rules page - * @param {object} query - * @returns {string} - */ -export function getRulesUrl(query, organization /*: ?string */) { - const path = organization ? `/organizations/${organization}/rules` : '/coding_rules'; - - if (query) { - const serializedQuery = Object.keys(query) - .map(criterion => `${encodeURIComponent(criterion)}=${encodeURIComponent(query[criterion])}`) - .join('|'); - - // return a string (not { pathname }) to help react-router's Link handle this properly - return path + '#' + serializedQuery; - } - - return path; -} - -/** - * Generate URL for the rules page filtering only active deprecated rules - * @param {object} query - * @returns {string} - */ -export function getDeprecatedActiveRulesUrl(query = {}, organization /*: ?string */) { - const baseQuery = { activation: 'true', statuses: 'DEPRECATED' }; - return getRulesUrl({ ...query, ...baseQuery }, organization); -} - -export const getProjectsUrl = () => window.baseUrl + '/projects'; - -export const getMarkdownHelpUrl = () => window.baseUrl + '/markdown/help'; diff --git a/server/sonar-web/src/main/js/helpers/urls.ts b/server/sonar-web/src/main/js/helpers/urls.ts new file mode 100644 index 00000000000..3cf8cfbb6fd --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/urls.ts @@ -0,0 +1,142 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 { stringify } from 'querystring'; +import { getProfilePath } from '../apps/quality-profiles/utils'; + +interface Query { + [x: string]: string; +} + +interface Location { + pathname: string; + query?: Query; +} + +/** + * Generate URL for a component's home page + */ +export function getComponentUrl(componentKey: string): string { + return (window as any).baseUrl + '/dashboard?id=' + encodeURIComponent(componentKey); +} + +export function getProjectUrl(key: string): Location { + return { pathname: '/dashboard', query: { id: key } }; +} + +/** + * Generate URL for a global issues page + */ +export function getIssuesUrl(query: Query): Location { + return { pathname: '/issues', query }; +} + +/** + * Generate URL for a component's issues page + */ +export function getComponentIssuesUrl(componentKey: string, query?: Query): Location { + return { pathname: '/project/issues', query: { ...query || {}, id: componentKey } }; +} + +export function getComponentIssuesUrlAsString(componentKey: string, query?: Query): string { + const path = getComponentIssuesUrl(componentKey, query); + return `${(window as any).baseUrl}${path.pathname}?${stringify(path.query)}`; +} + +/** + * Generate URL for a component's drilldown page + */ +export function getComponentDrilldownUrl(componentKey: string, metric: string): Location { + return { pathname: '/component_measures', query: { id: componentKey, metric } }; +} + +/** + * Generate URL for a component's measure history + */ +export function getComponentMeasureHistory(componentKey: string, metric: string): Location { + return { + pathname: '/project/activity', + query: { id: componentKey, graph: 'custom', custom_metrics: metric } + }; +} + +/** + * Generate URL for a component's permissions page + */ +export function getComponentPermissionsUrl(componentKey: string): Location { + return { pathname: '/project_roles', query: { id: componentKey } }; +} + +/** + * Generate URL for a quality profile + */ +export function getQualityProfileUrl( + name: string, + language: string, + organization?: string | null +): Location { + return getProfilePath(name, language, organization); +} + +export function getQualityGateUrl(key: string, organization?: string | null): Location { + return { + pathname: getQualityGatesUrl(organization).pathname + '/show/' + encodeURIComponent(key) + }; +} + +export function getQualityGatesUrl(organization?: string | null): Location { + return { + pathname: + (organization ? '/organizations/' + encodeURIComponent(organization) : '') + '/quality_gates' + }; +} + +/** + * Generate URL for the rules page + */ +export function getRulesUrl(query: { [x: string]: string }, organization?: string | null): string { + const path = organization ? `/organizations/${organization}/rules` : '/coding_rules'; + + if (query) { + const serializedQuery = Object.keys(query) + .map(criterion => `${encodeURIComponent(criterion)}=${encodeURIComponent(query[criterion])}`) + .join('|'); + + // return a string (not { pathname }) to help react-router's Link handle this properly + return path + '#' + serializedQuery; + } + + return path; +} + +/** + * Generate URL for the rules page filtering only active deprecated rules + */ +export function getDeprecatedActiveRulesUrl(query = {}, organization?: string | null): string { + const baseQuery = { activation: 'true', statuses: 'DEPRECATED' }; + return getRulesUrl({ ...query, ...baseQuery }, organization); +} + +export function getProjectsUrl(): string { + return (window as any).baseUrl + '/projects'; +} + +export function getMarkdownHelpUrl(): string { + return (window as any).baseUrl + '/markdown/help'; +}