]> source.dussan.org Git - sonarqube.git/commitdiff
move some helpers to ts (#2399)
authorStas Vilchik <stas.vilchik@sonarsource.com>
Wed, 23 Aug 2017 07:38:42 +0000 (09:38 +0200)
committerGitHub <noreply@github.com>
Wed, 23 Aug 2017 07:38:42 +0000 (09:38 +0200)
26 files changed:
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx
server/sonar-web/src/main/js/apps/quality-profiles/utils.ts
server/sonar-web/src/main/js/helpers/__tests__/path-test.js [deleted file]
server/sonar-web/src/main/js/helpers/__tests__/path-test.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/__tests__/urls-test.js [deleted file]
server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/constants.js [deleted file]
server/sonar-web/src/main/js/helpers/constants.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/cookies.js [deleted file]
server/sonar-web/src/main/js/helpers/cookies.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/csv.js [deleted file]
server/sonar-web/src/main/js/helpers/csv.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/latinize.js [deleted file]
server/sonar-web/src/main/js/helpers/latinize.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/path.js [deleted file]
server/sonar-web/src/main/js/helpers/path.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/ratings.js [deleted file]
server/sonar-web/src/main/js/helpers/ratings.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/scrolling.js [deleted file]
server/sonar-web/src/main/js/helpers/scrolling.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/storage.js [deleted file]
server/sonar-web/src/main/js/helpers/storage.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/testUtils.js [deleted file]
server/sonar-web/src/main/js/helpers/testUtils.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/urls.js [deleted file]
server/sonar-web/src/main/js/helpers/urls.ts [new file with mode: 0644]

index cc7470d93ab5774ca9a034dfd10778c7df0b25e1..f79240d88a0e0ad5bf37018b736503b4f830af73 100644 (file)
@@ -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
     },
index b23906f430fe514ad4767c380957280acdb38b1c..cc7140c0fd49b5855b8e70bfeae4a89f431b8098 100644 (file)
@@ -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 (file)
index 3941b76..0000000
+++ /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 (file)
index 0000000..3941b76
--- /dev/null
@@ -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 (file)
index 9321a56..0000000
+++ /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 (file)
index 0000000..90f0417
--- /dev/null
@@ -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 (file)
index 8900b93..0000000
+++ /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 (file)
index 0000000..8900b93
--- /dev/null
@@ -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 (file)
index 8255c59..0000000
+++ /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 (file)
index 0000000..b3442b7
--- /dev/null
@@ -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 (file)
index cc49b2f..0000000
+++ /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 (file)
index 0000000..6838ee1
--- /dev/null
@@ -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 (file)
index 18b5cfe..0000000
+++ /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 (file)
index 0000000..1397450
--- /dev/null
@@ -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 (file)
index f140021..0000000
+++ /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 (file)
index 0000000..2ea8d4f
--- /dev/null
@@ -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 (file)
index 2bcce15..0000000
+++ /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 (file)
index 0000000..c1880e3
--- /dev/null
@@ -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 (file)
index 7e1fd53..0000000
+++ /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 (file)
index 0000000..a36c6ef
--- /dev/null
@@ -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 (file)
index 404daf5..0000000
+++ /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<string> */) {
-  save(PROJECT_ACTIVITY_GRAPH_CUSTOM, metrics ? metrics.join(',') : '');
-}
-export function getCustomGraph() /*: Array<string> */ {
-  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 (file)
index 0000000..783a7c5
--- /dev/null
@@ -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 (file)
index a69169c..0000000
+++ /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 (file)
index 0000000..deed350
--- /dev/null
@@ -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<void> {
+  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 (file)
index 52fe92d..0000000
+++ /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 (file)
index 0000000..3cf8cfb
--- /dev/null
@@ -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';
+}