Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fleet] Handle unavailable spaces in agent policy space selector #201251

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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<typeof useLicense>;
const mockedUseFleetStatus = useFleetStatus as jest.MockedFunction<typeof useFleetStatus>;

describe('Agent policy advanced options content', () => {
let testRender: TestRenderer;
Expand All @@ -40,13 +47,18 @@ 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,
isManaged = false,
policyId = 'agent-policy-1',
newAgentPolicy = false,
packagePolicy = [createPackagePolicyMock()],
spaceIds = ['default'],
} = {}) => {
if (newAgentPolicy) {
mockAgentPolicy = generateNewAgentPolicyWithDefaults();
Expand All @@ -56,6 +68,7 @@ describe('Agent policy advanced options content', () => {
package_policies: packagePolicy,
id: policyId,
is_managed: isManaged,
space_ids: spaceIds,
};
}

Expand All @@ -72,6 +85,7 @@ describe('Agent policy advanced options content', () => {
};

beforeEach(() => {
mockedUseFleetStatus.mockReturnValue({} as any);
testRender = createFleetTestRendererMock();
});
afterEach(() => {
Expand Down Expand Up @@ -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();
});
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,12 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> =
const isManagedorAgentlessPolicy =
agentPolicy.is_managed === true || agentPolicy?.supports_agentless === true;

const agentPolicyFormContect = useAgentPolicyFormContext();
const userHasAccessToAllPolicySpaces = useMemo(
() => 'space_ids' in agentPolicy && !agentPolicy.space_ids?.includes('?'),
[agentPolicy]
);

const agentPolicyFormContext = useAgentPolicyFormContext();

const AgentTamperProtectionSectionContent = useMemo(
() => (
Expand Down Expand Up @@ -309,32 +314,52 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> =
description={
<FormattedMessage
id="xpack.fleet.agentPolicyForm.spaceDescription"
defaultMessage="Select one or more spaces for this policy or create a new one. {link}"
defaultMessage="Select one or more spaces for this policy or create a new one. {link}{tooltip}"
values={{
link: (
link: userHasAccessToAllPolicySpaces && (
<EuiLink
target="_blank"
href={getAbsolutePath('/app/management/kibana/spaces/create')}
external
data-test-subj="spaceSelectorInputLink"
>
<FormattedMessage
id="xpack.fleet.agentPolicyForm.createSpaceLink"
defaultMessage="Create space"
/>
</EuiLink>
),
tooltip: !userHasAccessToAllPolicySpaces && (
<EuiIconTip
type="iInCircle"
color="subdued"
content={i18n.translate('xpack.fleet.agentPolicyForm.spaceTooltip', {
defaultMessage: 'Access to all policy spaces is required for edit.',
})}
/>
),
}}
/>
}
data-test-subj="spaceSelectorInput"
>
<SpaceSelector
isDisabled={disabled || agentPolicy.is_managed === true}
isDisabled={
disabled || agentPolicy.is_managed === true || !userHasAccessToAllPolicySpaces
}
value={
'space_ids' in agentPolicy && agentPolicy.space_ids
? agentPolicy.space_ids
? agentPolicy.space_ids.map((id) =>
id === '?'
? i18n.translate(
'xpack.fleet.agentPolicyForm.spaceSelector.unavailableSpaceBadgeLabel',
{ defaultMessage: 'Unavailable space' }
)
: id
)
: [spaceId || 'default']
}
setInvalidSpaceError={agentPolicyFormContect?.setInvalidSpaceError}
setInvalidSpaceError={agentPolicyFormContext?.setInvalidSpaceError}
onChange={(newValue) => {
if (newValue.length === 0) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,11 @@ import { DevtoolsRequestFlyoutButton } from '../../../../../components';
import { ExperimentalFeaturesService } from '../../../../../services';
import { generateUpdateAgentPolicyDevToolsRequest } from '../../../services';

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',
Expand All @@ -61,6 +60,13 @@ const pickAgentPolicyKeysToSend = (agentPolicy: AgentPolicy) =>
'monitoring_http',
'monitoring_diagnostics',
]);
return {
...partialPolicy,
...(!agentPolicy.space_ids?.includes('?') && {
space_ids: agentPolicy.space_ids,
}),
};
};

const FormWrapper = styled.div`
max-width: 1200px;
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -20498,7 +20498,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.",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -20467,7 +20467,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}統合も追加され、システムログとメトリックを収集します。",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -20122,7 +20122,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} 集成以收集系统日志和指标。",
Expand Down