From: Stas Vilchik Date: Tue, 15 May 2018 15:10:00 +0000 (+0200) Subject: rewrite some components in ts (#243) X-Git-Tag: 7.5~1181 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=5386cb6010e7469db0c8f0fa5972973b9a2fa266;p=sonarqube.git rewrite some components in ts (#243) --- 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/@types/json.d.ts b/server/sonar-web/src/main/js/@types/json.d.ts new file mode 100644 index 00000000000..0f858f5d256 --- /dev/null +++ b/server/sonar-web/src/main/js/@types/json.d.ts @@ -0,0 +1,23 @@ +/* + * 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 '*.json' { + const value: any; + export default value; +} 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 { {({ 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 { } 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 ( 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; 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 {
{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 { + barsWidth: number; + data: Array; + height: number; + onBarClick?: (point: DataPoint & T) => void; + padding?: [number, number, number, number]; + width: number; + xTicks?: string[]; + xValues?: string[]; +} + +export default class BarChart extends React.PureComponent> { + handleClick = (point: DataPoint & T) => { + if (this.props.onBarClick) { + this.props.onBarClick(point); + } + }; + + renderXTicks = (xScale: ScaleBand, yScale: ScaleLinear) => { + 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 = ( + this.handleClick(point)} + style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }} + x={x} + y={y}> + {tick} + + ); + return ( + + {text} + + ); + }); + return {ticks}; + }; + + renderXValues = (xScale: ScaleBand, yScale: ScaleLinear) => { + 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 = ( + this.handleClick(point)} + style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }} + x={x} + y={y}> + {value} + + ); + return ( + + {text} + + ); + }); + return {ticks}; + }; + + renderBars = (xScale: ScaleBand, yScale: ScaleLinear) => { + 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 = ( + this.handleClick(point)} + style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }} + width={this.props.barsWidth} + x={x} + y={y} + /> + ); + return ( + + {rect} + + ); + }); + return {bars}; + }; + + 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() + .domain(data.map(d => d.x)) + .range([0, availableWidth]) + .paddingInner(relativeInnerPadding); + const yScale = scaleLinear() + .domain([0, maxY]) + .range([availableHeight, 0]); + + return ( + + + {this.renderXTicks(xScale, yScale)} + {this.renderXValues(xScale, yScale)} + {this.renderBars(xScale, yScale)} + + + ); + } +} 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 { 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 { 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) => { if (this.node && this.state.zoom > 1) { const rect = this.node.getBoundingClientRect(); @@ -176,8 +185,8 @@ export default class BubbleChart extends React.Component { 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 { 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 ( { 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 ( { }; 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 { ); }); - 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 ( { onWheel={this.onWheel} ref={node => (this.node = node)} 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.js deleted file mode 100644 index 6d21cca808f..00000000000 --- a/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.js +++ /dev/null @@ -1,60 +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 classNames from 'classnames'; -import { formatMeasure } from '../../helpers/measures'; - -/*:: type Props = { - className?: string, - colorScale: Object, - colorNA?: string, - metricType: string -}; */ - -export default function ColorBoxLegend( - { className, colorScale, colorNA, metricType } /*: Props */ -) { - const colorDomain = colorScale.domain(); - const colorRange = colorScale.range(); - return ( -
- {colorDomain.map((value, idx) => ( -
- - - - {formatMeasure(value, metricType)} -
- ))} - {colorNA && ( -
- - - - N/A -
- )} -
- ); -} diff --git a/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx b/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx new file mode 100644 index 00000000000..cf2a140d2a2 --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx @@ -0,0 +1,60 @@ +/* + * 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 * as classNames from 'classnames'; +import { ScaleLinear, ScaleOrdinal } from 'd3-scale'; +import { formatMeasure } from '../../helpers/measures'; + +interface Props { + className?: string; + colorNA?: string; + colorScale: + | ScaleOrdinal // used for LEVEL type + | ScaleLinear; // used for RATING or PERCENT type + metricType: string; +} + +export default function ColorBoxLegend({ className, colorScale, colorNA, metricType }: Props) { + const colorDomain: Array = colorScale.domain(); + const colorRange = colorScale.range(); + return ( +
+ {colorDomain.map((value, idx) => ( +
+ + + + {formatMeasure(value, metricType)} +
+ ))} + {colorNA && ( +
+ + + + N/A +
+ )} +
+ ); +} diff --git a/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.js b/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.js deleted file mode 100644 index 06ca596b336..00000000000 --- a/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.js +++ /dev/null @@ -1,98 +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'; - -/*:: type Props = { - className?: string, - colorScale: Object, - colorNA?: string, - direction?: number, - padding?: Array, - height: 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(); - if (direction === 1) { - colorRange.reverse(); - } - - const colorDomain = colorScale.domain(); - const lastColorIdx = colorRange.length - 1; - const lastDomainIdx = colorDomain.length - 1; - const widthNoPadding = width - padding[1]; - const rectHeight = height - padding[0]; - return ( - - - - {colorRange.map((color, idx) => ( - - ))} - - - - - {colorDomain.map((d, idx) => ( - - {d} - - ))} - - {colorNA && ( - - - - N/A - - - )} - - ); -} diff --git a/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx b/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx new file mode 100644 index 00000000000..5ea00b6be59 --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx @@ -0,0 +1,98 @@ +/* + * 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 { ScaleLinear, ScaleOrdinal } from 'd3-scale'; + +interface Props { + className?: string; + colorNA?: string; + colorScale: + | ScaleOrdinal // used for LEVEL type + | ScaleLinear; // 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: Array = colorScale.range(); + if (direction === 1) { + colorRange.reverse(); + } + + const colorDomain: Array = colorScale.domain(); + const lastColorIdx = colorRange.length - 1; + const lastDomainIdx = colorDomain.length - 1; + const widthNoPadding = width - padding[1]; + const rectHeight = height - padding[0]; + return ( + + + + {colorRange.map((color, idx) => ( + + ))} + + + + + {colorDomain.map((d, idx) => ( + + {d} + + ))} + + {colorNA && ( + + + + N/A + + + )} + + ); +} diff --git a/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.js b/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.js deleted file mode 100644 index 3d8a07b375c..00000000000 --- a/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.js +++ /dev/null @@ -1,44 +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 classNames from 'classnames'; -import { formatMeasure } from '../../helpers/measures'; -import { RATING_COLORS } from '../../helpers/constants'; - -export default function ColorRatingsLegend({ className } /*: { className?: string } */) { - return ( -
- {[1, 2, 3, 4, 5].map(rating => ( -
- - - - {formatMeasure(rating, 'RATING')} -
- ))} -
- ); -} diff --git a/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.tsx b/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.tsx new file mode 100644 index 00000000000..80e44f7c11e --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/ColorRatingsLegend.tsx @@ -0,0 +1,47 @@ +/* + * 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 * as classNames from 'classnames'; +import { formatMeasure } from '../../helpers/measures'; +import { RATING_COLORS } from '../../helpers/constants'; + +interface Props { + className?: string; +} + +export default function ColorRatingsLegend({ className }: Props) { + return ( +
+ {[1, 2, 3, 4, 5].map(rating => ( +
+ + + + {formatMeasure(rating, '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() + .sort(null) + .value(d => d.value); + + const sectors = pie(props.data).map((d, i) => { + return ( + + ); + }); + + return ( + + + {sectors} + + + ); +} + +interface SectorProps { + data: PieArcDatum; + fill: string; + radius: number; + thickness: number; +} + +function Sector(props: SectorProps) { + const arc = d3Arc>() + .outerRadius(props.radius) + .innerRadius(props.radius - props.thickness); + const d = arc(props.data) as string; + return ; +} diff --git a/server/sonar-web/src/main/js/components/charts/LineChart.tsx b/server/sonar-web/src/main/js/components/charts/LineChart.tsx new file mode 100644 index 00000000000..2d8d5f18058 --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/LineChart.tsx @@ -0,0 +1,192 @@ +/* + * 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 { extent, max } from 'd3-array'; +import { scaleLinear, ScaleLinear } from 'd3-scale'; +import { area as d3Area, line as d3Line, curveBasis } from 'd3-shape'; +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 { + renderBackdrop(xScale: ScaleLinear, yScale: ScaleLinear) { + const { displayBackdrop = true } = this.props; + + if (!displayBackdrop) { + return null; + } + + const area = d3Area() + .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; + if (this.props.backdropConstraints) { + const c = this.props.backdropConstraints; + data = data.filter(d => c[0] <= d.x && d.x <= c[1]); + } + + return ; + } + + renderPoints(xScale: ScaleLinear, yScale: ScaleLinear) { + 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 ; + }); + return {points}; + } + + renderVerticalGrid(xScale: ScaleLinear, yScale: ScaleLinear) { + 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 ; + }); + return {lines}; + } + + renderXTicks(xScale: ScaleLinear, yScale: ScaleLinear) { + const { xTicks = [] } = this.props; + + if (!xTicks.length) { + return null; + } + + const ticks = xTicks.map((tick, index) => { + const point = this.props.data[index]; + const x = xScale(point.x); + const y = yScale.range()[0]; + return ( + + {tick} + + ); + }); + return {ticks}; + } + + renderXValues(xScale: ScaleLinear, yScale: ScaleLinear) { + const { xValues = [] } = this.props; + + if (!xValues.length) { + return null; + } + + const ticks = xValues.map((value, index) => { + const point = this.props.data[index]; + const x = xScale(point.x); + const y = yScale(point.y); + return ( + + {value} + + ); + }); + return {ticks}; + } + + renderLine(xScale: ScaleLinear, yScale: ScaleLinear) { + const p = d3Line() + .x(d => xScale(d.x)) + .y(d => yScale(d.y)) + .defined(d => d.y != null) + .curve(curveBasis); + return ; + } + + renderChart = (width: number) => { + const { height, padding = [10, 10, 10, 10] } = this.props; + + if (!width || !height) { + return
; + } + + const availableWidth = width - padding[1] - padding[3]; + const availableHeight = height - padding[0] - padding[2]; + + const xScale = scaleLinear() + .domain(extent(this.props.data, d => d.x) as [number, number]) + .range([0, availableWidth]); + const yScale = scaleLinear().range([availableHeight, 0]); + + if (this.props.domain) { + yScale.domain(this.props.domain); + } else { + const maxY = max(this.props.data, d => d.y) as number; + yScale.domain([0, maxY]); + } + + return ( + + + {this.renderVerticalGrid(xScale, yScale)} + {this.renderBackdrop(xScale, yScale)} + {this.renderLine(xScale, yScale)} + {this.renderPoints(xScale, yScale)} + {this.renderXTicks(xScale, yScale)} + {this.renderXValues(xScale, yScale)} + + + ); + }; + + render() { + return this.props.width !== undefined ? ( + this.renderChart(this.props.width) + ) : ( + {size => this.renderChart(size.width)} + ); + } +} diff --git a/server/sonar-web/src/main/js/components/charts/TreeMap.js b/server/sonar-web/src/main/js/components/charts/TreeMap.js deleted file mode 100644 index 2b526fd0fe2..00000000000 --- a/server/sonar-web/src/main/js/components/charts/TreeMap.js +++ /dev/null @@ -1,115 +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 { 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 -}; */ - -/*:: type Props = {| - items: Array, - onRectangleClick?: string => void, - height: number, - width: number -|}; */ - -export default class TreeMap extends React.PureComponent { - /*:: props: Props; */ - - mostCommitPrefix = (labels /*: Array */) => { - const sortedLabels = labels.slice(0).sort(); - const firstLabel = sortedLabels[0]; - const firstLabelLength = firstLabel.length; - const lastLabel = sortedLabels[sortedLabels.length - 1]; - let i = 0; - while (i < firstLabelLength && firstLabel.charAt(i) === lastLabel.charAt(i)) { - i++; - } - const prefix = firstLabel.substr(0, i); - const prefixTokens = prefix.split(/[\s\\/]/); - const lastPrefixPart = prefixTokens[prefixTokens.length - 1]; - return prefix.substr(0, prefix.length - lastPrefixPart.length); - }; - - renderNoData() { - return ( -
-
- {translate('no_data')} -
-
- ); - } - - render() { - const { items, height, width } = this.props; - if (items.length <= 0) { - return this.renderNoData(); - } - - const hierarchy = d3Hierarchy({ children: items }) - .sum(d => d.size) - .sort((a, b) => b.value - a.value); - - const treemap = d3Treemap() - .round(true) - .size([width, height]); - - const nodes = treemap(hierarchy).leaves(); - const prefix = this.mostCommitPrefix(items.map(item => item.label)); - const halfWidth = width / 2; - return ( -
-
- {nodes.map(node => ( - - ))} -
-
- ); - } -} diff --git a/server/sonar-web/src/main/js/components/charts/TreeMap.tsx b/server/sonar-web/src/main/js/components/charts/TreeMap.tsx new file mode 100644 index 00000000000..9ee5d2320f7 --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/TreeMap.tsx @@ -0,0 +1,116 @@ +/* + * 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 { treemap as d3Treemap, hierarchy as d3Hierarchy } from 'd3-hierarchy'; +import TreeMapRect from './TreeMapRect'; +import { translate } from '../../helpers/l10n'; + +interface TreeMapItem { + color: string; + icon?: React.ReactNode; + key: string; + label: string; + link?: string; + size: number; + tooltip?: React.ReactNode; +} + +interface HierarchicalTreemapItem extends TreeMapItem { + children?: TreeMapItem[]; +} + +interface Props { + height: number; + items: TreeMapItem[]; + onRectangleClick?: (item: string) => void; + width: number; +} + +export default class TreeMap extends React.PureComponent { + mostCommitPrefix = (labels: string[]) => { + const sortedLabels = labels.slice(0).sort(); + const firstLabel = sortedLabels[0]; + const firstLabelLength = firstLabel.length; + const lastLabel = sortedLabels[sortedLabels.length - 1]; + let i = 0; + while (i < firstLabelLength && firstLabel.charAt(i) === lastLabel.charAt(i)) { + i++; + } + const prefix = firstLabel.substr(0, i); + const prefixTokens = prefix.split(/[\s\\/]/); + const lastPrefixPart = prefixTokens[prefixTokens.length - 1]; + return prefix.substr(0, prefix.length - lastPrefixPart.length); + }; + + renderNoData() { + return ( +
+
+ {translate('no_data')} +
+
+ ); + } + + render() { + const { items, height, width } = this.props; + if (items.length <= 0) { + return this.renderNoData(); + } + + const hierarchy = d3Hierarchy({ children: items } as HierarchicalTreemapItem) + .sum(d => d.size) + .sort((a, b) => (b.value || 0) - (a.value || 0)); + + const treemap = d3Treemap() + .round(true) + .size([width, height]); + + const nodes = treemap(hierarchy).leaves(); + const prefix = this.mostCommitPrefix(items.map(item => item.label)); + const halfWidth = width / 2; + return ( +
+
+ {nodes.map(node => ( + + ))} +
+
+ ); + } +} diff --git a/server/sonar-web/src/main/js/components/charts/TreeMapRect.js b/server/sonar-web/src/main/js/components/charts/TreeMapRect.js deleted file mode 100644 index 9cc3c2e0738..00000000000 --- a/server/sonar-web/src/main/js/components/charts/TreeMapRect.js +++ /dev/null @@ -1,121 +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 { Link } from 'react-router'; -import classNames from 'classnames'; -import { scaleLinear } from 'd3-scale'; -import LinkIcon from '../icons-components/LinkIcon'; -import Tooltip 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; */ - - handleLinkClick = (e /*: Event */) => e.stopPropagation(); - - handleRectClick = () => { - if (this.props.onClick != null) { - this.props.onClick(this.props.itemKey); - } - }; - - renderLink = () => { - const { link, height, width } = this.props; - const hasMinSize = width >= 24 && height >= 24 && (width >= 48 || height >= 50); - if (!hasMinSize || link == null) { - return null; - } - return ( - - - - ); - }; - - renderCell = () => { - const cellStyles = { - left: this.props.x, - top: this.props.y, - width: this.props.width, - height: this.props.height, - backgroundColor: this.props.fill, - fontSize: SIZE_SCALE(this.props.width / this.props.label.length), - lineHeight: `${this.props.height}px`, - cursor: this.props.onClick != null ? 'pointer' : 'default' - }; - const isTextVisible = this.props.width >= 40 && this.props.height >= 45; - const isIconVisible = this.props.width >= 24 && this.props.height >= 26; - - const label = this.props.prefix - ? `${this.props.prefix}
${this.props.label.substr(this.props.prefix.length)}` - : this.props.label; - - return ( -
-
- {isIconVisible && ( - - {this.props.icon} - - )} - {isTextVisible && ( - - )} -
- {this.renderLink()} -
- ); - }; - - render() { - const { placement, tooltip } = this.props; - return ( - - {this.renderCell()} - - ); - } -} diff --git a/server/sonar-web/src/main/js/components/charts/TreeMapRect.tsx b/server/sonar-web/src/main/js/components/charts/TreeMapRect.tsx new file mode 100644 index 00000000000..75e8cdc8db5 --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/TreeMapRect.tsx @@ -0,0 +1,120 @@ +/* + * 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 { Link } from 'react-router'; +import * as classNames from 'classnames'; +import { scaleLinear } from 'd3-scale'; +import LinkIcon from '../icons-components/LinkIcon'; +import Tooltip, { Placement } from '../controls/Tooltip'; + +const SIZE_SCALE = scaleLinear() + .domain([3, 15]) + .range([11, 18]) + .clamp(true); + +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; +} + +export default class TreeMapRect extends React.PureComponent { + handleLinkClick = (event: React.MouseEvent) => { + event.stopPropagation(); + }; + + handleRectClick = () => { + if (this.props.onClick) { + this.props.onClick(this.props.itemKey); + } + }; + + renderLink = () => { + const { link, height, width } = this.props; + const hasMinSize = width >= 24 && height >= 24 && (width >= 48 || height >= 50); + if (!hasMinSize || link == null) { + return null; + } + return ( + + + + ); + }; + + renderCell = () => { + const cellStyles = { + left: this.props.x, + top: this.props.y, + width: this.props.width, + height: this.props.height, + backgroundColor: this.props.fill, + fontSize: SIZE_SCALE(this.props.width / this.props.label.length), + lineHeight: `${this.props.height}px`, + cursor: this.props.onClick != null ? 'pointer' : 'default' + }; + const isTextVisible = this.props.width >= 40 && this.props.height >= 45; + const isIconVisible = this.props.width >= 24 && this.props.height >= 26; + + const label = this.props.prefix + ? `${this.props.prefix}
${this.props.label.substr(this.props.prefix.length)}` + : this.props.label; + + return ( +
+
+ {isIconVisible && ( + + {this.props.icon} + + )} + {isTextVisible && ( + + )} +
+ {this.renderLink()} +
+ ); + }; + + render() { + const { placement, tooltip } = this.props; + return ( + + {this.renderCell()} + + ); + } +} diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/BarChart-test.tsx b/server/sonar-web/src/main/js/components/charts/__tests__/BarChart-test.tsx new file mode 100644 index 00000000000..0b109c12b0a --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/__tests__/BarChart-test.tsx @@ -0,0 +1,57 @@ +/* + * 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 { shallow } from 'enzyme'; +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(); + expect(chart.find('.bar-chart-bar').length).toBe(3); +}); + +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( + + ); + expect(chart.find('.bar-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( + + ); + expect(chart.find('.bar-chart-tick').length).toBe(3); +}); + +it('should display bars, ticks and values', () => { + const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }]; + const ticks = ['A', 'B', 'C']; + const values = ['A', 'B', 'C']; + const chart = shallow( + + ); + 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.js deleted file mode 100644 index 347d1df976e..00000000000 --- a/server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.js +++ /dev/null @@ -1,41 +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 { 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(); - 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(); - 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(); - chart.find(Bubble).forEach(bubble => expect(bubble).toMatchSnapshot()); -}); diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.tsx b/server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.tsx new file mode 100644 index 00000000000..07c73da2b87 --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/__tests__/BubbleChart-test.tsx @@ -0,0 +1,41 @@ +/* + * 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 { 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(); + 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(); + 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(); + chart.find(Bubble).forEach(bubble => expect(bubble).toMatchSnapshot()); +}); diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/LineChart-test.tsx b/server/sonar-web/src/main/js/components/charts/__tests__/LineChart-test.tsx new file mode 100644 index 00000000000..533bd5aeddb --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/__tests__/LineChart-test.tsx @@ -0,0 +1,42 @@ +/* + * 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 { shallow } from 'enzyme'; +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(); + 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(); + 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(); + 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.js deleted file mode 100644 index 246f3a840b8..00000000000 --- a/server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.js +++ /dev/null @@ -1,34 +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 { shallow } from 'enzyme'; -import TreeMap from '../TreeMap'; - -it('should display', () => { - const items = [ - { key: '1', size: 10, color: '#777', label: 'SonarQube :: Server' }, - { key: '2', size: 30, color: '#777', label: 'SonarQube :: Web' }, - { key: '3', size: 20, color: '#777', label: 'SonarQube :: Search' } - ]; - const chart = shallow( - {}} /> - ); - expect(chart.find('TreeMapRect')).toHaveLength(3); -}); diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.tsx b/server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.tsx new file mode 100644 index 00000000000..96fbe933b41 --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/__tests__/TreeMap-test.tsx @@ -0,0 +1,34 @@ +/* + * 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 { shallow } from 'enzyme'; +import TreeMap from '../TreeMap'; + +it('should display', () => { + const items = [ + { key: '1', size: 10, color: '#777', label: 'SonarQube :: Server' }, + { key: '2', size: 30, color: '#777', label: 'SonarQube :: Web' }, + { key: '3', size: 20, color: '#777', label: 'SonarQube :: Search' } + ]; + const chart = shallow( + {}} 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.js.snap deleted file mode 100644 index fbbd76666bd..00000000000 --- a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.js.snap +++ /dev/null @@ -1,181 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display bubbles 1`] = ` - - - - - - - -`; - -exports[`should display bubbles 2`] = ` - - - - - - - -`; - -exports[`should render bubble links 1`] = ` - - - - - - - - - - - -`; - -exports[`should render bubble links 2`] = ` - - - - - - - - - - - -`; - -exports[`should render bubbles with click handlers 1`] = ` - - - - - - - -`; - -exports[`should render bubbles with click handlers 2`] = ` - - - - - - - -`; diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.tsx.snap b/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.tsx.snap new file mode 100644 index 00000000000..fbbd76666bd --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/BubbleChart-test.tsx.snap @@ -0,0 +1,181 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should display bubbles 1`] = ` + + + + + + + +`; + +exports[`should display bubbles 2`] = ` + + + + + + + +`; + +exports[`should render bubble links 1`] = ` + + + + + + + + + + + +`; + +exports[`should render bubble links 2`] = ` + + + + + + + + + + + +`; + +exports[`should render bubbles with click handlers 1`] = ` + + + + + + + +`; + +exports[`should render bubbles with click handlers 2`] = ` + + + + + + + +`; 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__/bar-chart-test.js deleted file mode 100644 index 933ac88ca14..00000000000 --- a/server/sonar-web/src/main/js/components/charts/__tests__/bar-chart-test.js +++ /dev/null @@ -1,57 +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 { shallow } from 'enzyme'; -import { BarChart } from '../bar-chart'; - -it('should display bars', () => { - const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }]; - const chart = shallow(); - expect(chart.find('.bar-chart-bar').length).toBe(3); -}); - -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( - - ); - expect(chart.find('.bar-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( - - ); - expect(chart.find('.bar-chart-tick').length).toBe(3); -}); - -it('should display bars, ticks and values', () => { - const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }]; - const ticks = ['A', 'B', 'C']; - const values = ['A', 'B', 'C']; - const chart = shallow( - - ); - 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__/line-chart-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/line-chart-test.js deleted file mode 100644 index 9b2b0018c8a..00000000000 --- a/server/sonar-web/src/main/js/components/charts/__tests__/line-chart-test.js +++ /dev/null @@ -1,42 +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 { shallow } from 'enzyme'; -import { LineChart } from '../line-chart'; - -it('should display line', () => { - const data = [{ x: 1, y: 10 }, { x: 2, y: 30 }, { x: 3, y: 20 }]; - const chart = shallow(); - 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(); - 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(); - expect(chart.find('.line-chart-tick').length).toBe(3); -}); 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 = ( - - {tick} - - ); - return ( - - {text} - - ); - }); - return {ticks}; - }, - - 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 = ( - - {value} - - ); - return ( - - {text} - - ); - }); - return {ticks}; - }, - - 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 = ( - - ); - return ( - - {rect} - - ); - }); - return {bars}; - }, - - render() { - if (!this.state.width || !this.state.height) { - return
; - } - - 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 ( - - - {this.renderXTicks(xScale, yScale)} - {this.renderXValues(xScale, yScale)} - {this.renderBars(xScale, yScale)} - - - ); - } -}); 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 ; -} - -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
; - } - - 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 ( - - ); - }); - - return ( - - - {sectors} - - - ); - } -}); diff --git a/server/sonar-web/src/main/js/components/charts/line-chart.js b/server/sonar-web/src/main/js/components/charts/line-chart.js deleted file mode 100644 index af99622368b..00000000000 --- a/server/sonar-web/src/main/js/components/charts/line-chart.js +++ /dev/null @@ -1,183 +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 { extent, max } from 'd3-array'; -import { 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) { - return null; - } - - const area = d3Area() - .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; - if (this.props.backdropConstraints) { - const c = this.props.backdropConstraints; - data = data.filter(d => c[0] <= d.x && d.x <= c[1]); - } - return ; - }, - - renderPoints(xScale, yScale) { - if (!this.props.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 ; - }); - return {points}; - }, - - renderVerticalGrid(xScale, yScale) { - if (!this.props.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 ; - }); - return {lines}; - }, - - 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 = xScale(point.x); - const y = yScale.range()[0]; - return ( - - {tick} - - ); - }); - return {ticks}; - }, - - 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 = xScale(point.x); - const y = yScale(point.y); - return ( - - {value} - - ); - }); - return {ticks}; - }, - - renderLine(xScale, yScale) { - const p = d3Line() - .x(d => xScale(d.x)) - .y(d => yScale(d.y)) - .defined(d => d.y != null) - .curve(curveBasis); - return ; - }, - - render() { - if (!this.state.width || !this.state.height) { - return
; - } - - 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]; - - let maxY; - const xScale = scaleLinear() - .domain(extent(this.props.data, d => d.x)) - .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); - yScale.domain([0, maxY]); - } - - return ( - - - {this.renderVerticalGrid(xScale, yScale, maxY)} - {this.renderBackdrop(xScale, yScale)} - {this.renderLine(xScale, yScale)} - {this.renderPoints(xScale, yScale)} - {this.renderXTicks(xScale, yScale)} - {this.renderXValues(xScale, yScale)} - - - ); - } -}); diff --git a/server/sonar-web/src/main/js/components/common/ClockIcon.js b/server/sonar-web/src/main/js/components/common/ClockIcon.js deleted file mode 100644 index e0e696128aa..00000000000 --- a/server/sonar-web/src/main/js/components/common/ClockIcon.js +++ /dev/null @@ -1,49 +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 classNames from 'classnames'; - -/*:: -type Props = { - className?: string, - size?: number -}; -*/ - -export default function ClockIcon(props /*: Props */) { - /* eslint max-len: 0 */ - return ( - - - - - - - ); -} - -ClockIcon.defaultProps = { - size: 16 -}; diff --git a/server/sonar-web/src/main/js/components/common/LocationIndex.js b/server/sonar-web/src/main/js/components/common/LocationIndex.js deleted file mode 100644 index f3ae1bf7e88..00000000000 --- a/server/sonar-web/src/main/js/components/common/LocationIndex.js +++ /dev/null @@ -1,51 +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 classNames from 'classnames'; -import './LocationIndex.css'; - -/*:: -type Props = { - children?: React.Element<*>, - leading?: boolean, - onClick?: () => void, - selected?: boolean -}; -*/ - -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 ( -
- {children} -
- ); -} - -LocationIndex.defaultProps = { - selected: false -}; diff --git a/server/sonar-web/src/main/js/components/common/LocationIndex.tsx b/server/sonar-web/src/main/js/components/common/LocationIndex.tsx new file mode 100644 index 00000000000..15b143e7876 --- /dev/null +++ b/server/sonar-web/src/main/js/components/common/LocationIndex.tsx @@ -0,0 +1,47 @@ +/* + * 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 * as classNames from 'classnames'; +import './LocationIndex.css'; + +interface Props { + children?: React.ReactNode; + leading?: boolean; + onClick?: () => void; + selected?: boolean; + [x: string]: any; +} + +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 ( +
+ {children} +
+ ); +} diff --git a/server/sonar-web/src/main/js/components/common/LocationMessage.js b/server/sonar-web/src/main/js/components/common/LocationMessage.js deleted file mode 100644 index 491ac9e5460..00000000000 --- a/server/sonar-web/src/main/js/components/common/LocationMessage.js +++ /dev/null @@ -1,38 +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 classNames from 'classnames'; -import './LocationMessage.css'; - -/*:: -type Props = { - children?: React.Element<*>, - selected: boolean -}; -*/ - -export default function LocationMessage(props /*: Props */) { - return ( -
- {props.children} -
- ); -} diff --git a/server/sonar-web/src/main/js/components/common/LocationMessage.tsx b/server/sonar-web/src/main/js/components/common/LocationMessage.tsx new file mode 100644 index 00000000000..bcee4be2683 --- /dev/null +++ b/server/sonar-web/src/main/js/components/common/LocationMessage.tsx @@ -0,0 +1,35 @@ +/* + * 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 * as classNames from 'classnames'; +import './LocationMessage.css'; + +interface Props { + children?: React.ReactNode; + selected: boolean; +} + +export default function LocationMessage(props: Props) { + return ( +
+ {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.js deleted file mode 100644 index d4b52885ac0..00000000000 --- a/server/sonar-web/src/main/js/components/common/OrganizationHelmet.js +++ /dev/null @@ -1,34 +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 Helmet from 'react-helmet'; - -/*:: -type Props = { - title: string, - organization?: ?{ name: string } -}; -*/ - -export default function OrganizationHelmet({ title, organization } /*: Props */) { - const defaultTitle = title + (organization ? ' - ' + organization.name : ''); - return ; -} diff --git a/server/sonar-web/src/main/js/components/common/OrganizationHelmet.tsx b/server/sonar-web/src/main/js/components/common/OrganizationHelmet.tsx new file mode 100644 index 00000000000..e842eaae6c7 --- /dev/null +++ b/server/sonar-web/src/main/js/components/common/OrganizationHelmet.tsx @@ -0,0 +1,31 @@ +/* + * 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 Helmet from 'react-helmet'; + +interface Props { + organization?: { name: string }; + title: string; +} + +export default function OrganizationHelmet({ title, organization }: Props) { + const defaultTitle = title + (organization ? ' - ' + organization.name : ''); + return ; +} diff --git a/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.js b/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.js deleted file mode 100644 index b6934cea2c6..00000000000 --- a/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.js +++ /dev/null @@ -1,53 +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 { Link } from 'react-router'; -import { translate, hasMessage } from '../../helpers/l10n'; -import './UpgradeOrganizationBox.css'; - -/*:: -type Props = { - organization: string -}; -*/ - -export default function UpgradeOrganizationBox(props /*: Props */) { - return ( -
-

{translate('billing.upgrade_box.header')}

- -

{translate('billing.upgrade_box.text')}

- - {hasMessage('billing.upgrade_box.button') && ( -
- - {translate('billing.upgrade_box.button')} - -
- )} -
- ); -} diff --git a/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.tsx b/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.tsx new file mode 100644 index 00000000000..baeb9ad0dba --- /dev/null +++ b/server/sonar-web/src/main/js/components/common/UpgradeOrganizationBox.tsx @@ -0,0 +1,50 @@ +/* + * 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 { Link } from 'react-router'; +import { translate, hasMessage } from '../../helpers/l10n'; +import './UpgradeOrganizationBox.css'; + +interface Props { + organization: string; +} + +export default function UpgradeOrganizationBox({ organization }: Props) { + return ( +
+

{translate('billing.upgrade_box.header')}

+ +

{translate('billing.upgrade_box.text')}

+ + {hasMessage('billing.upgrade_box.button') && ( +
+ + {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.js deleted file mode 100644 index 0d0782009b7..00000000000 --- a/server/sonar-web/src/main/js/components/controls/GlobalMessages.js +++ /dev/null @@ -1,64 +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 PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { ERROR, SUCCESS } from '../../store/globalMessages/duck'; -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 - }; - - renderMessage = message => { - const className = classNames('process-spinner', 'shown', { - 'process-spinner-failed': message.level === ERROR, - 'process-spinner-success': message.level === SUCCESS - }); - return ( -
- {message.message} - -
- ); - }; - - render() { - const { messages } = this.props; - - if (messages.length === 0) { - return null; - } - - return
{messages.map(this.renderMessage)}
; - } -} diff --git a/server/sonar-web/src/main/js/components/controls/GlobalMessages.tsx b/server/sonar-web/src/main/js/components/controls/GlobalMessages.tsx new file mode 100644 index 00000000000..95ee65b06e2 --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/GlobalMessages.tsx @@ -0,0 +1,62 @@ +/* + * 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 * as classNames from 'classnames'; +import { Button } from '../ui/buttons'; + +interface Message { + id: string; + level: 'ERROR' | 'SUCCESS'; + message: string; +} + +interface Props { + closeGlobalMessage: (id: string) => void; + messages: Message[]; +} + +export default class GlobalMessages extends React.PureComponent { + renderMessage = (message: Message) => { + const className = classNames('process-spinner', 'shown', { + 'process-spinner-failed': message.level === 'ERROR', + 'process-spinner-success': message.level === 'SUCCESS' + }); + return ( +
+ {message.message} + +
+ ); + }; + + render() { + const { messages } = this.props; + + if (messages.length === 0) { + return null; + } + + return
{messages.map(this.renderMessage)}
; + } +} diff --git a/server/sonar-web/src/main/js/components/controls/Toggle.js b/server/sonar-web/src/main/js/components/controls/Toggle.js deleted file mode 100644 index 4cbabfece09..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Toggle.js +++ /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. - */ -import React from 'react'; -import PropTypes from 'prop-types'; -import 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 - }; - - handleClick = value => { - if (this.props.onChange) { - 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 }); - - return ( - - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/Toggle.tsx b/server/sonar-web/src/main/js/components/controls/Toggle.tsx new file mode 100644 index 00000000000..b35d121f9e8 --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/Toggle.tsx @@ -0,0 +1,54 @@ +/* + * 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 * as classNames from 'classnames'; +import { Button } from '../ui/buttons'; +import './styles.css'; + +export interface Props { + name?: string; + onChange?: (value: boolean) => void; + value: boolean | string; +} + +export default class Toggle extends React.PureComponent { + getValue = () => { + const { value } = this.props; + return typeof value === 'string' ? value === 'true' : value; + }; + + handleClick = () => { + if (this.props.onChange) { + const value = this.getValue(); + this.props.onChange(!value); + } + }; + + render() { + const value = this.getValue(); + const className = classNames('boolean-toggle', { 'boolean-toggle-on': value }); + + return ( + + ); + } +} 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.js deleted file mode 100644 index 5c2e7458776..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.js +++ /dev/null @@ -1,47 +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 { shallow } from 'enzyme'; -import React from 'react'; -import ListFooter from '../ListFooter'; -import { click } from '../../../helpers/testUtils'; - -it('should render "3 of 5 shown"', () => { - const listFooter = shallow(); - expect(listFooter.text()).toContain('x_of_y_shown.3.5'); -}); - -it('should not render "show more"', () => { - const listFooter = shallow(); - expect(listFooter.find('a').length).toBe(0); -}); - -it('should not render "show more"', () => { - const listFooter = shallow(); - expect(listFooter.find('a').length).toBe(0); -}); - -it('should "show more"', () => { - const loadMore = jest.fn(); - const listFooter = shallow(); - const link = listFooter.find('a'); - expect(link.length).toBe(1); - click(link); - expect(loadMore).toBeCalled(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx new file mode 100644 index 00000000000..b8de25e41f1 --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx @@ -0,0 +1,47 @@ +/* + * 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 { shallow } from 'enzyme'; +import ListFooter from '../ListFooter'; +import { click } from '../../../helpers/testUtils'; + +it('should render "3 of 5 shown"', () => { + const listFooter = shallow(); + expect(listFooter.text()).toContain('x_of_y_shown.3.5'); +}); + +it('should not render "show more"', () => { + const listFooter = shallow(); + expect(listFooter.find('a').length).toBe(0); +}); + +it('should not render "show more"', () => { + const listFooter = shallow(); + expect(listFooter.find('a').length).toBe(0); +}); + +it('should "show more"', () => { + const loadMore = jest.fn(); + const listFooter = shallow(); + const link = listFooter.find('a'); + expect(link.length).toBe(1); + click(link); + expect(loadMore).toBeCalled(); +}); 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.js deleted file mode 100644 index 3245074388a..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.js +++ /dev/null @@ -1,39 +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 { shallow } from 'enzyme'; -import React from 'react'; -import Toggle from '../Toggle'; -import { click } from '../../../helpers/testUtils'; - -function getSample(props) { - return true} value={true} {...props} />; -} - -it('should render', () => { - const Toggle = shallow(getSample()); - expect(Toggle.is('Button')).toBe(true); -}); - -it('should call onChange', () => { - const onChange = jest.fn(); - const Toggle = shallow(getSample({ onChange })); - click(Toggle); - expect(onChange).toBeCalledWith(false); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.tsx new file mode 100644 index 00000000000..7d3e8ae2d0d --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.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 { shallow } from 'enzyme'; +import Toggle, { Props } from '../Toggle'; +import { click } from '../../../helpers/testUtils'; + +it('should render', () => { + const Toggle = shallowRender(); + expect(Toggle.is('Button')).toBe(true); +}); + +it('should call onChange', () => { + const onChange = jest.fn(); + const Toggle = shallowRender({ onChange }); + click(Toggle); + expect(onChange).toBeCalledWith(false); +}); + +function shallowRender(props?: Partial) { + return shallow( true} value={true} {...props} />); +} diff --git a/server/sonar-web/src/main/js/components/icons-components/BugTrackerIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/BugTrackerIcon.tsx new file mode 100644 index 00000000000..f42e84aaa6e --- /dev/null +++ b/server/sonar-web/src/main/js/components/icons-components/BugTrackerIcon.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 BugTrackerIcon({ className, fill = 'currentColor', size = 16 }: IconProps) { + return ( + + + + ); +} diff --git a/server/sonar-web/src/main/js/components/icons-components/ClockIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/ClockIcon.tsx new file mode 100644 index 00000000000..d5da0ec03e9 --- /dev/null +++ b/server/sonar-web/src/main/js/components/icons-components/ClockIcon.tsx @@ -0,0 +1,40 @@ +/* + * 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 * as classNames from 'classnames'; +import { IconProps } from './types'; + +export default function ClockIcon({ className, size = 16 }: IconProps) { + return ( + + + + + + + ); +} 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 ( + + ; + + ); +} 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`] = ` - + 7 `; diff --git a/server/sonar-web/src/main/js/components/shared/SeverityIcon.js b/server/sonar-web/src/main/js/components/shared/SeverityIcon.js deleted file mode 100644 index 4a7575edab2..00000000000 --- a/server/sonar-web/src/main/js/components/shared/SeverityIcon.js +++ /dev/null @@ -1,30 +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 classNames from 'classnames'; - -export default function SeverityIcon(props /*: { severity: ?string, className?: string } */) { - if (!props.severity) { - return null; - } - const className = classNames('icon-severity-' + props.severity.toLowerCase(), props.className); - return ; -} diff --git a/server/sonar-web/src/main/js/components/shared/SeverityIcon.tsx b/server/sonar-web/src/main/js/components/shared/SeverityIcon.tsx new file mode 100644 index 00000000000..38ee50884a4 --- /dev/null +++ b/server/sonar-web/src/main/js/components/shared/SeverityIcon.tsx @@ -0,0 +1,35 @@ +/* + * 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 * as classNames from 'classnames'; + +interface Props { + className?: string; + severity: string | null | undefined; +} + +export default function SeverityIcon(props: Props) { + if (!props.severity) { + return null; + } + return ( + + ); +} diff --git a/server/sonar-web/src/main/js/components/shared/StatusHelper.js b/server/sonar-web/src/main/js/components/shared/StatusHelper.js deleted file mode 100644 index 2c2532605ad..00000000000 --- a/server/sonar-web/src/main/js/components/shared/StatusHelper.js +++ /dev/null @@ -1,41 +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 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)})`; - return ( - - - {translate('issue.status', props.status)} - {resolution} - - ); -} diff --git a/server/sonar-web/src/main/js/components/shared/StatusHelper.tsx b/server/sonar-web/src/main/js/components/shared/StatusHelper.tsx new file mode 100644 index 00000000000..b6921effdac --- /dev/null +++ b/server/sonar-web/src/main/js/components/shared/StatusHelper.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 StatusIcon from './StatusIcon'; +import { translate } from '../../helpers/l10n'; + +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 ( + + + {translate('issue.status', props.status)} + {resolution} + + ); +} diff --git a/server/sonar-web/src/main/js/components/shared/StatusIcon.js b/server/sonar-web/src/main/js/components/shared/StatusIcon.js deleted file mode 100644 index ed8c418ee31..00000000000 --- a/server/sonar-web/src/main/js/components/shared/StatusIcon.js +++ /dev/null @@ -1,27 +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 classNames from 'classnames'; - -export default function StatusIcon(props /*: { status: string, className?: string } */) { - const className = classNames('icon-status-' + props.status.toLowerCase(), props.className); - return ; -} diff --git a/server/sonar-web/src/main/js/components/shared/StatusIcon.tsx b/server/sonar-web/src/main/js/components/shared/StatusIcon.tsx new file mode 100644 index 00000000000..d043b034406 --- /dev/null +++ b/server/sonar-web/src/main/js/components/shared/StatusIcon.tsx @@ -0,0 +1,30 @@ +/* + * 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 * as classNames from 'classnames'; + +interface Props { + className?: string; + status: string; +} + +export default function StatusIcon({ className, status }: Props) { + return ; +} 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.js deleted file mode 100644 index 32097c900fd..00000000000 --- a/server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.js +++ /dev/null @@ -1,35 +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 { shallow } from 'enzyme'; -import QualifierIcon from '../QualifierIcon'; - -it('should render icon', () => { - expect(shallow()).toMatchSnapshot(); - expect(shallow()).toMatchSnapshot(); -}); - -it('should not render icon', () => { - expect(shallow().type()).toBeNull(); -}); - -it('should render with custom class', () => { - expect(shallow()).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.tsx b/server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.tsx new file mode 100644 index 00000000000..06169277552 --- /dev/null +++ b/server/sonar-web/src/main/js/components/shared/__tests__/QualifierIcon-test.tsx @@ -0,0 +1,35 @@ +/* + * 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 { shallow } from 'enzyme'; +import QualifierIcon from '../QualifierIcon'; + +it('should render icon', () => { + expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); +}); + +it('should not render icon', () => { + expect(shallow().type()).toBeNull(); +}); + +it('should render with custom class', () => { + expect(shallow()).toMatchSnapshot(); +}); 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.js.snap deleted file mode 100644 index 3e1625b3e32..00000000000 --- a/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.js.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render icon 1`] = ` - -`; - -exports[`should render icon 2`] = ` - -`; - -exports[`should render with custom class 1`] = ` - -`; diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.tsx.snap b/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.tsx.snap new file mode 100644 index 00000000000..3e1625b3e32 --- /dev/null +++ b/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/QualifierIcon-test.tsx.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render icon 1`] = ` + +`; + +exports[`should render icon 2`] = ` + +`; + +exports[`should render with custom class 1`] = ` + +`; 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 ( - - - - ); -} diff --git a/server/sonar-web/src/main/js/components/ui/BugTrackerIcon.js b/server/sonar-web/src/main/js/components/ui/BugTrackerIcon.js deleted file mode 100644 index 45b233ba806..00000000000 --- a/server/sonar-web/src/main/js/components/ui/BugTrackerIcon.js +++ /dev/null @@ -1,41 +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'; - -export default function BugTrackerIcon() { - /* eslint-disable max-len */ - return ( - - - - - - ); -} 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 ; + return ; } 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.js deleted file mode 100644 index 3a315a07599..00000000000 --- a/server/sonar-web/src/main/js/components/ui/__tests__/Level-test.js +++ /dev/null @@ -1,27 +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 { shallow } from 'enzyme'; -import React from 'react'; -import Level from '../Level'; - -it('should render', () => { - const rating = shallow(); - expect(rating.is('.level-ERROR')).toBe(true); -}); diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/Level-test.tsx b/server/sonar-web/src/main/js/components/ui/__tests__/Level-test.tsx new file mode 100644 index 00000000000..7706ee2414b --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/__tests__/Level-test.tsx @@ -0,0 +1,27 @@ +/* + * 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 { shallow } from 'enzyme'; +import Level from '../Level'; + +it('should render', () => { + const rating = shallow(); + expect(rating.is('.level-ERROR')).toBe(true); +}); 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) => 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/json.d.ts b/server/sonar-web/src/main/js/typings/json.d.ts deleted file mode 100644 index 0f858f5d256..00000000000 --- a/server/sonar-web/src/main/js/typings/json.d.ts +++ /dev/null @@ -1,23 +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 '*.json' { - const value: any; - export default value; -} 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 { - 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 {} -} 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"