From 94a74f5b472fc930e3cc5529c9193230d26a3d46 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 13 Sep 2021 09:25:43 -0400 Subject: [PATCH] [Fleet] disable upgrade action when package does not have upgrade available (#111510) (#111940) * fix: consolidate hasUpgrade logic * tidy: move type defs to top of file * test: add unit tests for actions menu * tidy: PR feedback Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Mark Hopkin --- .../detail/policies/package_policies.tsx | 43 +++---- .../package_policy_actions_menu.test.tsx | 121 ++++++++++++++++++ .../package_policy_actions_menu.tsx | 15 ++- 3 files changed, 152 insertions(+), 27 deletions(-) create mode 100644 x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx index 677ca545029fe..07a61410e9a6b 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx @@ -45,16 +45,25 @@ import { PackagePolicyActionsMenu, } from '../../../../../components'; -import type { PackagePolicyAndAgentPolicy } from './use_package_policies_with_agent_policy'; import { usePackagePoliciesWithAgentPolicy } from './use_package_policies_with_agent_policy'; import { Persona } from './persona'; +interface PackagePoliciesPanelProps { + name: string; + version: string; +} + +interface InMemoryPackagePolicyAndAgentPolicy { + packagePolicy: InMemoryPackagePolicy; + agentPolicy: GetAgentPoliciesResponseItem; +} + const AddAgentButton = styled(EuiButtonIcon)` margin-left: ${(props) => props.theme.eui.euiSizeS}; `; const IntegrationDetailsLink = memo<{ - packagePolicy: PackagePolicyAndAgentPolicy['packagePolicy']; + packagePolicy: InMemoryPackagePolicyAndAgentPolicy['packagePolicy']; }>(({ packagePolicy }) => { const { getHref } = useLink(); return ( @@ -71,10 +80,6 @@ const IntegrationDetailsLink = memo<{ ); }); -interface PackagePoliciesPanelProps { - name: string; - version: string; -} export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps) => { const { search } = useLocation(); const history = useHistory(); @@ -109,12 +114,12 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps const updatableIntegrationRecord = updatableIntegrations.get( packagePolicy.package?.name ?? '' ); - const hasUpgrade = !!updatableIntegrationRecord && updatableIntegrationRecord.policiesToUpgrade.some( - ({ id }) => id === packagePolicy.policy_id + ({ pkgPolicyId }) => pkgPolicyId === packagePolicy.id ); + return { agentPolicy, packagePolicy: { @@ -143,7 +148,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps }, [history]); const handleTableOnChange = useCallback( - ({ page }: CriteriaWithPagination) => { + ({ page }: CriteriaWithPagination) => { setPagination({ currentPage: page.index + 1, pageSize: page.size, @@ -196,7 +201,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps }; }, [name, version, getHref, agentEnrollmentFlyoutExtension]); - const columns: Array> = useMemo( + const columns: Array> = useMemo( () => [ { field: 'packagePolicy.name', @@ -213,16 +218,6 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps defaultMessage: 'Version', }), render(_version, { agentPolicy, packagePolicy }) { - const updatableIntegrationRecord = updatableIntegrations.get( - packagePolicy.package?.name ?? '' - ); - - const hasUpgrade = - !!updatableIntegrationRecord && - updatableIntegrationRecord.policiesToUpgrade.some( - ({ pkgPolicyId }) => pkgPolicyId === packagePolicy.id - ); - return ( @@ -235,7 +230,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps - {hasUpgrade && ( + {packagePolicy.hasUpgrade && ( @@ -358,7 +353,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps }, }, ], - [getHref, updatableIntegrations, viewDataStep] + [getHref, viewDataStep] ); const noItemsMessage = useMemo(() => { diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx new file mode 100644 index 0000000000000..63a3a93b7e894 --- /dev/null +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { act } from '@testing-library/react'; + +import type { AgentPolicy, InMemoryPackagePolicy } from '../types'; +import { createIntegrationsTestRendererMock } from '../mock'; + +import { PackagePolicyActionsMenu } from './package_policy_actions_menu'; + +function renderMenu({ + agentPolicy, + packagePolicy, + showAddAgent = false, + defaultIsOpen = true, +}: { + agentPolicy: AgentPolicy; + packagePolicy: InMemoryPackagePolicy; + showAddAgent?: boolean; + defaultIsOpen?: boolean; +}) { + const renderer = createIntegrationsTestRendererMock(); + + const utils = renderer.render( + + ); + + return { utils }; +} + +function createMockAgentPolicy(props: Partial = {}): AgentPolicy { + return { + id: 'some-uuid1', + namespace: 'default', + monitoring_enabled: [], + name: 'Test Policy', + description: '', + is_default: false, + is_preconfigured: false, + status: 'active', + is_managed: false, + revision: 1, + updated_at: '', + updated_by: 'elastic', + package_policies: [], + ...props, + }; +} + +function createMockPackagePolicy( + props: Partial = {} +): InMemoryPackagePolicy { + return { + id: 'some-uuid2', + name: 'mock-package-policy', + description: '', + created_at: '', + created_by: '', + updated_at: '', + updated_by: '', + policy_id: '', + enabled: true, + output_id: '', + namespace: 'default', + inputs: [], + revision: 1, + hasUpgrade: false, + ...props, + }; +} + +test('Should disable upgrade button if package does not have upgrade', async () => { + const agentPolicy = createMockAgentPolicy(); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: false }); + const { utils } = renderMenu({ agentPolicy, packagePolicy }); + await act(async () => { + const upgradeButton = utils.getByText('Upgrade integration policy').closest('button'); + expect(upgradeButton).toBeDisabled(); + }); +}); + +test('Should enable upgrade button if package has upgrade', async () => { + const agentPolicy = createMockAgentPolicy(); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); + const { utils } = renderMenu({ agentPolicy, packagePolicy }); + await act(async () => { + const upgradeButton = utils.getByText('Upgrade integration policy').closest('button'); + expect(upgradeButton).not.toBeDisabled(); + }); +}); + +test('Should not be able to delete integration from a managed policy', async () => { + const agentPolicy = createMockAgentPolicy({ is_managed: true }); + const packagePolicy = createMockPackagePolicy(); + const { utils } = renderMenu({ agentPolicy, packagePolicy }); + await act(async () => { + expect(utils.queryByText('Delete integration')).toBeNull(); + }); +}); + +test('Should be able to delete integration from a non-managed policy', async () => { + const agentPolicy = createMockAgentPolicy({ is_managed: false }); + const packagePolicy = createMockPackagePolicy(); + const { utils } = renderMenu({ agentPolicy, packagePolicy }); + await act(async () => { + expect(utils.queryByText('Delete integration')).not.toBeNull(); + }); +}); diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx index 2030f57764756..eefa3c870f283 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx @@ -24,13 +24,21 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ packagePolicy: InMemoryPackagePolicy; viewDataStep?: EuiStepProps; showAddAgent?: boolean; + defaultIsOpen?: boolean; upgradePackagePolicyHref: string; -}> = ({ agentPolicy, packagePolicy, viewDataStep, showAddAgent, upgradePackagePolicyHref }) => { +}> = ({ + agentPolicy, + packagePolicy, + viewDataStep, + showAddAgent, + upgradePackagePolicyHref, + defaultIsOpen = false, +}) => { const [isEnrollmentFlyoutOpen, setIsEnrollmentFlyoutOpen] = useState(false); const { getHref } = useLink(); const hasWriteCapabilities = useCapabilities().write; const refreshAgentPolicy = useAgentPolicyRefresh(); - const [isActionsMenuOpen, setIsActionsMenuOpen] = useState(false); + const [isActionsMenuOpen, setIsActionsMenuOpen] = useState(defaultIsOpen); const onEnrollmentFlyoutClose = useMemo(() => { return () => setIsEnrollmentFlyoutOpen(false); @@ -84,6 +92,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ disabled={!packagePolicy.hasUpgrade} icon="refresh" href={upgradePackagePolicyHref} + key="packagePolicyUpgrade" > setIsActionsMenuOpen(isOpen)} + onChange={(open) => setIsActionsMenuOpen(open)} /> );