Skip to content

Commit 4e71453

Browse files
committed
upcoming: [UIE-9813] - Implement routing for Cloud Manager Marketplace
1 parent 7c026eb commit 4e71453

File tree

10 files changed

+148
-3
lines changed

10 files changed

+148
-3
lines changed

packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,4 +590,23 @@ describe('PrimaryNav', () => {
590590

591591
expect(databaseNavItem).toBeVisible();
592592
});
593+
594+
it('should show Partner Referral menu item if the user has the account capability and the flag is enabled', async () => {
595+
const flags: Partial<Flags> = {
596+
marketplace: {
597+
enabled: true,
598+
beta: false,
599+
la: false,
600+
ga: false,
601+
},
602+
};
603+
604+
const { findByTestId } = renderWithTheme(<PrimaryNav {...props} />, {
605+
flags,
606+
});
607+
608+
const marketplaceNavItem = await findByTestId('menu-item-Partner Referral');
609+
610+
expect(marketplaceNavItem).toBeVisible();
611+
});
593612
});

packages/manager/src/components/PrimaryNav/PrimaryNav.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { useIsACLPEnabled } from 'src/features/CloudPulse/Utils/utils';
2222
import { useIsDatabasesEnabled } from 'src/features/Databases/utilities';
2323
import { useIsACLPLogsEnabled } from 'src/features/Delivery/deliveryUtils';
2424
import { useIsIAMEnabled } from 'src/features/IAM/hooks/useIsIAMEnabled';
25+
import { useIsMarketplaceEnabled } from 'src/features/Marketplace/utils';
2526
import { useIsNetworkLoadBalancerEnabled } from 'src/features/NetworkLoadBalancers/utils';
2627
import { useIsPlacementGroupsEnabled } from 'src/features/PlacementGroups/utils';
2728
import { useFlags } from 'src/hooks/useFlags';
@@ -54,13 +55,14 @@ export type NavEntity =
5455
| 'Longview'
5556
| 'Maintenance'
5657
| 'Managed'
57-
| 'Marketplace'
5858
| 'Metrics'
5959
| 'Monitor'
6060
| 'Network Load Balancer'
6161
| 'NodeBalancers'
6262
| 'Object Storage'
63+
| 'Partner Referrals'
6364
| 'Placement Groups'
65+
| 'Quick Deploy Apps'
6466
| 'Quotas'
6567
| 'Service Transfers'
6668
| 'StackScripts'
@@ -121,6 +123,9 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
121123

122124
const { isNetworkLoadBalancerEnabled } = useIsNetworkLoadBalancerEnabled();
123125

126+
const { isMarketplaceFeatureEnabled, isMarketplaceBetaEnabled } =
127+
useIsMarketplaceEnabled();
128+
124129
const {
125130
data: preferences,
126131
error: preferencesError,
@@ -176,9 +181,18 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
176181
},
177182
{
178183
attr: { 'data-qa-one-click-nav-btn': true },
179-
display: 'Marketplace',
184+
display: !isMarketplaceFeatureEnabled
185+
? 'Marketplace'
186+
: 'Quick Deploy Apps',
180187
to: '/linodes/create/marketplace',
181188
},
189+
{
190+
attr: { 'data-qa-one-click-nav-btn': true },
191+
display: 'Partner Referrals',
192+
hide: !isMarketplaceFeatureEnabled,
193+
isBeta: isMarketplaceFeatureEnabled && isMarketplaceBetaEnabled,
194+
to: '/cloud-marketplace/catalog',
195+
},
182196
],
183197
name: 'Compute',
184198
},
@@ -352,6 +366,8 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
352366
isIAMBeta,
353367
isIAMEnabled,
354368
iamRbacPrimaryNavChanges,
369+
isMarketplaceFeatureEnabled,
370+
isMarketplaceBetaEnabled,
355371
isNetworkLoadBalancerEnabled,
356372
limitsEvolution,
357373
]

packages/manager/src/dev-tools/FeatureFlagTool.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const options: { flag: keyof Flags; label: string }[] = [
4040
{ flag: 'linodeDiskEncryption', label: 'Linode Disk Encryption (LDE)' },
4141
{ flag: 'linodeInterfaces', label: 'Linode Interfaces' },
4242
{ flag: 'lkeEnterprise2', label: 'LKE-Enterprise' },
43+
{ flag: 'marketplace', label: 'Marketplace' },
4344
{ flag: 'networkLoadBalancer', label: 'Network Load Balancer' },
4445
{ flag: 'nodebalancerIpv6', label: 'NodeBalancer Dual Stack (IPv6)' },
4546
{ flag: 'nodebalancerVpc', label: 'NodeBalancer-VPC Integration' },

packages/manager/src/featureFlags.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ interface FirewallRulesetsAndPrefixLists extends BetaFeatureFlag {
177177
la: boolean;
178178
}
179179

180+
interface Marketplace extends BetaFeatureFlag {
181+
ga: boolean;
182+
la: boolean;
183+
}
184+
180185
export interface Flags {
181186
acceleratedPlans: AcceleratedPlansFlag;
182187
aclp: AclpFlag;
@@ -223,6 +228,7 @@ export interface Flags {
223228
linodeInterfaces: LinodeInterfacesFlag;
224229
lkeEnterprise2: LkeEnterpriseFlag;
225230
mainContentBanner: MainContentBanner;
231+
marketplace: Marketplace;
226232
marketplaceAppOverrides: MarketplaceAppOverride[];
227233
metadata: boolean;
228234
mtc: MTC;
@@ -344,12 +350,12 @@ export type ProductInformationBannerLocation =
344350
| 'Identity and Access'
345351
| 'Images'
346352
| 'Kubernetes'
347-
| 'LinodeCreate' // Use for Marketplace banners
348353
| 'Linodes'
349354
| 'LoadBalancers'
350355
| 'Logs'
351356
| 'Longview'
352357
| 'Managed'
358+
| 'Marketplace'
353359
| 'Network LoadBalancers'
354360
| 'NodeBalancers'
355361
| 'Object Storage'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Notice } from '@linode/ui';
2+
import * as React from 'react';
3+
4+
export const MarketplaceLanding = () => {
5+
return (
6+
<Notice variant="info">Partner Referral Catalog is coming soon...</Notice>
7+
);
8+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { createLazyRoute } from '@tanstack/react-router';
2+
3+
import { MarketplaceLanding } from './MarketplaceLanding';
4+
5+
export const marketplaceLazyRoute = createLazyRoute(
6+
'/cloud-marketplace/catalog'
7+
)({
8+
component: MarketplaceLanding,
9+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useFlags } from 'src/hooks/useFlags';
2+
3+
/**
4+
* Returns whether or not features related to the Marketplace project
5+
* should be enabled, and whether they are in beta, LA, or GA.
6+
*
7+
* Note: Currently, this just uses the `Marketplace` feature flag as a source of truth,
8+
* but will eventually also look at account capabilities if available.
9+
*/
10+
export const useIsMarketplaceEnabled = () => {
11+
const flags = useFlags();
12+
13+
if (!flags) {
14+
return {
15+
isMarketplaceFeatureEnabled: false,
16+
isMarketplaceBetaEnabled: false,
17+
isMarketplaceLAEnabled: false,
18+
isMarketplaceGAEnabled: false,
19+
};
20+
}
21+
22+
// @TODO: Cloud Manager Marketplace - check for customer tag/account capability when it exists
23+
return {
24+
isMarketplaceFeatureEnabled: flags.marketplace?.enabled,
25+
isMarketplaceBetaEnabled: flags.marketplace?.beta,
26+
isMarketplaceLAEnabled: flags.marketplace?.la,
27+
isMarketplaceGAEnabled: flags.marketplace?.ga,
28+
};
29+
};

packages/manager/src/routes/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { loginHistoryRouteTree } from './loginHistory/';
2929
import { longviewRouteTree } from './longview';
3030
import { maintenanceRouteTree } from './maintenance';
3131
import { managedRouteTree } from './managed';
32+
import { marketplaceRouteTree } from './marketplace';
3233
import { cloudPulseMetricsRouteTree } from './metrics';
3334
import { networkLoadBalancersRouteTree } from './networkLoadBalancer';
3435
import { nodeBalancersRouteTree } from './nodeBalancers';
@@ -80,6 +81,7 @@ export const routeTree = rootRoute.addChildren([
8081
longviewRouteTree,
8182
maintenanceRouteTree,
8283
managedRouteTree,
84+
marketplaceRouteTree,
8385
networkLoadBalancersRouteTree,
8486
nodeBalancersRouteTree,
8587
objectStorageRouteTree,
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NotFound } from '@linode/ui';
2+
import { Outlet } from '@tanstack/react-router';
3+
import React from 'react';
4+
5+
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
6+
import { ProductInformationBanner } from 'src/components/ProductInformationBanner/ProductInformationBanner';
7+
import { SuspenseLoader } from 'src/components/SuspenseLoader';
8+
import { useIsMarketplaceEnabled } from 'src/features/Marketplace/utils';
9+
10+
export const MarketplaceRoute = () => {
11+
const { isMarketplaceFeatureEnabled } = useIsMarketplaceEnabled();
12+
13+
if (!isMarketplaceFeatureEnabled) {
14+
return <NotFound />;
15+
}
16+
return (
17+
<React.Suspense fallback={<SuspenseLoader />}>
18+
<DocumentTitleSegment segment="Marketplace" />
19+
<ProductInformationBanner bannerLocation="Marketplace" />
20+
<Outlet />
21+
</React.Suspense>
22+
);
23+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { createRoute, redirect } from '@tanstack/react-router';
2+
3+
import { rootRoute } from '../root';
4+
import { MarketplaceRoute } from './MarketplaceRoute';
5+
6+
export const marketplaceRoute = createRoute({
7+
component: MarketplaceRoute,
8+
getParentRoute: () => rootRoute,
9+
path: 'cloud-marketplace',
10+
});
11+
12+
export const marketplaceLandingRoute = createRoute({
13+
beforeLoad: async () => {
14+
throw redirect({ to: '/cloud-marketplace/catalog' });
15+
},
16+
getParentRoute: () => marketplaceRoute,
17+
path: '/',
18+
});
19+
20+
export const marketplaceCatlogRoute = createRoute({
21+
getParentRoute: () => marketplaceRoute,
22+
path: '/catalog',
23+
}).lazy(() =>
24+
import('src/features/Marketplace/marketplaceLazyRoute').then(
25+
(m) => m.marketplaceLazyRoute
26+
)
27+
);
28+
29+
export const marketplaceRouteTree = marketplaceRoute.addChildren([
30+
marketplaceLandingRoute,
31+
marketplaceCatlogRoute,
32+
]);

0 commit comments

Comments
 (0)