Skip to content

Commit 4d61cd6

Browse files
[DI-26731] - Alerts contextual view enhancement (linode#12730)
* [DI-26371] - Update handler, reset state, update query * [DI-26371] - Update useffect * [DI-26371] - update mutation hook * [DI-26371] - Fix mutation query hook * [DI-26371] - Fix mutation query hook * [DI-26731] - Add comments * [DI-26731] - Add changeset * [DI-26731] - Fix saved state issue
1 parent de83a80 commit 4d61cd6

File tree

5 files changed

+82
-14
lines changed

5 files changed

+82
-14
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+
CloudPulse - Alerts: Update handler in `AlertReusableComponenr.tsx`, reset state in `AlertInformationActionTable.tsx`, update query in `alerts.ts` ([#12730](https://github.com/linode/manager/pull/12730))

packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertInformationActionTable.tsx

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ALERTS_BETA_PROMPT } from 'src/features/Linodes/constants';
1616
import { useServiceAlertsMutation } from 'src/queries/cloudpulse/alerts';
1717
import { getAPIErrorOrDefault } from 'src/utilities/errorUtils';
1818

19+
import { compareArrays } from '../../Utils/FilterBuilder';
1920
import { useContextualAlertsState } from '../../Utils/utils';
2021
import { AlertConfirmationDialog } from '../AlertsLanding/AlertConfirmationDialog';
2122
import { ALERT_SCOPE_TOOLTIP_CONTEXTUAL } from '../constants';
@@ -57,10 +58,13 @@ export interface AlertInformationActionTableProps {
5758

5859
/**
5960
* Called when an alert is toggled on or off.
60-
* Only use in create flow.
6161
* @param payload enabled alerts ids
62+
* @param hasUnsavedChanges boolean to check if there are unsaved changes
6263
*/
63-
onToggleAlert?: (payload: CloudPulseAlertsPayload) => void;
64+
onToggleAlert?: (
65+
payload: CloudPulseAlertsPayload,
66+
hasUnsavedChanges?: boolean
67+
) => void;
6468

6569
/**
6670
* Column name by which columns will be ordered by default
@@ -104,9 +108,13 @@ export interface AlertRowPropsOptions {
104108

105109
/**
106110
* Callback function to handle alert toggle
107-
* Only use in create flow.
111+
* @param payload enabled alerts ids
112+
* @param hasUnsavedChanges boolean to check if there are unsaved changes
108113
*/
109-
onToggleAlert?: (payload: CloudPulseAlertsPayload) => void;
114+
onToggleAlert?: (
115+
payload: CloudPulseAlertsPayload,
116+
hasUnsavedChanges?: boolean
117+
) => void;
110118
}
111119

112120
export const AlertInformationActionTable = (
@@ -135,8 +143,13 @@ export const AlertInformationActionTable = (
135143
const isEditMode = !!entityId;
136144
const isCreateMode = !isEditMode;
137145

138-
const { enabledAlerts, setEnabledAlerts, hasUnsavedChanges } =
139-
useContextualAlertsState(alerts, entityId);
146+
const {
147+
enabledAlerts,
148+
setEnabledAlerts,
149+
hasUnsavedChanges,
150+
initialState,
151+
resetToInitialState,
152+
} = useContextualAlertsState(alerts, entityId);
140153

141154
const { mutateAsync: updateAlerts } = useServiceAlertsMutation(
142155
serviceType,
@@ -145,7 +158,7 @@ export const AlertInformationActionTable = (
145158

146159
// To send initial state of alerts through toggle handler function
147160
React.useEffect(() => {
148-
if (onToggleAlert) {
161+
if (!isEditMode && onToggleAlert) {
149162
onToggleAlert(enabledAlerts);
150163
}
151164
}, []);
@@ -165,6 +178,8 @@ export const AlertInformationActionTable = (
165178
enqueueSnackbar('Your settings for alerts have been saved.', {
166179
variant: 'success',
167180
});
181+
// Reset the state to sync with the updated alerts from API
182+
resetToInitialState();
168183
})
169184
.catch(() => {
170185
enqueueSnackbar('Alerts changes were not saved, please try again.', {
@@ -176,7 +191,7 @@ export const AlertInformationActionTable = (
176191
setIsDialogOpen(false);
177192
});
178193
},
179-
[updateAlerts, enqueueSnackbar]
194+
[updateAlerts, enqueueSnackbar, resetToInitialState]
180195
);
181196

182197
const handleToggleAlert = React.useCallback(
@@ -199,15 +214,19 @@ export const AlertInformationActionTable = (
199214
alertIds.push(alert.id);
200215
}
201216

202-
// Only call onToggleAlert in create flow
217+
const hasNewUnsavedChanges =
218+
!compareArrays(newPayload.system ?? [], initialState.system ?? []) ||
219+
!compareArrays(newPayload.user ?? [], initialState.user ?? []);
220+
221+
// Call onToggleAlert in both create and edit flow
203222
if (onToggleAlert) {
204-
onToggleAlert(newPayload);
223+
onToggleAlert(newPayload, hasNewUnsavedChanges);
205224
}
206225

207226
return newPayload;
208227
});
209228
},
210-
[onToggleAlert, setEnabledAlerts]
229+
[initialState, onToggleAlert, setEnabledAlerts]
211230
);
212231

213232
const handleCustomPageChange = React.useCallback(

packages/manager/src/features/CloudPulse/Alerts/ContextualView/AlertReusableComponent.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,12 @@ interface AlertReusableComponentProps {
4444
/**
4545
* Called when an alert is toggled on or off.
4646
* @param payload enabled alerts ids
47+
* @param hasUnsavedChanges boolean to check if there are unsaved changes
4748
*/
48-
onToggleAlert?: (payload: CloudPulseAlertsPayload) => void;
49+
onToggleAlert?: (
50+
payload: CloudPulseAlertsPayload,
51+
hasUnsavedChanges?: boolean
52+
) => void;
4953

5054
/**
5155
* Region ID for the selected entity

packages/manager/src/features/CloudPulse/Utils/utils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const useIsACLPEnabled = (): {
8484
/**
8585
* @param alerts List of alerts to be displayed
8686
* @param entityId Id of the selected entity
87-
* @returns enabledAlerts, setEnabledAlerts, hasUnsavedChanges, initialState
87+
* @returns enabledAlerts, setEnabledAlerts, hasUnsavedChanges, initialState, resetToInitialState
8888
*/
8989
export const useContextualAlertsState = (
9090
alerts: Alert[],
@@ -123,6 +123,11 @@ export const useContextualAlertsState = (
123123

124124
const [enabledAlerts, setEnabledAlerts] = React.useState(initialState);
125125

126+
// Reset function to sync with latest initial state
127+
const resetToInitialState = React.useCallback(() => {
128+
setEnabledAlerts(initialState);
129+
}, [initialState]);
130+
126131
// Check if the enabled alerts have changed from the initial state
127132
const hasUnsavedChanges = React.useMemo(() => {
128133
return (
@@ -136,6 +141,7 @@ export const useContextualAlertsState = (
136141
setEnabledAlerts,
137142
hasUnsavedChanges,
138143
initialState,
144+
resetToInitialState,
139145
};
140146
};
141147

packages/manager/src/queries/cloudpulse/alerts.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,44 @@ export const useServiceAlertsMutation = (
252252
mutationFn: (payload: CloudPulseAlertsPayload) => {
253253
return updateServiceAlerts(serviceType, entityId, payload);
254254
},
255-
onSuccess() {
255+
onSuccess(_, payload) {
256+
const allAlerts = queryClient.getQueryData<Alert[]>(
257+
queryFactory.alerts._ctx.all().queryKey
258+
);
259+
260+
// Get alerts previously enabled for this entity
261+
const oldEnabledAlertIds =
262+
allAlerts
263+
?.filter((alert) => alert.entity_ids.includes(entityId))
264+
.map((alert) => alert.id) || [];
265+
266+
// Combine enabled user and system alert IDs from payload
267+
const newEnabledAlertIds = [
268+
...(payload.user ?? []),
269+
...(payload.system ?? []),
270+
];
271+
272+
// Get unique list of all enabled alert IDs for cache invalidation
273+
const alertIdsToInvalidate = Array.from(
274+
new Set([...oldEnabledAlertIds, ...newEnabledAlertIds])
275+
);
276+
256277
queryClient.invalidateQueries({
257278
queryKey: queryFactory.resources(serviceType).queryKey,
258279
});
280+
281+
queryClient.invalidateQueries({
282+
queryKey: queryFactory.alerts._ctx.all().queryKey,
283+
});
284+
285+
alertIdsToInvalidate.forEach((alertId) => {
286+
queryClient.invalidateQueries({
287+
queryKey: queryFactory.alerts._ctx.alertByServiceTypeAndId(
288+
serviceType,
289+
String(alertId)
290+
).queryKey,
291+
});
292+
});
259293
},
260294
});
261295
};

0 commit comments

Comments
 (0)