Skip to content

Commit 1414925

Browse files
upcoming: [DI-28500] - Enable the Alerts Notification Channel Tab (#13150)
* upcoming: [DI-28500] - Introduce Alert's Notification Channel Management tab * upcoming: [DI-28500] - filter and render enabled Tabs only * add changeset * test[DI-28587]: Add permission tests for Notification Channel Management * test[DI-28587]: Add permission tests for Notification Channel Management --------- Co-authored-by: agorthi-akamai <[email protected]>
1 parent 39c8d72 commit 1414925

File tree

6 files changed

+154
-6
lines changed

6 files changed

+154
-6
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Upcoming Features
3+
---
4+
5+
Introduce and conditionally render Notification Channels tab under ACLP-Alerting ([#13150](https://github.com/linode/manager/pull/13150))
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* @file Integration Tests for CloudPulse Alerting — Notification Channel Listing Page
3+
*
4+
* Covers three access-control behaviors:
5+
* 1. Access is allowed when `notificationChannels` is true.
6+
* 2. Navigation/tab visibility is blocked when `notificationChannels` is false.
7+
* 3. Direct URL access is blocked when `notificationChannels` is false.
8+
* 4. All access is blocked when CloudPulse (`aclp`) is disabled.
9+
*/
10+
11+
import { mockGetAccount } from 'support/intercepts/account';
12+
import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags';
13+
import { ui } from 'support/ui';
14+
15+
import { accountFactory } from 'src/factories';
16+
17+
import type { Flags } from 'src/featureFlags';
18+
19+
describe('Notification Channel Listing Page — Access Control', () => {
20+
beforeEach(() => {
21+
mockGetAccount(accountFactory.build());
22+
});
23+
24+
it('allows access when notificationChannels is enabled', () => {
25+
const flags: Partial<Flags> = {
26+
aclp: { beta: true, enabled: true },
27+
aclpAlerting: {
28+
accountAlertLimit: 10,
29+
accountMetricLimit: 10,
30+
alertDefinitions: true,
31+
beta: true,
32+
recentActivity: false,
33+
notificationChannels: true,
34+
},
35+
};
36+
37+
mockAppendFeatureFlags(flags);
38+
cy.visitWithLogin('/linodes');
39+
40+
ui.nav.findItemByTitle('Alerts').should('be.visible').click();
41+
ui.tabList
42+
.findTabByTitle('Notification Channels')
43+
.should('be.visible')
44+
.click();
45+
46+
cy.url().should('endWith', 'alerts/notification-channels');
47+
});
48+
49+
it('hides the Notification Channels tab when notificationChannels is disabled', () => {
50+
const flags: Partial<Flags> = {
51+
aclp: { beta: true, enabled: true },
52+
aclpAlerting: {
53+
accountAlertLimit: 10,
54+
accountMetricLimit: 10,
55+
alertDefinitions: true,
56+
beta: true,
57+
recentActivity: false,
58+
notificationChannels: false,
59+
},
60+
};
61+
62+
mockAppendFeatureFlags(flags);
63+
cy.visitWithLogin('/linodes');
64+
65+
ui.nav.findItemByTitle('Alerts').should('be.visible').click();
66+
67+
// Tab should not render at all
68+
ui.tabList.findTabByTitle('Notification Channels').should('not.exist');
69+
});
70+
71+
it('blocks all access when CloudPulse is disabled', () => {
72+
const flags: Partial<Flags> = {
73+
aclp: { beta: true, enabled: false }, // CloudPulse OFF
74+
aclpAlerting: {
75+
accountAlertLimit: 10,
76+
accountMetricLimit: 10,
77+
alertDefinitions: true,
78+
beta: true,
79+
recentActivity: false,
80+
notificationChannels: true,
81+
},
82+
};
83+
84+
mockAppendFeatureFlags(flags);
85+
cy.visitWithLogin('/alerts/notification-channels');
86+
87+
// Application should return fallback
88+
cy.findByText('Not Found').should('be.visible');
89+
});
90+
91+
it('blocks direct URL access to /alerts/notification-channels when notificationChannels is disabled', () => {
92+
const flags: Partial<Flags> = {
93+
aclp: { beta: true, enabled: true },
94+
95+
aclpAlerting: {
96+
accountAlertLimit: 10,
97+
accountMetricLimit: 10,
98+
alertDefinitions: true,
99+
beta: true,
100+
recentActivity: false,
101+
notificationChannels: false, // feature OFF → user should not enter page
102+
},
103+
};
104+
105+
mockAppendFeatureFlags(flags);
106+
cy.visitWithLogin('/alerts/notification-channels');
107+
// Tab must not exist
108+
ui.tabList.findTabByTitle('Notification Channels').should('not.exist');
109+
});
110+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { Paper } from '@linode/ui';
2+
import React from 'react';
3+
4+
export const NotificationChannelListing = () => {
5+
return <Paper>Notification Channel Page</Paper>; // Temporary placeholder
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createLazyRoute } from '@tanstack/react-router';
2+
3+
import { NotificationChannelListing } from './NotificationChannelListing';
4+
5+
export const cloudPulseAlertsNotificationChannelsListingLazyRoute =
6+
createLazyRoute('/alerts/notification-channels')({
7+
component: NotificationChannelListing,
8+
});

packages/manager/src/routes/alerts/CloudPulseAlertsRoute.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,15 @@ export const CloudPulseAlertsRoute = () => {
2323
title: 'Definitions',
2424
disabled: !flags.aclpAlerting?.alertDefinitions,
2525
},
26+
{
27+
to: '/alerts/notification-channels',
28+
title: 'Notification Channels',
29+
disabled: !flags.aclpAlerting?.notificationChannels,
30+
},
2631
]);
2732

33+
const visibleTabs = tabs.filter((tab) => !tab.disabled);
34+
2835
if (!isACLPEnabled) {
2936
return <NotFound />;
3037
}
@@ -39,14 +46,16 @@ export const CloudPulseAlertsRoute = () => {
3946
spacingBottom={4}
4047
/>
4148
<Tabs index={tabIndex} onChange={handleTabChange}>
42-
<TanStackTabLinkList tabs={tabs} />
49+
<TanStackTabLinkList tabs={visibleTabs} />
4350
<React.Suspense fallback={<SuspenseLoader />}>
4451
<TabPanels>
45-
<SafeTabPanel index={0}>
46-
<Paper>
47-
<Outlet />
48-
</Paper>
49-
</SafeTabPanel>
52+
{visibleTabs.map((_, index) => (
53+
<SafeTabPanel index={index} key={index}>
54+
<Paper>
55+
<Outlet />
56+
</Paper>
57+
</SafeTabPanel>
58+
))}
5059
</TabPanels>
5160
</React.Suspense>
5261
</Tabs>

packages/manager/src/routes/alerts/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ const cloudPulseAlertsDefinitionsCatchAllRoute = createRoute({
6868
},
6969
});
7070

71+
const cloudPulseNotificationChannelsRoute = createRoute({
72+
getParentRoute: () => cloudPulseAlertsRoute,
73+
path: 'notification-channels',
74+
}).lazy(() =>
75+
import(
76+
'src/features/CloudPulse/Alerts/NotificationChannels/NotificationsChannelsListing/cloudPulseAlertsNotificationChannelsListingLazyRoute'
77+
).then((m) => m.cloudPulseAlertsNotificationChannelsListingLazyRoute)
78+
);
79+
7180
export const cloudPulseAlertsRouteTree = cloudPulseAlertsRoute.addChildren([
7281
cloudPulseAlertsIndexRoute,
7382
cloudPulseAlertsDefinitionsRoute.addChildren([
@@ -76,4 +85,5 @@ export const cloudPulseAlertsRouteTree = cloudPulseAlertsRoute.addChildren([
7685
cloudPulseAlertsDefinitionsEditRoute,
7786
]),
7887
cloudPulseAlertsDefinitionsCatchAllRoute,
88+
cloudPulseNotificationChannelsRoute,
7989
]);

0 commit comments

Comments
 (0)