Skip to content

Commit

Permalink
feat: [M3-8834] - Display new Accelerated plans in Plans Panel (#11287)
Browse files Browse the repository at this point in the history
* get initial helper text to show up

* bullet pointed notice

* tooltip showing

* update plan title

* some cleanup / remove unused props

* update way to customize accelerated's plan name

* added some mock premium plans

* transfer link

* hide accelerated plans behind feature flag

* add test for utils

* eslint fix

* Added changeset: Accelerated Linode plans in Linode/LKE create flow

* use planType instead of plans to determine accelerated table naming

* remove region availability notice, will be communicated as part of beta comms

* Update packages/manager/src/features/components/PlansPanel/PlanInformation.tsx

Co-authored-by: Alban Bailly <130582365+abailly-akamai@users.noreply.github.com>

* make constant for copy, try to match figma banner mockup more

* Update packages/manager/src/features/Kubernetes/CreateCluster/NodePoolPanel.tsx

Co-authored-by: Banks Nussman <115251059+bnussman-akamai@users.noreply.github.com>

* make logic more readable

* ux updates: accelerated plan notices

---------

Co-authored-by: Alban Bailly <130582365+abailly-akamai@users.noreply.github.com>
Co-authored-by: Banks Nussman <115251059+bnussman-akamai@users.noreply.github.com>
  • Loading branch information
3 people authored Nov 25, 2024
1 parent 23fa3c7 commit 1b0733f
Show file tree
Hide file tree
Showing 13 changed files with 278 additions and 69 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-11287-added-1732119985965.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Added
---

Accelerated Linode plans in Linode/LKE create flow ([#11287](https://github.com/linode/manager/pull/11287))
5 changes: 5 additions & 0 deletions packages/manager/src/__data__/regionsData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ export const regions: Region[] = [
'Vlans',
'VPCs',
'Metadata',
'NETINT Quadra T1U',
'Premium Plans',
],
country: 'in',
Expand Down Expand Up @@ -395,6 +396,7 @@ export const regions: Region[] = [
'Vlans',
'VPCs',
'Metadata',
'NETINT Quadra T1U',
'Premium Plans',
'Placement Group',
],
Expand Down Expand Up @@ -454,6 +456,7 @@ export const regions: Region[] = [
'Vlans',
'VPCs',
'Metadata',
'NETINT Quadra T1U',
'Premium Plans',
'Placement Group',
],
Expand Down Expand Up @@ -536,6 +539,7 @@ export const regions: Region[] = [
'Block Storage',
'Object Storage',
'GPU Linodes',
'NETINT Quadra T1U',
'Kubernetes',
'Cloud Firewall',
'Vlans',
Expand Down Expand Up @@ -657,6 +661,7 @@ export const regions: Region[] = [
'Block Storage',
'Object Storage',
'GPU Linodes',
'NETINT Quadra T1U',
'Kubernetes',
'Cloud Firewall',
'Vlans',
Expand Down
6 changes: 6 additions & 0 deletions packages/manager/src/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ interface gpuV2 {
transferBanner: boolean;
}

interface AcceleratedPlansFlag {
linodePlans: boolean;
lkePlans: boolean;
}

interface DesignUpdatesBannerFlag extends BaseFeatureFlag {
key: string;
link: string;
Expand All @@ -92,6 +97,7 @@ interface AclpAlerting {
recentActivity: boolean;
}
export interface Flags {
acceleratedPlans: AcceleratedPlansFlag;
aclp: AclpFlag;
aclpAlerting: AclpAlerting;
aclpReadEndpoint: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as React from 'react';

import { useIsDiskEncryptionFeatureEnabled } from 'src/components/Encryption/utils';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import { useIsAcceleratedPlansEnabled } from 'src/features/components/PlansPanel/utils';
import { useRegionsQuery } from 'src/queries/regions/regions';
import { doesRegionSupportFeature } from 'src/utilities/doesRegionSupportFeature';
import { extendType } from 'src/utilities/extendType';
Expand Down Expand Up @@ -69,6 +70,8 @@ const Panel = (props: NodePoolPanelProps) => {
isDiskEncryptionFeatureEnabled,
} = useIsDiskEncryptionFeatureEnabled();

const { isAcceleratedLKEPlansEnabled } = useIsAcceleratedPlansEnabled();

const regions = useRegionsQuery().data ?? [];

const [typeCountMap, setTypeCountMap] = React.useState<Map<string, number>>(
Expand Down Expand Up @@ -109,9 +112,15 @@ const Panel = (props: NodePoolPanelProps) => {
getTypeCount={(planId) =>
typeCountMap.get(planId) ?? DEFAULT_PLAN_COUNT
}
types={extendedTypes.filter(
(t) => t.class !== 'nanode' && t.class !== 'gpu'
)} // No Nanodes or GPUs in clusters
types={extendedTypes.filter((t) => {
if (!isAcceleratedLKEPlansEnabled && t.class === 'accelerated') {
// Accelerated plans will appear only if they are enabled (account capability exists and feature flag on)
return false;
}

// No Nanodes or GPUs in Kubernetes clusters
return t.class !== 'nanode' && t.class !== 'gpu';
})}
error={apiError}
hasSelectedRegion={hasSelectedRegion}
header="Add Node Pools"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ import type { PlanWithAvailability } from './types';
import type { Region } from '@linode/api-v4';
import type { LinodeTypeClass } from '@linode/api-v4/lib/linodes';
import type { Theme } from '@mui/material/styles';

export interface PlanSelectionFilterOptionsTable {
header?: string;
planFilter?: (plan: PlanWithAvailability) => boolean;
}

interface PlanSelectionDividers {
flag: boolean;
planType: LinodeTypeClass;
tables: PlanSelectionFilterOptionsTable[];
}

export interface PlanContainerProps {
allDisabledPlans: PlanWithAvailability[];
currentPlanHeading?: string;
Expand Down Expand Up @@ -68,15 +80,6 @@ export const PlanContainer = (props: PlanContainerProps) => {
!flags.dbaasV2?.beta &&
flags.dbaasV2?.enabled &&
(isDatabaseCreateFlow || isDatabaseResizeFlow);
interface PlanSelectionDividerTable {
header?: string;
planFilter?: (plan: PlanWithAvailability) => boolean;
}
interface PlanSelectionDividers {
flag: boolean;
planType: LinodeTypeClass;
tables: PlanSelectionDividerTable[];
}

/**
* This features allows us to divide the GPU plans into two separate tables.
Expand All @@ -102,7 +105,7 @@ export const PlanContainer = (props: PlanContainerProps) => {
];

const renderPlanSelection = React.useCallback(
(filterOptions?: PlanSelectionDividerTable) => {
(filterOptions?: PlanSelectionFilterOptionsTable) => {
const _plans = filterOptions?.planFilter
? plans.filter(filterOptions.planFilter)
: plans;
Expand Down Expand Up @@ -213,7 +216,6 @@ export const PlanContainer = (props: PlanContainerProps) => {
shouldDisplayNoRegionSelectedMessage
}
key={`plan-filter-${idx}`}
planFilter={table.planFilter}
plans={plans}
showNetwork={showNetwork}
showTransfer={showTransfer}
Expand All @@ -227,6 +229,8 @@ export const PlanContainer = (props: PlanContainerProps) => {
shouldDisplayNoRegionSelectedMessage
}
key={planType}
planType={planType}
plans={plans}
renderPlanSelection={renderPlanSelection}
showNetwork={showNetwork}
showTransfer={showTransfer}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
HIGH_MEMORY_COMPUTE_INSTANCES_LINK,
PREMIUM_COMPUTE_INSTANCES_LINK,
SHARED_COMPUTE_INSTANCES_LINK,
TRANSFER_COSTS_LINK,
} from './constants';
import { MetalNotice } from './MetalNotice';
import { PlansAvailabilityNotice } from './PlansAvailabilityNotice';
Expand Down Expand Up @@ -52,6 +53,31 @@ export const PlanInformation = (props: PlanInformationProps) => {
const showGPUEgressBanner = Boolean(useFlags().gpuv2?.egressBanner);
const showTransferBanner = Boolean(useFlags().gpuv2?.transferBanner);

const showLimitedAvailabilityBanner =
hasSelectedRegion &&
isSelectedRegionEligibleForPlan &&
!hideLimitedAvailabilityBanner &&
hasMajorityOfPlansDisabled;

const transferBanner = (
<Notice
spacingBottom={
planType === 'accelerated' && !showLimitedAvailabilityBanner ? 24 : 8
}
variant="warning"
>
<Typography
fontFamily={(theme: Theme) => theme.font.bold}
fontSize="1rem"
>
Some plans do not include bundled network transfer. If the transfer
allotment is 0, all outbound network transfer is subject to charges.
<br />
<Link to={TRANSFER_COSTS_LINK}>Learn more about transfer costs</Link>.
</Typography>
</Notice>
);

return (
<>
{planType === 'gpu' ? (
Expand All @@ -74,23 +100,7 @@ export const PlanInformation = (props: PlanInformationProps) => {
</Typography>
</Notice>
)}
{showTransferBanner && (
<Notice spacingBottom={8} variant="warning">
<Typography
fontFamily={(theme: Theme) => theme.font.bold}
fontSize="1rem"
>
Some plans do not include bundled network transfer. If the
transfer allotment is 0, all outbound network transfer is
subject to charges.
<br />
<Link to="https://techdocs.akamai.com/cloud-computing/docs/network-transfer-usage-and-costs">
Learn more about transfer costs
</Link>
.
</Typography>
</Notice>
)}
{showTransferBanner && transferBanner}
<PlansAvailabilityNotice
hasSelectedRegion={hasSelectedRegion}
isSelectedRegionEligibleForPlan={isSelectedRegionEligibleForPlan}
Expand All @@ -99,6 +109,7 @@ export const PlanInformation = (props: PlanInformationProps) => {
/>
</>
) : null}
{planType === 'accelerated' && transferBanner}
{planType === 'metal' ? (
<MetalNotice
dataTestId="metal-notice"
Expand All @@ -116,25 +127,22 @@ export const PlanInformation = (props: PlanInformationProps) => {
regionsData={regionsData || []}
/>
) : null}
{hasSelectedRegion &&
isSelectedRegionEligibleForPlan &&
!hideLimitedAvailabilityBanner &&
hasMajorityOfPlansDisabled && (
<Notice
sx={(theme: Theme) => ({
marginBottom: theme.spacing(3),
marginLeft: 0,
marginTop: 0,
padding: `${theme.spacing(0.5)} ${theme.spacing(2)}`,
})}
dataTestId={limitedAvailabilityBannerTestId}
variant="warning"
>
<StyledNoticeTypography>
These plans have limited deployment availability.
</StyledNoticeTypography>
</Notice>
)}
{showLimitedAvailabilityBanner && (
<Notice
sx={(theme: Theme) => ({
marginBottom: theme.spacing(3),
marginLeft: 0,
marginTop: 0,
padding: `${theme.spacing(0.5)} ${theme.spacing(2)}`,
})}
dataTestId={limitedAvailabilityBannerTestId}
variant="warning"
>
<StyledNoticeTypography>
These plans have limited deployment availability.
</StyledNoticeTypography>
</Notice>
)}
<ClassDescriptionCopy planType={planType} />
</>
);
Expand Down Expand Up @@ -168,6 +176,11 @@ export const ClassDescriptionCopy = (props: ExtendedPlanType) => {
planTypeLabel = 'GPU';
docLink = GPU_COMPUTE_INSTANCES_LINK;
break;
case 'accelerated':
// TODO: accelerated plans - acquire doc link
planTypeLabel = 'Accelerated';
docLink = '#';
break;
default:
planTypeLabel = null;
docLink = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@ import { PLAN_SELECTION_NO_REGION_SELECTED_MESSAGE } from 'src/utilities/pricing

import { StyledTable, StyledTableCell } from './PlanContainer.styles';

import type { PlanSelectionFilterOptionsTable } from './PlanContainer';
import type { PlanWithAvailability } from './types';
import type { LinodeTypeClass } from '@linode/api-v4/';
import type { TooltipIconStatus } from '@linode/ui';

interface PlanSelectionFilterOptionsTable {
header?: string;
planFilter?: (plan: PlanWithAvailability) => boolean;
}

interface PlanSelectionTableProps {
filterOptions?: PlanSelectionFilterOptionsTable;
planFilter?: (plan: PlanWithAvailability) => boolean;
planType?: LinodeTypeClass;
plans?: PlanWithAvailability[];
renderPlanSelection: (
filterOptions?: PlanSelectionFilterOptionsTable | undefined
Expand Down Expand Up @@ -51,6 +48,7 @@ const tableCells = [
export const PlanSelectionTable = (props: PlanSelectionTableProps) => {
const {
filterOptions,
planType,
plans,
renderPlanSelection,
shouldDisplayNoRegionSelectedMessage,
Expand All @@ -63,10 +61,12 @@ export const PlanSelectionTable = (props: PlanSelectionTableProps) => {
const showTransferTooltip = React.useCallback(
(cellName: string) =>
plans?.some((plan) => {
return (
const showTooltipForGPUPlans =
flags.gpuv2?.transferBanner &&
plan.class === 'gpu' &&
filterOptions?.header?.includes('Ada') &&
filterOptions?.header?.includes('Ada');
return (
(showTooltipForGPUPlans || plan.class === 'accelerated') &&
cellName === 'Transfer'
);
}),
Expand Down Expand Up @@ -120,6 +120,9 @@ export const PlanSelectionTable = (props: PlanSelectionTableProps) => {
) {
cellName = 'Usable Storage';
}
if (isPlanCell && planType === 'accelerated') {
cellName = 'NETINT Quadra T1U';
}
return (
<StyledTableCell
center={center}
Expand Down Expand Up @@ -154,7 +157,7 @@ export const PlanSelectionTable = (props: PlanSelectionTableProps) => {
message={PLAN_SELECTION_NO_REGION_SELECTED_MESSAGE}
/>
) : (
renderPlanSelection(filterOptions)
renderPlanSelection()
)}
</TableBody>
</StyledTable>
Expand Down
20 changes: 11 additions & 9 deletions packages/manager/src/features/components/PlansPanel/PlansPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { getIsDistributedRegion } from 'src/components/RegionSelect/RegionSelect
import { useIsGeckoEnabled } from 'src/components/RegionSelect/RegionSelect.utils';
import { TabbedPanel } from 'src/components/TabbedPanel/TabbedPanel';
import { useFlags } from 'src/hooks/useFlags';
import { useAccount } from 'src/queries/account/account';
import { useRegionAvailabilityQuery } from 'src/queries/regions/regions';
import { plansNoticesUtils } from 'src/utilities/planNotices';
import { getQueryParamsFromQueryString } from 'src/utilities/queryParams';
Expand All @@ -21,6 +20,7 @@ import {
getPlanSelectionsByPlanType,
planTabInfoContent,
replaceOrAppendPlaceholder512GbPlans,
useIsAcceleratedPlansEnabled,
} from './utils';

import type { PlanSelectionType } from './types';
Expand Down Expand Up @@ -88,20 +88,22 @@ export const PlansPanel = (props: PlansPanelProps) => {
location.search
);

const { data: account } = useAccount();
const hasVPUCapability = account?.capabilities?.includes('NETINT Quadra T1U');
const { isAcceleratedLinodePlansEnabled } = useIsAcceleratedPlansEnabled();

const { data: regionAvailabilities } = useRegionAvailabilityQuery(
selectedRegionID || '',
Boolean(flags.soldOutChips) && selectedRegionID !== undefined
);

const _types = types.filter(
(type) =>
!type.id.includes('dedicated-edge') &&
!type.id.includes('nanode-edge') &&
(!hasVPUCapability ? type.class !== 'accelerated' : true)
);
const _types = types.filter((type) => {
if (!isAcceleratedLinodePlansEnabled && type.class === 'accelerated') {
return false;
}

return (
!type.id.includes('dedicated-edge') && !type.id.includes('nanode-edge')
);
});
const _plans = getPlanSelectionsByPlanType(
flags.disableLargestGbPlans
? replaceOrAppendPlaceholder512GbPlans(_types)
Expand Down
Loading

0 comments on commit 1b0733f

Please sign in to comment.