Skip to content

Commit

Permalink
upcoming: [M3-7724] - Linode plan table updates for Edge regions (#10255
Browse files Browse the repository at this point in the history
)

## Description 📝
API work for Edge plans will not be ready for Beta. So, we need to hardcode the plans ourselves until then. 

## Changes  🔄
List any change relevant to the reviewer.
- Edge regions will only display dedicated plans minus the 256gb and 516gb plans
- Edge region price is $0 for Beta and a warning explanation notice is displayed

## How to test 🧪

### Prerequisites
(How to setup test environment)
- Ensure you have the right customer tag for testing new dcs (reach out for more info)

### Verification steps
(How to verify changes)
- Go to `/linodes/create` and select an Edge region
- You should not see the tab control, only the Dedicated Linode Plan Table minus the 256gb and 516gb plans
- The summary section should reflect the $0 price
- Core regions should still display the same plans as prod
  • Loading branch information
hana-akamai authored Mar 12, 2024
1 parent 48bf7e4 commit 0830c44
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Linode plan table updates for Edge regions ([#10255](https://github.com/linode/manager/pull/10255))
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,11 @@ export class LinodeCreate extends React.PureComponent<
});
}

const linodeIsInEdgeRegion = getIsEdgeRegion(
regionsData,
selectedRegionID ?? ''
);

