Skip to content

Commit

Permalink
feat: prettify large numbers in metrics (#2176)
Browse files Browse the repository at this point in the history
* prettify large numbers

* add tooltip for larger numbers

* add test ids, add unit test

* move dependency to devDependency

* remove unused import

* use conditional render component

* use prettify large number component for feature overview metrics
  • Loading branch information
aneeshrelan committed Oct 12, 2022
1 parent e1b903a commit 1a09d17
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 5 deletions.
1 change: 1 addition & 0 deletions frontend/package.json
Expand Up @@ -69,6 +69,7 @@
"immer": "9.0.15",
"jsdom": "20.0.1",
"lodash.clonedeep": "4.5.0",
"millify": "^5.0.1",
"msw": "0.47.4",
"pkginfo": "0.4.1",
"plausible-tracker": "0.3.8",
Expand Down
@@ -0,0 +1,62 @@
import { render } from 'utils/testRenderer';
import { screen } from '@testing-library/react';
import { PrettifyLargeNumber } from './PrettifyLargeNumber';
import { LARGE_NUMBER_PRETTIFIED } from 'utils/testIds';

describe('PrettifyLargeNumber', () => {
it('should render number with separator for value less than threshold', async () => {
render(<PrettifyLargeNumber value={999999} threshold={1000000} />);

const prettifiedText = await screen.getByTestId(
LARGE_NUMBER_PRETTIFIED
);

expect(prettifiedText.textContent).toBe('999,999');
});

it('should render prettified number for value equal to the threshold', async () => {
render(<PrettifyLargeNumber value={1000000} threshold={1000000} />);

const prettifiedText = await screen.getByTestId(
LARGE_NUMBER_PRETTIFIED
);

expect(prettifiedText.textContent).toBe('1M');
});

it('should render prettified number for value greater than threshold', async () => {
render(<PrettifyLargeNumber value={12345678} threshold={1000000} />);

const prettifiedText = await screen.getByTestId(
LARGE_NUMBER_PRETTIFIED
);

expect(prettifiedText.textContent).toBe('12.35M');
});

it('should render prettified number with tooltip having raw value for value greater than threshold', async () => {
render(<PrettifyLargeNumber value={12345678} threshold={1000000} />);

const prettifiedText = await screen.getByTestId(
LARGE_NUMBER_PRETTIFIED
);

expect(prettifiedText.getAttribute('aria-label')).toBe('12,345,678');
});

it('should render prettified number with provided significant figures for value greater than threshold', async () => {
render(
<PrettifyLargeNumber
value={12345678}
threshold={1000000}
precision={4}
/>
);

const prettifiedText = await screen.getByTestId(
LARGE_NUMBER_PRETTIFIED
);

expect(prettifiedText.textContent).toBe('12.3457M');
});
});
@@ -0,0 +1,54 @@
import { FC } from 'react';
import millify from 'millify';
import { Tooltip } from '@mui/material';
import { LARGE_NUMBER_PRETTIFIED } from 'utils/testIds';
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';

interface IPrettifyLargeNumberProps {
/**
* Value to prettify
*/
value: number;
/**
* Threshold above which the number will be prettified. Values lower than this will just have comma separators added
* @default 1_000_000
*/
threshold?: number;
/**
* The number of significant figures
* @default 2
*/
precision?: number;
}

export const PrettifyLargeNumber: FC<IPrettifyLargeNumberProps> = ({
value,
threshold = 1_000_000,
precision = 2,
}) => {
let prettyValue: string;
let showTooltip = false;

if (value < threshold) {
prettyValue = value.toLocaleString();
} else {
prettyValue = millify(value, { precision });
showTooltip = true;
}

const valueSpan = (
<span data-testid={LARGE_NUMBER_PRETTIFIED}>{prettyValue}</span>
);

return (
<ConditionallyRender
condition={showTooltip}
show={
<Tooltip title={value.toLocaleString()} arrow>
{valueSpan}
</Tooltip>
}
elseShow={valueSpan}
/>
);
};
@@ -1,6 +1,7 @@
import { calculatePercentage } from 'utils/calculatePercentage';
import { useStyles } from './FeatureMetricsStats.styles';
import { Grid } from '@mui/material';
import { PrettifyLargeNumber } from 'component/common/PrettifyLargeNumber/PrettifyLargeNumber';

export interface IFeatureMetricsStatsProps {
totalYes: number;
Expand Down Expand Up @@ -34,7 +35,9 @@ export const FeatureMetricsStats = ({
<Grid item xs={12} sm={4}>
<article className={styles.item}>
<h3 className={styles.title}>Exposure</h3>
<p className={styles.value}>{totalYes}</p>
<p className={styles.value}>
<PrettifyLargeNumber value={totalYes} />
</p>
<p className={styles.text}>
Total exposure of the feature in the environment{' '}
{hoursSuffix}.
Expand All @@ -56,7 +59,9 @@ export const FeatureMetricsStats = ({
<Grid item xs={12} sm={4}>
<article className={styles.item}>
<h3 className={styles.title}>Requests</h3>
<p className={styles.value}>{totalYes + totalNo}</p>
<p className={styles.value}>
<PrettifyLargeNumber value={totalYes + totalNo} />
</p>
<p className={styles.text}>
Total requests for the feature in the environment{' '}
{hoursSuffix}.
Expand Down
Expand Up @@ -4,6 +4,7 @@ import { IFeatureEnvironmentMetrics } from 'interfaces/featureToggle';
import { calculatePercentage } from 'utils/calculatePercentage';
import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle';
import { useStyles } from './FeatureOverviewEnvironmentMetrics.styles';
import { PrettifyLargeNumber } from 'component/common/PrettifyLargeNumber/PrettifyLargeNumber';

interface IFeatureOverviewEnvironmentMetrics {
environmentMetric?: IFeatureEnvironmentMetrics;
Expand Down Expand Up @@ -68,9 +69,15 @@ const FeatureOverviewEnvironmentMetrics = ({
<p className={styles.percentage}>{percentage}%</p>
<p className={styles.infoParagraph}>
The feature has been requested{' '}
<b>{environmentMetric.yes + environmentMetric.no} times</b>{' '}
and exposed <b>{environmentMetric.yes} times</b> in the last
hour
<b>
<PrettifyLargeNumber value={total} /> times
</b>{' '}
and exposed{' '}
<b>
<PrettifyLargeNumber value={environmentMetric.yes} />{' '}
times
</b>{' '}
in the last hour
</p>
</div>
<div className={styles.percentageCircle} data-loading>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/utils/testIds.ts
Expand Up @@ -73,3 +73,4 @@ export const AUTH_PAGE_ID = 'AUTH_PAGE_ID';
export const ANNOUNCER_ELEMENT_TEST_ID = 'ANNOUNCER_ELEMENT_TEST_ID';
export const INSTANCE_STATUS_BAR_ID = 'INSTANCE_STATUS_BAR_ID';
export const TOAST_TEXT = 'TOAST_TEXT';
export const LARGE_NUMBER_PRETTIFIED = 'LARGE_NUMBER_PRETTIFIED';
29 changes: 29 additions & 0 deletions frontend/yarn.lock
Expand Up @@ -3319,6 +3319,15 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"

cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"

clone@^1.0.2:
version "1.0.4"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
Expand Down Expand Up @@ -5513,6 +5522,13 @@ micromatch@^4.0.2, micromatch@^4.0.4:
braces "^3.0.2"
picomatch "^2.3.1"

millify@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/millify/-/millify-5.0.1.tgz#f3f2cebf4d3071e127c05942f827c49754a03754"
integrity sha512-1IacXjRDMbRevt2++mBnrI2iFxljWlQapMUT9Bs+uAF3o/TrYdE46Uf6CqlmoOWMX1JDAlMorXPv4/hM1eE/kw==
dependencies:
yargs "^17.0.1"

mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
Expand Down Expand Up @@ -7217,6 +7233,19 @@ yargs@^16.2.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"

yargs@^17.0.1:
version "17.6.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.0.tgz#e134900fc1f218bc230192bdec06a0a5f973e46c"
integrity sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==
dependencies:
cliui "^8.0.1"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.0.0"

yargs@^17.3.1:
version "17.4.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.1.tgz#ebe23284207bb75cee7c408c33e722bfb27b5284"
Expand Down

0 comments on commit 1a09d17

Please sign in to comment.