Skip to content

Commit

Permalink
[Fleet] disable upgrade action when package does not have upgrade ava…
Browse files Browse the repository at this point in the history
…ilable (elastic#111510) (elastic#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 <[email protected]>

Co-authored-by: Mark Hopkin <[email protected]>
  • Loading branch information
kibanamachine and hop-dev authored Sep 13, 2021
1 parent 1d8ef4c commit 94a74f5
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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();
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -143,7 +148,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
}, [history]);

const handleTableOnChange = useCallback(
({ page }: CriteriaWithPagination<PackagePolicyAndAgentPolicy>) => {
({ page }: CriteriaWithPagination<InMemoryPackagePolicyAndAgentPolicy>) => {
setPagination({
currentPage: page.index + 1,
pageSize: page.size,
Expand Down Expand Up @@ -196,7 +201,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
};
}, [name, version, getHref, agentEnrollmentFlyoutExtension]);

const columns: Array<EuiTableFieldDataColumnType<PackagePolicyAndAgentPolicy>> = useMemo(
const columns: Array<EuiTableFieldDataColumnType<InMemoryPackagePolicyAndAgentPolicy>> = useMemo(
() => [
{
field: 'packagePolicy.name',
Expand All @@ -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 (
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
Expand All @@ -235,7 +230,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
</EuiText>
</EuiFlexItem>

{hasUpgrade && (
{packagePolicy.hasUpgrade && (
<EuiFlexItem grow={false}>
<EuiButton
size="s"
Expand Down Expand Up @@ -274,7 +269,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
truncateText: true,
align: 'left',
width: '8ch',
render({ packagePolicy, agentPolicy }: PackagePolicyAndAgentPolicy) {
render({ packagePolicy, agentPolicy }: InMemoryPackagePolicyAndAgentPolicy) {
const count = agentPolicy?.agents ?? 0;

return (
Expand Down Expand Up @@ -327,7 +322,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
defaultMessage: 'Last Updated',
}),
truncateText: true,
render(updatedAt: PackagePolicyAndAgentPolicy['packagePolicy']['updated_at']) {
render(updatedAt: InMemoryPackagePolicyAndAgentPolicy['packagePolicy']['updated_at']) {
return (
<span className="eui-textTruncate" title={updatedAt}>
<FormattedRelative value={updatedAt} />
Expand Down Expand Up @@ -358,7 +353,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
},
},
],
[getHref, updatableIntegrations, viewDataStep]
[getHref, viewDataStep]
);

const noItemsMessage = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -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(
<PackagePolicyActionsMenu
agentPolicy={agentPolicy}
packagePolicy={packagePolicy}
showAddAgent={showAddAgent}
upgradePackagePolicyHref=""
defaultIsOpen={defaultIsOpen}
key="test1"
/>
);

return { utils };
}

function createMockAgentPolicy(props: Partial<AgentPolicy> = {}): 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> = {}
): 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();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -84,6 +92,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
disabled={!packagePolicy.hasUpgrade}
icon="refresh"
href={upgradePackagePolicyHref}
key="packagePolicyUpgrade"
>
<FormattedMessage
id="xpack.fleet.policyDetails.packagePoliciesTable.upgradeActionTitle"
Expand Down Expand Up @@ -135,7 +144,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
<ContextMenuActions
isOpen={isActionsMenuOpen}
items={menuItems}
onChange={(isOpen) => setIsActionsMenuOpen(isOpen)}
onChange={(open) => setIsActionsMenuOpen(open)}
/>
</>
);
Expand Down

0 comments on commit 94a74f5

Please sign in to comment.