diff --git a/packages/manager/.changeset/pr-13301-upcoming-features-1768997478204.md b/packages/manager/.changeset/pr-13301-upcoming-features-1768997478204.md
new file mode 100644
index 00000000000..b2ac5efb976
--- /dev/null
+++ b/packages/manager/.changeset/pr-13301-upcoming-features-1768997478204.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Upcoming Features
+---
+
+CloudPulse-Alerts: Exclude account/region alerts in api payload while updating alerts for a linode and fix state reset issue on save ([#13301](https://github.com/linode/manager/pull/13301))
diff --git a/packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertInformationActionTable.test.tsx b/packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertInformationActionTable.test.tsx
index e1191701576..ca42245978a 100644
--- a/packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertInformationActionTable.test.tsx
+++ b/packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertInformationActionTable.test.tsx
@@ -13,6 +13,18 @@ import type {
TableColumnHeader,
} from './AlertInformationActionTable';
+const mockUpdateAlerts = vi.fn();
+
+vi.mock('src/queries/cloudpulse/useAlertsMutation', async () => {
+ const actual = await vi.importActual(
+ 'src/queries/cloudpulse/useAlertsMutation'
+ );
+ return {
+ ...actual,
+ useAlertsMutation: () => mockUpdateAlerts,
+ };
+});
+
const serviceType = 'linode';
const entityId = '123';
const entityName = 'test-instance';
@@ -22,6 +34,27 @@ const alerts = [
service_type: serviceType,
status: 'enabled',
}),
+ alertFactory.build({
+ id: 9,
+ entity_ids: [],
+ service_type: serviceType,
+ type: 'user',
+ scope: 'entity',
+ }),
+ alertFactory.build({
+ id: 10,
+ entity_ids: [],
+ service_type: serviceType,
+ type: 'user',
+ scope: 'account',
+ }),
+ alertFactory.build({
+ id: 11,
+ entity_ids: [],
+ service_type: serviceType,
+ type: 'user',
+ scope: 'region',
+ }),
];
const columns: TableColumnHeader[] = [
{ columnName: 'Alert Name', label: 'label' },
@@ -39,6 +72,11 @@ const props: AlertInformationActionTableProps = {
};
describe('Alert Listing Reusable Table for contextual view', () => {
+ beforeEach(() => {
+ mockUpdateAlerts.mockClear();
+ mockUpdateAlerts.mockResolvedValue({});
+ });
+
it('Should render alert table', async () => {
renderWithTheme();
@@ -112,4 +150,24 @@ describe('Alert Listing Reusable Table for contextual view', () => {
const saveButton = screen.getByTestId('save-alerts');
expect(saveButton).toBeDisabled();
});
+
+ it('Should send correct payload to the API when save button is clicked in edit mode', async () => {
+ renderWithTheme();
+
+ // Toggle entity-level user alert with ID 2 to enable it
+ const userAlertRow = await screen.findByTestId('9');
+ await userEvent.click(await within(userAlertRow).findByRole('checkbox'));
+
+ const saveButton = screen.getByTestId('save-alerts');
+ expect(saveButton).not.toBeDisabled();
+ await userEvent.click(saveButton);
+
+ // Verify that account and region level alerts are not included in the payload
+ expect(mockUpdateAlerts).toHaveBeenCalledWith({
+ alerts: {
+ system_alerts: [1, 2, 3, 4, 5, 6, 7],
+ user_alerts: [9],
+ },
+ });
+ });
});
diff --git a/packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertInformationActionTable.tsx b/packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertInformationActionTable.tsx
index a8968c2b6f2..bb8c301df1e 100644
--- a/packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertInformationActionTable.tsx
+++ b/packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertInformationActionTable.tsx
@@ -149,23 +149,16 @@ export const AlertInformationActionTable = (
const payloadAlertType = (alert: Alert) =>
alert.type === 'system' ? 'system_alerts' : 'user_alerts';
- const {
- enabledAlerts,
- setEnabledAlerts,
- hasUnsavedChanges,
- initialState,
- resetToInitialState,
- } = useContextualAlertsState(alerts, entityId);
+ const { enabledAlerts, setEnabledAlerts, hasUnsavedChanges, initialState } =
+ useContextualAlertsState(alerts, entityId);
+
+ const isAccountOrRegionAlert = (alert: Alert) =>
+ alert.scope === 'region' || alert.scope === 'account';
// Mutation to update alerts as per service type
const updateAlerts = useAlertsMutation(serviceType, entityId ?? '');
React.useEffect(() => {
- // To send initial state of alerts through toggle handler function (For Create Flow)
- if (!isEditMode && onToggleAlert) {
- onToggleAlert(enabledAlerts);
- }
-
return () => {
// Cleanup on unmount (For Edit flow)
if (isEditMode && onToggleAlert) {
@@ -195,8 +188,7 @@ export const AlertInformationActionTable = (
enqueueSnackbar('Your settings for alerts have been saved.', {
variant: 'success',
});
- // Reset the state to sync with the updated alerts from API
- resetToInitialState();
+ onToggleAlert?.({}, false);
invalidateAclpAlerts(queryClient, serviceType, entityId, payload);
})
.catch(() => {
@@ -209,7 +201,7 @@ export const AlertInformationActionTable = (
setIsDialogOpen(false);
});
},
- [updateAlerts, enqueueSnackbar, resetToInitialState]
+ [updateAlerts, enqueueSnackbar, onToggleAlert]
);
const handleToggleAlert = React.useCallback(
@@ -325,9 +317,12 @@ export const AlertInformationActionTable = (
if (!(isEditMode || isCreateMode)) {
return null;
}
- const status = enabledAlerts[
- payloadAlertType(alert)
- ]?.includes(alert.id);
+ // If alert is account or region level, enable it by default and if it is entity type alert, check if it is enabled for that entity
+ const status =
+ isAccountOrRegionAlert(alert) ||
+ enabledAlerts[payloadAlertType(alert)]?.includes(
+ alert.id
+ );
return (
{
});
});
- it('should include alerts that match entityId or account/region level alerts in initial states', () => {
+ it('should include alerts that match entityId in initial states', () => {
const entityId = '123';
const alerts = [
alertFactory.build({
@@ -275,13 +275,6 @@ describe('useContextualAlertsState', () => {
entity_ids: [entityId],
scope: 'entity',
}),
- alertFactory.build({
- id: 3,
- label: 'alert3',
- type: 'system',
- entity_ids: ['456'],
- scope: 'region',
- }),
];
const { result } = renderHook(() =>
@@ -289,7 +282,6 @@ describe('useContextualAlertsState', () => {
);
expect(result.current.initialState.system_alerts).toContain(1);
- expect(result.current.initialState.system_alerts).toContain(3);
expect(result.current.initialState.user_alerts).toContain(2);
});
diff --git a/packages/manager/src/features/CloudPulse/Utils/utils.ts b/packages/manager/src/features/CloudPulse/Utils/utils.ts
index b18b3a8bf0e..f5dcb3dde17 100644
--- a/packages/manager/src/features/CloudPulse/Utils/utils.ts
+++ b/packages/manager/src/features/CloudPulse/Utils/utils.ts
@@ -127,13 +127,10 @@ export const useContextualAlertsState = (
};
alerts.forEach((alert) => {
- const isAccountOrRegion =
- alert.scope === 'region' || alert.scope === 'account';
-
- // include alerts which has either account or region level scope or entityId is present in the alert's entity_ids
+ // include alerts for which entityId is present in the alert's entity_ids
const shouldInclude = entityId
- ? isAccountOrRegion || alert.entity_ids.includes(entityId)
- : isAccountOrRegion;
+ ? alert.entity_ids.includes(entityId)
+ : false;
if (shouldInclude) {
const payloadAlertType =