From 743a9abfa9d797a713fac9c1b7d3edb33784ba6f Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Wed, 26 Apr 2023 14:37:39 -0400 Subject: [PATCH 1/4] [Fleet] Show request diagnostics for managed policy in agent table --- .../components/table_row_actions.test.tsx | 137 ++++++++++++++++++ .../components/table_row_actions.tsx | 37 +++-- 2 files changed, 158 insertions(+), 16 deletions(-) create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx new file mode 100644 index 0000000000000..810fe0f9617db --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx @@ -0,0 +1,137 @@ +/* + * 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 { fireEvent } from '@testing-library/dom'; + +import { createFleetTestRendererMock } from '../../../../../../mock'; +import type { Agent, AgentPolicy } from '../../../../types'; +import { ExperimentalFeaturesService } from '../../../../services'; +import { useAuthz } from '../../../../../../hooks/use_authz'; + +import { TableRowActions } from './table_row_actions'; + +jest.mock('../../../../../../hooks/use_fleet_status', () => ({ + FleetStatusProvider: (props: any) => { + return props.children; + }, +})); + +jest.mock('../../../../../../services/experimental_features'); +jest.mock('../../../../../../hooks/use_authz'); + +const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService); +const mockedUseAuthz = jest.mocked(useAuthz); + +function renderTableRowActions({ + agent, + agentPolicy, +}: { + agent: Agent; + agentPolicy?: AgentPolicy; +}) { + const renderer = createFleetTestRendererMock(); + + const utils = renderer.render( + + ); + + fireEvent.click(utils.getByTestId('agentActionsBtn')); + + return { utils }; +} +describe('TableRowActions', () => { + beforeEach(() => { + mockedExperimentalFeaturesService.get.mockReturnValue({ + diagnosticFileUploadEnabled: true, + } as any); + mockedUseAuthz.mockReturnValue({ + fleet: { + all: true, + }, + } as any); + }); + + describe('Request Diagnotics action', () => { + function renderAndGetDiagnosticsButton({ + agent, + agentPolicy, + }: { + agent: Agent; + agentPolicy?: AgentPolicy; + }) { + const { utils } = renderTableRowActions({ + agent, + agentPolicy, + }); + + return utils.queryByTestId('requestAgentDiagnosticsBtn'); + } + + it('should not render action if feature is disabled', async () => { + mockedExperimentalFeaturesService.get.mockReturnValue({ + diagnosticFileUploadEnabled: false, + } as any); + const res = renderAndGetDiagnosticsButton({ + agent: {} as Agent, + agentPolicy: {} as AgentPolicy, + }); + expect(res).toBe(null); + }); + + it('should render an active action button if agent version >= 8.7', async () => { + const res = renderAndGetDiagnosticsButton({ + agent: { + status: 'online', + local_metadata: { elastic: { agent: { version: '8.8.0' } } }, + } as any, + agentPolicy: {} as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).toBeEnabled(); + }); + + it('should render an active action button if agent version >= 8.7 and policy is_managed', async () => { + const res = renderAndGetDiagnosticsButton({ + agent: { + status: 'online', + local_metadata: { elastic: { agent: { version: '8.8.0' } } }, + } as any, + agentPolicy: { + is_managed: true, + } as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).toBeEnabled(); + }); + + it('should render a disabled action button if agent version < 8.7', async () => { + const res = renderAndGetDiagnosticsButton({ + agent: { + status: 'online', + local_metadata: { elastic: { agent: { version: '8.6.0' } } }, + } as any, + agentPolicy: { + is_managed: true, + } as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).not.toBeEnabled(); + }); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx index 243eabadcf3b7..e3e56ed2696af 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx @@ -80,6 +80,7 @@ export const TableRowActions: React.FunctionComponent<{ /> , { @@ -99,6 +100,7 @@ export const TableRowActions: React.FunctionComponent<{ )} , { @@ -111,24 +113,27 @@ export const TableRowActions: React.FunctionComponent<{ /> ); + } - if (diagnosticFileUploadEnabled) { - menuItems.push( - { - onRequestDiagnosticsClick(); - }} - > - - - ); - } + if (diagnosticFileUploadEnabled) { + menuItems.push( + { + onRequestDiagnosticsClick(); + }} + > + + + ); } + return ( Date: Wed, 26 Apr 2023 16:36:47 -0400 Subject: [PATCH 2/4] show view json for managed policy too --- .../components/action_menu.test.tsx | 167 ++++++++++++++++++ .../components/actions_menu.tsx | 9 +- 2 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx new file mode 100644 index 0000000000000..3b5979cec3e9a --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx @@ -0,0 +1,167 @@ +/* + * 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 { fireEvent } from '@testing-library/dom'; + +import { createFleetTestRendererMock } from '../../../../../../mock'; +import type { Agent, AgentPolicy } from '../../../../types'; +import { ExperimentalFeaturesService } from '../../../../services'; +import { useAuthz } from '../../../../../../hooks/use_authz'; + +import { AgentDetailsActionMenu } from './actions_menu'; + +jest.mock('../../../../../../hooks/use_fleet_status', () => ({ + FleetStatusProvider: (props: any) => { + return props.children; + }, +})); + +jest.mock('../../../../../../services/experimental_features'); +jest.mock('../../../../../../hooks/use_authz'); + +const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService); +const mockedUseAuthz = jest.mocked(useAuthz); + +function renderActions({ agent, agentPolicy }: { agent: Agent; agentPolicy?: AgentPolicy }) { + const renderer = createFleetTestRendererMock(); + + const utils = renderer.render( + + ); + + fireEvent.click(utils.getByRole('button')); + + return { utils }; +} +describe('AgentDetailsActionMenu', () => { + beforeEach(() => { + mockedExperimentalFeaturesService.get.mockReturnValue({ + diagnosticFileUploadEnabled: true, + } as any); + mockedUseAuthz.mockReturnValue({ + fleet: { + all: true, + }, + } as any); + }); + + describe('Request Diagnotics action', () => { + function renderAndGetDiagnosticsButton({ + agent, + agentPolicy, + }: { + agent: Agent; + agentPolicy?: AgentPolicy; + }) { + const { utils } = renderActions({ + agent, + agentPolicy, + }); + + return utils.queryByTestId('requestAgentDiagnosticsBtn'); + } + + it('should not render action if feature is disabled', async () => { + mockedExperimentalFeaturesService.get.mockReturnValue({ + diagnosticFileUploadEnabled: false, + } as any); + const res = renderAndGetDiagnosticsButton({ + agent: {} as Agent, + agentPolicy: {} as AgentPolicy, + }); + expect(res).toBe(null); + }); + + it('should render an active action button if agent version >= 8.7', async () => { + const res = renderAndGetDiagnosticsButton({ + agent: { + status: 'online', + local_metadata: { elastic: { agent: { version: '8.8.0' } } }, + } as any, + agentPolicy: {} as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).toBeEnabled(); + }); + + it('should render an active action button if agent version >= 8.7 and policy is_managed', async () => { + const res = renderAndGetDiagnosticsButton({ + agent: { + status: 'online', + local_metadata: { elastic: { agent: { version: '8.8.0' } } }, + } as any, + agentPolicy: { + is_managed: true, + } as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).toBeEnabled(); + }); + + it('should render a disabled action button if agent version < 8.7', async () => { + const res = renderAndGetDiagnosticsButton({ + agent: { + status: 'online', + local_metadata: { elastic: { agent: { version: '8.6.0' } } }, + } as any, + agentPolicy: { + is_managed: true, + } as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).not.toBeEnabled(); + }); + }); + + describe('View agent JSON action', () => { + function renderAndGetViewJSONButton({ + agent, + agentPolicy, + }: { + agent: Agent; + agentPolicy?: AgentPolicy; + }) { + const { utils } = renderActions({ + agent, + agentPolicy, + }); + + return utils.queryByTestId('viewAgentDetailsJsonBtn'); + } + + it('should render an active button', async () => { + const res = renderAndGetViewJSONButton({ + agent: {} as any, + agentPolicy: {} as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).toBeEnabled(); + }); + + it('should render an active button for managed agent policy', async () => { + const res = renderAndGetViewJSONButton({ + agent: {} as any, + agentPolicy: { + is_managed: true, + } as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).toBeEnabled(); + }); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx index d4710e71de9c2..1341e853cc173 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx @@ -108,6 +108,9 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ defaultMessage="Upgrade agent" /> , + ]; + + menuItems.push( { @@ -115,13 +118,14 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ setIsAgentDetailsJsonFlyoutOpen(!isAgentDetailsJsonFlyoutOpen); }} key="agentDetailsJson" + data-test-subj="viewAgentDetailsJsonBtn" > - , - ]; + + ); if (diagnosticFileUploadEnabled) { menuItems.push( @@ -131,6 +135,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ onClick={() => { setIsRequestDiagnosticsModalOpen(true); }} + data-test-subj="requestAgentDiagnosticsBtn" key="requestDiagnostics" > Date: Wed, 26 Apr 2023 16:43:47 -0400 Subject: [PATCH 3/4] Show action menu for managed agents --- .../agent_details_page/components/action_menu.test.tsx | 1 + .../agents/agent_details_page/components/actions_menu.tsx | 6 +++--- .../fleet/sections/agents/agent_details_page/index.tsx | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx index 3b5979cec3e9a..c88b2c0aedcad 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx @@ -43,6 +43,7 @@ function renderActions({ agent, agentPolicy }: { agent: Agent; agentPolicy?: Age return { utils }; } + describe('AgentDetailsActionMenu', () => { beforeEach(() => { mockedExperimentalFeaturesService.get.mockReturnValue({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx index 1341e853cc173..f96e85eea0053 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx @@ -67,7 +67,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ onClick={() => { setIsReassignFlyoutOpen(true); }} - disabled={!agent.active} + disabled={!agent.active || agentPolicy?.is_managed} key="reassignPolicy" > , { setIsUnenrollModalOpen(true); }} @@ -97,7 +97,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ , { setIsUpgradeModalOpen(true); }} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx index 28589906bd2c7..5b0e993a5a675 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx @@ -117,7 +117,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { <> - {!isAgentPolicyLoading && !agentPolicyData?.item?.is_managed && ( + {!isAgentPolicyLoading && ( Date: Thu, 27 Apr 2023 08:12:36 -0400 Subject: [PATCH 4/4] Fix after review --- .../components/actions_menu.tsx | 92 ++++++++++--------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx index f96e85eea0053..80651ad5a4ab3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx @@ -61,54 +61,58 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ } }, [onCancelReassign, setIsReassignFlyoutOpen]); - const menuItems = [ - { - setIsReassignFlyoutOpen(true); - }} - disabled={!agent.active || agentPolicy?.is_managed} - key="reassignPolicy" - > - - , - { - setIsUnenrollModalOpen(true); - }} - key="unenrollAgent" - > - {isUnenrolling ? ( + const menuItems = []; + + if (!agentPolicy?.is_managed) { + menuItems.push( + { + setIsReassignFlyoutOpen(true); + }} + disabled={!agent.active && !agentPolicy} + key="reassignPolicy" + > - ) : ( + , + { + setIsUnenrollModalOpen(true); + }} + key="unenrollAgent" + > + {isUnenrolling ? ( + + ) : ( + + )} + , + { + setIsUpgradeModalOpen(true); + }} + key="upgradeAgent" + > - )} - , - { - setIsUpgradeModalOpen(true); - }} - key="upgradeAgent" - > - - , - ]; + + ); + } menuItems.push(