Skip to content

Commit

Permalink
feat: [M3-7144] - MNTP Dialog Updates for DC-specific pricing (#9692)
Browse files Browse the repository at this point in the history
* feat: [M3-7144] Transfer Pool Dialog initial changes

* feat: [M3-7144] Formatting all the things

* feat: [M3-7144] fix tests

* Added changeset: Network Transfer Dialog copy and typography updates

* feat: [fix-M3-7144] add missing period

* feat: [fix-M3-7144] feedback

* feat: [fix-M3-7144] feedback

* feat: [fix-M3-7144] feedback 2
  • Loading branch information
abailly-akamai authored Sep 19, 2023
1 parent 09b599e commit bc25cd6
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Update Monthly Network Transfer Pool dialog copy and typography ([#9692](https://github.com/linode/manager/pull/9692))
1 change: 1 addition & 0 deletions packages/manager/src/components/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const Dialog = (props: DialogProps) => {
{titleBottomBorder && <StyledHr />}
<DialogContent
sx={{
overflowX: 'hidden',
paddingBottom: theme.spacing(3),
}}
className={className}
Expand Down
3 changes: 2 additions & 1 deletion packages/manager/src/components/TooltipIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ interface Props
* Enables a leaveDelay of 3000ms
* @default false
*/
leaveDelay?: boolean;
leaveDelay?: number;
/**
* Sets the icon and color
*/
Expand Down Expand Up @@ -142,6 +142,7 @@ export const TooltipIcon = (props: Props) => {
return (
<Tooltip
classes={classes}
componentsProps={props.componentsProps}
data-qa-help-tooltip
disableInteractive={!interactive}
enterTouchDelay={0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ describe('TransferDisplayDialog', () => {
const transferButton = await findByText(TRANSFER_DISPLAY_BUTTON);
fireEvent.click(transferButton);

expect(getByTestId('general-transfer-pool-display')).toBeInTheDocument();
expect(getByTestId('region-transfer-pool-display')).toBeInTheDocument();
expect(getByTestId('global-transfer-pool-header')).toBeInTheDocument();
expect(getByTestId('other-transfer-pools-header')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { styled } from '@mui/material/styles';
import { useTheme } from '@mui/material/styles';
import * as React from 'react';

Expand All @@ -7,9 +8,10 @@ import { Divider } from 'src/components/Divider';
import { Typography } from 'src/components/Typography';

import { DocsLink } from '../DocsLink/DocsLink';
import { TransferDisplayDialogHeader } from './TransferDisplayDialogHeader';
import { TransferDisplayUsage } from './TransferDisplayUsage';
import { NETWORK_TRANSFER_QUOTA_DOCS_LINKS } from './constants';
import { getDaysRemaining } from './utils';
import { formatRegionList, getDaysRemaining } from './utils';

import type { RegionTransferPool } from './utils';

Expand Down Expand Up @@ -37,11 +39,16 @@ export const TransferDisplayDialog = React.memo(
} = props;
const theme = useTheme();
const daysRemainingInMonth = getDaysRemaining();
const listOfOtherRegionTransferPools: string[] =
regionTransferPools.length > 0
? regionTransferPools.map((pool) => pool.regionName)
: [];
const otherRegionPools = formatRegionList(listOfOtherRegionTransferPools);

const transferQuotaDocsText =
used === 0
? 'Compute instances, NodeBalancers, and Object Storage include network transfer.'
: 'View products and services that include network transfer, and learn how to optimize network usage to avoid billing surprises.';
: 'In some regions, the monthly network transfer is calculated and tracked independently. Transfer overages will be billed separately.';

return (
<Dialog
Expand All @@ -54,40 +61,35 @@ export const TransferDisplayDialog = React.memo(
{/**
* Global Transfer Pool Display
*/}
<Typography
data-testid="general-transfer-pool-display"
fontFamily={theme.font.bold}
marginBottom={theme.spacing()}
>
Global Network Transfer Pool
</Typography>
<TransferDisplayDialogHeader
tooltipText={`The Global Pool includes transfer associated with active services in your devices' regions${
listOfOtherRegionTransferPools.length > 0
? ` except for ${otherRegionPools}.`
: '.'
}
`}
dataTestId="global-transfer-pool-header"
headerText="Global Network Transfer Pool"
/>
<TransferDisplayUsage
pullUsagePct={generalPoolUsagePct}
quota={quota}
used={used}
/>
<Divider
sx={{ marginBottom: theme.spacing(2), marginTop: theme.spacing(3) }}
/>
<StyledDivider />
{/**
* DC-specific Transfer Pool Display
*/}
{regionTransferPools.length > 0 && (
<>
<Typography
data-testid="region-transfer-pool-display"
fontFamily={theme.font.bold}
marginBottom={theme.spacing()}
>
Data Center-Specific Network Transfer Pools
</Typography>
<Typography
marginBottom={theme.spacing()}
marginTop={theme.spacing()}
>
In some regions, the monthly network transfer is calculated and
tracked independently. These regions are listed below. Transfer
overages will be billed separately.
<TransferDisplayDialogHeader
dataTestId="other-transfer-pools-header"
headerText="Other Transfer Pools"
tooltipText="In some regions, the monthly network transfer is calculated and tracked independently. Transfer overages will be billed separately."
/>
<Typography marginBottom={theme.spacing(2)} marginTop={-1}>
These data center-specific transfer pools are not included in the
Global Transfer Pool.
</Typography>

{regionTransferPools.map((pool, key) => (
Expand All @@ -97,7 +99,6 @@ export const TransferDisplayDialog = React.memo(
>
<Typography
fontFamily={theme.font.bold}
fontSize={theme.typography.body2.fontSize}
marginBottom={theme.spacing()}
>
{pool.regionName}{' '}
Expand Down Expand Up @@ -137,3 +138,13 @@ export const TransferDisplayDialog = React.memo(
);
}
);

const StyledDivider = styled(Divider, {
label: 'TransferDisplayDialogDivider',
})(({ theme }) => ({
borderColor: theme.color.border3,
marginBottom: theme.spacing(2),
marginLeft: theme.spacing(-3),
marginTop: theme.spacing(3),
width: `calc(100% + ${theme.spacing(6)})`,
}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useTheme } from '@mui/material/styles';
import * as React from 'react';

import { TooltipIcon } from 'src/components/TooltipIcon';
import { Typography } from 'src/components/Typography';

interface Props {
dataTestId: string;
headerText: string;
tooltipText: string;
}

export const TransferDisplayDialogHeader = React.memo((props: Props) => {
const { dataTestId, headerText, tooltipText } = props;
const theme = useTheme();

return (
<Typography
data-testid={dataTestId}
fontFamily={theme.font.bold}
fontSize={theme.typography.h3.fontSize}
>
{headerText}
<TooltipIcon
componentsProps={{
tooltip: {
style: {
marginTop: -8,
minWidth: 250,
},
},
}}
status="help"
sxTooltipIcon={{ left: -2, top: -2 }}
text={tooltipText}
/>
</Typography>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('TransferDisplayDialogUsage', () => {
const progressBars = getAllByRole('progressbar');

expect(progressBars.length).toBe(3);
expect(getByTestId('general-transfer-pool-display')).toBeInTheDocument();
expect(getByTestId('global-transfer-pool-header')).toBeInTheDocument();

expect(await findByText('9000 GB Used (36%)')).toBeInTheDocument();
expect(await findByText('8500 GB Used (85%)')).toBeInTheDocument();
Expand All @@ -62,7 +62,7 @@ describe('TransferDisplayDialogUsage', () => {

const progressBars = getAllByRole('progressbar');

expect(getByTestId('general-transfer-pool-display')).toBeInTheDocument();
expect(getByTestId('global-transfer-pool-header')).toBeInTheDocument();
expect(progressBars.length).toBe(1);
expect(progressBars[0]).toHaveAttribute('aria-valuenow', '36');
});
Expand Down
17 changes: 17 additions & 0 deletions packages/manager/src/components/TransferDisplay/utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import {
calculatePoolUsagePct,
formatPoolUsagePct,
formatRegionList,
getDaysRemaining,
getRegionTransferPools,
} from './utils';
Expand Down Expand Up @@ -72,3 +73,19 @@ describe('formatPoolUsagePct', () => {
expect(formattedPct).toBe('85%');
});
});

describe('formatRegionList', () => {
it('should format the list of regions correctly', () => {
const listOfNoRegions = [''];
const formattedListNoRegions = formatRegionList(listOfNoRegions);
expect(formattedListNoRegions).toBe('');

const listOfOneRegion = ['Newark, NJ'];
const formattedListOneRegion = formatRegionList(listOfOneRegion);
expect(formattedListOneRegion).toBe('Newark, NJ');

const listOfRegions = ['Newark, NJ', 'Dallas, TX', 'Fremont, CA'];
const formattedList = formatRegionList(listOfRegions);
expect(formattedList).toBe('Newark, NJ, Dallas, TX and Fremont, CA');
});
});
24 changes: 24 additions & 0 deletions packages/manager/src/components/TransferDisplay/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,27 @@ export const getRegionTransferPools = (
export const formatPoolUsagePct = (pct: number): string => {
return `${pct.toFixed(pct < 1 ? 2 : 0)}%`;
};

/**
* Format a list of regions into a readable string.
* @param regions
* @returns string
*
* @example formatRegionList(['Region 1', 'Region 2', 'Region 3']) // 'Region 1, Region 2 and Region 3'
* @example formatRegionList(['Region 1, Region 2']) // 'Region 1 and Region 2'
* @example formatRegionList(['Region 1']) // 'Region 1'
* @example formatRegionList([]) // ''
*/
export const formatRegionList = (regions: string[]) => {
const length = regions.length;

if (length === 0) {
return '';
} else if (length === 1) {
return regions[0];
} else {
const lastRegion = regions.pop();

return `${regions.join(', ')} and ${lastRegion}`;
}
};

0 comments on commit bc25cd6

Please sign in to comment.