From f8735b93a017fc627f32e4d4d3782cb54bf2ea8b Mon Sep 17 00:00:00 2001 From: hrao Date: Fri, 7 Nov 2025 12:52:21 +0530 Subject: [PATCH 01/11] upcoming: [UIE-9559, UIE-9560] - Implement routing for Network Load Balancer --- packages/api-v4/src/account/types.ts | 1 + .../src/components/PrimaryNav/PrimaryNav.tsx | 5 ++ packages/manager/src/featureFlags.ts | 1 + .../NetworkLoadBalancersLanding.tsx | 20 +++++ .../networkLoadBalancersLazyRoute.tsx | 7 ++ .../features/NetworkLoadBalancers/utils.ts | 20 +++++ packages/manager/src/routes/index.tsx | 2 + .../src/routes/networkLoadBalancer/index.ts | 82 +++++++++++++++++++ .../networkLoadBalancersLazyRoute.tsx | 14 ++++ 9 files changed, 152 insertions(+) create mode 100644 packages/manager/src/features/NetworkLoadBalancers/NetworkLoadBalancersLanding.tsx create mode 100644 packages/manager/src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute.tsx create mode 100644 packages/manager/src/features/NetworkLoadBalancers/utils.ts create mode 100644 packages/manager/src/routes/networkLoadBalancer/index.ts create mode 100644 packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx diff --git a/packages/api-v4/src/account/types.ts b/packages/api-v4/src/account/types.ts index 02fb1516200..d719b6cf49e 100644 --- a/packages/api-v4/src/account/types.ts +++ b/packages/api-v4/src/account/types.ts @@ -79,6 +79,7 @@ export const accountCapabilities = [ 'Managed Databases', 'Managed Databases Beta', 'NETINT Quadra T1U', + 'Network LoadBalancer', 'NodeBalancers', 'Object Storage Access Key Regions', 'Object Storage Endpoint Types', diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx index 4c14e98bbf3..b05c5eb19d3 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx @@ -55,6 +55,7 @@ export type NavEntity = | 'Marketplace' | 'Metrics' | 'Monitor' + | 'Network Load Balancers' | 'NodeBalancers' | 'Object Storage' | 'Placement Groups' @@ -197,6 +198,10 @@ export const PrimaryNav = (props: PrimaryNavProps) => { display: 'Firewalls', to: '/firewalls', }, + { + display: 'Network Load Balancers', + to: '/netloadbalancers', + }, { display: 'NodeBalancers', to: '/nodebalancers', diff --git a/packages/manager/src/featureFlags.ts b/packages/manager/src/featureFlags.ts index ac48bcb0230..0ff6aebbb82 100644 --- a/packages/manager/src/featureFlags.ts +++ b/packages/manager/src/featureFlags.ts @@ -334,6 +334,7 @@ export type ProductInformationBannerLocation = | 'Logs' | 'Longview' | 'Managed' + | 'Network LoadBalancers' | 'NodeBalancers' | 'Object Storage' | 'Placement Groups' diff --git a/packages/manager/src/features/NetworkLoadBalancers/NetworkLoadBalancersLanding.tsx b/packages/manager/src/features/NetworkLoadBalancers/NetworkLoadBalancersLanding.tsx new file mode 100644 index 00000000000..8bf6fa0792d --- /dev/null +++ b/packages/manager/src/features/NetworkLoadBalancers/NetworkLoadBalancersLanding.tsx @@ -0,0 +1,20 @@ +import { Notice } from '@linode/ui'; +import * as React from 'react'; + +import { LandingHeader } from 'src/components/LandingHeader'; + +export const NetworkLoadBalancersLanding = () => { + return ( + <> + + Network Load Balancers are coming soon... + + ); +}; diff --git a/packages/manager/src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute.tsx b/packages/manager/src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute.tsx new file mode 100644 index 00000000000..ea465dd264f --- /dev/null +++ b/packages/manager/src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute.tsx @@ -0,0 +1,7 @@ +import { createLazyRoute } from '@tanstack/react-router'; + +import { NetworkLoadBalancersLanding } from './NetworkLoadBalancersLanding'; + +export const networkLoadBalancersLazyRoute = createLazyRoute('/betas')({ + component: NetworkLoadBalancersLanding, +}); diff --git a/packages/manager/src/features/NetworkLoadBalancers/utils.ts b/packages/manager/src/features/NetworkLoadBalancers/utils.ts new file mode 100644 index 00000000000..46cfa85be8a --- /dev/null +++ b/packages/manager/src/features/NetworkLoadBalancers/utils.ts @@ -0,0 +1,20 @@ +import { useAccount } from '@linode/queries'; +import { isFeatureEnabledV2 } from '@linode/utilities'; + +/** + * + * @returns an object that contains boolean property to check whether Network LoadBalancer is enabled or not + */ +export const useIsNetworkLoadBalancerEnabled = (): { + isNetworkLoadBalancerEnabled: boolean; +} => { + const { data: account } = useAccount(); + + const isNetworkLoadBalancerEnabled = isFeatureEnabledV2( + 'Network LoadBalancer', + true, + account?.capabilities ?? [] + ); + + return { isNetworkLoadBalancerEnabled }; +}; diff --git a/packages/manager/src/routes/index.tsx b/packages/manager/src/routes/index.tsx index 2647d63ab12..3c2193f36fa 100644 --- a/packages/manager/src/routes/index.tsx +++ b/packages/manager/src/routes/index.tsx @@ -30,6 +30,7 @@ import { longviewRouteTree } from './longview'; import { maintenanceRouteTree } from './maintenance'; import { managedRouteTree } from './managed'; import { cloudPulseMetricsRouteTree } from './metrics'; +import { networkLoadBalancersRouteTree } from './networkLoadBalancer'; import { nodeBalancersRouteTree } from './nodeBalancers'; import { objectStorageRouteTree } from './objectStorage'; import { placementGroupsRouteTree } from './placementGroups'; @@ -79,6 +80,7 @@ export const routeTree = rootRoute.addChildren([ longviewRouteTree, maintenanceRouteTree, managedRouteTree, + networkLoadBalancersRouteTree, nodeBalancersRouteTree, objectStorageRouteTree, placementGroupsRouteTree, diff --git a/packages/manager/src/routes/networkLoadBalancer/index.ts b/packages/manager/src/routes/networkLoadBalancer/index.ts new file mode 100644 index 00000000000..0bd34fc432e --- /dev/null +++ b/packages/manager/src/routes/networkLoadBalancer/index.ts @@ -0,0 +1,82 @@ +import { createRoute, redirect } from '@tanstack/react-router'; + +import { rootRoute } from '../root'; +import { NetworkLoadBalancersRoute } from './networkLoadBalancersLazyRoute'; + +const networkLoadBalancersRoute = createRoute({ + component: NetworkLoadBalancersRoute, + getParentRoute: () => rootRoute, + path: 'netloadbalancers', +}); + +const networkLoadBalancersIndexRoute = createRoute({ + getParentRoute: () => networkLoadBalancersRoute, + path: '/', +}).lazy(() => + import( + 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' + ).then((m) => m.networkLoadBalancersLazyRoute) +); + +const networkLoadBalancerDetailRoute = createRoute({ + beforeLoad: async ({ params }) => { + throw redirect({ + params: { + id: params.id, + }, + to: '/netloadbalancers/$id/listeners', + }); + }, + getParentRoute: () => networkLoadBalancersRoute, + path: '$id', +}).lazy(() => + import( + 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' + ).then((m) => m.networkLoadBalancersLazyRoute) +); + +const networkLoadBalancerListenersRoute = createRoute({ + getParentRoute: () => networkLoadBalancersRoute, + path: '$id/listeners', +}).lazy(() => + import( + 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' + ).then((m) => m.networkLoadBalancersLazyRoute) +); + +const networkLoadBalancerListenerDetailRoute = createRoute({ + beforeLoad: async ({ params }) => { + throw redirect({ + params: { + id: params.id, + }, + to: '/netloadbalancers/$id/listeners', + }); + }, + getParentRoute: () => networkLoadBalancerListenersRoute, + path: '$nodeId', +}).lazy(() => + import( + 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' + ).then((m) => m.networkLoadBalancersLazyRoute) +); + +const networkLoadBalancerNodesRoute = createRoute({ + getParentRoute: () => networkLoadBalancerListenersRoute, + path: '$listenerId/nodes', +}).lazy(() => + import( + 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' + ).then((m) => m.networkLoadBalancersLazyRoute) +); + +export const networkLoadBalancersRouteTree = + networkLoadBalancersRoute.addChildren([ + networkLoadBalancersIndexRoute, + networkLoadBalancerDetailRoute.addChildren([ + networkLoadBalancerListenersRoute.addChildren([ + networkLoadBalancerListenerDetailRoute, + networkLoadBalancerNodesRoute, + ]), + ]), + ]); diff --git a/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx b/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx new file mode 100644 index 00000000000..4ace071508c --- /dev/null +++ b/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx @@ -0,0 +1,14 @@ +import { Outlet } from '@tanstack/react-router'; +import React from 'react'; + +import { ProductInformationBanner } from 'src/components/ProductInformationBanner/ProductInformationBanner'; +import { SuspenseLoader } from 'src/components/SuspenseLoader'; + +export const NetworkLoadBalancersRoute = () => { + return ( + }> + + + + ); +}; From 5998c7e062acceb88faa448713c417a12c53d4ff Mon Sep 17 00:00:00 2001 From: hrao Date: Tue, 11 Nov 2025 13:21:48 +0530 Subject: [PATCH 02/11] added support for feature flag --- .../src/components/PrimaryNav/PrimaryNav.tsx | 1 + .../manager/src/dev-tools/FeatureFlagTool.tsx | 1 + packages/manager/src/featureFlags.ts | 1 + .../NetworkLoadBalancers/utils.test.ts | 42 +++++++++++++++++++ .../features/NetworkLoadBalancers/utils.ts | 9 +++- .../networkLoadBalancersLazyRoute.tsx | 6 ++- 6 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 packages/manager/src/features/NetworkLoadBalancers/utils.test.ts diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx index b05c5eb19d3..2b12d7a99e8 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx @@ -200,6 +200,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { }, { display: 'Network Load Balancers', + hide: !flags.networkLoadBalancer, to: '/netloadbalancers', }, { diff --git a/packages/manager/src/dev-tools/FeatureFlagTool.tsx b/packages/manager/src/dev-tools/FeatureFlagTool.tsx index b6c0bf419fb..2f97d5a9359 100644 --- a/packages/manager/src/dev-tools/FeatureFlagTool.tsx +++ b/packages/manager/src/dev-tools/FeatureFlagTool.tsx @@ -40,6 +40,7 @@ const options: { flag: keyof Flags; label: string }[] = [ { flag: 'linodeDiskEncryption', label: 'Linode Disk Encryption (LDE)' }, { flag: 'linodeInterfaces', label: 'Linode Interfaces' }, { flag: 'lkeEnterprise2', label: 'LKE-Enterprise' }, + { flag: 'networkLoadBalancer', label: 'Network Load Balancer' }, { flag: 'nodebalancerIpv6', label: 'NodeBalancer Dual Stack (IPv6)' }, { flag: 'nodebalancerVpc', label: 'NodeBalancer-VPC Integration' }, { flag: 'objMultiCluster', label: 'OBJ Multi-Cluster' }, diff --git a/packages/manager/src/featureFlags.ts b/packages/manager/src/featureFlags.ts index 0ff6aebbb82..62c07d5cbdb 100644 --- a/packages/manager/src/featureFlags.ts +++ b/packages/manager/src/featureFlags.ts @@ -211,6 +211,7 @@ export interface Flags { marketplaceAppOverrides: MarketplaceAppOverride[]; metadata: boolean; mtc: MTC; + networkLoadBalancer: boolean; nodebalancerIpv6: boolean; nodebalancerVpc: boolean; objectStorageGen2: BaseFeatureFlag; diff --git a/packages/manager/src/features/NetworkLoadBalancers/utils.test.ts b/packages/manager/src/features/NetworkLoadBalancers/utils.test.ts new file mode 100644 index 00000000000..aa679304b4b --- /dev/null +++ b/packages/manager/src/features/NetworkLoadBalancers/utils.test.ts @@ -0,0 +1,42 @@ +import { renderHook, waitFor } from '@testing-library/react'; + +import { accountFactory } from 'src/factories'; +import { http, HttpResponse, server } from 'src/mocks/testServer'; +import { wrapWithTheme } from 'src/utilities/testHelpers'; + +import { useIsNetworkLoadBalancerEnabled } from './utils'; + +describe('useIsNetworkLoadBalancerEnabled', () => { + it('returns true if the feature is enabled', async () => { + const options = { flags: { networkLoadBalancer: true } }; + const account = accountFactory.build({ + capabilities: ['Network LoadBalancer'], + }); + + server.use( + http.get('*/v4*/account', () => { + return HttpResponse.json(account); + }) + ); + + const { result } = renderHook(() => useIsNetworkLoadBalancerEnabled(), { + wrapper: (ui) => wrapWithTheme(ui, options), + }); + + await waitFor(() => { + expect(result.current.isNetworkLoadBalancerEnabled).toBe(true); + }); + }); + + it('returns false if the feature is NOT enabled', async () => { + const options = { flags: { networkLoadBalancer: false } }; + + const { result } = renderHook(() => useIsNetworkLoadBalancerEnabled(), { + wrapper: (ui) => wrapWithTheme(ui, options), + }); + + await waitFor(() => { + expect(result.current.isNetworkLoadBalancerEnabled).toBe(false); + }); + }); +}); diff --git a/packages/manager/src/features/NetworkLoadBalancers/utils.ts b/packages/manager/src/features/NetworkLoadBalancers/utils.ts index 46cfa85be8a..66c9a2a2865 100644 --- a/packages/manager/src/features/NetworkLoadBalancers/utils.ts +++ b/packages/manager/src/features/NetworkLoadBalancers/utils.ts @@ -1,6 +1,8 @@ import { useAccount } from '@linode/queries'; import { isFeatureEnabledV2 } from '@linode/utilities'; +import { useFlags } from 'src/hooks/useFlags'; + /** * * @returns an object that contains boolean property to check whether Network LoadBalancer is enabled or not @@ -9,10 +11,15 @@ export const useIsNetworkLoadBalancerEnabled = (): { isNetworkLoadBalancerEnabled: boolean; } => { const { data: account } = useAccount(); + const flags = useFlags(); + + if (!flags) { + return { isNetworkLoadBalancerEnabled: false }; + } const isNetworkLoadBalancerEnabled = isFeatureEnabledV2( 'Network LoadBalancer', - true, + Boolean(flags.networkLoadBalancer), account?.capabilities ?? [] ); diff --git a/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx b/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx index 4ace071508c..a1e3056fa09 100644 --- a/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx +++ b/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx @@ -1,14 +1,18 @@ +import { NotFound } from '@linode/ui'; import { Outlet } from '@tanstack/react-router'; import React from 'react'; import { ProductInformationBanner } from 'src/components/ProductInformationBanner/ProductInformationBanner'; import { SuspenseLoader } from 'src/components/SuspenseLoader'; +import { useFlags } from 'src/hooks/useFlags'; export const NetworkLoadBalancersRoute = () => { + const flags = useFlags(); + const { networkLoadBalancer } = flags; return ( }> - + {networkLoadBalancer ? : } ); }; From c6440a549c9a66c6f97a9bb701055cb51a7ef75f Mon Sep 17 00:00:00 2001 From: hrao Date: Tue, 11 Nov 2025 18:42:38 +0530 Subject: [PATCH 03/11] PR feedback @tanushree-akamai --- .../NetworkLoadBalancers/networkLoadBalancersLazyRoute.tsx | 4 +++- packages/manager/src/routes/networkLoadBalancer/index.ts | 5 ++++- ...dBalancersLazyRoute.tsx => networkLoadBalancersRoute.tsx} | 0 3 files changed, 7 insertions(+), 2 deletions(-) rename packages/manager/src/routes/networkLoadBalancer/{networkLoadBalancersLazyRoute.tsx => networkLoadBalancersRoute.tsx} (100%) diff --git a/packages/manager/src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute.tsx b/packages/manager/src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute.tsx index ea465dd264f..def65acf048 100644 --- a/packages/manager/src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute.tsx +++ b/packages/manager/src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute.tsx @@ -2,6 +2,8 @@ import { createLazyRoute } from '@tanstack/react-router'; import { NetworkLoadBalancersLanding } from './NetworkLoadBalancersLanding'; -export const networkLoadBalancersLazyRoute = createLazyRoute('/betas')({ +export const networkLoadBalancersLazyRoute = createLazyRoute( + '/netloadbalancers' +)({ component: NetworkLoadBalancersLanding, }); diff --git a/packages/manager/src/routes/networkLoadBalancer/index.ts b/packages/manager/src/routes/networkLoadBalancer/index.ts index 0bd34fc432e..3fee561c91a 100644 --- a/packages/manager/src/routes/networkLoadBalancer/index.ts +++ b/packages/manager/src/routes/networkLoadBalancer/index.ts @@ -1,7 +1,7 @@ import { createRoute, redirect } from '@tanstack/react-router'; import { rootRoute } from '../root'; -import { NetworkLoadBalancersRoute } from './networkLoadBalancersLazyRoute'; +import { NetworkLoadBalancersRoute } from './networkLoadBalancersRoute'; const networkLoadBalancersRoute = createRoute({ component: NetworkLoadBalancersRoute, @@ -35,6 +35,7 @@ const networkLoadBalancerDetailRoute = createRoute({ ).then((m) => m.networkLoadBalancersLazyRoute) ); +// TODO: Update to the lazy route for listeners when implemented const networkLoadBalancerListenersRoute = createRoute({ getParentRoute: () => networkLoadBalancersRoute, path: '$id/listeners', @@ -44,6 +45,7 @@ const networkLoadBalancerListenersRoute = createRoute({ ).then((m) => m.networkLoadBalancersLazyRoute) ); +// TODO: Update to the lazy route for listeners when implemented const networkLoadBalancerListenerDetailRoute = createRoute({ beforeLoad: async ({ params }) => { throw redirect({ @@ -61,6 +63,7 @@ const networkLoadBalancerListenerDetailRoute = createRoute({ ).then((m) => m.networkLoadBalancersLazyRoute) ); +// TODO: Update to the lazy route for nodes when implemented const networkLoadBalancerNodesRoute = createRoute({ getParentRoute: () => networkLoadBalancerListenersRoute, path: '$listenerId/nodes', diff --git a/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx b/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersRoute.tsx similarity index 100% rename from packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersLazyRoute.tsx rename to packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersRoute.tsx From edd0c480aa6ae5d996c049e40ae7912cd4f3ab7c Mon Sep 17 00:00:00 2001 From: hrao Date: Tue, 11 Nov 2025 18:47:58 +0530 Subject: [PATCH 04/11] add unit test for Network Load Balancers Item in primary nav component --- .../components/PrimaryNav/PrimaryNav.test.tsx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx index c560e1d0815..f4082269339 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx @@ -449,4 +449,34 @@ describe('PrimaryNav', () => { ).toBeNull(); }); }); + + it('should show Network Load Balancers menu item if the user has the account capability and the flag is enabled', async () => { + queryMocks.usePreferences.mockReturnValue({ + data: preference, + }); + + const account = accountFactory.build({ + capabilities: ['Network LoadBalancer'], + }); + + server.use( + http.get('*/account', () => { + return HttpResponse.json(account); + }) + ); + + const flags: Partial = { + networkLoadBalancer: true, + }; + + const { findByTestId } = renderWithTheme(, { + flags, + }); + + const databaseNavItem = await findByTestId( + 'menu-item-Network Load Balancers' + ); + + expect(databaseNavItem).toBeVisible(); + }); }); From a1e4a6754e223fc8cb2a3bbb3428f669018cb3b9 Mon Sep 17 00:00:00 2001 From: hrao Date: Wed, 12 Nov 2025 12:31:12 +0530 Subject: [PATCH 05/11] Added changeset: Implement feature flag and routing for NLB --- .../.changeset/pr-13068-upcoming-features-1762930872294.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-13068-upcoming-features-1762930872294.md diff --git a/packages/manager/.changeset/pr-13068-upcoming-features-1762930872294.md b/packages/manager/.changeset/pr-13068-upcoming-features-1762930872294.md new file mode 100644 index 00000000000..47909ba6d28 --- /dev/null +++ b/packages/manager/.changeset/pr-13068-upcoming-features-1762930872294.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Implement feature flag and routing for NLB ([#13068](https://github.com/linode/manager/pull/13068)) From aa72ae216840fa0deee3dcd3180cbb3bbfbb5452 Mon Sep 17 00:00:00 2001 From: hrao Date: Wed, 12 Nov 2025 16:38:31 +0530 Subject: [PATCH 06/11] correct routing for nlb --- .../components/PrimaryNav/PrimaryNav.test.tsx | 4 ---- .../src/routes/networkLoadBalancer/index.ts | 17 +++++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx index f4082269339..1c6eaa960a4 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx @@ -451,10 +451,6 @@ describe('PrimaryNav', () => { }); it('should show Network Load Balancers menu item if the user has the account capability and the flag is enabled', async () => { - queryMocks.usePreferences.mockReturnValue({ - data: preference, - }); - const account = accountFactory.build({ capabilities: ['Network LoadBalancer'], }); diff --git a/packages/manager/src/routes/networkLoadBalancer/index.ts b/packages/manager/src/routes/networkLoadBalancer/index.ts index 3fee561c91a..f15da4988c3 100644 --- a/packages/manager/src/routes/networkLoadBalancer/index.ts +++ b/packages/manager/src/routes/networkLoadBalancer/index.ts @@ -22,13 +22,13 @@ const networkLoadBalancerDetailRoute = createRoute({ beforeLoad: async ({ params }) => { throw redirect({ params: { - id: params.id, + nlbId: params.nlbId, }, - to: '/netloadbalancers/$id/listeners', + to: '/netloadbalancers/$nlbId/listeners', }); }, getParentRoute: () => networkLoadBalancersRoute, - path: '$id', + path: '$nlbId', }).lazy(() => import( 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' @@ -38,25 +38,26 @@ const networkLoadBalancerDetailRoute = createRoute({ // TODO: Update to the lazy route for listeners when implemented const networkLoadBalancerListenersRoute = createRoute({ getParentRoute: () => networkLoadBalancersRoute, - path: '$id/listeners', + path: '$nlbId/listeners', }).lazy(() => import( 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' ).then((m) => m.networkLoadBalancersLazyRoute) ); -// TODO: Update to the lazy route for listeners when implemented +// TODO: Update to the lazy route for nodes when implemented const networkLoadBalancerListenerDetailRoute = createRoute({ beforeLoad: async ({ params }) => { throw redirect({ params: { - id: params.id, + nlbId: params.nlbId, + listenerId: params.listenerId, }, - to: '/netloadbalancers/$id/listeners', + to: '/netloadbalancers/$nlbId/listeners/$listenerId/nodes', }); }, getParentRoute: () => networkLoadBalancerListenersRoute, - path: '$nodeId', + path: '$listenerId', }).lazy(() => import( 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' From 5ecab0bccd6840c60f9d4dadfd5f8f14972c36f7 Mon Sep 17 00:00:00 2001 From: hrao Date: Wed, 12 Nov 2025 18:46:32 +0530 Subject: [PATCH 07/11] fix failing unit test --- .../src/components/PrimaryNav/PrimaryNav.test.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx index 8670180cda3..4dcd60b3c81 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx @@ -567,11 +567,11 @@ describe('PrimaryNav', () => { capabilities: ['Network LoadBalancer'], }); - server.use( - http.get('*/account', () => { - return HttpResponse.json(account); - }) - ); + queryMocks.useAccount.mockReturnValue({ + data: account, + isLoading: false, + error: null, + }); const flags: Partial = { networkLoadBalancer: true, From 2708ea087c43618018e25ffdaccff2a7e1993c87 Mon Sep 17 00:00:00 2001 From: hrao Date: Thu, 13 Nov 2025 18:57:45 +0530 Subject: [PATCH 08/11] PR feedback --- .../src/components/PrimaryNav/PrimaryNav.tsx | 5 +++- .../src/routes/networkLoadBalancer/index.ts | 27 +++---------------- .../networkLoadBalancersRoute.tsx | 11 +++++--- 3 files changed, 15 insertions(+), 28 deletions(-) diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx index 37df715eb57..cf18a96b72c 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx @@ -22,6 +22,7 @@ import { useIsACLPEnabled } from 'src/features/CloudPulse/Utils/utils'; import { useIsDatabasesEnabled } from 'src/features/Databases/utilities'; import { useIsACLPLogsEnabled } from 'src/features/Delivery/deliveryUtils'; import { useIsIAMEnabled } from 'src/features/IAM/hooks/useIsIAMEnabled'; +import { useIsNetworkLoadBalancerEnabled } from 'src/features/NetworkLoadBalancers/utils'; import { useIsPlacementGroupsEnabled } from 'src/features/PlacementGroups/utils'; import { useFlags } from 'src/hooks/useFlags'; @@ -116,6 +117,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { const { isDatabasesEnabled, isDatabasesV2Beta } = useIsDatabasesEnabled(); const { isIAMBeta, isIAMEnabled } = useIsIAMEnabled(); + const { isNetworkLoadBalancerEnabled } = useIsNetworkLoadBalancerEnabled(); const { data: preferences, @@ -205,7 +207,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { }, { display: 'Network Load Balancers', - hide: !flags.networkLoadBalancer, + hide: isNetworkLoadBalancerEnabled, to: '/netloadbalancers', }, { @@ -346,6 +348,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { isIAMBeta, isIAMEnabled, iamRbacPrimaryNavChanges, + isNetworkLoadBalancerEnabled, limitsEvolution, ] ); diff --git a/packages/manager/src/routes/networkLoadBalancer/index.ts b/packages/manager/src/routes/networkLoadBalancer/index.ts index f15da4988c3..37db26c8321 100644 --- a/packages/manager/src/routes/networkLoadBalancer/index.ts +++ b/packages/manager/src/routes/networkLoadBalancer/index.ts @@ -29,23 +29,13 @@ const networkLoadBalancerDetailRoute = createRoute({ }, getParentRoute: () => networkLoadBalancersRoute, path: '$nlbId', -}).lazy(() => - import( - 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' - ).then((m) => m.networkLoadBalancersLazyRoute) -); +}); -// TODO: Update to the lazy route for listeners when implemented const networkLoadBalancerListenersRoute = createRoute({ getParentRoute: () => networkLoadBalancersRoute, path: '$nlbId/listeners', -}).lazy(() => - import( - 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' - ).then((m) => m.networkLoadBalancersLazyRoute) -); +}); -// TODO: Update to the lazy route for nodes when implemented const networkLoadBalancerListenerDetailRoute = createRoute({ beforeLoad: async ({ params }) => { throw redirect({ @@ -58,21 +48,12 @@ const networkLoadBalancerListenerDetailRoute = createRoute({ }, getParentRoute: () => networkLoadBalancerListenersRoute, path: '$listenerId', -}).lazy(() => - import( - 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' - ).then((m) => m.networkLoadBalancersLazyRoute) -); +}); -// TODO: Update to the lazy route for nodes when implemented const networkLoadBalancerNodesRoute = createRoute({ getParentRoute: () => networkLoadBalancerListenersRoute, path: '$listenerId/nodes', -}).lazy(() => - import( - 'src/features/NetworkLoadBalancers/networkLoadBalancersLazyRoute' - ).then((m) => m.networkLoadBalancersLazyRoute) -); +}); export const networkLoadBalancersRouteTree = networkLoadBalancersRoute.addChildren([ diff --git a/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersRoute.tsx b/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersRoute.tsx index a1e3056fa09..85ca98e8304 100644 --- a/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersRoute.tsx +++ b/packages/manager/src/routes/networkLoadBalancer/networkLoadBalancersRoute.tsx @@ -4,15 +4,18 @@ import React from 'react'; import { ProductInformationBanner } from 'src/components/ProductInformationBanner/ProductInformationBanner'; import { SuspenseLoader } from 'src/components/SuspenseLoader'; -import { useFlags } from 'src/hooks/useFlags'; +import { useIsNetworkLoadBalancerEnabled } from 'src/features/NetworkLoadBalancers/utils'; export const NetworkLoadBalancersRoute = () => { - const flags = useFlags(); - const { networkLoadBalancer } = flags; + const { isNetworkLoadBalancerEnabled } = useIsNetworkLoadBalancerEnabled(); + + if (!isNetworkLoadBalancerEnabled) { + return ; + } return ( }> - {networkLoadBalancer ? : } + ); }; From 9487aeeafd351a0c841d965dcbcb4b0cab05a69f Mon Sep 17 00:00:00 2001 From: hrao Date: Fri, 14 Nov 2025 10:29:00 +0530 Subject: [PATCH 09/11] fix nlb item visibility in side nav --- packages/manager/src/components/PrimaryNav/PrimaryNav.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx index cf18a96b72c..6ea129e0583 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx @@ -207,7 +207,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { }, { display: 'Network Load Balancers', - hide: isNetworkLoadBalancerEnabled, + hide: !isNetworkLoadBalancerEnabled, to: '/netloadbalancers', }, { From eb9ed17e31d210ca076c551797331e8ab0a8c73c Mon Sep 17 00:00:00 2001 From: hrao Date: Mon, 17 Nov 2025 10:22:34 +0530 Subject: [PATCH 10/11] removed nlb routes that are not yet implemented --- .../src/routes/networkLoadBalancer/index.ts | 49 +------------------ 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/packages/manager/src/routes/networkLoadBalancer/index.ts b/packages/manager/src/routes/networkLoadBalancer/index.ts index 37db26c8321..80427760f2f 100644 --- a/packages/manager/src/routes/networkLoadBalancer/index.ts +++ b/packages/manager/src/routes/networkLoadBalancer/index.ts @@ -1,4 +1,4 @@ -import { createRoute, redirect } from '@tanstack/react-router'; +import { createRoute } from '@tanstack/react-router'; import { rootRoute } from '../root'; import { NetworkLoadBalancersRoute } from './networkLoadBalancersRoute'; @@ -18,50 +18,5 @@ const networkLoadBalancersIndexRoute = createRoute({ ).then((m) => m.networkLoadBalancersLazyRoute) ); -const networkLoadBalancerDetailRoute = createRoute({ - beforeLoad: async ({ params }) => { - throw redirect({ - params: { - nlbId: params.nlbId, - }, - to: '/netloadbalancers/$nlbId/listeners', - }); - }, - getParentRoute: () => networkLoadBalancersRoute, - path: '$nlbId', -}); - -const networkLoadBalancerListenersRoute = createRoute({ - getParentRoute: () => networkLoadBalancersRoute, - path: '$nlbId/listeners', -}); - -const networkLoadBalancerListenerDetailRoute = createRoute({ - beforeLoad: async ({ params }) => { - throw redirect({ - params: { - nlbId: params.nlbId, - listenerId: params.listenerId, - }, - to: '/netloadbalancers/$nlbId/listeners/$listenerId/nodes', - }); - }, - getParentRoute: () => networkLoadBalancerListenersRoute, - path: '$listenerId', -}); - -const networkLoadBalancerNodesRoute = createRoute({ - getParentRoute: () => networkLoadBalancerListenersRoute, - path: '$listenerId/nodes', -}); - export const networkLoadBalancersRouteTree = - networkLoadBalancersRoute.addChildren([ - networkLoadBalancersIndexRoute, - networkLoadBalancerDetailRoute.addChildren([ - networkLoadBalancerListenersRoute.addChildren([ - networkLoadBalancerListenerDetailRoute, - networkLoadBalancerNodesRoute, - ]), - ]), - ]); + networkLoadBalancersRoute.addChildren([networkLoadBalancersIndexRoute]); From 3544d0e598dd78d96b04c3e767a0f27756820b2d Mon Sep 17 00:00:00 2001 From: hrao Date: Mon, 17 Nov 2025 12:56:21 +0530 Subject: [PATCH 11/11] ux writing fixes --- .../manager/src/components/PrimaryNav/PrimaryNav.test.tsx | 2 +- packages/manager/src/components/PrimaryNav/PrimaryNav.tsx | 4 ++-- .../NetworkLoadBalancers/NetworkLoadBalancersLanding.tsx | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx index 4dcd60b3c81..835b35727eb 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx @@ -582,7 +582,7 @@ describe('PrimaryNav', () => { }); const databaseNavItem = await findByTestId( - 'menu-item-Network Load Balancers' + 'menu-item-Network Load Balancer' ); expect(databaseNavItem).toBeVisible(); diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx index 6ea129e0583..f2b0ef1ab18 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx @@ -57,7 +57,7 @@ export type NavEntity = | 'Marketplace' | 'Metrics' | 'Monitor' - | 'Network Load Balancers' + | 'Network Load Balancer' | 'NodeBalancers' | 'Object Storage' | 'Placement Groups' @@ -206,7 +206,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { to: '/firewalls', }, { - display: 'Network Load Balancers', + display: 'Network Load Balancer', hide: !isNetworkLoadBalancerEnabled, to: '/netloadbalancers', }, diff --git a/packages/manager/src/features/NetworkLoadBalancers/NetworkLoadBalancersLanding.tsx b/packages/manager/src/features/NetworkLoadBalancers/NetworkLoadBalancersLanding.tsx index 8bf6fa0792d..373a1e0e883 100644 --- a/packages/manager/src/features/NetworkLoadBalancers/NetworkLoadBalancersLanding.tsx +++ b/packages/manager/src/features/NetworkLoadBalancers/NetworkLoadBalancersLanding.tsx @@ -8,13 +8,13 @@ export const NetworkLoadBalancersLanding = () => { <> - Network Load Balancers are coming soon... + Network Load Balancer is coming soon... ); };