From e5dff3b42f656ce912d3ed43e07f3d73c3a8caa7 Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Fri, 7 Mar 2025 13:30:20 -0800 Subject: [PATCH 1/8] Show the APL section only for standard cluster tiers --- .../cypress/e2e/core/kubernetes/lke-create.spec.ts | 6 ++++++ .../Kubernetes/CreateCluster/CreateCluster.tsx | 11 +++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/manager/cypress/e2e/core/kubernetes/lke-create.spec.ts b/packages/manager/cypress/e2e/core/kubernetes/lke-create.spec.ts index d45924c64b3..69574538c57 100644 --- a/packages/manager/cypress/e2e/core/kubernetes/lke-create.spec.ts +++ b/packages/manager/cypress/e2e/core/kubernetes/lke-create.spec.ts @@ -1086,6 +1086,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 not shown 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 @@ -1215,6 +1216,11 @@ describe('LKE Cluster Creation with LKE-E', () => { .should('be.enabled') .click(); + // Confirm the APL section is not shown. + cy.findByTestId('apl-label').should('not.exist'); + cy.findByTestId('apl-radio-button-yes').should('not.exist'); + cy.findByTestId('apl-radio-button-no').should('not.exist'); + // Confirm the expected available plans display. validEnterprisePlanTabs.forEach((tab) => { ui.tabList.findTabByTitle(tab).should('be.visible'); diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx index 47a3cc8aea3..744c548e120 100644 --- a/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx +++ b/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx @@ -115,6 +115,9 @@ export const CreateCluster = () => { isLoading: isLoadingKubernetesTypes, } = useKubernetesTypesQuery(selectedTier === 'enterprise'); + // LKE-E does not support APL at this time. + const isAPLEnabled = showAPL && selectedTier === 'standard'; + const handleClusterTierSelection = (tier: KubernetesTier) => { setSelectedTier(tier); @@ -242,7 +245,7 @@ export const CreateCluster = () => { region: selectedRegion?.id, }; - if (showAPL) { + if (isAPLEnabled) { payload = { ...payload, apl_enabled }; } @@ -251,7 +254,7 @@ export const CreateCluster = () => { } const createClusterFn = - showAPL || isLkeEnterpriseLAFeatureEnabled + isAPLEnabled || isLkeEnterpriseLAFeatureEnabled ? createKubernetesClusterBeta : createKubernetesCluster; @@ -447,7 +450,7 @@ export const CreateCluster = () => { /> - {showAPL && ( + {isAPLEnabled && ( <> @@ -460,7 +463,7 @@ export const CreateCluster = () => { )} - + {showHighAvailability && selectedTier !== 'enterprise' && ( Date: Fri, 7 Mar 2025 13:42:48 -0800 Subject: [PATCH 2/8] Added changeset: Disable APL for LKE-E clusters on create flow --- .../.changeset/pr-11809-upcoming-features-1741383768710.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-11809-upcoming-features-1741383768710.md diff --git a/packages/manager/.changeset/pr-11809-upcoming-features-1741383768710.md b/packages/manager/.changeset/pr-11809-upcoming-features-1741383768710.md new file mode 100644 index 00000000000..3e7e31310c6 --- /dev/null +++ b/packages/manager/.changeset/pr-11809-upcoming-features-1741383768710.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Disable APL for LKE-E clusters on create flow ([#11809](https://github.com/linode/manager/pull/11809)) From ebfb57b661dd75aac9220e122a31be170a63531f Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Mon, 10 Mar 2025 15:01:53 -0700 Subject: [PATCH 3/8] WIP - poc for what disabled, rather than hidden, section would look like --- .../CreateCluster/ApplicationPlatform.tsx | 13 +++++++-- .../CreateCluster/CreateCluster.tsx | 27 ++++++++++--------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx index 20d0f5557fc..7a33bec6504 100644 --- a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx +++ b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx @@ -3,6 +3,7 @@ import { Chip, FormControl, FormControlLabel, + Notice, Radio, RadioGroup, Typography, @@ -13,6 +14,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; } @@ -28,7 +30,7 @@ export const APLCopy = () => ( ); export const ApplicationPlatform = (props: APLProps) => { - const { setAPL, setHighAvailability } = props; + const { isSectionDisabled, setAPL, setHighAvailability } = props; const handleChange = (e: React.ChangeEvent) => { setAPL(e.target.value === 'yes'); @@ -53,15 +55,22 @@ export const ApplicationPlatform = (props: APLProps) => { + {isSectionDisabled && ( + + APL is not yet available for LKE Enterprise. + + )} handleChange(e)}> } - label={Yes, enable Akamai App Platform.} + disabled={isSectionDisabled} + label="Yes, enable Akamai App Platform." name="yes" value="yes" /> } + disabled={isSectionDisabled} label="No" name="no" value="no" diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx index 744c548e120..2144c5b5382 100644 --- a/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx +++ b/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx @@ -450,19 +450,20 @@ export const CreateCluster = () => { /> - {isAPLEnabled && ( - <> - - - - - - - - )} + {/* {isAPLEnabled && ( */} + <> + + + + + + + + {/* )} */} {showHighAvailability && selectedTier !== 'enterprise' && ( From b0626b23bfccb913e235718911cf76142b45f83e Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Wed, 12 Mar 2025 08:01:50 -0700 Subject: [PATCH 4/8] Update with proposed UX changes --- .../CreateCluster/ApplicationPlatform.tsx | 13 ++++--- .../CreateCluster/CreateCluster.tsx | 36 +++++++++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx index 7a33bec6504..76d165dc2a4 100644 --- a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx +++ b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx @@ -3,7 +3,6 @@ import { Chip, FormControl, FormControlLabel, - Notice, Radio, RadioGroup, Typography, @@ -29,9 +28,13 @@ export const APLCopy = () => ( ); +const APL_UNSUPPORTED_CHIP_COPY = ' - COMING SOON'; + export const ApplicationPlatform = (props: APLProps) => { const { isSectionDisabled, setAPL, setHighAvailability } = props; + const CHIP_COPY = `BETA${isSectionDisabled ? APL_UNSUPPORTED_CHIP_COPY : ''}`; + const handleChange = (e: React.ChangeEvent) => { setAPL(e.target.value === 'yes'); setHighAvailability(e.target.value === 'yes'); @@ -51,15 +54,10 @@ export const ApplicationPlatform = (props: APLProps) => { > Akamai App Platform - + - {isSectionDisabled && ( - - APL is not yet available for LKE Enterprise. - - )} handleChange(e)}> } @@ -69,6 +67,7 @@ export const ApplicationPlatform = (props: APLProps) => { value="yes" /> } disabled={isSectionDisabled} label="No" diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx index 435b74aaa08..a8b751f3004 100644 --- a/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx +++ b/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx @@ -116,7 +116,7 @@ export const CreateCluster = () => { } = useKubernetesTypesQuery(selectedTier === 'enterprise'); // LKE-E does not support APL at this time. - const isAPLEnabled = showAPL && selectedTier === 'standard'; + const isAPLSupported = showAPL && selectedTier === 'standard'; const handleClusterTierSelection = (tier: KubernetesTier) => { setSelectedTier(tier); @@ -245,7 +245,7 @@ export const CreateCluster = () => { region: selectedRegion?.id, }; - if (isAPLEnabled) { + if (isAPLSupported) { payload = { ...payload, apl_enabled }; } @@ -254,7 +254,7 @@ export const CreateCluster = () => { } const createClusterFn = - isAPLEnabled || isLkeEnterpriseLAFeatureEnabled + isAPLSupported || isLkeEnterpriseLAFeatureEnabled ? createKubernetesClusterBeta : createKubernetesCluster; @@ -450,21 +450,21 @@ export const CreateCluster = () => { /> - {/* {isAPLEnabled && ( */} - <> - - - - - - - - {/* )} */} - + {showAPL && ( + <> + + + + + + + + )} + {showHighAvailability && selectedTier !== 'enterprise' && ( Date: Wed, 12 Mar 2025 08:43:30 -0700 Subject: [PATCH 5/8] Update test coverage with mocked endpoints, UX changes --- .../e2e/core/kubernetes/lke-create.spec.ts | 26 ++++++++++++++----- .../CreateCluster/ApplicationPlatform.tsx | 7 ++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/packages/manager/cypress/e2e/core/kubernetes/lke-create.spec.ts b/packages/manager/cypress/e2e/core/kubernetes/lke-create.spec.ts index 69574538c57..45926ae70b0 100644 --- a/packages/manager/cypress/e2e/core/kubernetes/lke-create.spec.ts +++ b/packages/manager/cypress/e2e/core/kubernetes/lke-create.spec.ts @@ -13,6 +13,7 @@ import { nodePoolFactory, kubeLinodeFactory, lkeHighAvailabilityTypeFactory, + accountBetaFactory, } from 'src/factories'; import { mockCreateCluster, @@ -458,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( @@ -1086,7 +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 not shown while it remains unsupported + * - 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 @@ -1095,13 +1097,19 @@ describe('LKE Cluster Creation with LKE-E', () => { it('creates an LKE-E cluster with the account capability', () => { const clusterLabel = randomLabel(); const mockedEnterpriseCluster = kubernetesClusterFactory.build({ + k8s_version: latestEnterpriseTierKubernetesVersion.id, label: clusterLabel, region: 'us-iad', tier: 'enterprise', - k8s_version: latestEnterpriseTierKubernetesVersion.id, }); const mockedEnterpriseClusterPools = [nanodeMemoryPool, dedicatedCpuPool]; + mockGetAccountBeta( + accountBetaFactory.build({ + id: 'apl', + label: 'Akamai App Platform Beta', + }) + ).as('getAccountBeta'); mockGetAccount( accountFactory.build({ capabilities: [ @@ -1216,10 +1224,16 @@ describe('LKE Cluster Creation with LKE-E', () => { .should('be.enabled') .click(); - // Confirm the APL section is not shown. - cy.findByTestId('apl-label').should('not.exist'); - cy.findByTestId('apl-radio-button-yes').should('not.exist'); - cy.findByTestId('apl-radio-button-no').should('not.exist'); + // 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) => { diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx index 76d165dc2a4..5ab994d00ef 100644 --- a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx +++ b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx @@ -54,7 +54,12 @@ export const ApplicationPlatform = (props: APLProps) => { > Akamai App Platform - + From 10009569cfe6521597e1e741434538a81401431a Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Wed, 12 Mar 2025 08:46:04 -0700 Subject: [PATCH 6/8] Tweak changeset --- .../.changeset/pr-11809-upcoming-features-1741383768710.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/.changeset/pr-11809-upcoming-features-1741383768710.md b/packages/manager/.changeset/pr-11809-upcoming-features-1741383768710.md index 3e7e31310c6..1c4345cb107 100644 --- a/packages/manager/.changeset/pr-11809-upcoming-features-1741383768710.md +++ b/packages/manager/.changeset/pr-11809-upcoming-features-1741383768710.md @@ -2,4 +2,4 @@ "@linode/manager": Upcoming Features --- -Disable APL for LKE-E clusters on create flow ([#11809](https://github.com/linode/manager/pull/11809)) +Disable Akamai App Plaform beta for LKE-E clusters on create flow ([#11809](https://github.com/linode/manager/pull/11809)) From b5362b1d9da472c8d66f2deff64c9ba8c39aea3c Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Wed, 12 Mar 2025 12:47:03 -0700 Subject: [PATCH 7/8] Update chip text size to small for consistency with other chips --- .../features/Kubernetes/CreateCluster/ApplicationPlatform.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx index 5ab994d00ef..fb475182f7c 100644 --- a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx +++ b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx @@ -58,6 +58,7 @@ export const ApplicationPlatform = (props: APLProps) => { color="primary" data-testid="apl-beta-chip" label={CHIP_COPY} + size="small" sx={{ ml: 1 }} /> From cfe66c9bac68f63eb975d59b5035e0484c970543 Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Thu, 13 Mar 2025 16:26:58 -0700 Subject: [PATCH 8/8] Fix bug preventing 'no' button from being checked --- .../ApplicationPlatform.test.tsx | 57 +++++++++++++++++++ .../CreateCluster/ApplicationPlatform.tsx | 18 +++++- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.test.tsx diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.test.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.test.tsx new file mode 100644 index 00000000000..dd8b6a74d01 --- /dev/null +++ b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.test.tsx @@ -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( + + ); + 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( + + ); + 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( + + ); + 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(); + }); +}); diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx index fb475182f7c..fe50fbed3ca 100644 --- a/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx +++ b/packages/manager/src/features/Kubernetes/CreateCluster/ApplicationPlatform.tsx @@ -33,6 +33,21 @@ const APL_UNSUPPORTED_CHIP_COPY = ' - COMING SOON'; export const ApplicationPlatform = (props: APLProps) => { const { isSectionDisabled, setAPL, setHighAvailability } = props; + const [isAPLChecked, setIsAPLChecked] = React.useState( + 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) => { @@ -71,14 +86,15 @@ export const ApplicationPlatform = (props: APLProps) => { label="Yes, enable Akamai App Platform." name="yes" value="yes" + checked={isAPLChecked} /> } disabled={isSectionDisabled} label="No" name="no" value="no" + checked={isAPLNotChecked} />