[Fleet] Add UI to add additional datastreams permissions (#210935)

This commit is contained in:
Nicolas Chaulet 2025-02-18 08:56:38 -05:00 committed by GitHub
parent dac36902f2
commit aa96382c71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 90 additions and 11 deletions

View file

@ -159,10 +159,9 @@ describe('StepDefinePackagePolicy', () => {
await userEvent.click(renderResult.getByText('Advanced options').closest('button')!);
await waitFor(() => {
expect(renderResult.getByTestId('comboBoxSearchInput')).toHaveAttribute(
'placeholder',
'ns'
);
expect(
renderResult.getByTestId('packagePolicyNamespaceInput').querySelector('input')
).toHaveAttribute('placeholder', 'ns');
});
});
@ -175,10 +174,9 @@ describe('StepDefinePackagePolicy', () => {
await userEvent.click(renderResult.getByText('Advanced options').closest('button')!);
await waitFor(() => {
expect(renderResult.getByTestId('comboBoxSearchInput')).toHaveAttribute(
'placeholder',
'default'
);
expect(
renderResult.getByTestId('packagePolicyNamespaceInput').querySelector('input')
).toHaveAttribute('placeholder', 'default');
});
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { memo, useState, useEffect } from 'react';
import React, { memo, useState, useEffect, useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
@ -21,13 +21,15 @@ import {
EuiCallOut,
EuiSpacer,
EuiSelect,
type EuiComboBoxOptionOption,
EuiIconTip,
} from '@elastic/eui';
import styled from 'styled-components';
import type { PackageInfo, NewPackagePolicy, RegistryVarsEntry } from '../../../../../types';
import { Loading } from '../../../../../components';
import { useStartServices } from '../../../../../hooks';
import { useGetEpmDatastreams, useStartServices } from '../../../../../hooks';
import { isAdvancedVar } from '../../services';
import type { PackagePolicyValidationResults } from '../../services';
@ -90,6 +92,26 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{
allowedOutputs,
} = useOutputs(packagePolicy, packageInfo.name);
const { data: epmDatastreamsRes } = useGetEpmDatastreams();
const datastreamsOptions = useMemo<Array<EuiComboBoxOptionOption<string>>>(
() =>
epmDatastreamsRes?.items?.map((item) => ({
label: item.name,
value: item.name,
})) ?? [],
[epmDatastreamsRes]
);
const selectedDatastreamOptions = useMemo<EuiComboBoxOptionOption[]>(
() =>
packagePolicy?.additional_datastreams_permissions?.map((item) => ({
label: item,
value: item,
})) ?? [],
[packagePolicy?.additional_datastreams_permissions]
);
// Reset output if switching to agentless and the current
// selected output is not allowed
useEffect(() => {
@ -404,6 +426,55 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{
<div />
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
isInvalid={validationResults?.additional_datastreams_permissions !== null}
error={validationResults?.additional_datastreams_permissions ?? []}
label={
<FormattedMessage
id="xpack.fleet.createPackagePolicy.stepConfigure.additionalPermissionsLabel"
defaultMessage="Add a reroute processor permission {tooltip}"
values={{
tooltip: (
<EuiIconTip
content={
<FormattedMessage
id="xpack.fleet.createPackagePolicy.stepConfigure.additionalPermissionsToolTip"
defaultMessage="Use the reroute processor to redirect data flows to another target index or data stream."
/>
}
position="right"
/>
),
}}
/>
}
>
<EuiComboBox
selectedOptions={selectedDatastreamOptions}
options={datastreamsOptions}
onChange={(val) => {
updatePackagePolicy({
additional_datastreams_permissions: val.map((v) => v.label),
});
}}
onCreateOption={(option) => {
const additionalPermissions =
packagePolicy.additional_datastreams_permissions ?? [];
updatePackagePolicy({
additional_datastreams_permissions: [...additionalPermissions, option],
});
}}
placeholder={i18n.translate(
'xpack.fleet.createPackagePolicy.stepConfigure.additionalPermissionsPlaceholder',
{
defaultMessage: 'Add a permission',
}
)}
/>
</EuiFormRow>
</EuiFlexItem>
{/* Advanced vars */}
{advancedVars.map((varDef) => {
const { name: varName, type: varType } = varDef;

View file

@ -11,6 +11,8 @@ import type { PackageDataStreamTypes } from '../../../../common/types';
import { dataStreamService } from '../../data_streams';
const VALID_STREAM_TYPES = ['logs', 'metrics', 'traces', 'synthetics', 'profiling'];
export async function getDataStreams(options: {
esClient: ElasticsearchClient;
type?: PackageDataStreamTypes;
@ -25,12 +27,20 @@ export async function getDataStreams(options: {
dataset: datasetQuery ? `*${datasetQuery}*` : '*',
});
const filteredDataStreams = uncategorisedOnly
let filteredDataStreams = uncategorisedOnly
? allDataStreams.filter((stream) => {
return !stream._meta || !stream._meta.managed_by || stream._meta.managed_by !== 'fleet';
})
: allDataStreams;
filteredDataStreams = filteredDataStreams.filter((stream) => {
const isValidStreamType = VALID_STREAM_TYPES.some((streamType) =>
stream.name.startsWith(streamType)
);
return isValidStreamType;
});
const mappedDataStreams = filteredDataStreams.map((dataStream) => {
return { name: dataStream.name };
});