Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Implement routing for Cloud Manager Marketplace ([#13222](https://github.com/linode/manager/pull/13222))
9 changes: 7 additions & 2 deletions packages/manager/src/GoTo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as React from 'react';

import { useIsDatabasesEnabled } from './features/Databases/utilities';
import { usePermissions } from './features/IAM/hooks/usePermissions';
import { useIsMarketplaceV2Enabled } from './features/Marketplace/utils';
import { useIsPlacementGroupsEnabled } from './features/PlacementGroups/utils';
import { useFlags } from './hooks/useFlags';
import { useGlobalKeyboardListener } from './hooks/useGlobalKeyboardListener';
Expand All @@ -24,6 +25,8 @@ export const GoTo = React.memo(() => {

const { isPlacementGroupsEnabled } = useIsPlacementGroupsEnabled();
const { isDatabasesEnabled } = useIsDatabasesEnabled();
const { isMarketplaceFeatureEnabled } = useIsMarketplaceV2Enabled();

const { goToOpen, setGoToOpen } = useGlobalKeyboardListener();

const onClose = () => {
Expand Down Expand Up @@ -99,9 +102,10 @@ export const GoTo = React.memo(() => {
display: 'Longview',
href: '/longview',
},

{
display: 'Marketplace',
display: !isMarketplaceFeatureEnabled
? 'Marketplace'
: 'Quick Deploy Apps',
href: '/linodes/create/marketplace',
},
...(iamRbacPrimaryNavChanges
Expand Down Expand Up @@ -133,6 +137,7 @@ export const GoTo = React.memo(() => {
permissions.is_account_admin,
isDatabasesEnabled,
isManagedAccount,
isMarketplaceFeatureEnabled,
isPlacementGroupsEnabled,
iamRbacPrimaryNavChanges,
]
Expand Down
20 changes: 18 additions & 2 deletions packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -630,10 +630,26 @@ describe('PrimaryNav', () => {
flags,
});

const databaseNavItem = await findByTestId(
const networkLoadbalancerNavItem = await findByTestId(
'menu-item-Network Load Balancer'
);

expect(databaseNavItem).toBeVisible();
expect(networkLoadbalancerNavItem).toBeVisible();
});

it('should show Partner Referral menu item if the user has the account capability and the flag is enabled', async () => {
const flags: Partial<Flags> = {
marketplaceV2: true,
};

const { findByTestId } = renderWithTheme(<PrimaryNav {...props} />, {
flags,
});

const partnerReferralNavItem = await findByTestId(
'menu-item-Partner Referrals'
);

expect(partnerReferralNavItem).toBeVisible();
});
});
19 changes: 17 additions & 2 deletions packages/manager/src/components/PrimaryNav/PrimaryNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import { useIsDatabasesEnabled } from 'src/features/Databases/utilities';
import { useIsACLPLogsEnabled } from 'src/features/Delivery/deliveryUtils';
import { useIsIAMEnabled } from 'src/features/IAM/hooks/useIsIAMEnabled';
import { useIsMarketplaceV2Enabled } from 'src/features/Marketplace/utils';
import { useIsNetworkLoadBalancerEnabled } from 'src/features/NetworkLoadBalancers/utils';
import { useIsPlacementGroupsEnabled } from 'src/features/PlacementGroups/utils';
import { useFlags } from 'src/hooks/useFlags';
Expand Down Expand Up @@ -54,13 +55,15 @@
| 'Longview'
| 'Maintenance'
| 'Managed'
| 'Marketplace'
| 'Marketplace' // TODO: Cloud Manager Marketplace - Remove marketplace references once 'Quick Deploy Apps' is fully rolled out

Check warning on line 58 in packages/manager/src/components/PrimaryNav/PrimaryNav.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Complete the task associated to this "TODO" comment. Raw Output: {"ruleId":"sonarjs/todo-tag","severity":1,"message":"Complete the task associated to this \"TODO\" comment.","line":58,"column":22,"nodeType":null,"messageId":"completeTODO","endLine":58,"endColumn":26}
| 'Metrics'
| 'Monitor'
| 'Network Load Balancer'
| 'NodeBalancers'
| 'Object Storage'
| 'Partner Referrals'
| 'Placement Groups'
| 'Quick Deploy Apps'
| 'Quotas'
| 'Service Transfers'
| 'StackScripts'
Expand Down Expand Up @@ -121,6 +124,8 @@

const { isNetworkLoadBalancerEnabled } = useIsNetworkLoadBalancerEnabled();

const { isMarketplaceFeatureEnabled } = useIsMarketplaceV2Enabled();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we also change this const to isMarketplaceV2FeatureEnabled?


const {
data: preferences,
error: preferencesError,
Expand Down Expand Up @@ -176,9 +181,18 @@
},
{
attr: { 'data-qa-one-click-nav-btn': true },
display: 'Marketplace',
display: !isMarketplaceFeatureEnabled
? 'Marketplace'
: 'Quick Deploy Apps',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would strongly recommend revisiting your naming conventions. You're "enabling marketplace", which essentially is removing marketplace. This is the kind of semantic logic pitfall that leads to bad DX and bugs down the line. Not sure if you had semantic requirements for your tickets, but if so I'd advise to correct the course before moving further. At the very least, if you can't change your flag (which i think you still should do), make sure your logic utilities reference quickDeployApps, not an existing Cloud Manager naming convention. (maybe "cloudMarketplace", marketplaceV2, but anything more explicit then marketplace whcih is already the feature name will go a long way).

It also is the opposite of the account capability you're introducing VS the legacy capability..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Thanks for pointing this out. I've renamed the flag to marketplaceV2 now

to: '/linodes/create/marketplace',
},
{
attr: { 'data-qa-one-click-nav-btn': true },
display: 'Partner Referrals',
hide: !isMarketplaceFeatureEnabled,
isBeta: isMarketplaceFeatureEnabled,
to: '/cloud-marketplace/catalog',
},
],
name: 'Compute',
},
Expand Down Expand Up @@ -353,6 +367,7 @@
isIAMBeta,
isIAMEnabled,
iamRbacPrimaryNavChanges,
isMarketplaceFeatureEnabled,
isNetworkLoadBalancerEnabled,
limitsEvolution,
]
Expand Down
1 change: 1 addition & 0 deletions packages/manager/src/dev-tools/FeatureFlagTool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: 'marketplaceV2', label: 'MarketplaceV2' },
{ flag: 'networkLoadBalancer', label: 'Network Load Balancer' },
{ flag: 'nodebalancerIpv6', label: 'NodeBalancer Dual Stack (IPv6)' },
{ flag: 'nodebalancerVpc', label: 'NodeBalancer-VPC Integration' },
Expand Down
3 changes: 2 additions & 1 deletion packages/manager/src/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ export interface Flags {
lkeEnterprise2: LkeEnterpriseFlag;
mainContentBanner: MainContentBanner;
marketplaceAppOverrides: MarketplaceAppOverride[];
marketplaceV2: boolean;
metadata: boolean;
mtc: MTC;
networkLoadBalancer: boolean;
Expand Down Expand Up @@ -356,12 +357,12 @@ export type ProductInformationBannerLocation =
| 'Identity and Access'
| 'Images'
| 'Kubernetes'
| 'LinodeCreate' // Use for Marketplace banners
| 'Linodes'
| 'LoadBalancers'
| 'Logs'
| 'Longview'
| 'Managed'
| 'Marketplace'
| 'Network LoadBalancers'
| 'NodeBalancers'
| 'Object Storage'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Notice } from '@linode/ui';
import * as React from 'react';

export const MarketplaceLanding = () => {
return (
<Notice variant="info">Partner Referral Catalog is coming soon...</Notice>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createLazyRoute } from '@tanstack/react-router';

import { MarketplaceLanding } from './MarketplaceLanding';

export const marketplaceLazyRoute = createLazyRoute(
'/cloud-marketplace/catalog'
)({
component: MarketplaceLanding,
});
23 changes: 23 additions & 0 deletions packages/manager/src/features/Marketplace/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useFlags } from 'src/hooks/useFlags';

/**
* Returns whether or not features related to the Marketplace project
* should be enabled.
*
* Note: Currently, this just uses the `marketplaceV2` feature flag as a source of truth,
* but will eventually also look at account capabilities if available.
*/
export const useIsMarketplaceV2Enabled = () => {
const flags = useFlags();

if (!flags) {
return {
isMarketplaceFeatureEnabled: false,
};
}

// @TODO: Cloud Manager Marketplace - check for customer tag/account capability when it exists

Check warning on line 19 in packages/manager/src/features/Marketplace/utils.ts

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Complete the task associated to this "TODO" comment. Raw Output: {"ruleId":"sonarjs/todo-tag","severity":1,"message":"Complete the task associated to this \"TODO\" comment.","line":19,"column":7,"nodeType":null,"messageId":"completeTODO","endLine":19,"endColumn":11}
return {
isMarketplaceFeatureEnabled: flags.marketplaceV2,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import NetworkIcon from 'src/assets/icons/entityIcons/networking.svg';
import StorageIcon from 'src/assets/icons/entityIcons/storage.svg';
import { useIsDatabasesEnabled } from 'src/features/Databases/utilities';
import { useIsMarketplaceV2Enabled } from 'src/features/Marketplace/utils';
import { useIsPlacementGroupsEnabled } from 'src/features/PlacementGroups/utils';

import {
Expand All @@ -30,10 +31,11 @@
| 'Image'
| 'Kubernetes'
| 'Linode'
| 'Marketplace'
| 'Marketplace' // TODO: Cloud Manager Marketplace - Remove marketplace references once 'Quick Deploy Apps' is fully rolled out

Check warning on line 34 in packages/manager/src/features/TopMenu/CreateMenu/CreateMenu.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Complete the task associated to this "TODO" comment. Raw Output: {"ruleId":"sonarjs/todo-tag","severity":1,"message":"Complete the task associated to this \"TODO\" comment.","line":34,"column":22,"nodeType":null,"messageId":"completeTODO","endLine":34,"endColumn":26}
| 'NodeBalancer'
| 'Object Storage'
| 'Placement Group'
| 'Quick Deploy Apps'
| 'Volume'
| 'VPC';

Expand All @@ -52,6 +54,7 @@

const { isDatabasesEnabled } = useIsDatabasesEnabled();
const { isPlacementGroupsEnabled } = useIsPlacementGroupsEnabled();
const { isMarketplaceFeatureEnabled } = useIsMarketplaceV2Enabled();

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
Expand Down Expand Up @@ -90,7 +93,9 @@
{
attr: { 'data-qa-one-click-add-new': true },
description: 'Deploy applications with ease',
display: 'Marketplace',
display: !isMarketplaceFeatureEnabled
? 'Marketplace'
: 'Quick Deploy Apps',
to: '/linodes/create/marketplace',
},
],
Expand Down
2 changes: 2 additions & 0 deletions packages/manager/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { loginHistoryRouteTree } from './loginHistory/';
import { longviewRouteTree } from './longview';
import { maintenanceRouteTree } from './maintenance';
import { managedRouteTree } from './managed';
import { marketplaceRouteTree } from './marketplace';
import { cloudPulseMetricsRouteTree } from './metrics';
import { networkLoadBalancersRouteTree } from './networkLoadBalancer';
import { nodeBalancersRouteTree } from './nodeBalancers';
Expand Down Expand Up @@ -80,6 +81,7 @@ export const routeTree = rootRoute.addChildren([
longviewRouteTree,
maintenanceRouteTree,
managedRouteTree,
marketplaceRouteTree,
networkLoadBalancersRouteTree,
nodeBalancersRouteTree,
objectStorageRouteTree,
Expand Down
23 changes: 23 additions & 0 deletions packages/manager/src/routes/marketplace/MarketplaceRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { NotFound } from '@linode/ui';
import { Outlet } from '@tanstack/react-router';
import React from 'react';

import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { ProductInformationBanner } from 'src/components/ProductInformationBanner/ProductInformationBanner';
import { SuspenseLoader } from 'src/components/SuspenseLoader';
import { useIsMarketplaceV2Enabled } from 'src/features/Marketplace/utils';

export const MarketplaceRoute = () => {
const { isMarketplaceFeatureEnabled } = useIsMarketplaceV2Enabled();

if (!isMarketplaceFeatureEnabled) {
return <NotFound />;
}
return (
<React.Suspense fallback={<SuspenseLoader />}>
<DocumentTitleSegment segment="Partner Referrals" />
<ProductInformationBanner bannerLocation="Marketplace" />
<Outlet />
</React.Suspense>
);
};
32 changes: 32 additions & 0 deletions packages/manager/src/routes/marketplace/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { createRoute, redirect } from '@tanstack/react-router';

import { rootRoute } from '../root';
import { MarketplaceRoute } from './MarketplaceRoute';

export const marketplaceRoute = createRoute({
component: MarketplaceRoute,
getParentRoute: () => rootRoute,
path: 'cloud-marketplace',
});

export const marketplaceLandingRoute = createRoute({
beforeLoad: async () => {
throw redirect({ to: '/cloud-marketplace/catalog' });
},
getParentRoute: () => marketplaceRoute,
path: '/',
});

export const marketplaceCatlogRoute = createRoute({
getParentRoute: () => marketplaceRoute,
path: '/catalog',
}).lazy(() =>
import('src/features/Marketplace/marketplaceLazyRoute').then(
(m) => m.marketplaceLazyRoute
)
);

export const marketplaceRouteTree = marketplaceRoute.addChildren([
marketplaceLandingRoute,
marketplaceCatlogRoute,
]);