if (typeDisplayInfo) {
const typeDisplayInfoCopy = cloneDeep(typeDisplayInfo);

Expand All @@ -392,7 +397,17 @@ export class LinodeCreate extends React.PureComponent<
)}/month $${hourlyPrice ?? UNKNOWN_PRICE}/hr`;
}

displaySections.push(typeDisplayInfoCopy);
// @TODO Gecko: Remove $0 hardcoding once plan data is returned from API
if (linodeIsInEdgeRegion) {
displaySections.push({
...typeDisplayInfoCopy,
details: '$0/month',
hourly: 0,
monthly: 0,
});
} else {
displaySections.push(typeDisplayInfoCopy);
}
}

const type = typesData.find(
Expand All @@ -406,7 +421,12 @@ export class LinodeCreate extends React.PureComponent<
type,
});

if (hasBackups && typeDisplayInfo && backupsMonthlyPrice) {
if (
hasBackups &&
typeDisplayInfo &&
backupsMonthlyPrice &&
!linodeIsInEdgeRegion
) {
displaySections.push(
renderBackupsDisplaySection(accountBackupsEnabled, backupsMonthlyPrice)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { styled } from '@mui/material/styles';
import { SxProps } from '@mui/system';
import React from 'react';

import { Box } from 'src/components/Box';
import { Notice } from 'src/components/Notice/Notice';
import { Paper } from 'src/components/Paper';
import { Typography } from 'src/components/Typography';

interface EdgePlanTableProps {
copy?: string;
docsLink?: JSX.Element;
error?: JSX.Element | string;
header: string;
innerClass?: string;
renderTable: () => React.JSX.Element;
rootClass?: string;
sx?: SxProps;
}

export const EdgePlanTable = React.memo((props: EdgePlanTableProps) => {
const {
copy,
docsLink,
error,
header,
innerClass,
renderTable,
rootClass,
sx,
} = props;

return (
<Paper
className={rootClass}
data-qa-tp={header}
sx={{ flexGrow: 1, ...sx }}
>
<div className={innerClass}>
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
{header && (
<Typography data-qa-tp-title variant="h2">
{header}
</Typography>
)}
{docsLink}
</Box>
{error && (
<Notice spacingBottom={0} spacingTop={12} variant="error">
{error}
</Notice>
)}
{copy && <StyledTypography data-qa-tp-copy>{copy}</StyledTypography>}
{renderTable()}
</div>
</Paper>
);
});

const StyledTypography = styled(Typography)(({ theme }) => ({
fontSize: '0.875rem',
marginTop: theme.spacing(1),
}));
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { StyledDisabledTableRow } from './PlansPanel.styles';

import type { PlanSelectionType } from './types';
import type { LinodeTypeClass, PriceObject, Region } from '@linode/api-v4';

export interface PlanSelectionProps {
currentPlanHeading?: string;
disabled?: boolean;
Expand Down Expand Up @@ -206,7 +207,7 @@ export const PlanSelection = (props: PlanSelectionProps) => {
{type.vcpus}
</TableCell>
<TableCell center data-qa-storage noWrap>
{convertMegabytesTo(type.disk, true)}
{type.disk === 0 ? 'N/A' : convertMegabytesTo(type.disk, true)}
</TableCell>
{shouldShowTransfer && type.transfer ? (
<TableCell center data-qa-transfer>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { useTheme } from '@mui/material/styles';
import * as React from 'react';
import { useLocation } from 'react-router-dom';

import { Notice } from 'src/components/Notice/Notice';
import { getIsLinodeCreateTypeEdgeSupported } from 'src/components/RegionSelect/RegionSelect.utils';
import { getIsEdgeRegion } from 'src/components/RegionSelect/RegionSelect.utils';
import { TabbedPanel } from 'src/components/TabbedPanel/TabbedPanel';
import { useFlags } from 'src/hooks/useFlags';
import { plansNoticesUtils } from 'src/utilities/planNotices';
import { getQueryParamsFromQueryString } from 'src/utilities/queryParams';

import { EdgePlanTable } from './EdgePlanTable';
import { PlanContainer } from './PlanContainer';
import { PlanInformation } from './PlanInformation';
import {
Expand All @@ -14,6 +21,8 @@ import {

import type { PlanSelectionType } from './types';
import type { LinodeTypeClass, Region } from '@linode/api-v4';
import type { LinodeCreateType } from 'src/features/Linodes/LinodesCreate/types';

interface Props {
className?: string;
copy?: string;
Expand Down Expand Up @@ -56,9 +65,50 @@ export const PlansPanel = (props: Props) => {
types,
} = props;

const flags = useFlags();
const theme = useTheme();
const location = useLocation();
const params = getQueryParamsFromQueryString(location.search);

const hideEdgeRegions =
!flags.gecko ||
!getIsLinodeCreateTypeEdgeSupported(params.type as LinodeCreateType);

const showEdgePlanTable =
!hideEdgeRegions &&
getIsEdgeRegion(regionsData ?? [], selectedRegionID ?? '');

const planTypes = getPlanSelectionsByPlanType(types);

const getDedicatedEdgePlanType = () => {
// 256gb and 512gb plans will not be supported for Edge
const plansUpTo128GB = planTypes.dedicated.filter(
(planType) =>
!['Dedicated 256 GB', 'Dedicated 512 GB'].includes(
planType.formattedLabel
)
);

return plansUpTo128GB.map((plan) => {
delete plan.transfer;
return {
...plan,
disk: 0,
price: {
hourly: 0,
monthly: 0,
},
};
});
};

// @TODO Gecko: Get plan data from API when it's available instead of hardcoding
const plans = showEdgePlanTable
? {
dedicated: getDedicatedEdgePlanType(),
}
: planTypes;

const plans = getPlanSelectionsByPlanType(types);
const {
hasSelectedRegion,
isPlanPanelDisabled,
Expand All @@ -83,6 +133,12 @@ export const PlansPanel = (props: Props) => {
planType={plan}
regionsData={regionsData || []}
/>
{showEdgePlanTable && (
<Notice
text="Edge region pricing is temporarily $0 during the beta period, after which standard pricing will begin."
variant="warning"
/>
)}
<PlanContainer
currentPlanHeading={currentPlanHeading}
disabled={disabled || isPlanPanelDisabled(plan)}
Expand All @@ -109,6 +165,22 @@ export const PlansPanel = (props: Props) => {
currentPlanHeading
);

if (showEdgePlanTable) {
return (
<EdgePlanTable
copy={copy}
data-qa-select-plan
docsLink={docsLink}
error={error}
header={header || 'Linode Plan'}
innerClass={props.tabbedPanelInnerClass}
renderTable={tabs[0].render}
rootClass={`${className} tabbedPanel`}
sx={{ marginTop: theme.spacing(3), width: '100%' }}
/>
);
}

return (
<TabbedPanel
copy={copy}
Expand Down

0 comments on commit 0830c44

Please sign in to comment.