[8.x] [Fleet] Enable read bulk agent actions (#206847) (#206942)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Fleet] Enable read bulk agent actions
(#206847)](https://github.com/elastic/kibana/pull/206847)

<!--- Backport version: 9.6.4 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Nicolas
Chaulet","email":"nicolas.chaulet@elastic.co"},"sourceCommit":{"committedDate":"2025-01-16T12:52:27Z","message":"[Fleet]
Enable read bulk agent actions
(#206847)","sha":"5e8d2b5907843178bd6b4ebb9bf4ca023f019506","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Fleet","v9.0.0","backport:prev-minor"],"title":"[Fleet]
Enable read bulk agent
actions","number":206847,"url":"https://github.com/elastic/kibana/pull/206847","mergeCommit":{"message":"[Fleet]
Enable read bulk agent actions
(#206847)","sha":"5e8d2b5907843178bd6b4ebb9bf4ca023f019506"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/206847","number":206847,"mergeCommit":{"message":"[Fleet]
Enable read bulk agent actions
(#206847)","sha":"5e8d2b5907843178bd6b4ebb9bf4ca023f019506"}}]}]
BACKPORT-->
This commit is contained in:
Nicolas Chaulet 2025-01-17 03:55:13 -05:00 committed by GitHub
parent 7437653934
commit 56ee044840
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 36 additions and 24 deletions

View file

@ -337,25 +337,21 @@ export const AgentListTable: React.FC<Props> = (props: Props) => {
totalItemCount: totalAgents,
pageSizeOptions,
}}
selection={
!authz.fleet.allAgents
? undefined
: {
selected,
onSelectionChange,
selectable: isAgentSelectable,
selectableMessage: (selectable, agent) => {
if (selectable) return '';
if (!agent.active) {
return 'This agent is not active';
}
if (agent.policy_id && agentPoliciesIndexedById[agent.policy_id].is_managed) {
return 'This action is not available for agents enrolled in an externally managed agent policy';
}
return '';
},
}
}
selection={{
selected,
onSelectionChange,
selectable: isAgentSelectable,
selectableMessage: (selectable, agent) => {
if (selectable) return '';
if (!agent.active) {
return 'This agent is not active';
}
if (agent.policy_id && agentPoliciesIndexedById[agent.policy_id].is_managed) {
return 'This action is not available for agents enrolled in an externally managed agent policy';
}
return '';
},
}}
onChange={onTableChange}
sorting={sorting}
/>

View file

@ -15,7 +15,7 @@ import { createFleetTestRendererMock } from '../../../../../../mock';
import type { LicenseService } from '../../../../services';
import { ExperimentalFeaturesService } from '../../../../services';
import { AgentReassignAgentPolicyModal } from '../../components/agent_reassign_policy_modal';
import { useAuthz } from '../../../../../../hooks/use_authz';
import { useLicense } from '../../../../../../hooks/use_license';
import { AgentBulkActions } from './bulk_actions';
@ -24,6 +24,7 @@ jest.mock('../../../../../../services/experimental_features');
const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService);
jest.mock('../../../../../../hooks/use_license');
jest.mock('../../../../../../hooks/use_authz');
const mockedUseLicence = useLicense as jest.MockedFunction<typeof useLicense>;
jest.mock('../../components/agent_reassign_policy_modal');
@ -51,6 +52,13 @@ describe('AgentBulkActions', () => {
mockedExperimentalFeaturesService.get.mockReturnValue({
diagnosticFileUploadEnabled: true,
} as any);
jest.mocked(useAuthz).mockReturnValue({
fleet: {
allAgents: true,
readAgents: true,
},
integrations: {},
} as any);
});
beforeEach(() => {

View file

@ -23,7 +23,7 @@ import {
AgentUnenrollAgentModal,
AgentUpgradeAgentModal,
} from '../../components';
import { useLicense } from '../../../../hooks';
import { useAuthz, useLicense } from '../../../../hooks';
import { LICENSE_FOR_SCHEDULE_UPGRADE, AGENTS_PREFIX } from '../../../../../../../common/constants';
import { ExperimentalFeaturesService } from '../../../../services';
@ -66,6 +66,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
sortOrder,
}) => {
const licenseService = useLicense();
const authz = useAuthz();
const isLicenceAllowingScheduleUpgrade = licenseService.hasAtLeast(LICENSE_FOR_SCHEDULE_UPGRADE);
// Bulk actions menu states
@ -119,6 +120,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
/>
),
icon: <EuiIcon type="tag" size="m" />,
disabled: !authz.fleet.allAgents,
onClick: (event: any) => {
setTagsPopoverButton((event.target as Element).closest('button')!);
setIsTagAddVisible(!isTagAddVisible);
@ -133,6 +135,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
/>
),
icon: <EuiIcon type="pencil" size="m" />,
disabled: !authz.fleet.allAgents,
onClick: () => {
closeMenu();
setIsReassignFlyoutOpen(true);
@ -150,6 +153,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
/>
),
icon: <EuiIcon type="refresh" size="m" />,
disabled: !authz.fleet.allAgents,
onClick: () => {
closeMenu();
setUpgradeModalState({ isOpen: true, isScheduled: false, isUpdating: false });
@ -167,7 +171,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
/>
),
icon: <EuiIcon type="timeRefresh" size="m" />,
disabled: !isLicenceAllowingScheduleUpgrade,
disabled: !authz.fleet.allAgents || !isLicenceAllowingScheduleUpgrade,
onClick: () => {
closeMenu();
setUpgradeModalState({ isOpen: true, isScheduled: true, isUpdating: false });
@ -185,6 +189,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
/>
),
icon: <EuiIcon type="refresh" size="m" />,
disabled: !authz.fleet.allAgents,
onClick: () => {
closeMenu();
setUpgradeModalState({ isOpen: true, isScheduled: false, isUpdating: true });
@ -203,6 +208,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
}}
/>
),
disabled: !authz.fleet.readAgents,
icon: <EuiIcon type="download" size="m" />,
onClick: () => {
closeMenu();
@ -222,6 +228,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
}}
/>
),
disabled: !authz.fleet.allAgents,
icon: <EuiIcon type="trash" size="m" />,
onClick: () => {
closeMenu();
@ -241,6 +248,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
}}
/>
),
disabled: !authz.fleet.readAgents,
icon: <EuiIcon type="exportAction" size="m" />,
onClick: () => {
closeMenu();

View file

@ -210,8 +210,8 @@ export const SearchAndFilterBar: React.FunctionComponent<SearchAndFilterBarProps
</EuiFilterButton>
</EuiFilterGroup>
</EuiFlexItem>
{(authz.fleet.allAgents && selectionMode === 'manual' && selectedAgents.length) ||
(authz.fleet.allAgents && selectionMode === 'query' && nAgentsInTable > 0) ? (
{(selectionMode === 'manual' && selectedAgents.length) ||
(selectionMode === 'query' && nAgentsInTable > 0) ? (
<EuiFlexItem grow={false}>
<AgentBulkActions
nAgentsInTable={nAgentsInTable}