mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Fleet] Handle unavailable spaces in agent policy space selector (#201251)
## Summary Closes https://github.com/elastic/kibana/issues/193827 This PR improves the space selector in agent policy setting to handle the case where the user does not have access to all policy spaces. In this case: * Space selection is disabled * The "Create space" link is hidden * A tooltip is shown to inform the user why the input is disabled * The inaccessible space badges are given an `Unavailable space` badge ### Screenshots For a user with access to all policy spaces (no change):  For a user with access to only a subset of policy spaces:  ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
a76084f30f
commit
db494181e3
8 changed files with 96 additions and 12 deletions
|
@ -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
|
||||
|
|
11
x-pack/plugins/fleet/common/constants/space_awareness.ts
Normal file
11
x-pack/plugins/fleet/common/constants/space_awareness.ts
Normal file
|
@ -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 = '?';
|
|
@ -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<typeof useLicense>;
|
||||
const mockedUseFleetStatus = useFleetStatus as jest.MockedFunction<typeof useFleetStatus>;
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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<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(UNKNOWN_SPACE),
|
||||
[agentPolicy]
|
||||
);
|
||||
|
||||
const agentPolicyFormContext = useAgentPolicyFormContext();
|
||||
|
||||
const AgentTamperProtectionSectionContent = useMemo(
|
||||
() => (
|
||||
|
@ -309,13 +315,14 @@ 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"
|
||||
|
@ -323,18 +330,30 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> =
|
|||
/>
|
||||
</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.filter((id) => id !== UNKNOWN_SPACE)
|
||||
: [spaceId || 'default']
|
||||
}
|
||||
setInvalidSpaceError={agentPolicyFormContect?.setInvalidSpaceError}
|
||||
setInvalidSpaceError={agentPolicyFormContext?.setInvalidSpaceError}
|
||||
onChange={(newValue) => {
|
||||
if (newValue.length === 0) {
|
||||
return;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -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}統合も追加され、システムログとメトリックを収集します。",
|
||||
|
|
|
@ -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} 集成以收集系统日志和指标。",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue