From 53c9f82d5ed08178ef731d08e6a650878dfbbfeb Mon Sep 17 00:00:00 2001 From: Wouter Admiraal Date: Fri, 26 May 2023 08:46:24 +0200 Subject: [PATCH] SONAR-19391 Use the new Histogram component --- .../main/js/components/charts/Histogram.css | 30 -- .../main/js/components/charts/Histogram.tsx | 140 ----- .../charts/LanguageDistribution.tsx | 34 +- .../charts/__tests__/Histogram-test.tsx | 66 --- .../__tests__/LanguageDistribution-test.tsx | 27 +- .../__snapshots__/Histogram-test.tsx.snap | 508 ------------------ .../LanguageDistribution-test.tsx.snap | 191 +++++-- 7 files changed, 181 insertions(+), 815 deletions(-) delete mode 100644 server/sonar-web/src/main/js/components/charts/Histogram.css delete mode 100644 server/sonar-web/src/main/js/components/charts/Histogram.tsx delete mode 100644 server/sonar-web/src/main/js/components/charts/__tests__/Histogram-test.tsx delete mode 100644 server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/Histogram-test.tsx.snap diff --git a/server/sonar-web/src/main/js/components/charts/Histogram.css b/server/sonar-web/src/main/js/components/charts/Histogram.css deleted file mode 100644 index 639646d7db3..00000000000 --- a/server/sonar-web/src/main/js/components/charts/Histogram.css +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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. - */ -.histogram-tick { - text-anchor: end !important; -} - -.histogram-tick-start { - text-anchor: start !important; -} - -.histogram-value { - text-anchor: start !important; -} diff --git a/server/sonar-web/src/main/js/components/charts/Histogram.tsx b/server/sonar-web/src/main/js/components/charts/Histogram.tsx deleted file mode 100644 index 8794270fa0b..00000000000 --- a/server/sonar-web/src/main/js/components/charts/Histogram.tsx +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { max } from 'd3-array'; -import { scaleBand, ScaleBand, scaleLinear, ScaleLinear } from 'd3-scale'; -import * as React from 'react'; -import Tooltip from '../controls/Tooltip'; -import './BarChart.css'; -import './Histogram.css'; - -interface Props { - alignTicks?: boolean; - bars: number[]; - height: number; - padding?: [number, number, number, number]; - yTicks?: string[]; - yTooltips?: string[]; - yValues?: string[]; - width: number; -} - -const BAR_HEIGHT = 10; -const DEFAULT_PADDING = [10, 10, 10, 10]; - -type XScale = ScaleLinear; -type YScale = ScaleBand; - -export default class Histogram extends React.PureComponent { - renderBar(d: number, index: number, xScale: XScale, yScale: YScale) { - const { alignTicks, padding = DEFAULT_PADDING } = this.props; - - const width = Math.round(xScale(d)) + /* minimum bar width */ 1; - const x = xScale.range()[0] + (alignTicks ? padding[3] : 0); - const y = Math.round((yScale(index) || 0) + yScale.bandwidth() / 2); - - return ; - } - - renderValue(d: number, index: number, xScale: XScale, yScale: YScale) { - const { alignTicks, padding = DEFAULT_PADDING, yValues } = this.props; - - const value = yValues && yValues[index]; - - if (!value) { - return null; - } - - const x = xScale(d) + (alignTicks ? padding[3] : 0); - const y = Math.round((yScale(index) || 0) + yScale.bandwidth() / 2 + BAR_HEIGHT / 2); - - return ( - - - {value} - - - ); - } - - renderTick(index: number, xScale: XScale, yScale: YScale) { - const { alignTicks, yTicks } = this.props; - - const tick = yTicks && yTicks[index]; - - if (!tick) { - return null; - } - - const x = xScale.range()[0]; - const y = Math.round((yScale(index) || 0) + yScale.bandwidth() / 2 + BAR_HEIGHT / 2); - const historyTickClass = alignTicks ? 'histogram-tick-start' : 'histogram-tick'; - - return ( - - {tick} - - ); - } - - renderBars(xScale: XScale, yScale: YScale) { - return ( - - {this.props.bars.map((d, index) => { - return ( - // eslint-disable-next-line react/no-array-index-key - - {this.renderBar(d, index, xScale, yScale)} - {this.renderValue(d, index, xScale, yScale)} - {this.renderTick(index, xScale, yScale)} - - ); - })} - - ); - } - - render() { - const { bars, width, height, padding = DEFAULT_PADDING } = this.props; - - const availableWidth = width - padding[1] - padding[3]; - const xScale: XScale = scaleLinear() - .domain([0, max(bars)!]) - .range([0, availableWidth]); - - const availableHeight = height - padding[0] - padding[2]; - const yScale: YScale = scaleBand() - .domain(bars.map((_, index) => index)) - .rangeRound([0, availableHeight]); - - return ( - - - {this.renderBars(xScale, yScale)} - - - ); - } -} diff --git a/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx b/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx index f1038db36b0..3d77f2149c5 100644 --- a/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx +++ b/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx @@ -17,16 +17,16 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { Histogram } from 'design-system'; import { sortBy } from 'lodash'; import * as React from 'react'; import withLanguagesContext from '../../app/components/languages/withLanguagesContext'; -import Histogram from '../../components/charts/Histogram'; import { translate } from '../../helpers/l10n'; import { formatMeasure } from '../../helpers/measures'; import { Languages } from '../../types/languages'; import { MetricType } from '../../types/metrics'; -interface LanguageDistributionProps { +export interface LanguageDistributionProps { distribution: string; languages: Languages; } @@ -34,24 +34,28 @@ interface LanguageDistributionProps { const NUMBER_FORMAT_THRESHOLD = 1000; export function LanguageDistribution(props: LanguageDistributionProps) { - let distribution = props.distribution.split(';').map((point) => { + const { distribution, languages } = props; + let parsedDistribution = distribution.split(';').map((point) => { const tokens = point.split('='); return { language: tokens[0], lines: parseInt(tokens[1], 10) }; }); - distribution = sortBy(distribution, (d) => -d.lines); + parsedDistribution = sortBy(parsedDistribution, (d) => -d.lines); - const data = distribution.map((d) => d.lines); - const yTicks = distribution.map((d) => getLanguageName(d.language)).map(cutLanguageName); - const yTooltips = distribution.map((d) => + const data = parsedDistribution.map((d) => d.lines); + const yTicks = parsedDistribution + .map((d) => getLanguageName(languages, d.language)) + .map(cutLanguageName); + const yTooltips = parsedDistribution.map((d) => d.lines > NUMBER_FORMAT_THRESHOLD ? formatMeasure(d.lines, MetricType.Integer) : '' ); - const yValues = distribution.map((d) => formatMeasure(d.lines, MetricType.ShortInteger)); + const yValues = parsedDistribution.map((d) => formatMeasure(d.lines, MetricType.ShortInteger)); return ( ); +} - function getLanguageName(langKey: string) { - if (langKey === '') { - return translate('unknown'); - } - const lang = props.languages[langKey]; - return lang ? lang.name : langKey; +function getLanguageName(languages: Languages, langKey: string) { + if (langKey === '') { + return translate('unknown'); } + const lang = languages[langKey]; + return lang ? lang.name : langKey; } function cutLanguageName(name: string) { diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/Histogram-test.tsx b/server/sonar-web/src/main/js/components/charts/__tests__/Histogram-test.tsx deleted file mode 100644 index a8325bb3387..00000000000 --- a/server/sonar-web/src/main/js/components/charts/__tests__/Histogram-test.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { scaleBand } from 'd3-scale'; -import { shallow } from 'enzyme'; -import * as React from 'react'; -import Histogram from '../Histogram'; - -jest.mock('d3-scale', () => { - const d3 = jest.requireActual('d3-scale'); - return { - ...d3, - scaleBand: jest.fn(d3.scaleBand), - }; -}); - -beforeEach(jest.clearAllMocks); - -it('renders correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect(shallowRender({ alignTicks: true })).toMatchSnapshot('align ticks'); - expect(shallowRender({ yValues: ['100.0', '75.0', '150.0'] })).toMatchSnapshot('with yValues'); - expect( - shallowRender({ yTicks: ['a', 'b', 'c'], yValues: ['100.0', '75.0', '150.0'] }) - ).toMatchSnapshot('with yValues and yTicks'); - expect( - shallowRender({ - yTicks: ['a', 'b', 'c'], - yTooltips: ['a - 100', 'b - 75', 'c - 150'], - yValues: ['100.0', '75.0', '150.0'], - }) - ).toMatchSnapshot('with yValues, yTicks and yTooltips'); -}); - -it('correctly handles yScale() returning undefined', () => { - const yScale = () => undefined; - yScale.bandwidth = () => 1; - - (scaleBand as jest.Mock).mockReturnValueOnce({ - domain: () => ({ rangeRound: () => yScale }), - }); - - expect( - shallowRender({ yValues: ['100.0', '75.0', '150.0'], yTicks: ['a', 'b', 'c'] }) - ).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx b/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx index ee7486a9b61..3466cbef9a8 100644 --- a/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx +++ b/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx @@ -17,17 +17,22 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { shallow } from 'enzyme'; + import * as React from 'react'; -import { LanguageDistribution } from '../LanguageDistribution'; +import { renderComponent } from '../../../helpers/testReactTestingUtils'; +import LanguageDistribution, { LanguageDistributionProps } from '../LanguageDistribution'; -it('renders', () => { - expect( - shallow( - - ) - ).toMatchSnapshot(); +it('should render correctly', () => { + const { container } = renderLanguageDistribution(); + expect(container).toMatchSnapshot(); }); + +function renderLanguageDistribution(props: Partial = {}) { + return renderComponent( + + ); +} diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/Histogram-test.tsx.snap b/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/Histogram-test.tsx.snap deleted file mode 100644 index 9f2ac323b09..00000000000 --- a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/Histogram-test.tsx.snap +++ /dev/null @@ -1,508 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`correctly handles yScale() returning undefined 1`] = ` - - - - - - - - 100.0 - - - - a - - - - - - - 75.0 - - - - b - - - - - - - 150.0 - - - - c - - - - - -`; - -exports[`renders correctly: align ticks 1`] = ` - - - - - - - - - - - - - - - -`; - -exports[`renders correctly: default 1`] = ` - - - - - - - - - - - - - - - -`; - -exports[`renders correctly: with yValues 1`] = ` - - - - - - - - 100.0 - - - - - - - - 75.0 - - - - - - - - 150.0 - - - - - - -`; - -exports[`renders correctly: with yValues and yTicks 1`] = ` - - - - - - - - 100.0 - - - - a - - - - - - - 75.0 - - - - b - - - - - - - 150.0 - - - - c - - - - - -`; - -exports[`renders correctly: with yValues, yTicks and yTooltips 1`] = ` - - - - - - - - 100.0 - - - - a - - - - - - - 75.0 - - - - b - - - - - - - 150.0 - - - - c - - - - - -`; diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/LanguageDistribution-test.tsx.snap b/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/LanguageDistribution-test.tsx.snap index 5f729e9ef4b..5fed7969987 100644 --- a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/LanguageDistribution-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/LanguageDistribution-test.tsx.snap @@ -1,48 +1,149 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`renders 1`] = ` - +exports[`should render correctly 1`] = ` +.emotion-0 { + fill: rgb(93,108,208); +} + +.emotion-2 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 400; + fill: rgb(106,117,144); +} + +.e1vbniy52 .emotion-2 { + fill: rgb(255,255,255); +} + +
+ + + + + + + 1.7short_number_suffix.k + + + Java + + + + + + 845 + + + JavaScript + + + + + + 73 + + + cpp + + + + + + 15 + + + unknown + + + + + +
`; -- 2.39.5