diff --git a/x-pack/plugins/fleet/common/constants/index.ts b/x-pack/plugins/fleet/common/constants/index.ts index 8ebfe005960c4..f51e85f22c526 100644 --- a/x-pack/plugins/fleet/common/constants/index.ts +++ b/x-pack/plugins/fleet/common/constants/index.ts @@ -25,6 +25,7 @@ export * from './message_signing_keys'; export * from './locators'; export * from './secrets'; export * from './uninstall_token'; +export * from './space_awareness'; // TODO: This is the default `index.max_result_window` ES setting, which dictates // the maximum amount of results allowed to be returned from a search. It's possible diff --git a/x-pack/plugins/fleet/common/constants/space_awareness.ts b/x-pack/plugins/fleet/common/constants/space_awareness.ts new file mode 100644 index 0000000000000..c89d0f4cddb00 --- /dev/null +++ b/x-pack/plugins/fleet/common/constants/space_awareness.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +/** + * The identifier in a saved object's `namespaces` array when it is shared to an unknown space (e.g., one that the end user is not authorized to see). + */ +export const UNKNOWN_SPACE = '?'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx index e404b30a37ced..61846bdbd7e24 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx @@ -18,6 +18,8 @@ import type { AgentPolicy, NewAgentPolicy } from '../../../../../../../common/ty import { useLicense } from '../../../../../../hooks/use_license'; +import { useFleetStatus } from '../../../../hooks'; + import type { LicenseService } from '../../../../../../../common/services'; import { generateNewAgentPolicyWithDefaults } from '../../../../../../../common/services'; @@ -26,8 +28,13 @@ import type { ValidationResults } from '../agent_policy_validation'; import { AgentPolicyAdvancedOptionsContent } from '.'; jest.mock('../../../../../../hooks/use_license'); +jest.mock('../../../../hooks', () => ({ + ...jest.requireActual('../../../../hooks'), + useFleetStatus: jest.fn(), +})); const mockedUseLicence = useLicense as jest.MockedFunction; +const mockedUseFleetStatus = useFleetStatus as jest.MockedFunction; describe('Agent policy advanced options content', () => { let testRender: TestRenderer; @@ -40,6 +47,10 @@ describe('Agent policy advanced options content', () => { hasAtLeast: () => true, isPlatinum: () => true, } as unknown as LicenseService); + const useSpaceAwareness = () => + mockedUseFleetStatus.mockReturnValue({ + isSpaceAwarenessEnabled: true, + } as any); const render = ({ isProtected = false, @@ -47,6 +58,7 @@ describe('Agent policy advanced options content', () => { policyId = 'agent-policy-1', newAgentPolicy = false, packagePolicy = [createPackagePolicyMock()], + spaceIds = ['default'], } = {}) => { if (newAgentPolicy) { mockAgentPolicy = generateNewAgentPolicyWithDefaults(); @@ -56,6 +68,7 @@ describe('Agent policy advanced options content', () => { package_policies: packagePolicy, id: policyId, is_managed: isManaged, + space_ids: spaceIds, }; } @@ -72,6 +85,7 @@ describe('Agent policy advanced options content', () => { }; beforeEach(() => { + mockedUseFleetStatus.mockReturnValue({} as any); testRender = createFleetTestRendererMock(); }); afterEach(() => { @@ -173,4 +187,39 @@ describe('Agent policy advanced options content', () => { expect(renderResult.queryByText('This policy has no custom fields')).toBeInTheDocument(); }); }); + + describe('Space selector', () => { + beforeEach(() => { + usePlatinumLicense(); + }); + + describe('when space awareness is disabled', () => { + it('should not be rendered', () => { + render(); + expect(renderResult.queryByTestId('spaceSelectorInput')).not.toBeInTheDocument(); + }); + }); + + describe('when space awareness is enabled', () => { + beforeEach(() => { + useSpaceAwareness(); + }); + + describe('when the user has access to all policy spaces', () => { + it('should render the space selection input with the Create space link', () => { + render(); + expect(renderResult.queryByTestId('spaceSelectorInput')).toBeInTheDocument(); + expect(renderResult.queryByTestId('spaceSelectorInputLink')).toBeInTheDocument(); + }); + }); + + describe('when the user does not have access to all policy spaces', () => { + it('should render the space selection input without the Create space link', () => { + render({ spaceIds: ['default', '?'] }); + expect(renderResult.queryByTestId('spaceSelectorInput')).toBeInTheDocument(); + expect(renderResult.queryByTestId('spaceSelectorInputLink')).not.toBeInTheDocument(); + }); + }); + }); + }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index 305148584f545..b0889f825727f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -34,6 +34,7 @@ import { LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE, dataTypes, DEFAULT_MAX_AGENT_POLICIES_WITH_INACTIVITY_TIMEOUT, + UNKNOWN_SPACE, } from '../../../../../../../common/constants'; import type { NewAgentPolicy, AgentPolicy } from '../../../../types'; import { @@ -127,7 +128,12 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = const isManagedorAgentlessPolicy = agentPolicy.is_managed === true || agentPolicy?.supports_agentless === true; - const agentPolicyFormContect = useAgentPolicyFormContext(); + const userHasAccessToAllPolicySpaces = useMemo( + () => 'space_ids' in agentPolicy && !agentPolicy.space_ids?.includes(UNKNOWN_SPACE), + [agentPolicy] + ); + + const agentPolicyFormContext = useAgentPolicyFormContext(); const AgentTamperProtectionSectionContent = useMemo( () => ( @@ -309,13 +315,14 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = description={ = /> ), + tooltip: !userHasAccessToAllPolicySpaces && ( + + ), }} /> } + data-test-subj="spaceSelectorInput" > id !== UNKNOWN_SPACE) : [spaceId || 'default'] } - setInvalidSpaceError={agentPolicyFormContect?.setInvalidSpaceError} + setInvalidSpaceError={agentPolicyFormContext?.setInvalidSpaceError} onChange={(newValue) => { if (newValue.length === 0) { return; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx index 9de7a3f22adff..e0ea955cf5afe 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx @@ -39,13 +39,13 @@ import { import { DevtoolsRequestFlyoutButton } from '../../../../../components'; import { ExperimentalFeaturesService } from '../../../../../services'; import { generateUpdateAgentPolicyDevToolsRequest } from '../../../services'; +import { UNKNOWN_SPACE } from '../../../../../../../../common/constants'; -const pickAgentPolicyKeysToSend = (agentPolicy: AgentPolicy) => - pick(agentPolicy, [ +const pickAgentPolicyKeysToSend = (agentPolicy: AgentPolicy) => { + const partialPolicy = pick(agentPolicy, [ 'name', 'description', 'namespace', - 'space_ids', 'monitoring_enabled', 'unenroll_timeout', 'inactivity_timeout', @@ -61,6 +61,13 @@ const pickAgentPolicyKeysToSend = (agentPolicy: AgentPolicy) => 'monitoring_http', 'monitoring_diagnostics', ]); + return { + ...partialPolicy, + ...(!agentPolicy.space_ids?.includes(UNKNOWN_SPACE) && { + space_ids: agentPolicy.space_ids, + }), + }; +}; const FormWrapper = styled.div` max-width: 1200px; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 06506ff9d1c93..0672227df5017 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -20488,7 +20488,6 @@ "xpack.fleet.agentPolicyForm.newAgentPolicyFieldLabel": "Nouveau nom de la stratégie d'agent", "xpack.fleet.agentPolicyForm.outputOptionDisabledTypeNotSupportedText": "La sortie {outputType} pour l'intégration des agents n'est pas prise en charge pour Fleet Server, Synthetics ou APM.", "xpack.fleet.agentPolicyForm.outputOptionDisableOutputTypeText": "La sortie {outputType} pour l'intégration des agents n'est pas prise en charge pour Fleet Server, Synthetics ou APM.", - "xpack.fleet.agentPolicyForm.spaceDescription": "Sélectionnez un ou plusieurs espaces pour cette politique ou créez un nouvel espace. {link}", "xpack.fleet.agentPolicyForm.spaceFieldLabel": "Espaces", "xpack.fleet.agentPolicyForm.systemMonitoringText": "Collecte des logs et des mesures du système", "xpack.fleet.agentPolicyForm.systemMonitoringTooltipText": "Cela ajoutera également une intégration {system} pour collecter les logs et les indicateurs du système.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d4c397428a8e0..c8781e36fe43a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -20457,7 +20457,6 @@ "xpack.fleet.agentPolicyForm.newAgentPolicyFieldLabel": "新しいエージェントポリシー名", "xpack.fleet.agentPolicyForm.outputOptionDisabledTypeNotSupportedText": "Fleet Server、Synthetics、APMではエージェント統合の{outputType}出力はサポートされていません。", "xpack.fleet.agentPolicyForm.outputOptionDisableOutputTypeText": "Fleet Server、Synthetics、APMではエージェント統合の{outputType}出力はサポートされていません。", - "xpack.fleet.agentPolicyForm.spaceDescription": "このポリシーに1つ以上のスペースを選択するか、新しいスペースを作成します。{link}", "xpack.fleet.agentPolicyForm.spaceFieldLabel": "スペース", "xpack.fleet.agentPolicyForm.systemMonitoringText": "システムログとメトリックの収集", "xpack.fleet.agentPolicyForm.systemMonitoringTooltipText": "これにより、{system}統合も追加され、システムログとメトリックを収集します。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index e5ee0c1ede629..c6bb9b8da3ae9 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -20112,7 +20112,6 @@ "xpack.fleet.agentPolicyForm.newAgentPolicyFieldLabel": "新代理策略名称", "xpack.fleet.agentPolicyForm.outputOptionDisabledTypeNotSupportedText": "Fleet 服务器、Synthetics 或 APM 不支持代理集成的 {outputType} 输出。", "xpack.fleet.agentPolicyForm.outputOptionDisableOutputTypeText": "Fleet 服务器、Synthetics 或 APM 不支持代理集成的 {outputType} 输出。", - "xpack.fleet.agentPolicyForm.spaceDescription": "为此策略选择一个或多个工作区,或创建新工作区。{link}", "xpack.fleet.agentPolicyForm.spaceFieldLabel": "工作区", "xpack.fleet.agentPolicyForm.systemMonitoringText": "收集系统日志和指标", "xpack.fleet.agentPolicyForm.systemMonitoringTooltipText": "这还会添加 {system} 集成以收集系统日志和指标。",