Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Disable Akamai App Plaform beta for LKE-E clusters on create flow ([#11809](https://github.com/linode/manager/pull/11809))
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { randomItem, randomLabel, randomNumber } from 'support/util/random';
import { getRegionById } from 'support/util/regions';
import { chooseRegion } from 'support/util/regions';

import { lkeEnterpriseTypeFactory } from 'src/factories';
import { accountBetaFactory, lkeEnterpriseTypeFactory } from 'src/factories';
import {
accountFactory,
dedicatedTypeFactory,
Expand Down Expand Up @@ -459,6 +459,7 @@ describe('LKE Cluster Creation with APL enabled', () => {
ui.regionSelect.find().click().type(`${clusterRegion.label}{enter}`);

cy.findByTestId('apl-label').should('have.text', 'Akamai App Platform');
cy.findByTestId('apl-beta-chip').should('have.text', 'BETA');
cy.findByTestId('apl-radio-button-yes').should('be.visible').click();
cy.findByTestId('ha-radio-button-yes').should('be.disabled');
cy.get(
Expand Down Expand Up @@ -1087,6 +1088,7 @@ describe('LKE Cluster Creation with LKE-E', () => {
* - Confirms that HA is enabled by default with LKE-E selection
* - Confirms an LKE-E supported region can be selected
* - Confirms an LKE-E supported k8 version can be selected
* - Confirms the APL section is disabled while it remains unsupported
* - Confirms at least one IP must be provided for ACL
* - Confirms the checkout bar displays the correct LKE-E info
* - Confirms an enterprise cluster can be created with the correct chip, version, and price
Expand All @@ -1102,6 +1104,12 @@ describe('LKE Cluster Creation with LKE-E', () => {
});
const mockedEnterpriseClusterPools = [nanodeMemoryPool, dedicatedCpuPool];

mockGetAccountBeta(
accountBetaFactory.build({
id: 'apl',
label: 'Akamai App Platform Beta',
})
).as('getAccountBeta');
mockGetAccount(
accountFactory.build({
capabilities: [
Expand Down Expand Up @@ -1216,6 +1224,17 @@ describe('LKE Cluster Creation with LKE-E', () => {
.should('be.enabled')
.click();

// Confirm the APL section is disabled and unsupported.
cy.findByTestId('apl-label').should('be.visible');
cy.findByTestId('apl-beta-chip').should(
'have.text',
'BETA - COMING SOON'
);
cy.findByTestId('apl-radio-button-yes').should('be.disabled');
cy.findByTestId('apl-radio-button-no').within(() => {
cy.findByRole('radio').should('be.disabled').should('be.checked');
});

// Confirm the expected available plans display.
validEnterprisePlanTabs.forEach((tab) => {
ui.tabList.findTabByTitle(tab).should('be.visible');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import userEvent from '@testing-library/user-event';
import React from 'react';

import { renderWithTheme } from 'src/utilities/testHelpers';

import { ApplicationPlatform } from './ApplicationPlatform';

const MockDefaultProps = {
isSectionDisabled: false,
setAPL: vi.fn(),
setHighAvailability: vi.fn(),
};

describe('ApplicationPlatform', () => {
it('renders enabled but unchecked radio buttons with the section enabled', () => {
const { getByRole } = renderWithTheme(
<ApplicationPlatform {...MockDefaultProps} />
);
const yesRadio = getByRole('radio', { name: /yes/i });
const noRadio = getByRole('radio', { name: /no/i });

expect(yesRadio).toBeEnabled();
expect(yesRadio).not.toBeChecked();
expect(noRadio).toBeEnabled();
expect(noRadio).not.toBeChecked();
});

it('toggles checked state correctly with the section enabled', async () => {
const { getByRole } = renderWithTheme(
<ApplicationPlatform {...MockDefaultProps} />
);
const yesRadio = getByRole('radio', { name: /yes/i });
const noRadio = getByRole('radio', { name: /no/i });

// Confirm both buttons can be clicked.
await userEvent.click(yesRadio);
expect(yesRadio).toBeChecked();
expect(noRadio).not.toBeChecked();

await userEvent.click(noRadio);
expect(noRadio).toBeChecked();
expect(yesRadio).not.toBeChecked();
});

it('renders disabled radio buttons and the "no" option checked with the section disabled', () => {
const { getByRole } = renderWithTheme(
<ApplicationPlatform {...MockDefaultProps} isSectionDisabled />
);
const yesRadio = getByRole('radio', { name: /yes/i });
const noRadio = getByRole('radio', { name: /no/i });

expect(yesRadio).toBeDisabled();
expect(yesRadio).not.toBeChecked();
expect(noRadio).toBeDisabled();
expect(noRadio).toBeChecked();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { FormLabel } from 'src/components/FormLabel';
import { Link } from 'src/components/Link';

export interface APLProps {
isSectionDisabled: boolean;
setAPL: (apl: boolean) => void;
setHighAvailability: (ha: boolean | undefined) => void;
}
Expand All @@ -27,8 +28,27 @@ export const APLCopy = () => (
</Typography>
);

const APL_UNSUPPORTED_CHIP_COPY = ' - COMING SOON';

export const ApplicationPlatform = (props: APLProps) => {
const { setAPL, setHighAvailability } = props;
const { isSectionDisabled, setAPL, setHighAvailability } = props;

const [isAPLChecked, setIsAPLChecked] = React.useState<boolean | undefined>(
isSectionDisabled ? false : undefined
);
const [isAPLNotChecked, setIsAPLNotChecked] = React.useState<
boolean | undefined
>(isSectionDisabled ? true : undefined);

/**
* Reset the radio buttons to the correct default state once the user toggles cluster tiers.
*/
React.useEffect(() => {
setIsAPLChecked(isSectionDisabled ? false : undefined);
setIsAPLNotChecked(isSectionDisabled ? true : undefined);
}, [isSectionDisabled]);

const CHIP_COPY = `BETA${isSectionDisabled ? APL_UNSUPPORTED_CHIP_COPY : ''}`;

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setAPL(e.target.value === 'yes');
Expand All @@ -49,22 +69,32 @@ export const ApplicationPlatform = (props: APLProps) => {
>
<Box alignItems="center" display="flex" flexDirection="row">
<Typography data-testid="apl-label">Akamai App Platform</Typography>
<Chip color="primary" label="BETA" sx={{ ml: 1 }} />
<Chip
color="primary"
data-testid="apl-beta-chip"
label={CHIP_COPY}
size="small"
sx={{ ml: 1 }}
/>
</Box>
</FormLabel>
<APLCopy />
<RadioGroup onChange={(e) => handleChange(e)}>
<FormControlLabel
control={<Radio data-testid="apl-radio-button-yes" />}
label={<Typography>Yes, enable Akamai App Platform.</Typography>}
disabled={isSectionDisabled}
label="Yes, enable Akamai App Platform."
name="yes"
value="yes"
checked={isAPLChecked}
/>
<FormControlLabel
control={<Radio data-testid="apl-radio-button-no" />}
disabled={isSectionDisabled}
label="No"
name="no"
value="no"
checked={isAPLNotChecked}
/>
</RadioGroup>
</FormControl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ export const CreateCluster = () => {
isLoading: isLoadingKubernetesTypes,
} = useKubernetesTypesQuery(selectedTier === 'enterprise');

// LKE-E does not support APL at this time.
const isAPLSupported = showAPL && selectedTier === 'standard';

const handleClusterTierSelection = (tier: KubernetesTier) => {
setSelectedTier(tier);

Expand Down Expand Up @@ -242,7 +245,7 @@ export const CreateCluster = () => {
region: selectedRegion?.id,
};

if (showAPL) {
if (isAPLSupported) {
payload = { ...payload, apl_enabled };
}

Expand All @@ -251,7 +254,7 @@ export const CreateCluster = () => {
}

const createClusterFn =
showAPL || isLkeEnterpriseLAFeatureEnabled
isAPLSupported || isLkeEnterpriseLAFeatureEnabled
? createKubernetesClusterBeta
: createKubernetesCluster;

Expand Down Expand Up @@ -453,6 +456,7 @@ export const CreateCluster = () => {
<StyledStackWithTabletBreakpoint>
<Stack>
<ApplicationPlatform
isSectionDisabled={!isAPLSupported}
setAPL={setApl_enabled}
setHighAvailability={setHighAvailability}
/>
Expand Down