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[ Allow to specify a datastream id in the edit integration page #135321

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/types/models/package_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface PackagePolicyConfigRecordEntry {
export type PackagePolicyConfigRecord = Record<string, PackagePolicyConfigRecordEntry>;

export interface NewPackagePolicyInputStream {
id?: string;
enabled: boolean;
keep_enabled?: boolean;
data_stream: {
Expand All @@ -41,6 +42,7 @@ export interface PackagePolicyInputStream extends NewPackagePolicyInputStream {
}

export interface NewPackagePolicyInput {
id?: string;
type: string;
policy_template?: string;
enabled: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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.
*/

import { useRouteMatch } from 'react-router-dom';

import { createFleetTestRendererMock } from '../../../../../../mock';

import { usePackagePolicyEditorPageUrl } from './datastream_hooks';

const mockedUseRouteMatch = useRouteMatch as jest.MockedFunction<typeof useRouteMatch>;

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useRouteMatch: jest.fn(),
}));

describe('usePackagePolicyEditorPageUrl', () => {
it('should render an integration url if no policy id is provided', () => {
const renderer = createFleetTestRendererMock();
mockedUseRouteMatch.mockReturnValue({
params: { packagePolicyId: 'test-package-policy-id' },
} as any);
const { result } = renderer.renderHook(() => usePackagePolicyEditorPageUrl());
expect(result.current).toBe('/mock/app/integrations/edit-integration/test-package-policy-id');
});

it('should render a fleet url if a policy id is provided', () => {
const renderer = createFleetTestRendererMock();
mockedUseRouteMatch.mockReturnValue({
params: { policyId: 'policy1', packagePolicyId: 'test-package-policy-id' },
} as any);
const { result } = renderer.renderHook(() => usePackagePolicyEditorPageUrl());
expect(result.current).toBe(
'/mock/app/fleet/policies/policy1/edit-integration/test-package-policy-id'
);
});

it('should add datastream Id if provided', () => {
const renderer = createFleetTestRendererMock();
mockedUseRouteMatch.mockReturnValue({
params: { policyId: 'policy1', packagePolicyId: 'test-package-policy-id' },
} as any);
const { result } = renderer.renderHook(() =>
usePackagePolicyEditorPageUrl('test-datastream-id')
);
expect(result.current).toBe(
'/mock/app/fleet/policies/policy1/edit-integration/test-package-policy-id?datastreamId=test-datastream-id'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ import { useRouteMatch } from 'react-router-dom';

import { useLink } from '../../../../hooks';

export function usePackagePolicyEditorPageUrl() {
export function usePackagePolicyEditorPageUrl(dataStreamId?: string) {
const {
params: { packagePolicyId, policyId },
} = useRouteMatch<{ policyId: string; packagePolicyId: string }>();
const { getHref } = useLink();

return packagePolicyId && policyId
? getHref('edit_integration', {
policyId,
packagePolicyId,
})
: getHref('integration_policy_edit', {
packagePolicyId,
});
const baseUrl =
packagePolicyId && policyId
? getHref('edit_integration', {
policyId,
packagePolicyId,
})
: getHref('integration_policy_edit', {
packagePolicyId,
});

return `${baseUrl}${dataStreamId ? `?datastreamId=${encodeURIComponent(dataStreamId)}` : ''}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be nice to add some unit tests on the url building logic

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { usePackagePolicyEditorPageUrl } from './datastream_hooks';

export interface PackagePolicyEditorDatastreamMappingsProps {
packageInfo: PackageInfo;
dataStream: { dataset: string; type: string };
packageInputStream: { id?: string; data_stream: { dataset: string; type: string } };
}

function useComponentTemplates(dataStream: { dataset: string; type: string }) {
Expand All @@ -35,8 +35,9 @@ function useComponentTemplates(dataStream: { dataset: string; type: string }) {

export const PackagePolicyEditorDatastreamMappings: React.FunctionComponent<
PackagePolicyEditorDatastreamMappingsProps
> = ({ dataStream, packageInfo }) => {
const pageUrl = usePackagePolicyEditorPageUrl();
> = ({ packageInputStream, packageInfo }) => {
const dataStream = packageInputStream.data_stream;
const pageUrl = usePackagePolicyEditorPageUrl(packageInputStream.id);

const { application, docLinks } = useStartServices();
const componentTemplateItems = useComponentTemplates(dataStream);
Expand Down Expand Up @@ -99,7 +100,7 @@ export const PackagePolicyEditorDatastreamMappings: React.FunctionComponent<
path: `/data/index_management/edit_component_template/${el.templateName}`,
});

application.navigateToUrl(`${url}?redirect_path=${pageUrl}`);
application.navigateToUrl(`${url}?step=mappings&redirect_path=${pageUrl}`);
},
available: ({ canEdit }) => !!canEdit,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('DatastreamPipelines', () => {

const result = renderer.render(
<PackagePolicyEditorDatastreamPipelines
dataStream={{ dataset: 'test', type: 'logs' }}
packageInputStream={{ data_stream: { dataset: 'test', type: 'logs' } }}
packageInfo={
{
version: '1.0.0',
Expand All @@ -62,7 +62,7 @@ describe('DatastreamPipelines', () => {

const result = renderer.render(
<PackagePolicyEditorDatastreamPipelines
dataStream={{ dataset: 'test', type: 'logs' }}
packageInputStream={{ data_stream: { dataset: 'test', type: 'logs' } }}
packageInfo={
{
version: '1.0.0',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { usePackagePolicyEditorPageUrl } from './datastream_hooks';

export interface PackagePolicyEditorDatastreamPipelinesProps {
packageInfo: PackageInfo;
dataStream: { dataset: string; type: string };
packageInputStream: { id?: string; data_stream: { dataset: string; type: string } };
}

interface PipelineItem {
Expand Down Expand Up @@ -92,11 +92,12 @@ function useDatastreamIngestPipelines(

export const PackagePolicyEditorDatastreamPipelines: React.FunctionComponent<
PackagePolicyEditorDatastreamPipelinesProps
> = ({ dataStream, packageInfo }) => {
> = ({ packageInputStream, packageInfo }) => {
const dataStream = packageInputStream.data_stream;
const { application, share, docLinks } = useStartServices();
const ingestPipelineLocator = share.url.locators.get('INGEST_PIPELINES_APP_LOCATOR');

const pageUrl = usePackagePolicyEditorPageUrl();
const pageUrl = usePackagePolicyEditorPageUrl(packageInputStream.id);

const { pipelines, addPipelineUrl, hasCustom, isLoading } = useDatastreamIngestPipelines(
packageInfo,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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.
*/

import { useMemo } from 'react';
import { useHistory } from 'react-router-dom';

export function useDataStreamId() {
const history = useHistory();

return useMemo(() => {
const searchParams = new URLSearchParams(history.location.search);
return searchParams.get('datastreamId') ?? undefined;
}, [history.location.search]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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.
*/

import { shouldShowStreamsByDefault } from './package_policy_input_panel';

describe('shouldShowStreamsByDefault', () => {
it('should return true if a datastreamId is provided and contained in the input', () => {
const res = shouldShowStreamsByDefault(
{} as any,
[],
{
enabled: true,
streams: [
{
id: 'datastream-id',
},
],
} as any,
'datastream-id'
);
expect(res).toBeTruthy();
});

it('should return false if a datastreamId is provided but not contained in the input', () => {
const res = shouldShowStreamsByDefault(
{} as any,
[],
{
enabled: true,
streams: [
{
id: 'datastream-1',
},
],
} as any,
'datastream-id'
);
expect(res).toBeFalsy();
});

it('should return false if a datastreamId is provided but the input is disabled', () => {
const res = shouldShowStreamsByDefault(
{} as any,
[],
{
enabled: false,
streams: [
{
id: 'datastream-id',
},
],
} as any,
'datastream-id'
);
expect(res).toBeFalsy();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { hasInvalidButRequiredVar, countValidationErrors } from '../../../servic

import { PackagePolicyInputConfig } from './package_policy_input_config';
import { PackagePolicyInputStreamConfig } from './package_policy_input_stream';
import { useDataStreamId } from './hooks';

const ShortenedHorizontalRule = styled(EuiHorizontalRule)`
&&& {
Expand All @@ -40,26 +41,31 @@ const ShortenedHorizontalRule = styled(EuiHorizontalRule)`
}
`;

const shouldShowStreamsByDefault = (
export const shouldShowStreamsByDefault = (
packageInput: RegistryInput,
packageInputStreams: Array<RegistryStream & { data_stream: { dataset: string; type: string } }>,
packagePolicyInput: NewPackagePolicyInput
packagePolicyInput: NewPackagePolicyInput,
defaultDataStreamId?: string
): boolean => {
if (!packagePolicyInput.enabled) {
return false;
}

return (
packagePolicyInput.enabled &&
(hasInvalidButRequiredVar(packageInput.vars, packagePolicyInput.vars) ||
Boolean(
packageInputStreams.find(
(stream) =>
stream.enabled &&
hasInvalidButRequiredVar(
stream.vars,
packagePolicyInput.streams.find(
(pkgStream) => stream.data_stream.dataset === pkgStream.data_stream.dataset
)?.vars
)
hasInvalidButRequiredVar(packageInput.vars, packagePolicyInput.vars) ||
packageInputStreams.some(
(stream) =>
stream.enabled &&
hasInvalidButRequiredVar(
stream.vars,
packagePolicyInput.streams.find(
(pkgStream) => stream.data_stream.dataset === pkgStream.data_stream.dataset
)?.vars
)
))
) ||
packagePolicyInput.streams.some((stream) => {
return defaultDataStreamId && stream.id && stream.id === defaultDataStreamId;
})
);
};

Expand All @@ -83,9 +89,15 @@ export const PackagePolicyInputPanel: React.FunctionComponent<{
inputValidationResults,
forceShowErrors,
}) => {
const defaultDataStreamId = useDataStreamId();
// Showing streams toggle state
const [isShowingStreams, setIsShowingStreams] = useState<boolean>(
shouldShowStreamsByDefault(packageInput, packageInputStreams, packagePolicyInput)
const [isShowingStreams, setIsShowingStreams] = useState<boolean>(() =>
shouldShowStreamsByDefault(
packageInput,
packageInputStreams,
packagePolicyInput,
defaultDataStreamId
)
);

// Errors state
Expand Down
Loading