Browse Source

SONAR-12219 Fix formatting of rounded short numbers

tags/8.0
Grégoire Aubert 5 years ago
parent
commit
436296b4cd

+ 9
- 3
server/sonar-web/src/main/js/apps/about/sonarcloud/components/Statistics.tsx View File

@@ -21,6 +21,7 @@ import * as React from 'react';
import { throttle } from 'lodash';
import CountUp from 'react-countup';
import { formatMeasure } from '../../../../helpers/measures';
import { translate } from '../../../../helpers/l10n';
import { getBaseUrl } from '../../../../helpers/urls';
import './Statistics.css';

@@ -83,9 +84,14 @@ export class StatisticCard extends React.PureComponent<StatisticCardProps, Stati

render() {
const { statistic } = this.props;
const formattedString = formatMeasure(statistic.value, 'SHORT_INT');
const value = parseFloat(formattedString.slice(0, -1));
const suffix = formattedString.substr(-1);
const formattedString = formatMeasure(statistic.value, 'SHORT_INT', {
roundingFunc: Math.floor
});
const value = parseFloat(formattedString);
let suffix = formattedString.replace(value.toString(), '');
if (suffix === translate('short_number_suffix.g')) {
suffix = ' ' + translate('billion');
}
return (
<div className="sc-stat-card sc-big-spacer-top" ref={node => (this.container = node)}>
<div className="sc-stat-icon">

+ 28
- 7
server/sonar-web/src/main/js/apps/about/sonarcloud/components/__tests__/Statistics-test.tsx View File

@@ -18,19 +18,40 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { shallow } from 'enzyme';
import { shallow, ShallowWrapper } from 'enzyme';
import Statistics, { StatisticCard } from '../Statistics';

const STATISTICS = {
icon: 'stat-icon',
text: 'my stat',
value: 26666
};
const STATISTICS = { icon: 'stat-icon', text: 'my stat', value: 26666 };

it('should render', () => {
expect(shallow(<Statistics statistics={[STATISTICS]} />)).toMatchSnapshot();
});

it('should render StatisticCard', () => {
expect(shallow(<StatisticCard statistic={STATISTICS} />)).toMatchSnapshot();
expect(shallowRender()).toMatchSnapshot();
});

it('should render big numbers correctly', () => {
function checkCountUp(wrapper: ShallowWrapper, end: number, suffix: string) {
expect(wrapper.find('CountUp').prop('end')).toBe(end);
expect(wrapper.find('CountUp').prop('suffix')).toBe(suffix);
}

checkCountUp(
shallowRender({ statistic: { ...STATISTICS, value: 999003632 } }),
999,
'short_number_suffix.m'
);
checkCountUp(
shallowRender({ statistic: { ...STATISTICS, value: 999861538 } }),
999,
'short_number_suffix.m'
);
checkCountUp(shallowRender({ statistic: { ...STATISTICS, value: 1100021731 } }), 1.1, ' billion');
});

function shallowRender(props: Partial<StatisticCard['props']> = {}) {
const wrapper = shallow(<StatisticCard statistic={STATISTICS} {...props} />);
wrapper.setState({ viewable: true });
return wrapper;
}

+ 8
- 0
server/sonar-web/src/main/js/apps/about/sonarcloud/components/__tests__/__snapshots__/Statistics-test.tsx.snap View File

@@ -33,6 +33,14 @@ exports[`should render StatisticCard 1`] = `
<div
className="sc-stat-content"
>
<CountUp
delay={0}
duration={4}
end={26}
suffix="short_number_suffix.k"
>
<Component />
</CountUp>
<span>
my stat
</span>

+ 8
- 3
server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts View File

@@ -60,7 +60,12 @@ describe('#formatMeasure()', () => {
expect(formatMeasure(1529, 'SHORT_INT')).toBe('1.5k');
expect(formatMeasure(10000, 'SHORT_INT')).toBe('10k');
expect(formatMeasure(10678, 'SHORT_INT')).toBe('11k');
expect(formatMeasure(1234567890, 'SHORT_INT')).toBe('1G');
expect(formatMeasure(9467890, 'SHORT_INT')).toBe('9.5M');
expect(formatMeasure(994567890, 'SHORT_INT')).toBe('995M');
expect(formatMeasure(999000001, 'SHORT_INT')).toBe('999M');
expect(formatMeasure(999567890, 'SHORT_INT')).toBe('1G');
expect(formatMeasure(1234567890, 'SHORT_INT')).toBe('1.2G');
expect(formatMeasure(11234567890, 'SHORT_INT')).toBe('11G');
});

it('should format FLOAT', () => {
@@ -130,8 +135,8 @@ describe('#formatMeasure()', () => {
expect(formatMeasure(-1 * ONE_MINUTE, 'SHORT_WORK_DUR')).toBe('-1min');

expect(formatMeasure(1529 * ONE_DAY, 'SHORT_WORK_DUR')).toBe('1.5kd');
expect(formatMeasure(1234567 * ONE_DAY, 'SHORT_WORK_DUR')).toBe('1Md');
expect(formatMeasure(1234567 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).toBe('1Md');
expect(formatMeasure(1234567 * ONE_DAY, 'SHORT_WORK_DUR')).toBe('1.2Md');
expect(formatMeasure(12345670 * ONE_DAY + 4 * ONE_HOUR, 'SHORT_WORK_DUR')).toBe('12Md');
});

it('should format RATING', () => {

+ 37
- 11
server/sonar-web/src/main/js/helpers/measures.ts View File

@@ -130,18 +130,44 @@ function intFormatter(value: number): string {
return numberFormatter(value);
}

function shortIntFormatter(value: number): string {
if (value >= 1e9) {
return numberFormatter(value / 1e9) + translate('short_number_suffix.g');
} else if (value >= 1e6) {
return numberFormatter(value / 1e6) + translate('short_number_suffix.m');
} else if (value >= 1e4) {
return numberFormatter(value / 1e3) + translate('short_number_suffix.k');
} else if (value >= 1e3) {
return numberFormatter(value / 1e3, 0, 1) + translate('short_number_suffix.k');
} else {
return numberFormatter(value);
const shortIntFormats = [
{ unit: 1e10, formatUnit: 1e9, fraction: 0, suffix: 'short_number_suffix.g' },
{ unit: 1e9, formatUnit: 1e9, fraction: 1, suffix: 'short_number_suffix.g' },
{ unit: 1e7, formatUnit: 1e6, fraction: 0, suffix: 'short_number_suffix.m' },
{ unit: 1e6, formatUnit: 1e6, fraction: 1, suffix: 'short_number_suffix.m' },
{ unit: 1e4, formatUnit: 1e3, fraction: 0, suffix: 'short_number_suffix.k' },
{ unit: 1e3, formatUnit: 1e3, fraction: 1, suffix: 'short_number_suffix.k' }
];

function shortIntFormatter(
value: number,
option?: { roundingFunc?: (x: number) => number }
): string {
const roundingFunc = (option && option.roundingFunc) || undefined;
for (let i = 0; i < shortIntFormats.length; i++) {
const { unit, formatUnit, fraction, suffix } = shortIntFormats[i];
const nextFraction = unit / (shortIntFormats[i + 1] ? shortIntFormats[i + 1].unit / 10 : 1);
const roundedValue = numberRound(value / unit, nextFraction, roundingFunc);
if (roundedValue >= 1) {
return (
numberFormatter(
numberRound(value / formatUnit, Math.pow(10, fraction), roundingFunc),
0,
fraction
) + translate(suffix)
);
}
}

return numberFormatter(value);
}

function numberRound(
value: number,
fraction: number = 1000,
roundingFunc: (x: number) => number = Math.round
) {
return roundingFunc(value * fraction) / fraction;
}

function floatFormatter(value: number): string {

+ 1
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -18,6 +18,7 @@ any=Any
ascending=Ascending
assignee=Assignee
author=Author
billion=Billion
bitbucket=Bitbucket
back=Back
backup=Backup

Loading…
Cancel
Save