From dbec10426e4a9032b934564103593cec3cd0088a Mon Sep 17 00:00:00 2001 From: pmakode-akamai Date: Wed, 31 Dec 2025 13:49:43 +0530 Subject: [PATCH 1/7] Update GP default sort to show newest (G8) -> oldest (G6) --- .../PlansPanel/utils/planFilters.test.ts | 16 ++++++++++++++++ .../PlansPanel/utils/planFilters.ts | 19 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/components/PlansPanel/utils/planFilters.test.ts b/packages/manager/src/features/components/PlansPanel/utils/planFilters.test.ts index 1c4e99cf5c5..7dddf55b744 100644 --- a/packages/manager/src/features/components/PlansPanel/utils/planFilters.test.ts +++ b/packages/manager/src/features/components/PlansPanel/utils/planFilters.test.ts @@ -11,6 +11,7 @@ import { filterPlansByGpuType, filterPlansByType, getAvailableTypes, + getGenerationRank, supportsTypeFiltering, } from './planFilters'; @@ -240,4 +241,19 @@ describe('planFilters utilities', () => { expect(result).toEqual(gpuPlans); }); }); + + describe('getGenerationRank', () => { + it('returns higher rank for newer generations', () => { + expect(getGenerationRank('g8-dedicated-4-2')).toBeGreaterThan( + getGenerationRank('g7-dedicated-4-2') + ); + expect(getGenerationRank('g7-dedicated-4-2')).toBeGreaterThan( + getGenerationRank('g6-dedicated-2') + ); + }); + + it('returns 0 for unknown generations', () => { + expect(getGenerationRank('legacy-plan')).toBe(0); + }); + }); }); diff --git a/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts b/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts index 9dd66d55a8d..9ada25d4ffd 100644 --- a/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts +++ b/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts @@ -68,6 +68,19 @@ export const filterPlansByGeneration = ( // Type Filtering // ============================================================================ +/** + * Determines the relative generation order of a plan based on its ID. + * + * Used to sort plans from newest to oldest when the "All" type + * filter is selected (G8 → G7 → G6). + */ +export const getGenerationRank = (planId: string): number => { + if (planId.startsWith('g8-')) return 3; + if (planId.startsWith('g7-')) return 2; + if (planId.startsWith('g6-')) return 1; + return 0; +}; + /** * Filter plans by type within a generation * @@ -88,9 +101,11 @@ export const filterPlansByType = ( generation: PlanFilterGeneration, type: PlanFilterType ): PlanWithAvailability[] => { - // "All" returns all plans unchanged + // "All" returns all plans, sorted from newest (G8) to oldest (G6) if (type === PLAN_FILTER_ALL) { - return plans; + return [...plans].sort( + (a, b) => getGenerationRank(b.id) - getGenerationRank(a.id) + ); } // G7, G6, and "All" generation only have "All" option (no sub-types) From 733c37e9416d5ff68608ab34fbf48ca7a413f396 Mon Sep 17 00:00:00 2001 From: pmakode-akamai Date: Wed, 31 Dec 2025 14:23:25 +0530 Subject: [PATCH 2/7] Minor comment updates --- .../src/features/components/PlansPanel/utils/planFilters.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts b/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts index 9ada25d4ffd..9cec18a885e 100644 --- a/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts +++ b/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts @@ -72,7 +72,7 @@ export const filterPlansByGeneration = ( * Determines the relative generation order of a plan based on its ID. * * Used to sort plans from newest to oldest when the "All" type - * filter is selected (G8 → G7 → G6). + * filter is selected (G8 -> G7 -> G6). */ export const getGenerationRank = (planId: string): number => { if (planId.startsWith('g8-')) return 3; From bf9b7807be4acf8e66399d5b5e4c7f6f2bbde2a4 Mon Sep 17 00:00:00 2001 From: pmakode-akamai Date: Wed, 31 Dec 2025 14:39:09 +0530 Subject: [PATCH 3/7] Added changeset: Update Generational Plans default sort to show newest (G8) -> oldest (G6) --- .../manager/.changeset/pr-13234-changed-1767172149210.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-13234-changed-1767172149210.md diff --git a/packages/manager/.changeset/pr-13234-changed-1767172149210.md b/packages/manager/.changeset/pr-13234-changed-1767172149210.md new file mode 100644 index 00000000000..770e04ff88d --- /dev/null +++ b/packages/manager/.changeset/pr-13234-changed-1767172149210.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Changed +--- + +Update Generational Plans default sort to show newest (G8) -> oldest (G6) ([#13234](https://github.com/linode/manager/pull/13234)) From 7fd61e2b0daac283d10a897f3c02b420c9ba2e8b Mon Sep 17 00:00:00 2001 From: pmakode-akamai Date: Fri, 2 Jan 2026 17:10:02 +0530 Subject: [PATCH 4/7] Make generation plan ranking more scalable --- .../PlansPanel/utils/planFilters.test.ts | 13 +++++++++++ .../PlansPanel/utils/planFilters.ts | 23 ++++++++++++------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/features/components/PlansPanel/utils/planFilters.test.ts b/packages/manager/src/features/components/PlansPanel/utils/planFilters.test.ts index 7dddf55b744..4196e192eb0 100644 --- a/packages/manager/src/features/components/PlansPanel/utils/planFilters.test.ts +++ b/packages/manager/src/features/components/PlansPanel/utils/planFilters.test.ts @@ -252,8 +252,21 @@ describe('planFilters utilities', () => { ); }); + it('handles multi-digit generations correctly', () => { + expect(getGenerationRank('g10-dedicated-2')).toBeGreaterThan( + getGenerationRank('g8-dedicated-4-2') + ); + expect(getGenerationRank('g11-dedicated-2')).toBeGreaterThan( + getGenerationRank('g10-dedicated-2') + ); + }); + it('returns 0 for unknown generations', () => { expect(getGenerationRank('legacy-plan')).toBe(0); + expect(getGenerationRank('gg-xyz')).toBe(0); + expect(getGenerationRank('g-pqr')).toBe(0); + expect(getGenerationRank('x123')).toBe(0); + expect(getGenerationRank('')).toBe(0); }); }); }); diff --git a/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts b/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts index 9cec18a885e..89b8ca003f9 100644 --- a/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts +++ b/packages/manager/src/features/components/PlansPanel/utils/planFilters.ts @@ -69,16 +69,23 @@ export const filterPlansByGeneration = ( // ============================================================================ /** - * Determines the relative generation order of a plan based on its ID. + * Returns the numeric generation of a plan based on its ID. + * Higher generation number = newer plan (shown first). * - * Used to sort plans from newest to oldest when the "All" type - * filter is selected (G8 -> G7 -> G6). + * Example: + * - "g8-dedicated-4-2" -> 8 + * - "g1-accelerated-netint-vpu" -> 1 + * - "legacy-plan" -> 0 */ export const getGenerationRank = (planId: string): number => { - if (planId.startsWith('g8-')) return 3; - if (planId.startsWith('g7-')) return 2; - if (planId.startsWith('g6-')) return 1; - return 0; + const generation = planId.split('-')[0]; // eg., "g8" or "legacy" + + // Safe fallback: must start with "g" + if (!generation.startsWith('g')) return 0; + + const num = Number(generation.slice(1)); + + return Number.isFinite(num) ? num : 0; }; /** @@ -101,7 +108,7 @@ export const filterPlansByType = ( generation: PlanFilterGeneration, type: PlanFilterType ): PlanWithAvailability[] => { - // "All" returns all plans, sorted from newest (G8) to oldest (G6) + // "All" returns all plans, sorted from newest to oldest generations if (type === PLAN_FILTER_ALL) { return [...plans].sort( (a, b) => getGenerationRank(b.id) - getGenerationRank(a.id) From a0576f0468e433676ea215cb5c7f491b8178496e Mon Sep 17 00:00:00 2001 From: pmakode-akamai Date: Mon, 5 Jan 2026 17:41:08 +0530 Subject: [PATCH 5/7] Update some e2e tests --- .../cypress/e2e/core/kubernetes/lke-update.spec.ts | 7 +++++++ .../cypress/e2e/core/linodes/create-linode.spec.ts | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/packages/manager/cypress/e2e/core/kubernetes/lke-update.spec.ts b/packages/manager/cypress/e2e/core/kubernetes/lke-update.spec.ts index 07bd5f6edd6..4623ef33e52 100644 --- a/packages/manager/cypress/e2e/core/kubernetes/lke-update.spec.ts +++ b/packages/manager/cypress/e2e/core/kubernetes/lke-update.spec.ts @@ -1405,6 +1405,13 @@ describe('LKE cluster updates', () => { .findByTitle(`Add a Node Pool: ${mockCluster.label}`) .should('be.visible') .within(() => { + // For the "Dedicated 4 GB", use filter to select G6 Dedicated instead of relying on pagination + ui.autocomplete.findByLabel('Dedicated Plans').click(); + + ui.autocompletePopper.find().within(() => { + cy.findByText('G6 Dedicated').should('be.visible').click(); + }); + cy.findByText('Dedicated 4 GB') .should('be.visible') .closest('tr') diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts index ef7213c5fae..eb6eec87f92 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts @@ -93,6 +93,16 @@ describe('Create Linode', () => { linodeCreatePage.setLabel(linodeLabel); linodeCreatePage.selectImage('Debian 12'); linodeCreatePage.selectRegionById(linodeRegion.id); + + // For the "Dedicated 4 GB" plan under the "Dedicated CPU" plan type, use filter to select G6 Dedicated instead of relying on pagination + if (planConfig.planType === 'Dedicated CPU') { + ui.autocomplete.findByLabel('Dedicated Plans').click(); + + ui.autocompletePopper.find().within(() => { + cy.findByText('G6 Dedicated').should('be.visible').click(); + }); + } + linodeCreatePage.selectPlan( planConfig.planType, planConfig.planLabel From b0448cf8a9fb3ea9bbc818d88388a68db8fef9c7 Mon Sep 17 00:00:00 2001 From: pmakode-akamai Date: Mon, 5 Jan 2026 18:29:16 +0530 Subject: [PATCH 6/7] Update more e2e test cases --- .../e2e/core/linodes/alerts-create.spec.ts | 18 ++++++++++++++++++ .../stackscripts/create-stackscripts.spec.ts | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/packages/manager/cypress/e2e/core/linodes/alerts-create.spec.ts b/packages/manager/cypress/e2e/core/linodes/alerts-create.spec.ts index dcb02fd5f66..43325319275 100644 --- a/packages/manager/cypress/e2e/core/linodes/alerts-create.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/alerts-create.spec.ts @@ -123,6 +123,12 @@ describe('Create flow when beta alerts enabled by region and feature flag', func cy.get('[data-qa-tp="Linode Plan"]') .should('be.visible') .within(() => { + // For the Dedicated 8 GB, Use filter to select G6 Dedicated instead of relying on pagination + ui.autocomplete.findByLabel('Dedicated Plans').click(); + ui.autocompletePopper.find().within(() => { + cy.findByText('G6 Dedicated').should('be.visible').click(); + }); + cy.get('[data-qa-plan-row="Dedicated 8 GB"]').click(); }); cy.get('[type="password"]').should('be.visible').scrollIntoView(); @@ -283,6 +289,12 @@ describe('Create flow when beta alerts enabled by region and feature flag', func cy.get('[data-qa-tp="Linode Plan"]') .should('be.visible') .within(() => { + // For the Dedicated 8 GB, Use filter to select G6 Dedicated instead of relying on pagination + ui.autocomplete.findByLabel('Dedicated Plans').click(); + ui.autocompletePopper.find().within(() => { + cy.findByText('G6 Dedicated').should('be.visible').click(); + }); + cy.get('[data-qa-plan-row="Dedicated 8 GB"]').click(); }); cy.get('[type="password"]').should('be.visible').scrollIntoView(); @@ -432,6 +444,12 @@ describe('Create flow when beta alerts enabled by region and feature flag', func cy.get('[data-qa-tp="Linode Plan"]') .should('be.visible') .within(() => { + // For the Dedicated 8 GB, Use filter to select G6 Dedicated instead of relying on pagination + ui.autocomplete.findByLabel('Dedicated Plans').click(); + ui.autocompletePopper.find().within(() => { + cy.findByText('G6 Dedicated').should('be.visible').click(); + }); + cy.get('[data-qa-plan-row="Dedicated 8 GB"]').click(); }); cy.get('[type="password"]').should('be.visible').scrollIntoView(); diff --git a/packages/manager/cypress/e2e/core/stackscripts/create-stackscripts.spec.ts b/packages/manager/cypress/e2e/core/stackscripts/create-stackscripts.spec.ts index 01a7dbe891e..22048718330 100644 --- a/packages/manager/cypress/e2e/core/stackscripts/create-stackscripts.spec.ts +++ b/packages/manager/cypress/e2e/core/stackscripts/create-stackscripts.spec.ts @@ -114,6 +114,13 @@ const fillOutLinodeForm = (label: string, regionName: string) => { cy.focused().type(label); cy.findByText('Dedicated CPU').should('be.visible').click(); + + // Use filter to select G6 Dedicated instead of relying on pagination + ui.autocomplete.findByLabel('Dedicated Plans').click(); + ui.autocompletePopper.find().within(() => { + cy.findByText('G6 Dedicated').should('be.visible').click(); + }); + cy.get('[id="g6-dedicated-2"]').click(); cy.findByLabelText('Root Password').should('be.visible').type(password); }; From 020aab974695a01b45eadbf9679c2fdcf94cc012 Mon Sep 17 00:00:00 2001 From: pmakode-akamai Date: Mon, 5 Jan 2026 18:40:48 +0530 Subject: [PATCH 7/7] Update e2e tests from stackscripts and marketplace --- .../cypress/e2e/core/oneClickApps/one-click-apps.spec.ts | 5 +++++ .../core/stackscripts/smoke-community-stackscripts.spec.ts | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts b/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts index bd5f13f4f28..8c1e15ab9bd 100644 --- a/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts +++ b/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts @@ -221,6 +221,11 @@ describe('OneClick Apps (OCA)', () => { cy.focused().type(`${region.id}{enter}`); // Choose a Linode plan + // For the Dedicated 8 GB, Use filter to select G6 Dedicated instead of relying on pagination + ui.autocomplete.findByLabel('Dedicated Plans').click(); + ui.autocompletePopper.find().within(() => { + cy.findByText('G6 Dedicated').should('be.visible').click(); + }); cy.get('[data-qa-plan-row="Dedicated 8 GB"]') .closest('tr') .within(() => { diff --git a/packages/manager/cypress/e2e/core/stackscripts/smoke-community-stackscripts.spec.ts b/packages/manager/cypress/e2e/core/stackscripts/smoke-community-stackscripts.spec.ts index 26b17237855..7e137192517 100644 --- a/packages/manager/cypress/e2e/core/stackscripts/smoke-community-stackscripts.spec.ts +++ b/packages/manager/cypress/e2e/core/stackscripts/smoke-community-stackscripts.spec.ts @@ -379,6 +379,13 @@ describe('Community Stackscripts integration tests', () => { // An error message shows up when no region is selected cy.contains('Plan is required.').should('be.visible'); + + // For the Dedicated 8 GB, Use filter to select G6 Dedicated instead of relying on pagination + ui.autocomplete.findByLabel('Dedicated Plans').click(); + ui.autocompletePopper.find().within(() => { + cy.findByText('G6 Dedicated').should('be.visible').click(); + }); + cy.get('[data-qa-plan-row="Dedicated 8 GB"]') .closest('tr') .within(() => {