aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorStas Vilchik <stas.vilchik@sonarsource.com>2018-05-15 17:10:00 +0200
committerSonarTech <sonartech@sonarsource.com>2018-05-15 20:20:50 +0200
commit5386cb6010e7469db0c8f0fa5972973b9a2fa266 (patch)
tree3fc0e12c1c69f9f9621f583d8955fd2c7acd10f4 /server/sonar-web
parent05a73f23b2e922de87d37dc101728c94dfee7648 (diff)
downloadsonarqube-5386cb6010e7469db0c8f0fa5972973b9a2fa266.tar.gz
sonarqube-5386cb6010e7469db0c8f0fa5972973b9a2fa266.zip
rewrite some components in ts (#243)
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/package.json2
-rw-r--r--server/sonar-web/src/main/js/@types/json.d.ts (renamed from server/sonar-web/src/main/js/typings/json.d.ts)0
-rw-r--r--server/sonar-web/src/main/js/app/components/search/Search.js2
-rw-r--r--server/sonar-web/src/main/js/app/components/search/SearchResult.js2
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/ComponentPin.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.js2
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/links/LinkRow.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/AppContainer.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/charts/BarChart.tsx169
-rw-r--r--server/sonar-web/src/main/js/components/charts/BubbleChart.tsx41
-rw-r--r--server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx (renamed from server/sonar-web/src/main/js/components/charts/ColorBoxLegend.js)26
-rw-r--r--server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx (renamed from server/sonar-web/src/main/js/components/charts/ColorGradientLegend.js)66
-rw-r--r--server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.tsx (renamed from server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.js)11
-rw-r--r--server/sonar-web/src/main/js/components/charts/DonutChart.tsx83
-rw-r--r--server/sonar-web/src/main/js/components/charts/LineChart.tsx (renamed from server/sonar-web/src/main/js/components/charts/line-chart.js)165
-rw-r--r--server/sonar-web/src/main/js/components/charts/TreeMap.tsx (renamed from server/sonar-web/src/main/js/components/charts/TreeMap.js)65
-rw-r--r--server/sonar-web/src/main/js/components/charts/TreeMapRect.tsx (renamed from server/sonar-web/src/main/js/components/charts/TreeMapRect.js)51
-rw-r--r--server/sonar-web/src/main/js/components/charts/__tests__/BarChart-test.tsx (renamed from server/sonar-web/src/main/js/components/charts/__tests__/bar-chart-test.js)12
-rw-r--r--server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.tsx (renamed from server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.js)8
-rw-r--r--server/sonar-web/src/main/js/components/charts/__tests__/LineChart-test.tsx (renamed from server/sonar-web/src/main/js/components/charts/__tests__/line-chart-test.js)10
-rw-r--r--server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.tsx (renamed from server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.js)4
-rw-r--r--server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.tsx.snap (renamed from server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/components/charts/bar-chart.js187
-rw-r--r--server/sonar-web/src/main/js/components/charts/donut-chart.js84
-rw-r--r--server/sonar-web/src/main/js/components/common/LocationIndex.tsx (renamed from server/sonar-web/src/main/js/components/common/LocationIndex.js)32
-rw-r--r--server/sonar-web/src/main/js/components/common/LocationMessage.tsx (renamed from server/sonar-web/src/main/js/components/common/LocationMessage.js)17
-rw-r--r--server/sonar-web/src/main/js/components/common/OrganizationHelmet.tsx (renamed from server/sonar-web/src/main/js/components/common/OrganizationHelmet.js)15
-rw-r--r--server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.tsx (renamed from server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.js)15
-rw-r--r--server/sonar-web/src/main/js/components/controls/GlobalMessages.tsx (renamed from server/sonar-web/src/main/js/components/controls/GlobalMessages.js)34
-rw-r--r--server/sonar-web/src/main/js/components/controls/Toggle.tsx (renamed from server/sonar-web/src/main/js/components/controls/Toggle.js)34
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx (renamed from server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.js)6
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.tsx (renamed from server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.js)16
-rw-r--r--server/sonar-web/src/main/js/components/icons-components/BugTrackerIcon.tsx (renamed from server/sonar-web/src/main/js/components/ui/BugTrackerIcon.js)32
-rw-r--r--server/sonar-web/src/main/js/components/icons-components/ClockIcon.tsx (renamed from server/sonar-web/src/main/js/components/common/ClockIcon.js)31
-rw-r--r--server/sonar-web/src/main/js/components/icons-components/PinIcon.tsx39
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.js.snap4
-rw-r--r--server/sonar-web/src/main/js/components/shared/SeverityIcon.tsx (renamed from server/sonar-web/src/main/js/components/shared/SeverityIcon.js)17
-rw-r--r--server/sonar-web/src/main/js/components/shared/StatusHelper.tsx (renamed from server/sonar-web/src/main/js/components/shared/StatusHelper.js)20
-rw-r--r--server/sonar-web/src/main/js/components/shared/StatusIcon.tsx (renamed from server/sonar-web/src/main/js/components/shared/StatusIcon.js)15
-rw-r--r--server/sonar-web/src/main/js/components/shared/WithStore.js52
-rw-r--r--server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.tsx (renamed from server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.js)2
-rw-r--r--server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.tsx.snap (renamed from server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/components/shared/pin-icon.js33
-rw-r--r--server/sonar-web/src/main/js/components/ui/CoverageRating.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/ui/__tests__/Level-test.tsx (renamed from server/sonar-web/src/main/js/components/ui/__tests__/Level-test.js)2
-rw-r--r--server/sonar-web/src/main/js/components/ui/buttons.tsx1
-rw-r--r--server/sonar-web/src/main/js/libs/third-party/VSS.SDK.min.js957
-rw-r--r--server/sonar-web/src/main/js/typings/rc-tooltip.d.ts54
-rw-r--r--server/sonar-web/yarn.lock14
54 files changed, 704 insertions, 1771 deletions
diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json
index aed2f5263af..283b02f948d 100644
--- a/server/sonar-web/package.json
+++ b/server/sonar-web/package.json
@@ -42,7 +42,9 @@
"@types/classnames": "2.2.3",
"@types/clipboard": "2.0.0",
"@types/d3-array": "1.2.1",
+ "@types/d3-hierarchy": "1.1.1",
"@types/d3-scale": "2.0.0",
+ "@types/d3-shape": "1.2.2",
"@types/enzyme": "3.1.10",
"@types/jest": "22.2.3",
"@types/keymaster": "1.6.28",
diff --git a/server/sonar-web/src/main/js/typings/json.d.ts b/server/sonar-web/src/main/js/@types/json.d.ts
index 0f858f5d256..0f858f5d256 100644
--- a/server/sonar-web/src/main/js/typings/json.d.ts
+++ b/server/sonar-web/src/main/js/@types/json.d.ts
diff --git a/server/sonar-web/src/main/js/app/components/search/Search.js b/server/sonar-web/src/main/js/app/components/search/Search.js
index 327844759f8..cd315cbfacf 100644
--- a/server/sonar-web/src/main/js/app/components/search/Search.js
+++ b/server/sonar-web/src/main/js/app/components/search/Search.js
@@ -29,7 +29,7 @@ import { sortQualifiers } from './utils';
/*:: import type { Component, More, Results } from './utils'; */
import RecentHistory from '../../components/RecentHistory';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
-import ClockIcon from '../../../components/common/ClockIcon';
+import ClockIcon from '../../../components/icons-components/ClockIcon';
import OutsideClickHandler from '../../../components/controls/OutsideClickHandler';
import SearchBox from '../../../components/controls/SearchBox';
import { getSuggestions } from '../../../api/components';
diff --git a/server/sonar-web/src/main/js/app/components/search/SearchResult.js b/server/sonar-web/src/main/js/app/components/search/SearchResult.js
index c4bd954c9bb..02cc378ce09 100644
--- a/server/sonar-web/src/main/js/app/components/search/SearchResult.js
+++ b/server/sonar-web/src/main/js/app/components/search/SearchResult.js
@@ -23,7 +23,7 @@ import { Link } from 'react-router';
/*:: import type { Component } from './utils'; */
import FavoriteIcon from '../../../components/icons-components/FavoriteIcon';
import QualifierIcon from '../../../components/shared/QualifierIcon';
-import ClockIcon from '../../../components/common/ClockIcon';
+import ClockIcon from '../../../components/icons-components/ClockIcon';
import Tooltip from '../../../components/controls/Tooltip';
import { getProjectUrl } from '../../../helpers/urls';
diff --git a/server/sonar-web/src/main/js/apps/code/components/ComponentPin.tsx b/server/sonar-web/src/main/js/apps/code/components/ComponentPin.tsx
index 3eadf905cbf..18d77d03f67 100644
--- a/server/sonar-web/src/main/js/apps/code/components/ComponentPin.tsx
+++ b/server/sonar-web/src/main/js/apps/code/components/ComponentPin.tsx
@@ -21,7 +21,7 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import { Component } from '../types';
import { BranchLike } from '../../../app/types';
-import PinIcon from '../../../components/shared/pin-icon';
+import PinIcon from '../../../components/icons-components/PinIcon';
import { WorkspaceContext } from '../../../components/workspace/context';
import { translate } from '../../../helpers/l10n';
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.js
index 62d23b385b4..6a79f5e3d56 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.js
@@ -205,9 +205,9 @@ export default class TreeMapView extends React.PureComponent {
<AutoSizer disableHeight={true}>
{({ width }) => (
<TreeMap
+ height={HEIGHT}
items={treemapItems}
onRectangleClick={this.props.handleSelect}
- height={HEIGHT}
width={width}
/>
)}
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx
index 5ba901f92e6..6096ada13a5 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/CreationDateFacet.tsx
@@ -28,7 +28,7 @@ import FacetItem from '../../../components/facet/FacetItem';
import { longFormatterOption } from '../../../components/intl/DateFormatter';
import DateFromNow from '../../../components/intl/DateFromNow';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
-import { BarChart } from '../../../components/charts/bar-chart';
+import BarChart from '../../../components/charts/BarChart';
import DateRangeInput from '../../../components/controls/DateRangeInput';
import { isSameDay, parseDate } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
diff --git a/server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx b/server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx
index 1b2bd3d04ec..2b372ce80dd 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { max } from 'd3-array';
-import { LineChart } from '../../../components/charts/line-chart';
+import LineChart from '../../../components/charts/LineChart';
import { HistoryItem } from '../../../api/time-machine';
const HEIGHT = 80;
@@ -49,17 +49,16 @@ export default class Timeline extends React.PureComponent<Props> {
}
const data = snapshots.map((snapshot, index) => {
- return { x: index, y: snapshot.value };
+ return { x: index, y: Number(snapshot.value) };
});
- const domain = [0, max(this.props.history, d => parseFloat(d.value))];
+ const domain = [0, max(this.props.history, d => parseFloat(d.value))] as [number, number];
return (
<LineChart
data={data}
- domain={domain}
- interpolate="basis"
displayBackdrop={true}
displayPoints={false}
displayVerticalGrid={false}
+ domain={domain}
height={HEIGHT}
padding={[0, 0, 0, 0]}
/>
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap
index c25e28b7e3f..3c01c85264d 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap
@@ -6,11 +6,11 @@ exports[`should render correctly with a "before" range 1`] = `
Array [
Object {
"x": 0,
- "y": "29.6",
+ "y": 29.6,
},
Object {
"x": 1,
- "y": "170.8",
+ "y": 170.8,
},
]
}
@@ -24,7 +24,6 @@ exports[`should render correctly with a "before" range 1`] = `
]
}
height={80}
- interpolate="basis"
padding={
Array [
0,
@@ -33,8 +32,6 @@ exports[`should render correctly with a "before" range 1`] = `
0,
]
}
- xTicks={Array []}
- xValues={Array []}
/>
`;
@@ -44,11 +41,11 @@ exports[`should render correctly with an "after" range 1`] = `
Array [
Object {
"x": 0,
- "y": "360",
+ "y": 360,
},
Object {
"x": 1,
- "y": "39",
+ "y": 39,
},
]
}
@@ -62,7 +59,6 @@ exports[`should render correctly with an "after" range 1`] = `
]
}
height={80}
- interpolate="basis"
padding={
Array [
0,
@@ -71,7 +67,5 @@ exports[`should render correctly with an "after" range 1`] = `
0,
]
}
- xTicks={Array []}
- xValues={Array []}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx
index 4996bae73c0..7a3caf2ab7a 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx
@@ -21,7 +21,7 @@ import * as React from 'react';
import { isProvided, getLinkName } from '../../project-admin/links/utils';
import { ProjectLink } from '../../../app/types';
import DetachIcon from '../../../components/icons-components/DetachIcon';
-import BugTrackerIcon from '../../../components/ui/BugTrackerIcon';
+import BugTrackerIcon from '../../../components/icons-components/BugTrackerIcon';
interface Props {
link: ProjectLink;
diff --git a/server/sonar-web/src/main/js/apps/project-admin/links/LinkRow.tsx b/server/sonar-web/src/main/js/apps/project-admin/links/LinkRow.tsx
index 0bd5d10cbd1..a39c7cfe903 100644
--- a/server/sonar-web/src/main/js/apps/project-admin/links/LinkRow.tsx
+++ b/server/sonar-web/src/main/js/apps/project-admin/links/LinkRow.tsx
@@ -22,7 +22,7 @@ import { isProvided, getLinkName } from './utils';
import { ProjectLink } from '../../../app/types';
import ConfirmButton from '../../../components/controls/ConfirmButton';
import DetachIcon from '../../../components/icons-components/DetachIcon';
-import BugTrackerIcon from '../../../components/ui/BugTrackerIcon';
+import BugTrackerIcon from '../../../components/icons-components/BugTrackerIcon';
import { Button } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx
index 3a7a834957f..35fd9354bff 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/App.tsx
@@ -31,7 +31,7 @@ interface Props {
children: React.ReactElement<any>;
languages: Languages;
onRequestFail: (reasong: any) => void;
- organization: { name: string; key: string } | null;
+ organization: { name: string; key: string } | undefined;
}
interface State {
@@ -113,8 +113,8 @@ export default class App extends React.PureComponent<Props, State> {
<div className="page page-limited">
<Suggestions suggestions="quality_profiles" />
<OrganizationHelmet
- title={translate('quality_profiles.page')}
organization={this.props.organization}
+ title={translate('quality_profiles.page')}
/>
{this.renderChild()}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/AppContainer.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/AppContainer.tsx
index 1f1d6d2f4a5..1da66735a8c 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/AppContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/AppContainer.tsx
@@ -26,7 +26,7 @@ import { Languages } from '../../../store/languages/reducer';
interface StateProps {
languages: Languages;
- organization: { name: string; key: string } | null;
+ organization: { name: string; key: string } | undefined;
}
interface DispatchProps {
@@ -37,7 +37,7 @@ const mapStateToProps = (state: any, ownProps: any) => ({
languages: getLanguages(state),
organization: ownProps.params.organizationKey
? getOrganizationByKey(state, ownProps.params.organizationKey)
- : null
+ : undefined
});
const mapDispatchToProps = (dispatch: any) => ({
diff --git a/server/sonar-web/src/main/js/components/charts/BarChart.tsx b/server/sonar-web/src/main/js/components/charts/BarChart.tsx
new file mode 100644
index 00000000000..7739f1d143d
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/charts/BarChart.tsx
@@ -0,0 +1,169 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { max } from 'd3-array';
+import { scaleLinear, scaleBand, ScaleLinear, ScaleBand } from 'd3-scale';
+import Tooltip from '../controls/Tooltip';
+
+interface DataPoint {
+ tooltip?: React.ReactNode;
+ x: number;
+ y: number;
+}
+
+interface Props<T> {
+ barsWidth: number;
+ data: Array<DataPoint & T>;
+ height: number;
+ onBarClick?: (point: DataPoint & T) => void;
+ padding?: [number, number, number, number];
+ width: number;
+ xTicks?: string[];
+ xValues?: string[];
+}
+
+export default class BarChart<T> extends React.PureComponent<Props<T>> {
+ handleClick = (point: DataPoint & T) => {
+ if (this.props.onBarClick) {
+ this.props.onBarClick(point);
+ }
+ };
+
+ renderXTicks = (xScale: ScaleBand<number>, yScale: ScaleLinear<number, number>) => {
+ const { data, xTicks = [] } = this.props;
+
+ if (!xTicks.length) {
+ return null;
+ }
+
+ const ticks = xTicks.map((tick, index) => {
+ const point = data[index];
+ const x = Math.round((xScale(point.x) as number) + xScale.bandwidth() / 2);
+ const y = yScale.range()[0];
+ const d = data[index];
+ const text = (
+ <text
+ className="bar-chart-tick"
+ dy="1.5em"
+ key={index}
+ onClick={() => this.handleClick(point)}
+ style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }}
+ x={x}
+ y={y}>
+ {tick}
+ </text>
+ );
+ return (
+ <Tooltip key={index} overlay={d.tooltip || undefined}>
+ {text}
+ </Tooltip>
+ );
+ });
+ return <g>{ticks}</g>;
+ };
+
+ renderXValues = (xScale: ScaleBand<number>, yScale: ScaleLinear<number, number>) => {
+ const { data, xValues = [] } = this.props;
+
+ if (!xValues.length) {
+ return null;
+ }
+
+ const ticks = xValues.map((value, index) => {
+ const point = data[index];
+ const x = Math.round((xScale(point.x) as number) + xScale.bandwidth() / 2);
+ const y = yScale(point.y);
+ const text = (
+ <text
+ className="bar-chart-tick"
+ dy="-1em"
+ key={index}
+ onClick={() => this.handleClick(point)}
+ style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }}
+ x={x}
+ y={y}>
+ {value}
+ </text>
+ );
+ return (
+ <Tooltip key={index} overlay={point.tooltip || undefined}>
+ {text}
+ </Tooltip>
+ );
+ });
+ return <g>{ticks}</g>;
+ };
+
+ renderBars = (xScale: ScaleBand<number>, yScale: ScaleLinear<number, number>) => {
+ const bars = this.props.data.map((point, index) => {
+ const x = Math.round(xScale(point.x) as number);
+ const maxY = yScale.range()[0];
+ const y = Math.round(yScale(point.y)) - /* minimum bar height */ 1;
+ const height = maxY - y;
+ const rect = (
+ <rect
+ className="bar-chart-bar"
+ height={height}
+ key={index}
+ onClick={() => this.handleClick(point)}
+ style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }}
+ width={this.props.barsWidth}
+ x={x}
+ y={y}
+ />
+ );
+ return (
+ <Tooltip key={index} overlay={point.tooltip || undefined}>
+ {rect}
+ </Tooltip>
+ );
+ });
+ return <g>{bars}</g>;
+ };
+
+ render() {
+ const { barsWidth, data, width, height, padding = [10, 10, 10, 10] } = this.props;
+
+ const availableWidth = width - padding[1] - padding[3];
+ const availableHeight = height - padding[0] - padding[2];
+
+ const innerPadding = (availableWidth - barsWidth * data.length) / (data.length - 1);
+ const relativeInnerPadding = innerPadding / (innerPadding + barsWidth);
+
+ const maxY = max(data, d => d.y) as number;
+ const xScale = scaleBand<number>()
+ .domain(data.map(d => d.x))
+ .range([0, availableWidth])
+ .paddingInner(relativeInnerPadding);
+ const yScale = scaleLinear()
+ .domain([0, maxY])
+ .range([availableHeight, 0]);
+
+ return (
+ <svg className="bar-chart" height={height} width={width}>
+ <g transform={`translate(${padding[3]}, ${padding[0]})`}>
+ {this.renderXTicks(xScale, yScale)}
+ {this.renderXValues(xScale, yScale)}
+ {this.renderBars(xScale, yScale)}
+ </g>
+ </svg>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/components/charts/BubbleChart.tsx b/server/sonar-web/src/main/js/components/charts/BubbleChart.tsx
index 40be474bb72..d280be68922 100644
--- a/server/sonar-web/src/main/js/components/charts/BubbleChart.tsx
+++ b/server/sonar-web/src/main/js/components/charts/BubbleChart.tsx
@@ -86,12 +86,12 @@ interface Props {
displayXTicks?: boolean;
displayYGrid?: boolean;
displayYTicks?: boolean;
- formatXTick: (tick: number) => string;
- formatYTick: (tick: number) => string;
+ formatXTick?: (tick: number) => string;
+ formatYTick?: (tick: number) => string;
height: number;
items: Item[];
onBubbleClick?: (link?: string) => void;
- padding: [number, number, number, number];
+ padding?: [number, number, number, number];
sizeDomain?: [number, number];
sizeRange?: [number, number];
xDomain?: [number, number];
@@ -115,9 +115,6 @@ export default class BubbleChart extends React.Component<Props, State> {
displayXTicks: true,
displayYGrid: true,
displayYTicks: true,
- formatXTick: (d: number) => d,
- formatYTick: (d: number) => d,
- padding: [10, 10, 10, 10],
sizeRange: [5, 45]
};
@@ -141,6 +138,18 @@ export default class BubbleChart extends React.Component<Props, State> {
document.removeEventListener('mousemove', this.updateZoomCenter);
}
+ get formatXTick() {
+ return this.props.formatXTick || ((d: number) => String(d));
+ }
+
+ get formatYTick() {
+ return this.props.formatYTick || ((d: number) => String(d));
+ }
+
+ get padding() {
+ return this.props.padding || [10, 10, 10, 10];
+ }
+
startMoving = (event: React.MouseEvent<SVGSVGElement>) => {
if (this.node && this.state.zoom > 1) {
const rect = this.node.getBoundingClientRect();
@@ -176,8 +185,8 @@ export default class BubbleChart extends React.Component<Props, State> {
event.preventDefault();
const rect = this.node.getBoundingClientRect();
- const mouseX = event.clientX - rect.left - this.props.padding[1];
- const mouseY = event.clientY - rect.top - this.props.padding[0];
+ const mouseX = event.clientX - rect.left - this.padding[1];
+ const mouseY = event.clientY - rect.top - this.padding[0];
let delta = event.deltaY;
if ((event as any).webkitDirectionInvertedFromDevice) {
@@ -308,7 +317,7 @@ export default class BubbleChart extends React.Component<Props, State> {
const ticks = xTicks.map((tick, index) => {
const x = xScale(tick);
const y = yScale.range()[0];
- const innerText = this.props.formatXTick(tick);
+ const innerText = this.formatXTick(tick);
return (
<text
className="bubble-chart-tick"
@@ -332,7 +341,7 @@ export default class BubbleChart extends React.Component<Props, State> {
const ticks = yTicks.map((tick, index) => {
const x = xScale.range()[0];
const y = yScale(tick);
- const innerText = this.props.formatYTick(tick);
+ const innerText = this.formatYTick(tick);
return (
<text
className="bubble-chart-tick bubble-chart-tick-y"
@@ -350,8 +359,8 @@ export default class BubbleChart extends React.Component<Props, State> {
};
renderChart = (width: number) => {
- const availableWidth = width - this.props.padding[1] - this.props.padding[3];
- const availableHeight = this.props.height - this.props.padding[0] - this.props.padding[2];
+ const availableWidth = width - this.padding[1] - this.padding[3];
+ const availableHeight = this.props.height - this.padding[0] - this.padding[2];
const xScale = scaleLinear()
.domain(this.props.xDomain || [0, max(this.props.items, d => d.x) || 0])
@@ -389,8 +398,8 @@ export default class BubbleChart extends React.Component<Props, State> {
);
});
- const xTicks = this.getTicks(xScale, this.props.formatXTick);
- const yTicks = this.getTicks(yScale, this.props.formatYTick);
+ const xTicks = this.getTicks(xScale, this.formatXTick);
+ const yTicks = this.getTicks(yScale, this.formatYTick);
return (
<svg
@@ -400,9 +409,9 @@ export default class BubbleChart extends React.Component<Props, State> {
onWheel={this.onWheel}
ref={node => (this.node = node)}
width={width}>
- <g transform={`translate(${this.props.padding[3]}, ${this.props.padding[0]})`}>
+ <g transform={`translate(${this.padding[3]}, ${this.padding[0]})`}>
<svg
- height={this.props.height - this.props.padding[0] - this.props.padding[2]}
+ height={this.props.height - this.padding[0] - this.padding[2]}
style={{ overflow: 'hidden' }}
width={width}>
{this.renderXGrid(xTicks, xScale, yScale, centerXDelta)}
diff --git a/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.js b/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx
index 6d21cca808f..cf2a140d2a2 100644
--- a/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.js
+++ b/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx
@@ -17,22 +17,22 @@
* 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 React from 'react';
-import classNames from 'classnames';
+import * as React from 'react';
+import * as classNames from 'classnames';
+import { ScaleLinear, ScaleOrdinal } from 'd3-scale';
import { formatMeasure } from '../../helpers/measures';
-/*:: type Props = {
- className?: string,
- colorScale: Object,
- colorNA?: string,
- metricType: string
-}; */
+interface Props {
+ className?: string;
+ colorNA?: string;
+ colorScale:
+ | ScaleOrdinal<string, string> // used for LEVEL type
+ | ScaleLinear<number, string | number>; // used for RATING or PERCENT type
+ metricType: string;
+}
-export default function ColorBoxLegend(
- { className, colorScale, colorNA, metricType } /*: Props */
-) {
- const colorDomain = colorScale.domain();
+export default function ColorBoxLegend({ className, colorScale, colorNA, metricType }: Props) {
+ const colorDomain: Array<number | string> = colorScale.domain();
const colorRange = colorScale.range();
return (
<div className={classNames('color-box-legend', className)}>
diff --git a/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.js b/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx
index 06ca596b336..5ea00b6be59 100644
--- a/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.js
+++ b/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx
@@ -17,60 +17,60 @@
* 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 React from 'react';
+import * as React from 'react';
+import { ScaleLinear, ScaleOrdinal } from 'd3-scale';
-/*:: type Props = {
- className?: string,
- colorScale: Object,
- colorNA?: string,
- direction?: number,
- padding?: Array<number>,
- height: number,
- width: number
-}; */
+interface Props {
+ className?: string;
+ colorNA?: string;
+ colorScale:
+ | ScaleOrdinal<string, string> // used for LEVEL type
+ | ScaleLinear<number, string | number>; // used for RATING or PERCENT type
+ direction?: number;
+ height: number;
+ padding?: [number, number, number, number];
+ width: number;
+}
const NA_SPACING = 4;
-export default function ColorGradientLegend(
- {
- className,
- colorScale,
- colorNA,
- direction,
- padding = [12, 24, 0, 0],
- height,
- width
- } /*: Props */
-) {
- const colorRange = colorScale.range();
+export default function ColorGradientLegend({
+ className,
+ colorScale,
+ colorNA,
+ direction,
+ padding = [12, 24, 0, 0],
+ height,
+ width
+}: Props) {
+ const colorRange: Array<string | number> = colorScale.range();
if (direction === 1) {
colorRange.reverse();
}
- const colorDomain = colorScale.domain();
+ const colorDomain: Array<string | number> = colorScale.domain();
const lastColorIdx = colorRange.length - 1;
const lastDomainIdx = colorDomain.length - 1;
const widthNoPadding = width - padding[1];
const rectHeight = height - padding[0];
return (
- <svg className={className} width={width} height={height}>
+ <svg className={className} height={height} width={width}>
<defs>
<linearGradient id="gradient-legend">
{colorRange.map((color, idx) => (
- <stop key={idx} offset={idx / lastColorIdx} stopColor={color} />
+ <stop key={idx} offset={idx / lastColorIdx} stopColor={String(color)} />
))}
</linearGradient>
</defs>
<g transform={`translate(${padding[3]}, ${padding[0]})`}>
- <rect fill="url(#gradient-legend)" x={0} y={0} height={rectHeight} width={widthNoPadding} />
+ <rect fill="url(#gradient-legend)" height={rectHeight} width={widthNoPadding} x={0} y={0} />
{colorDomain.map((d, idx) => (
<text
className="gradient-legend-text"
+ dy="-2px"
key={idx}
x={widthNoPadding * (idx / lastDomainIdx)}
- y={0}
- dy="-2px">
+ y={0}>
{d}
</text>
))}
@@ -79,16 +79,16 @@ export default function ColorGradientLegend(
<g transform={`translate(${widthNoPadding}, ${padding[0]})`}>
<rect
fill={colorNA}
- x={NA_SPACING}
- y={0}
height={rectHeight}
width={padding[1] - NA_SPACING}
+ x={NA_SPACING}
+ y={0}
/>
<text
className="gradient-legend-na"
+ dy="-2px"
x={NA_SPACING + (padding[1] - NA_SPACING) / 2}
- y={0}
- dy="-2px">
+ y={0}>
N/A
</text>
</g>
diff --git a/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.js b/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.tsx
index 3d8a07b375c..80e44f7c11e 100644
--- a/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.js
+++ b/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.tsx
@@ -17,13 +17,16 @@
* 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 React from 'react';
-import classNames from 'classnames';
+import * as React from 'react';
+import * as classNames from 'classnames';
import { formatMeasure } from '../../helpers/measures';
import { RATING_COLORS } from '../../helpers/constants';
-export default function ColorRatingsLegend({ className } /*: { className?: string } */) {
+interface Props {
+ className?: string;
+}
+
+export default function ColorRatingsLegend({ className }: Props) {
return (
<div className={classNames('color-box-legend', className)}>
{[1, 2, 3, 4, 5].map(rating => (
diff --git a/server/sonar-web/src/main/js/components/charts/DonutChart.tsx b/server/sonar-web/src/main/js/components/charts/DonutChart.tsx
new file mode 100644
index 00000000000..4cc5d0318f0
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/charts/DonutChart.tsx
@@ -0,0 +1,83 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { arc as d3Arc, pie as d3Pie, PieArcDatum } from 'd3-shape';
+
+interface DataPoint {
+ fill: string;
+ value: number;
+}
+
+interface Props {
+ data: DataPoint[];
+ height: number;
+ thickness: number;
+ padding?: [number, number, number, number];
+ width: number;
+}
+
+export default function DonutChart(props: Props) {
+ const { height, padding = [0, 0, 0, 0], width } = props;
+
+ const availableWidth = width - padding[1] - padding[3];
+ const availableHeight = height - padding[0] - padding[2];
+
+ const size = Math.min(availableWidth, availableHeight);
+ const radius = Math.floor(size / 2);
+
+ const pie = d3Pie<any, DataPoint>()
+ .sort(null)
+ .value(d => d.value);
+
+ const sectors = pie(props.data).map((d, i) => {
+ return (
+ <Sector
+ data={d}
+ fill={props.data[i].fill}
+ key={i}
+ radius={radius}
+ thickness={props.thickness}
+ />
+ );
+ });
+
+ return (
+ <svg className="donut-chart" height={height} width={width}>
+ <g transform={`translate(${padding[3]}, ${padding[0]})`}>
+ <g transform={`translate(${radius}, ${radius})`}>{sectors}</g>
+ </g>
+ </svg>
+ );
+}
+
+interface SectorProps {
+ data: PieArcDatum<DataPoint>;
+ fill: string;
+ radius: number;
+ thickness: number;
+}
+
+function Sector(props: SectorProps) {
+ const arc = d3Arc<any, PieArcDatum<DataPoint>>()
+ .outerRadius(props.radius)
+ .innerRadius(props.radius - props.thickness);
+ const d = arc(props.data) as string;
+ return <path d={d} style={{ fill: props.fill }} />;
+}
diff --git a/server/sonar-web/src/main/js/components/charts/line-chart.js b/server/sonar-web/src/main/js/components/charts/LineChart.tsx
index af99622368b..2d8d5f18058 100644
--- a/server/sonar-web/src/main/js/components/charts/line-chart.js
+++ b/server/sonar-web/src/main/js/components/charts/LineChart.tsx
@@ -17,160 +17,161 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
-import createReactClass from 'create-react-class';
-import PropTypes from 'prop-types';
+import * as React from 'react';
import { extent, max } from 'd3-array';
-import { scaleLinear } from 'd3-scale';
+import { scaleLinear, ScaleLinear } from 'd3-scale';
import { area as d3Area, line as d3Line, curveBasis } from 'd3-shape';
-import { ResizeMixin } from './../mixins/resize-mixin';
-
-export const LineChart = createReactClass({
- displayName: 'LineChart',
-
- propTypes: {
- data: PropTypes.arrayOf(PropTypes.object).isRequired,
- xTicks: PropTypes.arrayOf(PropTypes.any),
- xValues: PropTypes.arrayOf(PropTypes.any),
- padding: PropTypes.arrayOf(PropTypes.number),
- backdropConstraints: PropTypes.arrayOf(PropTypes.number),
- displayBackdrop: PropTypes.bool,
- displayPoints: PropTypes.bool,
- displayVerticalGrid: PropTypes.bool,
- height: PropTypes.number
- },
-
- mixins: [ResizeMixin],
-
- getDefaultProps() {
- return {
- displayBackdrop: true,
- displayPoints: true,
- displayVerticalGrid: true,
- xTicks: [],
- xValues: [],
- padding: [10, 10, 10, 10]
- };
- },
-
- getInitialState() {
- return { width: this.props.width, height: this.props.height };
- },
-
- renderBackdrop(xScale, yScale) {
- if (!this.props.displayBackdrop) {
+import { AutoSizer } from 'react-virtualized/dist/commonjs/AutoSizer';
+
+interface DataPoint {
+ x: number;
+ y: number;
+}
+
+interface Props {
+ backdropConstraints?: [number, number];
+ data: DataPoint[];
+ displayBackdrop?: boolean;
+ displayPoints?: boolean;
+ displayVerticalGrid?: boolean;
+ domain?: [number, number];
+ height: number;
+ padding?: [number, number, number, number];
+ width?: number;
+ xTicks?: {}[];
+ xValues?: {}[];
+}
+
+export default class LineChart extends React.PureComponent<Props> {
+ renderBackdrop(xScale: ScaleLinear<number, number>, yScale: ScaleLinear<number, number>) {
+ const { displayBackdrop = true } = this.props;
+
+ if (!displayBackdrop) {
return null;
}
- const area = d3Area()
+ const area = d3Area<DataPoint>()
.x(d => xScale(d.x))
.y0(yScale.range()[0])
.y1(d => yScale(d.y))
.defined(d => d.y != null)
.curve(curveBasis);
- let data = this.props.data;
+ let { data } = this.props;
if (this.props.backdropConstraints) {
const c = this.props.backdropConstraints;
data = data.filter(d => c[0] <= d.x && d.x <= c[1]);
}
- return <path className="line-chart-backdrop" d={area(data)} />;
- },
- renderPoints(xScale, yScale) {
- if (!this.props.displayPoints) {
+ return <path className="line-chart-backdrop" d={area(data) as string} />;
+ }
+
+ renderPoints(xScale: ScaleLinear<number, number>, yScale: ScaleLinear<number, number>) {
+ const { displayPoints = true } = this.props;
+
+ if (!displayPoints) {
return null;
}
+
const points = this.props.data.filter(point => point.y != null).map((point, index) => {
const x = xScale(point.x);
const y = yScale(point.y);
- return <circle key={index} className="line-chart-point" r="3" cx={x} cy={y} />;
+ return <circle className="line-chart-point" cx={x} cy={y} key={index} r="3" />;
});
return <g>{points}</g>;
- },
+ }
- renderVerticalGrid(xScale, yScale) {
- if (!this.props.displayVerticalGrid) {
+ renderVerticalGrid(xScale: ScaleLinear<number, number>, yScale: ScaleLinear<number, number>) {
+ const { displayVerticalGrid = true } = this.props;
+
+ if (!displayVerticalGrid) {
return null;
}
+
const lines = this.props.data.map((point, index) => {
const x = xScale(point.x);
const y1 = yScale.range()[0];
const y2 = yScale(point.y);
- return <line key={index} className="line-chart-grid" x1={x} x2={x} y1={y1} y2={y2} />;
+ return <line className="line-chart-grid" key={index} x1={x} x2={x} y1={y1} y2={y2} />;
});
return <g>{lines}</g>;
- },
+ }
- renderXTicks(xScale, yScale) {
- if (!this.props.xTicks.length) {
+ renderXTicks(xScale: ScaleLinear<number, number>, yScale: ScaleLinear<number, number>) {
+ const { xTicks = [] } = this.props;
+
+ if (!xTicks.length) {
return null;
}
- const ticks = this.props.xTicks.map((tick, index) => {
+
+ const ticks = xTicks.map((tick, index) => {
const point = this.props.data[index];
const x = xScale(point.x);
const y = yScale.range()[0];
return (
- <text key={index} className="line-chart-tick" x={x} y={y} dy="1.5em">
+ <text className="line-chart-tick" dy="1.5em" key={index} x={x} y={y}>
{tick}
</text>
);
});
return <g>{ticks}</g>;
- },
+ }
+
+ renderXValues(xScale: ScaleLinear<number, number>, yScale: ScaleLinear<number, number>) {
+ const { xValues = [] } = this.props;
- renderXValues(xScale, yScale) {
- if (!this.props.xValues.length) {
+ if (!xValues.length) {
return null;
}
- const ticks = this.props.xValues.map((value, index) => {
+
+ const ticks = xValues.map((value, index) => {
const point = this.props.data[index];
const x = xScale(point.x);
const y = yScale(point.y);
return (
- <text key={index} className="line-chart-tick" x={x} y={y} dy="-1em">
+ <text className="line-chart-tick" dy="-1em" key={index} x={x} y={y}>
{value}
</text>
);
});
return <g>{ticks}</g>;
- },
+ }
- renderLine(xScale, yScale) {
- const p = d3Line()
+ renderLine(xScale: ScaleLinear<number, number>, yScale: ScaleLinear<number, number>) {
+ const p = d3Line<DataPoint>()
.x(d => xScale(d.x))
.y(d => yScale(d.y))
.defined(d => d.y != null)
.curve(curveBasis);
- return <path className="line-chart-path" d={p(this.props.data)} />;
- },
+ return <path className="line-chart-path" d={p(this.props.data) as string} />;
+ }
- render() {
- if (!this.state.width || !this.state.height) {
+ renderChart = (width: number) => {
+ const { height, padding = [10, 10, 10, 10] } = this.props;
+
+ if (!width || !height) {
return <div />;
}
- const availableWidth = this.state.width - this.props.padding[1] - this.props.padding[3];
- const availableHeight = this.state.height - this.props.padding[0] - this.props.padding[2];
+ const availableWidth = width - padding[1] - padding[3];
+ const availableHeight = height - padding[0] - padding[2];
- let maxY;
const xScale = scaleLinear()
- .domain(extent(this.props.data, d => d.x))
+ .domain(extent(this.props.data, d => d.x) as [number, number])
.range([0, availableWidth]);
const yScale = scaleLinear().range([availableHeight, 0]);
if (this.props.domain) {
- maxY = this.props.domain[1];
yScale.domain(this.props.domain);
} else {
- maxY = max(this.props.data, d => d.y);
+ const maxY = max(this.props.data, d => d.y) as number;
yScale.domain([0, maxY]);
}
return (
- <svg className="line-chart" width={this.state.width} height={this.state.height}>
- <g transform={`translate(${this.props.padding[3]}, ${this.props.padding[0]})`}>
- {this.renderVerticalGrid(xScale, yScale, maxY)}
+ <svg className="line-chart" height={height} width={width}>
+ <g transform={`translate(${padding[3]}, ${padding[0]})`}>
+ {this.renderVerticalGrid(xScale, yScale)}
{this.renderBackdrop(xScale, yScale)}
{this.renderLine(xScale, yScale)}
{this.renderPoints(xScale, yScale)}
@@ -179,5 +180,13 @@ export const LineChart = createReactClass({
</g>
</svg>
);
+ };
+
+ render() {
+ return this.props.width !== undefined ? (
+ this.renderChart(this.props.width)
+ ) : (
+ <AutoSizer disableHeight={true}>{size => this.renderChart(size.width)}</AutoSizer>
+ );
}
-});
+}
diff --git a/server/sonar-web/src/main/js/components/charts/TreeMap.js b/server/sonar-web/src/main/js/components/charts/TreeMap.tsx
index 2b526fd0fe2..9ee5d2320f7 100644
--- a/server/sonar-web/src/main/js/components/charts/TreeMap.js
+++ b/server/sonar-web/src/main/js/components/charts/TreeMap.tsx
@@ -17,33 +17,34 @@
* 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 React from 'react';
+import * as React from 'react';
import { treemap as d3Treemap, hierarchy as d3Hierarchy } from 'd3-hierarchy';
import TreeMapRect from './TreeMapRect';
import { translate } from '../../helpers/l10n';
-/*:: export type TreeMapItem = {
- key: string,
- size: number,
- color: string,
- icon?: React.Element<*>,
- tooltip?: string | React.Element<*>,
- label: string,
- link?: string
-}; */
+interface TreeMapItem {
+ color: string;
+ icon?: React.ReactNode;
+ key: string;
+ label: string;
+ link?: string;
+ size: number;
+ tooltip?: React.ReactNode;
+}
-/*:: type Props = {|
- items: Array<TreeMapItem>,
- onRectangleClick?: string => void,
- height: number,
- width: number
-|}; */
+interface HierarchicalTreemapItem extends TreeMapItem {
+ children?: TreeMapItem[];
+}
-export default class TreeMap extends React.PureComponent {
- /*:: props: Props; */
+interface Props {
+ height: number;
+ items: TreeMapItem[];
+ onRectangleClick?: (item: string) => void;
+ width: number;
+}
- mostCommitPrefix = (labels /*: Array<string> */) => {
+export default class TreeMap extends React.PureComponent<Props> {
+ mostCommitPrefix = (labels: string[]) => {
const sortedLabels = labels.slice(0).sort();
const firstLabel = sortedLabels[0];
const firstLabelLength = firstLabel.length;
@@ -76,11 +77,11 @@ export default class TreeMap extends React.PureComponent {
return this.renderNoData();
}
- const hierarchy = d3Hierarchy({ children: items })
+ const hierarchy = d3Hierarchy({ children: items } as HierarchicalTreemapItem)
.sum(d => d.size)
- .sort((a, b) => b.value - a.value);
+ .sort((a, b) => (b.value || 0) - (a.value || 0));
- const treemap = d3Treemap()
+ const treemap = d3Treemap<TreeMapItem>()
.round(true)
.size([width, height]);
@@ -92,20 +93,20 @@ export default class TreeMap extends React.PureComponent {
<div className="treemap-container" style={{ width, height }}>
{nodes.map(node => (
<TreeMapRect
- key={node.data.key}
- x={node.x0}
- y={node.y0}
- width={node.x1 - node.x0}
- height={node.y1 - node.y0}
fill={node.data.color}
- label={node.data.label}
- prefix={prefix}
- itemKey={node.data.key}
+ height={node.y1 - node.y0}
icon={node.data.icon}
- tooltip={node.data.tooltip}
+ itemKey={node.data.key}
+ key={node.data.key}
+ label={node.data.label}
link={node.data.link}
onClick={this.props.onRectangleClick}
placement={node.x0 === 0 || node.x1 < halfWidth ? 'right' : 'left'}
+ prefix={prefix}
+ tooltip={node.data.tooltip}
+ width={node.x1 - node.x0}
+ x={node.x0}
+ y={node.y0}
/>
))}
</div>
diff --git a/server/sonar-web/src/main/js/components/charts/TreeMapRect.js b/server/sonar-web/src/main/js/components/charts/TreeMapRect.tsx
index 9cc3c2e0738..75e8cdc8db5 100644
--- a/server/sonar-web/src/main/js/components/charts/TreeMapRect.js
+++ b/server/sonar-web/src/main/js/components/charts/TreeMapRect.tsx
@@ -17,42 +17,41 @@
* 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 React from 'react';
+import * as React from 'react';
import { Link } from 'react-router';
-import classNames from 'classnames';
+import * as classNames from 'classnames';
import { scaleLinear } from 'd3-scale';
import LinkIcon from '../icons-components/LinkIcon';
-import Tooltip from '../controls/Tooltip';
+import Tooltip, { Placement } from '../controls/Tooltip';
const SIZE_SCALE = scaleLinear()
.domain([3, 15])
.range([11, 18])
.clamp(true);
-/*:: type Props = {|
- x: number,
- y: number,
- width: number,
- height: number,
- fill: string,
- label: string,
- prefix: string,
- icon?: React.Element<*>,
- tooltip?: string | React.Element<*>,
- itemKey: string,
- link?: string,
- onClick?: string => void,
- placement?: string
-|}; */
-
-export default class TreeMapRect extends React.PureComponent {
- /*:: props: Props; */
+interface Props {
+ fill: string;
+ height: number;
+ icon?: React.ReactNode;
+ itemKey: string;
+ label: string;
+ link?: string;
+ onClick?: (item: string) => void;
+ placement?: Placement;
+ prefix: string;
+ tooltip?: React.ReactNode;
+ width: number;
+ x: number;
+ y: number;
+}
- handleLinkClick = (e /*: Event */) => e.stopPropagation();
+export default class TreeMapRect extends React.PureComponent<Props> {
+ handleLinkClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.stopPropagation();
+ };
handleRectClick = () => {
- if (this.props.onClick != null) {
+ if (this.props.onClick) {
this.props.onClick(this.props.itemKey);
}
};
@@ -64,7 +63,7 @@ export default class TreeMapRect extends React.PureComponent {
return null;
}
return (
- <Link className="treemap-link" to={link} onClick={this.handleLinkClick}>
+ <Link className="treemap-link" onClick={this.handleLinkClick} to={link}>
<LinkIcon />
</Link>
);
@@ -91,9 +90,9 @@ export default class TreeMapRect extends React.PureComponent {
return (
<div
className="treemap-cell"
- style={cellStyles}
onClick={this.handleRectClick}
role="treeitem"
+ style={cellStyles}
tabIndex={0}>
<div className="treemap-inner" style={{ maxWidth: this.props.width }}>
{isIconVisible && (
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/bar-chart-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/BarChart-test.tsx
index 933ac88ca14..0b109c12b0a 100644
--- a/server/sonar-web/src/main/js/components/charts/__tests__/bar-chart-test.js
+++ b/server/sonar-web/src/main/js/components/charts/__tests__/BarChart-test.tsx
@@ -17,13 +17,13 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { shallow } from 'enzyme';
-import { BarChart } from '../bar-chart';
+import BarChart from '../BarChart';
it('should display bars', () => {
const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }];
- const chart = shallow(<BarChart data={data} width={100} height={100} barsWidth={20} />);
+ const chart = shallow(<BarChart barsWidth={20} data={data} height={100} width={100} />);
expect(chart.find('.bar-chart-bar').length).toBe(3);
});
@@ -31,7 +31,7 @@ it('should display ticks', () => {
const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }];
const ticks = ['A', 'B', 'C'];
const chart = shallow(
- <BarChart data={data} xTicks={ticks} width={100} height={100} barsWidth={20} />
+ <BarChart barsWidth={20} data={data} height={100} width={100} xTicks={ticks} />
);
expect(chart.find('.bar-chart-tick').length).toBe(3);
});
@@ -40,7 +40,7 @@ it('should display values', () => {
const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }];
const values = ['A', 'B', 'C'];
const chart = shallow(
- <BarChart data={data} xValues={values} width={100} height={100} barsWidth={20} />
+ <BarChart barsWidth={20} data={data} height={100} width={100} xValues={values} />
);
expect(chart.find('.bar-chart-tick').length).toBe(3);
});
@@ -50,7 +50,7 @@ it('should display bars, ticks and values', () => {
const ticks = ['A', 'B', 'C'];
const values = ['A', 'B', 'C'];
const chart = shallow(
- <BarChart data={data} xTicks={ticks} xValues={values} width={100} height={100} barsWidth={20} />
+ <BarChart barsWidth={20} data={data} height={100} width={100} xTicks={ticks} xValues={values} />
);
expect(chart.find('.bar-chart-bar').length).toBe(3);
expect(chart.find('.bar-chart-tick').length).toBe(6);
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.tsx
index 347d1df976e..07c73da2b87 100644
--- a/server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.js
+++ b/server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.tsx
@@ -17,25 +17,25 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { mount } from 'enzyme';
import BubbleChart, { Bubble } from '../BubbleChart';
it('should display bubbles', () => {
const items = [{ x: 1, y: 10, size: 7 }, { x: 2, y: 30, size: 5 }];
- const chart = mount(<BubbleChart items={items} height={100} />);
+ const chart = mount(<BubbleChart height={100} items={items} />);
chart.find(Bubble).forEach(bubble => expect(bubble).toMatchSnapshot());
});
it('should render bubble links', () => {
const items = [{ x: 1, y: 10, size: 7, link: 'foo' }, { x: 2, y: 30, size: 5, link: 'bar' }];
- const chart = mount(<BubbleChart items={items} height={100} />);
+ const chart = mount(<BubbleChart height={100} items={items} />);
chart.find(Bubble).forEach(bubble => expect(bubble).toMatchSnapshot());
});
it('should render bubbles with click handlers', () => {
const onClick = jest.fn();
const items = [{ x: 1, y: 10, size: 7, link: 'foo' }, { x: 2, y: 30, size: 5, link: 'bar' }];
- const chart = mount(<BubbleChart items={items} height={100} onBubbleClick={onClick} />);
+ const chart = mount(<BubbleChart height={100} items={items} onBubbleClick={onClick} />);
chart.find(Bubble).forEach(bubble => expect(bubble).toMatchSnapshot());
});
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/line-chart-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/LineChart-test.tsx
index 9b2b0018c8a..533bd5aeddb 100644
--- a/server/sonar-web/src/main/js/components/charts/__tests__/line-chart-test.js
+++ b/server/sonar-web/src/main/js/components/charts/__tests__/LineChart-test.tsx
@@ -17,26 +17,26 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { shallow } from 'enzyme';
-import { LineChart } from '../line-chart';
+import LineChart from '../LineChart';
it('should display line', () => {
const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }];
- const chart = shallow(<LineChart data={data} width={100} height={100} />);
+ const chart = shallow(<LineChart data={data} height={100} width={100} />);
expect(chart.find('.line-chart-path').length).toBe(1);
});
it('should display ticks', () => {
const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }];
const ticks = ['A', 'B', 'C'];
- const chart = shallow(<LineChart data={data} xTicks={ticks} width={100} height={100} />);
+ const chart = shallow(<LineChart data={data} height={100} width={100} xTicks={ticks} />);
expect(chart.find('.line-chart-tick').length).toBe(3);
});
it('should display values', () => {
const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }];
const values = ['A', 'B', 'C'];
- const chart = shallow(<LineChart data={data} xValues={values} width={100} height={100} />);
+ const chart = shallow(<LineChart data={data} height={100} width={100} xValues={values} />);
expect(chart.find('.line-chart-tick').length).toBe(3);
});
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.tsx
index 246f3a840b8..96fbe933b41 100644
--- a/server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.js
+++ b/server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.tsx
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { shallow } from 'enzyme';
import TreeMap from '../TreeMap';
@@ -28,7 +28,7 @@ it('should display', () => {
{ key: '3', size: 20, color: '#777', label: 'SonarQube :: Search' }
];
const chart = shallow(
- <TreeMap items={items} width={100} height={100} onRectangleClick={() => {}} />
+ <TreeMap height={100} items={items} onRectangleClick={() => {}} width={100} />
);
expect(chart.find('TreeMapRect')).toHaveLength(3);
});
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.js.snap b/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.tsx.snap
index fbbd76666bd..fbbd76666bd 100644
--- a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.js.snap
+++ b/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/components/charts/bar-chart.js b/server/sonar-web/src/main/js/components/charts/bar-chart.js
deleted file mode 100644
index c137b2f74e9..00000000000
--- a/server/sonar-web/src/main/js/components/charts/bar-chart.js
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 React from 'react';
-import createReactClass from 'create-react-class';
-import PropTypes from 'prop-types';
-import { max } from 'd3-array';
-import { scaleLinear, scaleBand } from 'd3-scale';
-import Tooltip from '../controls/Tooltip';
-import { ResizeMixin } from '../mixins/resize-mixin';
-
-export const BarChart = createReactClass({
- displayName: 'BarChart',
-
- propTypes: {
- data: PropTypes.arrayOf(PropTypes.object).isRequired,
- xTicks: PropTypes.arrayOf(PropTypes.any),
- xValues: PropTypes.arrayOf(PropTypes.any),
- height: PropTypes.number,
- padding: PropTypes.arrayOf(PropTypes.number),
- barsWidth: PropTypes.number.isRequired,
- onBarClick: PropTypes.func
- },
-
- mixins: [ResizeMixin],
-
- getDefaultProps() {
- return {
- xTicks: [],
- xValues: [],
- padding: [10, 10, 10, 10]
- };
- },
-
- getInitialState() {
- return { width: this.props.width, height: this.props.height };
- },
-
- componentDidUpdate(prevProps) {
- if (this.props.width && prevProps.width !== this.props.width) {
- this.setState({ width: this.props.width });
- }
- if (this.props.height && prevProps.height !== this.props.height) {
- this.setState({ height: this.props.height });
- }
- },
-
- handleClick(point) {
- this.props.onBarClick(point);
- },
-
- renderXTicks(xScale, yScale) {
- if (!this.props.xTicks.length) {
- return null;
- }
- const ticks = this.props.xTicks.map((tick, index) => {
- const point = this.props.data[index];
- const x = Math.round(xScale(point.x) + xScale.bandwidth() / 2);
- const y = yScale.range()[0];
- const d = this.props.data[index];
- const text = (
- <text
- className="bar-chart-tick"
- dy="1.5em"
- key={index}
- onClick={this.props.onBarClick && this.handleClick.bind(this, point)}
- style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }}
- x={x}
- y={y}>
- {tick}
- </text>
- );
- return (
- <Tooltip key={index} overlay={d.tooltip || undefined}>
- {text}
- </Tooltip>
- );
- });
- return <g>{ticks}</g>;
- },
-
- renderXValues(xScale, yScale) {
- if (!this.props.xValues.length) {
- return null;
- }
- const ticks = this.props.xValues.map((value, index) => {
- const point = this.props.data[index];
- const x = Math.round(xScale(point.x) + xScale.bandwidth() / 2);
- const y = yScale(point.y);
- const d = this.props.data[index];
- const text = (
- <text
- className="bar-chart-tick"
- dy="-1em"
- key={index}
- onClick={this.props.onBarClick && this.handleClick.bind(this, point)}
- style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }}
- x={x}
- y={y}>
- {value}
- </text>
- );
- return (
- <Tooltip key={index} overlay={d.tooltip || undefined}>
- {text}
- </Tooltip>
- );
- });
- return <g>{ticks}</g>;
- },
-
- renderBars(xScale, yScale) {
- const bars = this.props.data.map((d, index) => {
- const x = Math.round(xScale(d.x));
- const maxY = yScale.range()[0];
- const y = Math.round(yScale(d.y)) - /* minimum bar height */ 1;
- const height = maxY - y;
- const rect = (
- <rect
- className="bar-chart-bar"
- height={height}
- key={index}
- onClick={this.props.onBarClick && this.handleClick.bind(this, d)}
- style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }}
- width={this.props.barsWidth}
- x={x}
- y={y}
- />
- );
- return (
- <Tooltip key={index} overlay={d.tooltip || undefined}>
- {rect}
- </Tooltip>
- );
- });
- return <g>{bars}</g>;
- },
-
- render() {
- if (!this.state.width || !this.state.height) {
- return <div />;
- }
-
- const availableWidth = this.state.width - this.props.padding[1] - this.props.padding[3];
- const availableHeight = this.state.height - this.props.padding[0] - this.props.padding[2];
-
- const innerPadding =
- (availableWidth - this.props.barsWidth * this.props.data.length) /
- (this.props.data.length - 1);
- const relativeInnerPadding = innerPadding / (innerPadding + this.props.barsWidth);
-
- const maxY = max(this.props.data, d => d.y);
- const xScale = scaleBand()
- .domain(this.props.data.map(d => d.x))
- .range([0, availableWidth])
- .paddingInner(relativeInnerPadding);
- const yScale = scaleLinear()
- .domain([0, maxY])
- .range([availableHeight, 0]);
-
- return (
- <svg className="bar-chart" height={this.state.height} width={this.state.width}>
- <g transform={`translate(${this.props.padding[3]}, ${this.props.padding[0]})`}>
- {this.renderXTicks(xScale, yScale)}
- {this.renderXValues(xScale, yScale)}
- {this.renderBars(xScale, yScale)}
- </g>
- </svg>
- );
- }
-});
diff --git a/server/sonar-web/src/main/js/components/charts/donut-chart.js b/server/sonar-web/src/main/js/components/charts/donut-chart.js
deleted file mode 100644
index 08fd9b0bb24..00000000000
--- a/server/sonar-web/src/main/js/components/charts/donut-chart.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 React from 'react';
-import createReactClass from 'create-react-class';
-import PropTypes from 'prop-types';
-import { arc as d3Arc, pie as d3Pie } from 'd3-shape';
-import { ResizeMixin } from './../mixins/resize-mixin';
-
-function Sector(props) {
- const arc = d3Arc()
- .outerRadius(props.radius)
- .innerRadius(props.radius - props.thickness);
- return <path d={arc(props.data)} style={{ fill: props.fill }} />;
-}
-
-export const DonutChart = createReactClass({
- displayName: 'DonutChart',
-
- propTypes: {
- data: PropTypes.arrayOf(PropTypes.object).isRequired
- },
-
- mixins: [ResizeMixin],
-
- getDefaultProps() {
- return { thickness: 6, padding: [0, 0, 0, 0] };
- },
-
- getInitialState() {
- return { width: this.props.width, height: this.props.height };
- },
-
- render() {
- if (!this.state.width || !this.state.height) {
- return <div />;
- }
-
- const availableWidth = this.state.width - this.props.padding[1] - this.props.padding[3];
- const availableHeight = this.state.height - this.props.padding[0] - this.props.padding[2];
-
- const size = Math.min(availableWidth, availableHeight);
- const radius = Math.floor(size / 2);
-
- const pie = d3Pie()
- .sort(null)
- .value(d => d.value);
- const sectors = pie(this.props.data).map((d, i) => {
- return (
- <Sector
- data={d}
- fill={this.props.data[i].fill}
- key={i}
- radius={radius}
- thickness={this.props.thickness}
- />
- );
- });
-
- return (
- <svg className="donut-chart" height={this.state.height} width={this.state.width}>
- <g transform={`translate(${this.props.padding[3]}, ${this.props.padding[0]})`}>
- <g transform={`translate(${radius}, ${radius})`}>{sectors}</g>
- </g>
- </svg>
- );
- }
-});
diff --git a/server/sonar-web/src/main/js/components/common/LocationIndex.js b/server/sonar-web/src/main/js/components/common/LocationIndex.tsx
index f3ae1bf7e88..15b143e7876 100644
--- a/server/sonar-web/src/main/js/components/common/LocationIndex.js
+++ b/server/sonar-web/src/main/js/components/common/LocationIndex.tsx
@@ -17,35 +17,31 @@
* 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 React from 'react';
-import classNames from 'classnames';
+import * as React from 'react';
+import * as classNames from 'classnames';
import './LocationIndex.css';
-/*::
-type Props = {
- children?: React.Element<*>,
- leading?: boolean,
- onClick?: () => void,
- selected?: boolean
-};
-*/
+interface Props {
+ children?: React.ReactNode;
+ leading?: boolean;
+ onClick?: () => void;
+ selected?: boolean;
+ [x: string]: any;
+}
-export default function LocationIndex(props /*: Props */) {
+export default function LocationIndex(props: Props) {
const { children, leading, onClick, selected, ...other } = props;
const clickAttributes = onClick ? { onClick, role: 'button', tabIndex: 0 } : {};
-
// put {...others} because Tooltip sets some event handlers
return (
<div
- className={classNames('location-index', { 'is-leading': leading, selected })}
+ className={classNames('location-index', {
+ 'is-leading': leading,
+ selected
+ })}
{...clickAttributes}
{...other}>
{children}
</div>
);
}
-
-LocationIndex.defaultProps = {
- selected: false
-};
diff --git a/server/sonar-web/src/main/js/components/common/LocationMessage.js b/server/sonar-web/src/main/js/components/common/LocationMessage.tsx
index 491ac9e5460..bcee4be2683 100644
--- a/server/sonar-web/src/main/js/components/common/LocationMessage.js
+++ b/server/sonar-web/src/main/js/components/common/LocationMessage.tsx
@@ -17,19 +17,16 @@
* 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 React from 'react';
-import classNames from 'classnames';
+import * as React from 'react';
+import * as classNames from 'classnames';
import './LocationMessage.css';
-/*::
-type Props = {
- children?: React.Element<*>,
- selected: boolean
-};
-*/
+interface Props {
+ children?: React.ReactNode;
+ selected: boolean;
+}
-export default function LocationMessage(props /*: Props */) {
+export default function LocationMessage(props: Props) {
return (
<div className={classNames('location-message', { selected: props.selected })}>
{props.children}
diff --git a/server/sonar-web/src/main/js/components/common/OrganizationHelmet.js b/server/sonar-web/src/main/js/components/common/OrganizationHelmet.tsx
index d4b52885ac0..e842eaae6c7 100644
--- a/server/sonar-web/src/main/js/components/common/OrganizationHelmet.js
+++ b/server/sonar-web/src/main/js/components/common/OrganizationHelmet.tsx
@@ -17,18 +17,15 @@
* 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 React from 'react';
+import * as React from 'react';
import Helmet from 'react-helmet';
-/*::
-type Props = {
- title: string,
- organization?: ?{ name: string }
-};
-*/
+interface Props {
+ organization?: { name: string };
+ title: string;
+}
-export default function OrganizationHelmet({ title, organization } /*: Props */) {
+export default function OrganizationHelmet({ title, organization }: Props) {
const defaultTitle = title + (organization ? ' - ' + organization.name : '');
return <Helmet defaultTitle={defaultTitle} titleTemplate={'%s - ' + defaultTitle} />;
}
diff --git a/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.js b/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.tsx
index b6934cea2c6..baeb9ad0dba 100644
--- a/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.js
+++ b/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.tsx
@@ -17,19 +17,16 @@
* 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 React from 'react';
+import * as React from 'react';
import { Link } from 'react-router';
import { translate, hasMessage } from '../../helpers/l10n';
import './UpgradeOrganizationBox.css';
-/*::
-type Props = {
- organization: string
-};
-*/
+interface Props {
+ organization: string;
+}
-export default function UpgradeOrganizationBox(props /*: Props */) {
+export default function UpgradeOrganizationBox({ organization }: Props) {
return (
<div className="boxed-group boxed-group-inner upgrade-organization-box">
<h3 className="spacer-bottom">{translate('billing.upgrade_box.header')}</h3>
@@ -41,7 +38,7 @@ export default function UpgradeOrganizationBox(props /*: Props */) {
<Link
className="button"
to={{
- pathname: `organizations/${props.organization}/extension/billing/billing`,
+ pathname: `organizations/${organization}/extension/billing/billing`,
query: { page: 'upgrade' }
}}>
{translate('billing.upgrade_box.button')}
diff --git a/server/sonar-web/src/main/js/components/controls/GlobalMessages.js b/server/sonar-web/src/main/js/components/controls/GlobalMessages.tsx
index 0d0782009b7..95ee65b06e2 100644
--- a/server/sonar-web/src/main/js/components/controls/GlobalMessages.js
+++ b/server/sonar-web/src/main/js/components/controls/GlobalMessages.tsx
@@ -17,28 +17,26 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import { ERROR, SUCCESS } from '../../store/globalMessages/duck';
+import * as React from 'react';
+import * as classNames from 'classnames';
import { Button } from '../ui/buttons';
-export default class GlobalMessages extends React.PureComponent {
- static propTypes = {
- messages: PropTypes.arrayOf(
- PropTypes.shape({
- id: PropTypes.string.isRequired,
- message: PropTypes.string.isRequired,
- level: PropTypes.oneOf([ERROR, SUCCESS])
- })
- ),
- closeGlobalMessage: PropTypes.func.isRequired
- };
+interface Message {
+ id: string;
+ level: 'ERROR' | 'SUCCESS';
+ message: string;
+}
+
+interface Props {
+ closeGlobalMessage: (id: string) => void;
+ messages: Message[];
+}
- renderMessage = message => {
+export default class GlobalMessages extends React.PureComponent<Props> {
+ renderMessage = (message: Message) => {
const className = classNames('process-spinner', 'shown', {
- 'process-spinner-failed': message.level === ERROR,
- 'process-spinner-success': message.level === SUCCESS
+ 'process-spinner-failed': message.level === 'ERROR',
+ 'process-spinner-success': message.level === 'SUCCESS'
});
return (
<div className={className} key={message.id}>
diff --git a/server/sonar-web/src/main/js/components/controls/Toggle.js b/server/sonar-web/src/main/js/components/controls/Toggle.tsx
index 4cbabfece09..b35d121f9e8 100644
--- a/server/sonar-web/src/main/js/components/controls/Toggle.js
+++ b/server/sonar-web/src/main/js/components/controls/Toggle.tsx
@@ -17,36 +17,36 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
+import * as React from 'react';
+import * as classNames from 'classnames';
import { Button } from '../ui/buttons';
import './styles.css';
-export default class Toggle extends React.PureComponent {
- static propTypes = {
- value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).isRequired,
- name: PropTypes.string,
- onChange: PropTypes.func
+export interface Props {
+ name?: string;
+ onChange?: (value: boolean) => void;
+ value: boolean | string;
+}
+
+export default class Toggle extends React.PureComponent<Props> {
+ getValue = () => {
+ const { value } = this.props;
+ return typeof value === 'string' ? value === 'true' : value;
};
- handleClick = value => {
+ handleClick = () => {
if (this.props.onChange) {
+ const value = this.getValue();
this.props.onChange(!value);
}
};
render() {
- const { value } = this.props;
- const booleanValue = typeof value === 'string' ? value === 'true' : value;
-
- const className = classNames('boolean-toggle', { 'boolean-toggle-on': booleanValue });
+ const value = this.getValue();
+ const className = classNames('boolean-toggle', { 'boolean-toggle-on': value });
return (
- <Button
- className={className}
- name={this.props.name}
- onClick={() => this.handleClick(booleanValue)}>
+ <Button className={className} name={this.props.name} onClick={this.handleClick}>
<div className="boolean-toggle-handle" />
</Button>
);
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.js b/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx
index 5c2e7458776..b8de25e41f1 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.js
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx
@@ -17,8 +17,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import * as React from 'react';
import { shallow } from 'enzyme';
-import React from 'react';
import ListFooter from '../ListFooter';
import { click } from '../../../helpers/testUtils';
@@ -33,13 +33,13 @@ it('should not render "show more"', () => {
});
it('should not render "show more"', () => {
- const listFooter = shallow(<ListFooter count={5} total={5} loadMore={jest.fn()} />);
+ const listFooter = shallow(<ListFooter count={5} loadMore={jest.fn()} total={5} />);
expect(listFooter.find('a').length).toBe(0);
});
it('should "show more"', () => {
const loadMore = jest.fn();
- const listFooter = shallow(<ListFooter count={3} total={5} loadMore={loadMore} />);
+ const listFooter = shallow(<ListFooter count={3} loadMore={loadMore} total={5} />);
const link = listFooter.find('a');
expect(link.length).toBe(1);
click(link);
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.js b/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.tsx
index 3245074388a..7d3e8ae2d0d 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.js
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.tsx
@@ -17,23 +17,23 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import * as React from 'react';
import { shallow } from 'enzyme';
-import React from 'react';
-import Toggle from '../Toggle';
+import Toggle, { Props } from '../Toggle';
import { click } from '../../../helpers/testUtils';
-function getSample(props) {
- return <Toggle onChange={() => true} value={true} {...props} />;
-}
-
it('should render', () => {
- const Toggle = shallow(getSample());
+ const Toggle = shallowRender();
expect(Toggle.is('Button')).toBe(true);
});
it('should call onChange', () => {
const onChange = jest.fn();
- const Toggle = shallow(getSample({ onChange }));
+ const Toggle = shallowRender({ onChange });
click(Toggle);
expect(onChange).toBeCalledWith(false);
});
+
+function shallowRender(props?: Partial<Props>) {
+ return shallow(<Toggle onChange={() => true} value={true} {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/components/ui/BugTrackerIcon.js b/server/sonar-web/src/main/js/components/icons-components/BugTrackerIcon.tsx
index 45b233ba806..f42e84aaa6e 100644
--- a/server/sonar-web/src/main/js/components/ui/BugTrackerIcon.js
+++ b/server/sonar-web/src/main/js/components/icons-components/BugTrackerIcon.tsx
@@ -17,25 +17,23 @@
* 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 React from 'react';
+import * as React from 'react';
+import { IconProps } from './types';
-export default function BugTrackerIcon() {
- /* eslint-disable max-len */
+export default function BugTrackerIcon({ className, fill = 'currentColor', size = 16 }: IconProps) {
return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14" width="14" height="14">
- <g transform="matrix(1,0,0,1,0,1)">
- <path
- style={{
- fill: 'none',
- stroke: 'currentColor',
- strokeWidth: 2,
- strokeLinecap: 'round',
- strokeMiterlimit: '10'
- }}
- d="M12 9h-2L8 5 6.5 9.5l-2-6L3 9H1"
- />
- </g>
+ <svg
+ className={className}
+ height={size}
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={size}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink">
+ <path
+ d="M13.5 9.5c1.003.033 1.466 1.952 0 2h-2.618L9.685 9.107 8 14.162 6.096 8.45l-.832 3.05-2.829-.002c-.984-.097-1.369-1.951.065-1.998h1.236l2.168-7.95L8 7.838l1.315-3.945L12.118 9.5H13.5z"
+ style={{ fill }}
+ />
</svg>
);
}
diff --git a/server/sonar-web/src/main/js/components/common/ClockIcon.js b/server/sonar-web/src/main/js/components/icons-components/ClockIcon.tsx
index e0e696128aa..d5da0ec03e9 100644
--- a/server/sonar-web/src/main/js/components/common/ClockIcon.js
+++ b/server/sonar-web/src/main/js/components/icons-components/ClockIcon.tsx
@@ -17,33 +17,24 @@
* 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 React from 'react';
-import classNames from 'classnames';
+import * as React from 'react';
+import * as classNames from 'classnames';
+import { IconProps } from './types';
-/*::
-type Props = {
- className?: string,
- size?: number
-};
-*/
-
-export default function ClockIcon(props /*: Props */) {
- /* eslint max-len: 0 */
+export default function ClockIcon({ className, size = 16 }: IconProps) {
return (
<svg
- className={classNames('icon-clock', props.className)}
+ className={classNames('icon-clock', className)}
+ height={size}
+ version="1.1"
viewBox="0 0 16 16"
- width={props.size}
- height={props.size}>
+ width={size}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink">
<g fill="#fff" stroke="#ADADAD" transform="matrix(1.4 0 0 1.4 .3 .7)">
<circle cx="5.5" cy="5.2" r="5" />
- <path fillRule="nonzero" d="M5.6 2.9v2.7l2-.5" />
+ <path d="M5.6 2.9v2.7l2-.5" fillRule="nonzero" />
</g>
</svg>
);
}
-
-ClockIcon.defaultProps = {
- size: 16
-};
diff --git a/server/sonar-web/src/main/js/components/icons-components/PinIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/PinIcon.tsx
new file mode 100644
index 00000000000..3e83487feeb
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/icons-components/PinIcon.tsx
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { IconProps } from './types';
+
+export default function PinIcon({ className, fill = 'currentColor', size = 16 }: IconProps) {
+ return (
+ <svg
+ className={className}
+ height={size}
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={size}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink">
+ <path
+ d="M7.25 7.25v-3.5a.243.243 0 0 0-.07-.18A.243.243 0 0 0 7 3.5a.243.243 0 0 0-.18.07.243.243 0 0 0-.07.18v3.5c0 .073.023.133.07.18.047.047.107.07.18.07a.243.243 0 0 0 .18-.07.243.243 0 0 0 .07-.18zM12.5 10a.482.482 0 0 1-.148.352.482.482 0 0 1-.352.148H8.648l-.398 3.773a.29.29 0 0 1-.082.161.219.219 0 0 1-.16.066H8c-.141 0-.224-.07-.25-.211L7.156 10.5H4a.482.482 0 0 1-.352-.148A.482.482 0 0 1 3.5 10c0-.641.204-1.217.613-1.73.409-.513.871-.77 1.387-.77v-4a.96.96 0 0 1-.703-.297A.96.96 0 0 1 4.5 2.5a.96.96 0 0 1 .297-.703A.96.96 0 0 1 5.5 1.5h5a.96.96 0 0 1 .703.297.96.96 0 0 1 .297.703.96.96 0 0 1-.297.703.96.96 0 0 1-.703.297v4c.516 0 .978.257 1.387.77.409.513.613 1.089.613 1.73z"
+ style={{ fill }}
+ />;
+ </svg>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.js.snap b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.js.snap
index 8f3694dd8d0..93d4a3f72d2 100644
--- a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.js.snap
+++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.js.snap
@@ -1,9 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should count all code locations 1`] = `
-<LocationIndex
- selected={false}
->
+<LocationIndex>
7
</LocationIndex>
`;
diff --git a/server/sonar-web/src/main/js/components/shared/SeverityIcon.js b/server/sonar-web/src/main/js/components/shared/SeverityIcon.tsx
index 4a7575edab2..38ee50884a4 100644
--- a/server/sonar-web/src/main/js/components/shared/SeverityIcon.js
+++ b/server/sonar-web/src/main/js/components/shared/SeverityIcon.tsx
@@ -17,14 +17,19 @@
* 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 React from 'react';
-import classNames from 'classnames';
+import * as React from 'react';
+import * as classNames from 'classnames';
-export default function SeverityIcon(props /*: { severity: ?string, className?: string } */) {
+interface Props {
+ className?: string;
+ severity: string | null | undefined;
+}
+
+export default function SeverityIcon(props: Props) {
if (!props.severity) {
return null;
}
- const className = classNames('icon-severity-' + props.severity.toLowerCase(), props.className);
- return <i className={className} />;
+ return (
+ <i className={classNames('icon-severity-' + props.severity.toLowerCase(), props.className)} />
+ );
}
diff --git a/server/sonar-web/src/main/js/components/shared/StatusHelper.js b/server/sonar-web/src/main/js/components/shared/StatusHelper.tsx
index 2c2532605ad..b6921effdac 100644
--- a/server/sonar-web/src/main/js/components/shared/StatusHelper.js
+++ b/server/sonar-web/src/main/js/components/shared/StatusHelper.tsx
@@ -17,20 +17,18 @@
* 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 React from 'react';
+import * as React from 'react';
import StatusIcon from './StatusIcon';
import { translate } from '../../helpers/l10n';
-export default function StatusHelper(
- props /*: {
- resolution?: string,
- status: string,
- className?: string
-} */
-) {
- const resolution =
- props.resolution != null && ` (${translate('issue.resolution', props.resolution)})`;
+interface Props {
+ className?: string;
+ resolution: string | undefined;
+ status: string;
+}
+
+export default function StatusHelper(props: Props) {
+ const resolution = props.resolution && ` (${translate('issue.resolution', props.resolution)})`;
return (
<span className={props.className}>
<StatusIcon className="little-spacer-right" status={props.status} />
diff --git a/server/sonar-web/src/main/js/components/shared/StatusIcon.js b/server/sonar-web/src/main/js/components/shared/StatusIcon.tsx
index ed8c418ee31..d043b034406 100644
--- a/server/sonar-web/src/main/js/components/shared/StatusIcon.js
+++ b/server/sonar-web/src/main/js/components/shared/StatusIcon.tsx
@@ -17,11 +17,14 @@
* 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 React from 'react';
-import classNames from 'classnames';
+import * as React from 'react';
+import * as classNames from 'classnames';
-export default function StatusIcon(props /*: { status: string, className?: string } */) {
- const className = classNames('icon-status-' + props.status.toLowerCase(), props.className);
- return <i className={className} />;
+interface Props {
+ className?: string;
+ status: string;
+}
+
+export default function StatusIcon({ className, status }: Props) {
+ return <i className={classNames('icon-status-' + status.toLowerCase(), className)} />;
}
diff --git a/server/sonar-web/src/main/js/components/shared/WithStore.js b/server/sonar-web/src/main/js/components/shared/WithStore.js
deleted file mode 100644
index 2cdf9bb3b20..00000000000
--- a/server/sonar-web/src/main/js/components/shared/WithStore.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 React from 'react';
-import PropTypes from 'prop-types';
-import getStore from '../../app/utils/getStore';
-
-/*::
-type Props = {
- children: React.Element<*>
-};
-*/
-
-export default class WithStore extends React.PureComponent {
- /*:: props: Props; */
- /*:: store: {};
-*/
-
- static childContextTypes = {
- store: PropTypes.object
- };
-
- constructor(props /*: Props */) {
- super(props);
- this.store = getStore();
- }
-
- getChildContext() {
- return { store: this.store };
- }
-
- render() {
- return this.props.children;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.js b/server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.tsx
index 32097c900fd..06169277552 100644
--- a/server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.js
+++ b/server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.tsx
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { shallow } from 'enzyme';
import QualifierIcon from '../QualifierIcon';
diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.js.snap b/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.tsx.snap
index 3e1625b3e32..3e1625b3e32 100644
--- a/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.js.snap
+++ b/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/components/shared/pin-icon.js b/server/sonar-web/src/main/js/components/shared/pin-icon.js
deleted file mode 100644
index 9435d00ee8c..00000000000
--- a/server/sonar-web/src/main/js/components/shared/pin-icon.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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.
- */
-/* eslint max-len: 0 */
-import React from 'react';
-import * as theme from '../../app/theme';
-
-export default function PinIcon() {
- return (
- <svg width="9" height="14" viewBox="0 0 288 448">
- <path
- fill={theme.darkBlue}
- d="M120 216v-112q0-3.5-2.25-5.75t-5.75-2.25-5.75 2.25-2.25 5.75v112q0 3.5 2.25 5.75t5.75 2.25 5.75-2.25 2.25-5.75zM288 304q0 6.5-4.75 11.25t-11.25 4.75h-107.25l-12.75 120.75q-0.5 3-2.625 5.125t-5.125 2.125h-0.25q-6.75 0-8-6.75l-19-121.25h-101q-6.5 0-11.25-4.75t-4.75-11.25q0-30.75 19.625-55.375t44.375-24.625v-128q-13 0-22.5-9.5t-9.5-22.5 9.5-22.5 22.5-9.5h160q13 0 22.5 9.5t9.5 22.5-9.5 22.5-22.5 9.5v128q24.75 0 44.375 24.625t19.625 55.375z"
- />
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx b/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx
index 7439b850ff3..10ffc9e849b 100644
--- a/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx
+++ b/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { DonutChart } from '../charts/donut-chart';
+import DonutChart from '../charts/DonutChart';
import * as theme from '../../app/theme';
const SIZE_TO_WIDTH_MAPPING = { small: 16, normal: 24, big: 40, huge: 60 };
@@ -45,5 +45,5 @@ export default function CoverageRating({ muted = false, size = 'normal', value }
const width = SIZE_TO_WIDTH_MAPPING[size];
const thickness = SIZE_TO_THICKNESS_MAPPING[size];
- return <DonutChart data={data} width={width} height={width} thickness={thickness} />;
+ return <DonutChart data={data} height={width} thickness={thickness} width={width} />;
}
diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/Level-test.js b/server/sonar-web/src/main/js/components/ui/__tests__/Level-test.tsx
index 3a315a07599..7706ee2414b 100644
--- a/server/sonar-web/src/main/js/components/ui/__tests__/Level-test.js
+++ b/server/sonar-web/src/main/js/components/ui/__tests__/Level-test.tsx
@@ -17,8 +17,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import * as React from 'react';
import { shallow } from 'enzyme';
-import React from 'react';
import Level from '../Level';
it('should render', () => {
diff --git a/server/sonar-web/src/main/js/components/ui/buttons.tsx b/server/sonar-web/src/main/js/components/ui/buttons.tsx
index 82992ba0a64..1ede3bb8ce1 100644
--- a/server/sonar-web/src/main/js/components/ui/buttons.tsx
+++ b/server/sonar-web/src/main/js/components/ui/buttons.tsx
@@ -32,6 +32,7 @@ interface ButtonProps {
disabled?: boolean;
id?: string;
innerRef?: (node: HTMLElement | null) => void;
+ name?: string;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
preventDefault?: boolean;
stopPropagation?: boolean;
diff --git a/server/sonar-web/src/main/js/libs/third-party/VSS.SDK.min.js b/server/sonar-web/src/main/js/libs/third-party/VSS.SDK.min.js
deleted file mode 100644
index 5f6a76663bd..00000000000
--- a/server/sonar-web/src/main/js/libs/third-party/VSS.SDK.min.js
+++ /dev/null
@@ -1,957 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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.
- */
-// Copyright (C) Microsoft Corporation. All rights reserved.
-var XDM, VSS;
-(function(n) {
- function u() {
- return new o();
- }
- function s() {
- return (
- Math.floor(Math.random() * (f - t) + t).toString(36) +
- Math.floor(Math.random() * (f - t) + t).toString(36)
- );
- }
- var i, r, e;
- n.createDeferred = u;
- var o = (function() {
- function n() {
- var n = this;
- this._resolveCallbacks = [];
- this._rejectCallbacks = [];
- this._isResolved = !1;
- this._isRejected = !1;
- this.resolve = function(t) {
- n._resolve(t);
- };
- this.reject = function(t) {
- n._reject(t);
- };
- this.promise = {};
- this.promise.then = function(t, i) {
- return n._then(t, i);
- };
- }
- return (
- (n.prototype._then = function(t, i) {
- var u = this,
- r;
- return (!t && !i) || (this._isResolved && !t) || (this._isRejected && !i)
- ? this.promise
- : ((r = new n()),
- this._resolveCallbacks.push(function(n) {
- u._wrapCallback(t, n, r, !1);
- }),
- this._rejectCallbacks.push(function(n) {
- u._wrapCallback(i, n, r, !0);
- }),
- this._isResolved
- ? this._resolve(this._resolvedValue)
- : this._isRejected && this._reject(this._rejectValue),
- r.promise);
- }),
- (n.prototype._wrapCallback = function(n, t, i, r) {
- if (!n) {
- r ? i.reject(t) : i.resolve(t);
- return;
- }
- var u;
- try {
- u = n(t);
- } catch (f) {
- i.reject(f);
- return;
- }
- u === undefined
- ? i.resolve(t)
- : u && typeof u.then == 'function'
- ? u.then(
- function(n) {
- i.resolve(n);
- },
- function(n) {
- i.reject(n);
- }
- )
- : i.resolve(u);
- }),
- (n.prototype._resolve = function(n) {
- if (
- (this._isRejected ||
- this._isResolved ||
- ((this._isResolved = !0), (this._resolvedValue = n)),
- this._isResolved && this._resolveCallbacks.length > 0)
- ) {
- var t = this._resolveCallbacks.splice(0);
- window.setTimeout(function() {
- for (var i = 0, r = t.length; i < r; i++) t[i](n);
- });
- }
- }),
- (n.prototype._reject = function(n) {
- if (
- (this._isRejected ||
- this._isResolved ||
- ((this._isRejected = !0),
- (this._rejectValue = n),
- this._rejectCallbacks.length === 0 &&
- window.console &&
- window.console.warn &&
- (console.warn('Rejected XDM promise with no reject callbacks'),
- n && console.warn(n))),
- this._isRejected && this._rejectCallbacks.length > 0)
- ) {
- var t = this._rejectCallbacks.splice(0);
- window.setTimeout(function() {
- for (var i = 0, r = t.length; i < r; i++) t[i](n);
- });
- }
- }),
- n
- );
- })(),
- t = parseInt('10000000000', 36),
- f = Number.MAX_SAFE_INTEGER || 9007199254740991;
- i = (function() {
- function n() {
- this._registeredObjects = {};
- }
- return (
- (n.prototype.register = function(n, t) {
- this._registeredObjects[n] = t;
- }),
- (n.prototype.unregister = function(n) {
- delete this._registeredObjects[n];
- }),
- (n.prototype.getInstance = function(n, t) {
- var i = this._registeredObjects[n];
- return i ? (typeof i == 'function' ? i(t) : i) : null;
- }),
- n
- );
- })();
- n.XDMObjectRegistry = i;
- n.globalObjectRegistry = new i();
- r = (function() {
- function t(n, r) {
- r === void 0 && (r = null);
- this._nextMessageId = 1;
- this._deferreds = {};
- this._nextProxyFunctionId = 1;
- this._proxyFunctions = {};
- this._postToWindow = n;
- this._targetOrigin = r;
- this._channelObjectRegistry = new i();
- this._channelId = t._nextChannelId++;
- this._targetOrigin || (this._handshakeToken = s());
- }
- return (
- (t.prototype.getObjectRegistry = function() {
- return this._channelObjectRegistry;
- }),
- (t.prototype.invokeRemoteMethod = function(n, t, i, r, f) {
- var e = {
- id: this._nextMessageId++,
- methodName: n,
- instanceId: t,
- instanceContext: r,
- params: this._customSerializeObject(i, f),
- jsonrpc: '2.0',
- serializationSettings: f
- },
- o;
- return (
- this._targetOrigin || (e.handshakeToken = this._handshakeToken),
- (o = u()),
- (this._deferreds[e.id] = o),
- this._sendRpcMessage(e),
- o.promise
- );
- }),
- (t.prototype.getRemoteObjectProxy = function(n, t) {
- return this.invokeRemoteMethod(null, n, null, t);
- }),
- (t.prototype.invokeMethod = function(n, t) {
- var f = this,
- r,
- u,
- i;
- if (!t.methodName) {
- this._success(t, n, t.handshakeToken);
- return;
- }
- if (((r = n[t.methodName]), typeof r != 'function')) {
- this._error(t, new Error('RPC method not found: ' + t.methodName), t.handshakeToken);
- return;
- }
- try {
- u = [];
- t.params && (u = this._customDeserializeObject(t.params));
- i = r.apply(n, u);
- i && i.then && typeof i.then == 'function'
- ? i.then(
- function(n) {
- f._success(t, n, t.handshakeToken);
- },
- function(n) {
- f._error(t, n, t.handshakeToken);
- }
- )
- : this._success(t, i, t.handshakeToken);
- } catch (e) {
- this._error(t, e, t.handshakeToken);
- }
- }),
- (t.prototype.getRegisteredObject = function(t, i) {
- if (t === '__proxyFunctions') return this._proxyFunctions;
- var r = this._channelObjectRegistry.getInstance(t, i);
- return r || (r = n.globalObjectRegistry.getInstance(t, i)), r;
- }),
- (t.prototype.onMessage = function(n) {
- var u = this,
- t = n,
- i,
- r;
- if (t.instanceId) {
- if (((i = this.getRegisteredObject(t.instanceId, t.instanceContext)), !i)) return !1;
- typeof i.then == 'function'
- ? i.then(
- function(n) {
- u.invokeMethod(n, t);
- },
- function(n) {
- u._error(t, n, t.handshakeToken);
- }
- )
- : this.invokeMethod(i, t);
- } else {
- if (((r = this._deferreds[t.id]), !r)) return !1;
- t.error
- ? r.reject(this._customDeserializeObject([t.error])[0])
- : r.resolve(this._customDeserializeObject([t.result])[0]);
- delete this._deferreds[t.id];
- }
- return !0;
- }),
- (t.prototype.owns = function(n, t, i) {
- var r = i;
- if (this._postToWindow === n) {
- if (this._targetOrigin)
- return t
- ? t.toLowerCase() === 'null' ||
- this._targetOrigin.toLowerCase().indexOf(t.toLowerCase()) === 0
- : !1;
- if (r.handshakeToken && r.handshakeToken === this._handshakeToken)
- return (this._targetOrigin = t), !0;
- }
- return !1;
- }),
- (t.prototype.error = function(n, t) {
- var i = n;
- this._error(i, t, i.handshakeToken);
- }),
- (t.prototype._error = function(n, t, i) {
- var r = {
- id: n.id,
- error: this._customSerializeObject([t], n.serializationSettings)[0],
- jsonrpc: '2.0',
- handshakeToken: i
- };
- this._sendRpcMessage(r);
- }),
- (t.prototype._success = function(n, t, i) {
- var r = {
- id: n.id,
- result: this._customSerializeObject([t], n.serializationSettings)[0],
- jsonrpc: '2.0',
- handshakeToken: i
- };
- this._sendRpcMessage(r);
- }),
- (t.prototype._sendRpcMessage = function(n) {
- var t = JSON.stringify(n);
- this._postToWindow.postMessage(t, '*');
- }),
- (t.prototype._shouldSkipSerialization = function(n) {
- for (var r, i = 0, u = t.WINDOW_TYPES_TO_SKIP_SERIALIZATION.length; i < u; i++)
- if (((r = t.WINDOW_TYPES_TO_SKIP_SERIALIZATION[i]), window[r] && n instanceof window[r]))
- return !0;
- if (window.jQuery)
- for (i = 0, u = t.JQUERY_TYPES_TO_SKIP_SERIALIZATION.length; i < u; i++)
- if (
- ((r = t.JQUERY_TYPES_TO_SKIP_SERIALIZATION[i]),
- window.jQuery[r] && n instanceof window.jQuery[r])
- )
- return !0;
- return !1;
- }),
- (t.prototype._customSerializeObject = function(n, i, r, u, f) {
- var h = this,
- a,
- o,
- l,
- v,
- e,
- c,
- s;
- if (
- (r === void 0 && (r = null),
- u === void 0 && (u = 1),
- f === void 0 && (f = 1),
- !n || f > t.MAX_XDM_DEPTH) ||
- this._shouldSkipSerialization(n)
- )
- return null;
- if (
- ((a = function(t, e, o) {
- var s, c, l, a, v;
- try {
- s = t[o];
- } catch (y) {}
- ((c = typeof s), c !== 'undefined') &&
- ((l = -1),
- c === 'object' && (l = r.originalObjects.indexOf(s)),
- l >= 0
- ? ((a = r.newObjects[l]),
- a.__circularReferenceId || (a.__circularReferenceId = u++),
- (e[o] = { __circularReference: a.__circularReferenceId }))
- : c === 'function'
- ? ((v = h._nextProxyFunctionId++),
- (e[o] = {
- __proxyFunctionId: h._registerProxyFunction(s, n),
- __channelId: h._channelId
- }))
- : c === 'object'
- ? (e[o] =
- s && s instanceof Date
- ? { __proxyDate: s.getTime() }
- : h._customSerializeObject(s, i, r, u, f + 1))
- : o !== '__proxyFunctionId' && (e[o] = s));
- }),
- r || (r = { newObjects: [], originalObjects: [] }),
- r.originalObjects.push(n),
- n instanceof Array)
- )
- for (o = [], r.newObjects.push(o), e = 0, c = n.length; e < c; e++) a(n, o, e);
- else {
- o = {};
- r.newObjects.push(o);
- l = {};
- try {
- for (s in n) l[s] = !0;
- for (v = Object.getOwnPropertyNames(n), e = 0, c = v.length; e < c; e++) l[v[e]] = !0;
- } catch (y) {}
- for (s in l) ((s && s[0] !== '_') || (i && i.includeUnderscoreProperties)) && a(n, o, s);
- }
- return r.originalObjects.pop(), r.newObjects.pop(), o;
- }),
- (t.prototype._registerProxyFunction = function(n, t) {
- var i = this._nextProxyFunctionId++;
- return (
- (this._proxyFunctions['proxy' + i] = function() {
- return n.apply(t, Array.prototype.slice.call(arguments, 0));
- }),
- i
- );
- }),
- (t.prototype._customDeserializeObject = function(n, t) {
- var e = this,
- o = this,
- r,
- i,
- u,
- f;
- if (!n) return null;
- if (
- (t || (t = {}),
- (r = function(n, i) {
- var r = n[i],
- u = typeof r;
- i === '__circularReferenceId' && u === 'number'
- ? ((t[r] = n), delete n[i])
- : u === 'object' &&
- r &&
- (r.__proxyFunctionId
- ? (n[i] = function() {
- return o.invokeRemoteMethod(
- 'proxy' + r.__proxyFunctionId,
- '__proxyFunctions',
- Array.prototype.slice.call(arguments, 0),
- null,
- { includeUnderscoreProperties: !0 }
- );
- })
- : r.__proxyDate
- ? (n[i] = new Date(r.__proxyDate))
- : r.__circularReference
- ? (n[i] = t[r.__circularReference])
- : e._customDeserializeObject(r, t));
- }),
- n instanceof Array)
- )
- for (i = 0, u = n.length; i < u; i++) r(n, i);
- else if (typeof n == 'object') for (f in n) r(n, f);
- return n;
- }),
- (t._nextChannelId = 1),
- (t.MAX_XDM_DEPTH = 100),
- (t.WINDOW_TYPES_TO_SKIP_SERIALIZATION = ['Node', 'Window', 'Event']),
- (t.JQUERY_TYPES_TO_SKIP_SERIALIZATION = ['jQuery']),
- t
- );
- })();
- n.XDMChannel = r;
- e = (function() {
- function n() {
- this._channels = [];
- this._subscribe(window);
- }
- return (
- (n.get = function() {
- return this._default || (this._default = new n()), this._default;
- }),
- (n.prototype.addChannel = function(n, t) {
- var i = new r(n, t);
- return this._channels.push(i), i;
- }),
- (n.prototype.removeChannel = function(n) {
- this._channels = this._channels.filter(function(t) {
- return t !== n;
- });
- }),
- (n.prototype._handleMessageReceived = function(n) {
- var i, e, r, t, u, f;
- if (typeof n.data == 'string')
- try {
- t = JSON.parse(n.data);
- } catch (o) {}
- if (t) {
- for (u = !1, i = 0, e = this._channels.length; i < e; i++)
- (r = this._channels[i]),
- r.owns(n.source, n.origin, t) && ((f = r), (u = r.onMessage(t, n.origin) || u));
- !f ||
- u ||
- (window.console &&
- console.error('No handler found on any channel for message: ' + JSON.stringify(t)),
- t.instanceId &&
- f.error(t, 'The registered object ' + t.instanceId + ' could not be found.'));
- }
- }),
- (n.prototype._subscribe = function(n) {
- var t = this;
- n.addEventListener
- ? n.addEventListener('message', function(n) {
- t._handleMessageReceived(n);
- })
- : n.attachEvent('onmessage', function(n) {
- t._handleMessageReceived(n);
- });
- }),
- n
- );
- })();
- n.XDMChannelManager = e;
-})(XDM || (XDM = {})),
- (function(n) {
- function at() {
- function r() {
- n ||
- (n = setTimeout(function() {
- n = 0;
- tt();
- }, 50));
- }
- var n,
- i = !1,
- t;
- try {
- i = typeof document.cookie == 'string';
- } catch (f) {}
- i ||
- Object.defineProperty(Document.prototype, 'cookie', {
- get: function() {
- return '';
- },
- set: function() {}
- });
- t = !1;
- try {
- t = !!window.localStorage;
- } catch (f) {}
- t ||
- (delete window.localStorage,
- (u = new g(r)),
- Object.defineProperty(window, 'localStorage', { value: u }),
- delete window.sessionStorage,
- Object.defineProperty(window, 'sessionStorage', { value: new g() }));
- }
- function nt(f) {
- r = f || {};
- e = r.usePlatformScripts;
- a = r.usePlatformStyles;
- window.setTimeout(function() {
- var f = {
- notifyLoadSucceeded: !r.explicitNotifyLoaded,
- extensionReusedCallback: r.extensionReusedCallback,
- vssSDKVersion: n.VssSDKVersion
- };
- i.invokeRemoteMethod('initialHandshake', 'VSS.HostControl', [f]).then(function(n) {
- var f, r, o, h, l, s, v, i;
- if (
- ((t = n.pageContext),
- (b = t.webContext),
- (k = n.initialConfig || {}),
- (d = n.contribution),
- (c = n.extensionContext),
- n.sandboxedStorage)
- ) {
- if (((f = !1), u))
- if (n.sandboxedStorage.localStorage) {
- for (
- r = n.sandboxedStorage.localStorage, o = 0, h = Object.keys(u);
- o < h.length;
- o++
- )
- (i = h[o]), (l = u.getItem(i)), l !== r[i] && ((r[i] = l), (f = !0));
- for (s = 0, v = Object.keys(r); s < v.length; s++) (i = v[s]), u.setItem(i, r[i]);
- } else u.length > 0 && (f = !0);
- lt = !0;
- f && tt();
- }
- e || a ? ht() : w();
- });
- }, 0);
- }
- function tt() {
- var n = { localStorage: JSON.stringify(u || {}) };
- i.invokeRemoteMethod('updateSandboxedStorage', 'VSS.HostControl', [n]);
- }
- function pt(n, t) {
- var i;
- i = typeof n == 'string' ? [n] : n;
- t || (t = function() {});
- l
- ? it(i, t)
- : (r ? e || ((e = !0), s && ((s = !1), ht())) : nt({ usePlatformScripts: !0 }),
- rt(function() {
- it(i, t);
- }));
- }
- function it(n, i) {
- t.diagnostics.bundlingEnabled
- ? window.require(['VSS/Bundling'], function(t) {
- t.requireModules(n).spread(function() {
- i.apply(this, arguments);
- });
- })
- : window.require(n, i);
- }
- function rt(n) {
- s ? window.setTimeout(n, 0) : (f || (f = []), f.push(n));
- }
- function wt() {
- i.invokeRemoteMethod('notifyLoadSucceeded', 'VSS.HostControl');
- }
- function ut(n) {
- i.invokeRemoteMethod('notifyLoadFailed', 'VSS.HostControl', [n]);
- }
- function ft() {
- return b;
- }
- function bt() {
- return k;
- }
- function et() {
- return c;
- }
- function kt() {
- return d;
- }
- function dt(n, t) {
- return ot(n).then(function(n) {
- return (
- t || (t = {}),
- t.webContext || (t.webContext = ft()),
- t.extensionContext || (t.extensionContext = et()),
- n.getInstance(n.id, t)
- );
- });
- }
- function ot(t) {
- var r = XDM.createDeferred();
- return (
- n.ready(function() {
- i
- .invokeRemoteMethod('getServiceContribution', 'vss.hostManagement', [t])
- .then(function(n) {
- var t = n;
- t.getInstance = function(t, i) {
- return st(n, t, i);
- };
- r.resolve(t);
- }, r.reject);
- }),
- r.promise
- );
- }
- function gt(t) {
- var r = XDM.createDeferred();
- return (
- n.ready(function() {
- i
- .invokeRemoteMethod('getContributionsForTarget', 'vss.hostManagement', [t])
- .then(function(n) {
- var t = [];
- n.forEach(function(n) {
- var i = n;
- i.getInstance = function(t, i) {
- return st(n, t, i);
- };
- t.push(i);
- });
- r.resolve(t);
- }, r.reject);
- }),
- r.promise
- );
- }
- function st(t, r, u) {
- var f = XDM.createDeferred();
- return (
- n.ready(function() {
- i
- .invokeRemoteMethod('getBackgroundContributionInstance', 'vss.hostManagement', [
- t,
- r,
- u
- ])
- .then(f.resolve, f.reject);
- }),
- f.promise
- );
- }
- function ni(n, t) {
- i.getObjectRegistry().register(n, t);
- }
- function ti(n) {
- i.getObjectRegistry().unregister(n);
- }
- function ii(n, t) {
- return i.getObjectRegistry().getInstance(n, t);
- }
- function ri() {
- return i.invokeRemoteMethod('getAccessToken', 'VSS.HostControl');
- }
- function ui() {
- return i.invokeRemoteMethod('getAppToken', 'VSS.HostControl');
- }
- function fi(n, t) {
- o || (o = document.getElementsByTagName('body').item(0));
- var r = typeof n == 'number' ? n : o.scrollWidth,
- u = typeof t == 'number' ? t : o.scrollHeight;
- i.invokeRemoteMethod('resize', 'VSS.HostControl', [r, u]);
- }
- function ht() {
- var i = si(t.webContext),
- f,
- g,
- n,
- s,
- o,
- b,
- k,
- nt,
- tt,
- d,
- u;
- if (
- ((window.__vssPageContext = t),
- (window.__cultureInfo = t.microsoftAjaxConfig.cultureInfo),
- a !== !1 &&
- t.coreReferences.stylesheets &&
- t.coreReferences.stylesheets.forEach(function(n) {
- if (n.isCoreStylesheet) {
- var t = document.createElement('link');
- t.href = h(n.url, i);
- t.rel = 'stylesheet';
- p(t, 'head');
- }
- }),
- !e)
- ) {
- l = !0;
- w();
- return;
- }
- if (
- ((f = []),
- (g = !1),
- t.coreReferences.scripts &&
- (t.coreReferences.scripts.forEach(function(n) {
- if (n.isCoreModule) {
- var r = !1,
- t = window;
- n.identifier === 'JQuery'
- ? (r = !!t.jQuery)
- : n.identifier === 'JQueryUI'
- ? (r = !!(t.jQuery && t.jQuery.ui && t.jQuery.ui.version))
- : n.identifier === 'AMDLoader' &&
- (r = typeof t.define == 'function' && !!t.define.amd);
- r ? (g = !0) : f.push({ source: h(n.url, i) });
- }
- }),
- t.coreReferences.coreScriptsBundle &&
- !g &&
- (f = [{ source: h(t.coreReferences.coreScriptsBundle.url, i) }]),
- t.coreReferences.extensionCoreReferences &&
- f.push({ source: h(t.coreReferences.extensionCoreReferences.url, i) })),
- (n = { baseUrl: c.baseUri, contributionPaths: null, paths: {}, shim: {} }),
- r.moduleLoaderConfig &&
- (r.moduleLoaderConfig.baseUrl && (n.baseUrl = r.moduleLoaderConfig.baseUrl),
- oi(r.moduleLoaderConfig, n),
- ct(r.moduleLoaderConfig, n)),
- t.moduleLoaderConfig &&
- (ct(t.moduleLoaderConfig, n), (s = t.moduleLoaderConfig.contributionPaths), s))
- )
- for (o in s)
- if (
- s.hasOwnProperty(o) &&
- !n.paths[o] &&
- ((b = s[o].value),
- (n.paths[o] = b.match('^https?://') ? b : i + b),
- (k = t.moduleLoaderConfig.paths),
- k)
- ) {
- nt = o + '/';
- tt = v(i, t.moduleLoaderConfig.baseUrl);
- for (d in k)
- ei(d, nt) &&
- ((u = k[d]),
- u.match('^https?://') || (u = u[0] === '/' ? v(i, u) : v(tt, u)),
- (n.paths[d] = u));
- }
- window.__vssModuleLoaderConfig = n;
- f.push({ content: 'require.config(' + JSON.stringify(n) + ');' });
- y(f, 0, function() {
- l = !0;
- w();
- });
- }
- function ei(n, t) {
- return n && n.length >= t.length ? n.substr(0, t.length).localeCompare(t) === 0 : !1;
- }
- function v(n, t) {
- var i = n || '';
- return i[i.length - 1] !== '/' && (i += '/'), t && (i += t[0] === '/' ? t.substr(1) : t), i;
- }
- function oi(n, t, i) {
- var r, u;
- if (n.paths) {
- t.paths || (t.paths = {});
- for (r in n.paths)
- n.paths.hasOwnProperty(r) &&
- ((u = n.paths[r]), i && (u = i(r, n.paths[r])), u && (t.paths[r] = u));
- }
- }
- function ct(n, t) {
- if (n.shim) {
- t.shim || (t.shim = {});
- for (var i in n.shim) n.shim.hasOwnProperty(i) && (t.shim[i] = n.shim[i]);
- }
- }
- function si(n) {
- var r = n.account || n.host,
- t = r.uri,
- i = r.relativeUri;
- return (
- t &&
- i &&
- (t[t.length - 1] !== '/' && (t += '/'),
- i[i.length - 1] !== '/' && (i += '/'),
- (t = t.substr(0, t.length - i.length))),
- t
- );
- }
- function y(n, t, i) {
- var f = this,
- r,
- u;
- if (t >= n.length) {
- i.call(this);
- return;
- }
- r = document.createElement('script');
- r.type = 'text/javascript';
- n[t].source
- ? ((u = n[t].source),
- (r.src = u),
- r.addEventListener('load', function() {
- y.call(f, n, t + 1, i);
- }),
- r.addEventListener('error', function() {
- ut('Failed to load script: ' + u);
- }),
- p(r, 'head'))
- : n[t].content && ((r.textContent = n[t].content), p(r, 'head'), y.call(this, n, t + 1, i));
- }
- function p(n, t) {
- var i = document.getElementsByTagName(t)[0];
- i || ((i = document.createElement(t)), document.appendChild(i));
- i.appendChild(n);
- }
- function h(n, t) {
- var i = (n || '').toLowerCase();
- return (
- i.substr(0, 2) !== '//' &&
- i.substr(0, 5) !== 'http:' &&
- i.substr(0, 6) !== 'https:' &&
- (n = t + (i[0] === '/' ? '' : '/') + n),
- n
- );
- }
- function w() {
- var t = this,
- n;
- s = !0;
- f &&
- ((n = f),
- (f = null),
- n.forEach(function(n) {
- n.call(t);
- }));
- }
- var yt;
- n.VssSDKVersion = 2;
- n.VssSDKRestVersion = '4.0';
- var o,
- b,
- t,
- c,
- k,
- d,
- r,
- l = !1,
- e,
- a,
- s = !1,
- f,
- i = XDM.XDMChannelManager.get().addChannel(window.parent),
- u,
- lt = !1,
- g = (function() {
- function n() {
- t && t.call(this);
- }
- function i() {}
- var t;
- return (
- Object.defineProperties(i.prototype, {
- getItem: {
- get: function() {
- return function(n) {
- var t = this['' + n];
- return typeof t == 'undefined' ? null : t;
- };
- }
- },
- setItem: {
- get: function() {
- return function(t, i) {
- t = '' + t;
- var u = this[t],
- r = '' + i;
- u !== r && ((this[t] = r), n());
- };
- }
- },
- removeItem: {
- get: function() {
- return function(t) {
- t = '' + t;
- typeof this[t] != 'undefined' && (delete this[t], n());
- };
- }
- },
- clear: {
- get: function() {
- return function() {
- var r = Object.keys(this),
- t,
- i,
- u;
- if (r.length > 0) {
- for (t = 0, i = r; t < i.length; t++) (u = i[t]), delete this[u];
- n();
- }
- };
- }
- },
- key: {
- get: function() {
- return function(n) {
- return Object.keys(this)[n];
- };
- }
- },
- length: {
- get: function() {
- return Object.keys(this).length;
- }
- }
- }),
- i
- );
- })();
- if (!window.__vssNoSandboxShim)
- try {
- at();
- } catch (vt) {
- window.console &&
- window.console.warn &&
- window.console.warn(
- 'Failed to shim support for sandboxed properties: ' +
- vt.message +
- '. Set "window.__vssNoSandboxShim = true" in order to bypass the shim of sandboxed properties.'
- );
- }
- (function(n) {
- n.Dialog = 'ms.vss-web.dialog-service';
- n.Navigation = 'ms.vss-web.navigation-service';
- n.ExtensionData = 'ms.vss-web.data-service';
- })((yt = n.ServiceIds || (n.ServiceIds = {})));
- n.init = nt;
- n.require = pt;
- n.ready = rt;
- n.notifyLoadSucceeded = wt;
- n.notifyLoadFailed = ut;
- n.getWebContext = ft;
- n.getConfiguration = bt;
- n.getExtensionContext = et;
- n.getContribution = kt;
- n.getService = dt;
- n.getServiceContribution = ot;
- n.getServiceContributions = gt;
- n.register = ni;
- n.unregister = ti;
- n.getRegisteredObject = ii;
- n.getAccessToken = ri;
- n.getAppToken = ui;
- n.resize = fi;
- })(VSS || (VSS = {}));
diff --git a/server/sonar-web/src/main/js/typings/rc-tooltip.d.ts b/server/sonar-web/src/main/js/typings/rc-tooltip.d.ts
deleted file mode 100644
index 999b5b02c84..00000000000
--- a/server/sonar-web/src/main/js/typings/rc-tooltip.d.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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.
- */
-declare module 'rc-tooltip' {
- export type Trigger = 'hover' | 'click' | 'focus';
- export type Placement =
- | 'left'
- | 'right'
- | 'top'
- | 'bottom'
- | 'topLeft'
- | 'topRight'
- | 'bottomLeft'
- | 'bottomRight';
-
- export interface Props extends React.Props<any> {
- overlayClassName?: string;
- trigger?: Trigger[];
- mouseEnterDelay?: number;
- mouseLeaveDelay?: number;
- overlayStyle?: React.CSSProperties;
- prefixCls?: string;
- transitionName?: string;
- onVisibleChange?: () => void;
- visible?: boolean;
- defaultVisible?: boolean;
- placement?: Placement | Object;
- align?: Object;
- onPopupAlign?: (popupDomNode: Element, align: Object) => void;
- overlay: React.ReactNode;
- arrowContent?: React.ReactNode;
- getTooltipContainer?: () => Element;
- destroyTooltipOnHide?: boolean;
- }
-
- // the next line is crucial, it is absent in the original typings
- export default class Tooltip extends React.Component<Props> {}
-}
diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock
index fed42e3c350..ca97ba90123 100644
--- a/server/sonar-web/yarn.lock
+++ b/server/sonar-web/yarn.lock
@@ -32,12 +32,26 @@
version "1.2.1"
resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-1.2.1.tgz#e489605208d46a1c9d980d2e5772fa9c75d9ec65"
+"@types/d3-hierarchy@1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-1.1.1.tgz#f1b7f4bab0a9ecfb9c372a303ded97d83db3cbbf"
+
+"@types/d3-path@*":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-1.0.6.tgz#c1a7d2dc07b295fdd1c84dabe4404df991b48693"
+
"@types/d3-scale@2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-2.0.0.tgz#d40f2ff137f4fe9b13b45c5a8e14f39edd498dcf"
dependencies:
"@types/d3-time" "*"
+"@types/d3-shape@1.2.2":
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.2.2.tgz#f8dcdff7772a7ae37858bf04abd43848a78e590e"
+ dependencies:
+ "@types/d3-path" "*"
+
"@types/d3-time@*":
version "1.0.7"
resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-1.0.7.tgz#4266d7c9be15fa81256a88d1d052d61cd8dc572c"