[Fleet] Fix cache invalidation when deleting an integration policy (#218112)

This commit is contained in:
Nicolas Chaulet 2025-04-14 12:32:38 -04:00 committed by GitHub
parent 4b6daeb5ef
commit 36c743a07d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 98 additions and 71 deletions

View file

@ -19,6 +19,8 @@ import { sendGetAgents, useMultipleAgentPolicies } from '../hooks';
import { PackagePolicyDeleteProvider } from './package_policy_delete_provider';
jest.mock('../hooks', () => {
const mutateAsyncMock = jest.fn().mockResolvedValue({ data: [] });
return {
...jest.requireActual('../hooks'),
useMultipleAgentPolicies: jest.fn(),
@ -31,7 +33,7 @@ jest.mock('../hooks', () => {
useConfig: jest.fn().mockReturnValue({
agents: { enabled: true },
}),
sendDeletePackagePolicy: jest.fn().mockResolvedValue({ data: [] }),
useDeletePackagePolicyMutation: jest.fn().mockReturnValue({ mutateAsync: mutateAsyncMock }),
sendDeleteAgentPolicy: jest.fn().mockResolvedValue({ data: [] }),
};
});
@ -137,8 +139,7 @@ function createMockAgentPolicies(
}
}
// FLAKY: https://github.com/elastic/kibana/issues/199204
describe.skip('PackagePolicyDeleteProvider', () => {
describe('PackagePolicyDeleteProvider', () => {
it('Should show delete integrations action and cancel modal', async () => {
useMultipleAgentPoliciesMock.mockReturnValue({ canUseMultipleAgentPolicies: false });
sendGetAgentsMock.mockResolvedValue({

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { Fragment, useMemo, useRef, useState } from 'react';
import React, { Fragment, useCallback, useMemo, useRef, useState } from 'react';
import { EuiCallOut, EuiConfirmModal, EuiSpacer, EuiIconTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
@ -13,12 +13,12 @@ import { useHistory } from 'react-router-dom';
import {
useStartServices,
sendDeletePackagePolicy,
sendDeleteAgentPolicy,
useConfig,
sendGetAgents,
useMultipleAgentPolicies,
useLink,
useDeletePackagePolicyMutation,
} from '../hooks';
import { AGENTS_PREFIX } from '../../common/constants';
import type { AgentPolicy } from '../types';
@ -55,6 +55,8 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent<Props> = ({
const onSuccessCallback = useRef<OnSuccessCallback | null>(null);
const { canUseMultipleAgentPolicies } = useMultipleAgentPolicies();
const { mutateAsync: deletePackagePolicyMutationAsync } = useDeletePackagePolicyMutation();
const isShared = useMemo(() => {
if (agentPolicies?.length !== 1) {
return false;
@ -118,80 +120,84 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent<Props> = ({
[agentPolicies]
);
const deletePackagePolicies = useMemo(
() => async () => {
setIsLoading(true);
const deletePackagePolicies = useCallback(async () => {
setIsLoading(true);
try {
const { data } = await sendDeletePackagePolicy({ packagePolicyIds: packagePolicies });
const successfulResults = data?.filter((result) => result.success) || [];
const failedResults = data?.filter((result) => !result.success) || [];
try {
const data = await deletePackagePolicyMutationAsync({ packagePolicyIds: packagePolicies });
const successfulResults = data?.filter((result) => result.success) || [];
const failedResults = data?.filter((result) => !result.success) || [];
if (successfulResults.length) {
const hasMultipleSuccesses = successfulResults.length > 1;
const successMessage = hasMultipleSuccesses
? i18n.translate('xpack.fleet.deletePackagePolicy.successMultipleNotificationTitle', {
defaultMessage: 'Deleted {count} integrations',
values: { count: successfulResults.length },
})
: i18n.translate('xpack.fleet.deletePackagePolicy.successSingleNotificationTitle', {
defaultMessage: "Deleted integration ''{id}''",
values: { id: successfulResults[0].name || successfulResults[0].id },
});
if (successfulResults.length) {
const hasMultipleSuccesses = successfulResults.length > 1;
const successMessage = hasMultipleSuccesses
? i18n.translate('xpack.fleet.deletePackagePolicy.successMultipleNotificationTitle', {
defaultMessage: 'Deleted {count} integrations',
values: { count: successfulResults.length },
})
: i18n.translate('xpack.fleet.deletePackagePolicy.successSingleNotificationTitle', {
defaultMessage: "Deleted integration ''{id}''",
values: { id: successfulResults[0].name || successfulResults[0].id },
});
const agentlessPolicy = agentPolicies?.find(
(policy) => policy.supports_agentless === true
);
const agentlessPolicy = agentPolicies?.find((policy) => policy.supports_agentless === true);
if (!!agentlessPolicy) {
try {
await sendDeleteAgentPolicy({ agentPolicyId: agentlessPolicy.id });
if (from === 'fleet-policy-list') {
history.push(getPath('policies_list'));
}
} catch (e) {
notifications.toasts.addDanger(
i18n.translate(
'xpack.fleet.deletePackagePolicy.fatalErrorAgentlessNotificationTitle',
{
defaultMessage: 'Error deleting agentless deployment',
}
)
);
if (!!agentlessPolicy) {
try {
await sendDeleteAgentPolicy({ agentPolicyId: agentlessPolicy.id });
if (from === 'fleet-policy-list') {
history.push(getPath('policies_list'));
}
} catch (e) {
notifications.toasts.addDanger(
i18n.translate(
'xpack.fleet.deletePackagePolicy.fatalErrorAgentlessNotificationTitle',
{
defaultMessage: 'Error deleting agentless deployment',
}
)
);
}
notifications.toasts.addSuccess(successMessage);
}
if (failedResults.length) {
const hasMultipleFailures = failedResults.length > 1;
const failureMessage = hasMultipleFailures
? i18n.translate('xpack.fleet.deletePackagePolicy.failureMultipleNotificationTitle', {
defaultMessage: 'Error deleting {count} integrations',
values: { count: failedResults.length },
})
: i18n.translate('xpack.fleet.deletePackagePolicy.failureSingleNotificationTitle', {
defaultMessage: "Error deleting integration ''{id}''",
values: { id: failedResults[0].id },
});
notifications.toasts.addDanger(failureMessage);
}
if (onSuccessCallback.current) {
onSuccessCallback.current(successfulResults.map((result) => result.id));
}
} catch (e) {
notifications.toasts.addDanger(
i18n.translate('xpack.fleet.deletePackagePolicy.fatalErrorNotificationTitle', {
defaultMessage: 'Error deleting integration',
})
);
notifications.toasts.addSuccess(successMessage);
}
closeModal();
},
[closeModal, packagePolicies, notifications.toasts, agentPolicies, getPath, history, from]
);
if (failedResults.length) {
const hasMultipleFailures = failedResults.length > 1;
const failureMessage = hasMultipleFailures
? i18n.translate('xpack.fleet.deletePackagePolicy.failureMultipleNotificationTitle', {
defaultMessage: 'Error deleting {count} integrations',
values: { count: failedResults.length },
})
: i18n.translate('xpack.fleet.deletePackagePolicy.failureSingleNotificationTitle', {
defaultMessage: "Error deleting integration ''{id}''",
values: { id: failedResults[0].id },
});
notifications.toasts.addDanger(failureMessage);
}
if (onSuccessCallback.current) {
onSuccessCallback.current(successfulResults.map((result) => result.id));
}
} catch (e) {
notifications.toasts.addDanger(
i18n.translate('xpack.fleet.deletePackagePolicy.fatalErrorNotificationTitle', {
defaultMessage: 'Error deleting integration',
})
);
}
closeModal();
}, [
closeModal,
packagePolicies,
notifications.toasts,
agentPolicies,
deletePackagePolicyMutationAsync,
getPath,
history,
from,
]);
const renderModal = () => {
const isAgentlessPolicy = agentPolicies?.find((policy) => policy?.supports_agentless === true);

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { useMutation, useQuery } from '@tanstack/react-query';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { packagePolicyRouteService } from '../../services';
import type {
@ -59,6 +59,26 @@ export const sendDeletePackagePolicy = (body: DeletePackagePoliciesRequest['body
});
};
export function useDeletePackagePolicyMutation() {
const queryClient = useQueryClient();
return useMutation(
(body: DeletePackagePoliciesRequest['body']) => {
return sendRequestForRq<PostDeletePackagePoliciesResponse>({
path: packagePolicyRouteService.getDeletePath(),
method: 'post',
version: API_VERSIONS.public.v1,
body: JSON.stringify(body),
});
},
{
retry: false,
onSuccess: () => {
return queryClient.invalidateQueries({ queryKey: ['get-packages'] });
},
}
);
}
export function useGetPackagePoliciesQuery(
query: GetPackagePoliciesRequest['query'],
options: Partial<{ enabled: boolean }> = {}