Skip to content
Merged
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
5 changes: 5 additions & 0 deletions packages/api-v4/.changeset/pr-13062-added-1762436128763.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Added
---

Added `Akamai Cloud Pulse Logs ` to the `AccountCapability` type ([#13062](https://github.com/linode/manager/pull/13062))
1 change: 1 addition & 0 deletions packages/api-v4/src/account/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export type BillingSource = 'akamai' | 'linode';
export const accountCapabilities = [
'Akamai Cloud Load Balancer',
'Akamai Cloud Pulse',
'Akamai Cloud Pulse Logs',
'Block Storage',
'Block Storage Encryption',
'Cloud Firewall',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Limit Logs feature based on `Akamai Cloud Pulse Logs` Account Capability ([#13062](https://github.com/linode/manager/pull/13062))
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import type { AkamaiObjectStorageDetailsExtended } from '@linode/api-v4';
describe('Create Destination', () => {
beforeEach(() => {
mockAppendFeatureFlags({
aclpLogs: { enabled: true, beta: true },
aclpLogs: {
enabled: true,
beta: true,
bypassAccountCapabilities: true,
},
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import { kubernetesClusterFactory } from 'src/factories';
describe('Create Stream', () => {
beforeEach(() => {
mockAppendFeatureFlags({
aclpLogs: { enabled: true, beta: true },
aclpLogs: {
enabled: true,
beta: true,
bypassAccountCapabilities: true,
},
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('Destinations empty landing page', () => {
aclpLogs: {
enabled: true,
beta: true,
bypassAccountCapabilities: true,
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,11 @@ const mockDestinations: Destination[] = new Array(3)
describe('destinations landing checks for non-empty state', () => {
beforeEach(() => {
mockAppendFeatureFlags({
aclpLogs: { enabled: true, beta: true },
aclpLogs: {
enabled: true,
beta: true,
bypassAccountCapabilities: true,
},
});

// Mock setup to display the Destinations landing page in a non-empty state
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ import type { AkamaiObjectStorageDetailsExtended } from '@linode/api-v4';
describe('Edit Destination', () => {
beforeEach(() => {
mockAppendFeatureFlags({
aclpLogs: { enabled: true, beta: true },
aclpLogs: {
enabled: true,
beta: true,
bypassAccountCapabilities: true,
},
});
cy.visitWithLogin(`/logs/delivery/destinations/${mockDestination.id}/edit`);
mockGetDestination(mockDestination);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ import { kubernetesClusterFactory } from 'src/factories';
describe('Edit Stream', () => {
beforeEach(() => {
mockAppendFeatureFlags({
aclpLogs: { enabled: true, beta: true },
aclpLogs: {
enabled: true,
beta: true,
bypassAccountCapabilities: true,
},
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('Streams empty landing page', () => {
aclpLogs: {
enabled: true,
beta: true,
bypassAccountCapabilities: true,
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ const mockStreams: Stream[] = new Array(3)
describe('Streams non-empty landing page', () => {
beforeEach(() => {
mockAppendFeatureFlags({
aclpLogs: { enabled: true, beta: true },
aclpLogs: {
enabled: true,
beta: true,
bypassAccountCapabilities: true,
},
});

// Mock setup to display the Streams landing page in a non-empty state
Expand Down
90 changes: 90 additions & 0 deletions packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,96 @@
expect(betaChip).toBeVisible();
});

it('should show Logs menu item if user has capability and aclpLogs flag is enabled', async () => {
const account = accountFactory.build({
capabilities: ['Akamai Cloud Pulse Logs'],
});
server.use(http.get('*/account', () => HttpResponse.json(account)));

const flags = {
aclpLogs: {
enabled: true,
beta: false,
bypassAccountCapabilities: false,
},
};

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

const logsNavItem = await findByTestId('menu-item-Logs');

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

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Define a constant instead of duplicating this literal 4 times. Raw Output: {"ruleId":"sonarjs/no-duplicate-string","severity":1,"message":"Define a constant instead of duplicating this literal 4 times.","line":355,"column":44,"nodeType":"Literal","endLine":355,"endColumn":60}
expect(logsNavItem).toBeVisible();
expect(queryByTestId('betaChip')).toBeNull();
});

it('should not show Logs menu item if aclpLogs flag is not enabled', async () => {
const account = accountFactory.build({
capabilities: ['Akamai Cloud Pulse Logs'],
});
server.use(http.get('*/account', () => HttpResponse.json(account)));

const flags = {
aclpLogs: {
enabled: false,
beta: false,
bypassAccountCapabilities: true,
},
};

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

expect(queryByTestId('menu-item-Logs')).toBeNull();
});

it('should show Logs menu item if user lacks capability, bypassAccountCapabilities is true and aclpLogs flag is enabled', async () => {
const account = accountFactory.build({
capabilities: [],
});
server.use(http.get('*/account', () => HttpResponse.json(account)));

const flags = {
aclpLogs: {
enabled: true,
beta: true,
bypassAccountCapabilities: true,
},
};

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

const logsNavItem = await findByTestId('menu-item-Logs');
expect(logsNavItem).toBeVisible();
const betaChip = await findByTestId('betaChip');
expect(betaChip).toBeVisible();
});

it('should not show Logs menu item if user lacks capability, bypassAccountCapabilities is false and aclpLogs flag is enabled', async () => {
const account = accountFactory.build({
capabilities: [],
});
server.use(http.get('*/account', () => HttpResponse.json(account)));

const flags = {
aclpLogs: {
enabled: true,
beta: false,
bypassAccountCapabilities: false,
},
};

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

expect(queryByTestId('menu-item-Logs')).toBeNull();
});

it('should show Administration links if iamRbacPrimaryNavChanges flag is enabled', async () => {
const flags: Partial<Flags> = {
iamRbacPrimaryNavChanges: true,
Expand Down
8 changes: 6 additions & 2 deletions packages/manager/src/components/PrimaryNav/PrimaryNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from 'src/components/PrimaryNav/constants';
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 { useIsPlacementGroupsEnabled } from 'src/features/PlacementGroups/utils';
import { useFlags } from 'src/hooks/useFlags';
Expand Down Expand Up @@ -99,6 +100,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
const isManaged = accountSettings?.managed ?? false;

const { isACLPEnabled } = useIsACLPEnabled();
const { isACLPLogsEnabled, isACLPLogsBeta } = useIsACLPLogsEnabled();

const isAlertsEnabled =
isACLPEnabled &&
Expand Down Expand Up @@ -241,9 +243,9 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
},
{
display: 'Logs',
hide: !flags.aclpLogs?.enabled,
hide: !isACLPLogsEnabled,
to: '/logs/delivery',
isBeta: flags.aclpLogs?.beta,
isBeta: isACLPLogsBeta,
},
],
name: 'Monitor',
Expand Down Expand Up @@ -330,6 +332,8 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
isManaged,
isPlacementGroupsEnabled,
isACLPEnabled,
isACLPLogsBeta,
isACLPLogsEnabled,
isIAMBeta,
isIAMEnabled,
iamRbacPrimaryNavChanges,
Expand Down
9 changes: 8 additions & 1 deletion packages/manager/src/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ interface AclpFlag {
showWidgetDimensionFilters?: boolean;
}

interface AclpLogsFlag extends BetaFeatureFlag {
/**
* This property indicates whether to bypass account capabilities check or not
*/
bypassAccountCapabilities?: boolean;
}

interface LkeEnterpriseFlag extends BaseFeatureFlag {
ga: boolean;
la: boolean;
Expand Down Expand Up @@ -169,7 +176,7 @@ export interface Flags {
aclp: AclpFlag;
aclpAlerting: AclpAlerting;
aclpAlertServiceTypeConfig: AclpAlertServiceTypeConfig[];
aclpLogs: BetaFeatureFlag;
aclpLogs: AclpLogsFlag;
aclpReadEndpoint: string;
aclpResourceTypeMap: CloudPulseResourceTypeMapFlag[];
aclpServices: Partial<AclpServices>;
Expand Down
29 changes: 29 additions & 0 deletions packages/manager/src/features/Delivery/deliveryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,48 @@ import {
type StreamType,
streamType,
} from '@linode/api-v4';
import { useAccount } from '@linode/queries';
import { omitProps } from '@linode/ui';
import { isFeatureEnabledV2 } from '@linode/utilities';

import {
destinationTypeOptions,
streamTypeOptions,
} from 'src/features/Delivery/Shared/types';
import { useFlags } from 'src/hooks/useFlags';

import type {
AutocompleteOption,
DestinationDetailsForm,
FormMode,
} from 'src/features/Delivery/Shared/types';

/**
* Hook to determine if the ACLP Logs feature is enabled for the current user.

* @returns {{ isACLPLogsEnabled: boolean, isACLPLogsBeta: boolean }} An object indicating if the feature is enabled and if it is in beta.
*/
export const useIsACLPLogsEnabled = (): {
isACLPLogsBeta: boolean;
isACLPLogsEnabled: boolean;
} => {
const { data: account } = useAccount();
const flags = useFlags();

const isACLPLogsEnabled =
(flags.aclpLogs?.enabled && flags.aclpLogs?.bypassAccountCapabilities) ||
isFeatureEnabledV2(
'Akamai Cloud Pulse Logs',
!!flags.aclpLogs?.enabled,
account?.capabilities ?? []
);

return {
isACLPLogsBeta: !!flags.aclpLogs?.beta,
isACLPLogsEnabled,
};
};

export const getDestinationTypeOption = (
destinationTypeValue: string
): AutocompleteOption | undefined =>
Expand Down
8 changes: 4 additions & 4 deletions packages/manager/src/routes/delivery/DeliveryRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { Outlet } from '@tanstack/react-router';
import React from 'react';

import { SuspenseLoader } from 'src/components/SuspenseLoader';
import { useFlags } from 'src/hooks/useFlags';
import { useIsACLPLogsEnabled } from 'src/features/Delivery/deliveryUtils';

export const DeliveryRoute = () => {
const flags = useFlags();
const { aclpLogs } = flags;
const { isACLPLogsEnabled } = useIsACLPLogsEnabled();

return (
<React.Suspense fallback={<SuspenseLoader />}>
{aclpLogs?.enabled ? <Outlet /> : <NotFound />}
{isACLPLogsEnabled ? <Outlet /> : <NotFound />}
</React.Suspense>
);
};