Skip to content

Commit

Permalink
[Security Solution] fix security empty overview links (#101536) (#101832
Browse files Browse the repository at this point in the history
)

Co-authored-by: Joey F. Poon <joey.poon@elastic.co>
  • Loading branch information
kibanamachine and joeypoon authored Jun 9, 2021
1 parent 253da63 commit 1c2d803
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
* 2.0.
*/

import { HttpStart } from 'kibana/public';
import { Dispatch } from 'redux';
import { CoreStart, HttpStart } from 'kibana/public';
import {
EndpointAction,
HostInfo,
HostIsolationRequestBody,
HostIsolationResponse,
HostResultList,
Immutable,
ImmutableObject,
} from '../../../../../common/endpoint/types';
import { GetPolicyListResponse } from '../../policy/types';
import { ImmutableMiddlewareAPI, ImmutableMiddlewareFactory } from '../../../../common/store';
Expand Down Expand Up @@ -54,6 +56,7 @@ import {
import { isolateHost, unIsolateHost } from '../../../../common/lib/host_isolation';
import { AppAction } from '../../../../common/store/actions';
import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables';
import { ServerReturnedEndpointPackageInfo } from './action';

type EndpointPageStore = ImmutableMiddlewareAPI<EndpointState, AppAction>;

Expand All @@ -78,26 +81,14 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory<EndpointState

const { getState, dispatch } = store;

await getEndpointPackageInfo(getState(), dispatch, coreStart);

// Endpoint list
if (
(action.type === 'userChangedUrl' || action.type === 'appRequestedEndpointList') &&
isOnEndpointPage(getState()) &&
hasSelectedEndpoint(getState()) !== true
) {
if (!endpointPackageInfo(getState())) {
try {
const packageInfo = await sendGetEndpointSecurityPackage(coreStart.http);
dispatch({
type: 'serverReturnedEndpointPackageInfo',
payload: packageInfo,
});
} catch (error) {
// Ignore Errors, since this should not hinder the user's ability to use the UI
// eslint-disable-next-line no-console
console.error(error);
}
}

const { page_index: pageIndex, page_size: pageSize } = uiQueryParams(getState());
let endpointResponse;

Expand Down Expand Up @@ -523,3 +514,23 @@ const handleIsolateEndpointHost = async (
});
}
};

async function getEndpointPackageInfo(
state: ImmutableObject<EndpointState>,
dispatch: Dispatch<ServerReturnedEndpointPackageInfo>,
coreStart: CoreStart
) {
if (endpointPackageInfo(state)) return;

try {
const packageInfo = await sendGetEndpointSecurityPackage(coreStart.http);
dispatch({
type: 'serverReturnedEndpointPackageInfo',
payload: packageInfo,
});
} catch (error) {
// Ignore Errors, since this should not hinder the user's ability to use the UI
// eslint-disable-next-line no-console
console.error(error);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('Policy Details', () => {
describe('when displayed with invalid id', () => {
let releaseApiFailure: () => void;
beforeEach(() => {
http.get.mockImplementationOnce(async () => {
http.get.mockImplementation(async () => {
await new Promise((_, reject) => {
releaseApiFailure = reject.bind(null, new Error('policy not found'));
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -633,18 +633,21 @@ describe('When on the Trusted Apps Page', () => {
});
});

it('should close the flyout', async () => {
it('should close the flyout', () => {
expect(renderResult.queryByTestId('addTrustedAppFlyout')).toBeNull();
});

it('should show success toast notification', async () => {
it('should show success toast notification', () => {
expect(coreStart.notifications.toasts.addSuccess.mock.calls[0][0]).toEqual(
'"one app" has been added to the Trusted Applications list.'
);
});

it('should trigger the List to reload', async () => {
expect(coreStart.http.get.mock.calls[0][0]).toEqual(TRUSTED_APPS_LIST_API);
it('should trigger the List to reload', () => {
const isCalled = coreStart.http.get.mock.calls.some(
(call) => call[0].toString() === TRUSTED_APPS_LIST_API
);
expect(isCalled).toEqual(true);
});
});

Expand All @@ -666,18 +669,18 @@ describe('When on the Trusted Apps Page', () => {
});
});

it('should continue to show the flyout', async () => {
it('should continue to show the flyout', () => {
expect(renderResult.getByTestId('addTrustedAppFlyout')).not.toBeNull();
});

it('should enable the Cancel Button', async () => {
it('should enable the Cancel Button', () => {
expect(
(renderResult.getByTestId('addTrustedAppFlyout-cancelButton') as HTMLButtonElement)
.disabled
).toBe(false);
});

it('should show the dialog close button', async () => {
it('should show the dialog close button', () => {
expect(renderResult.getByTestId('euiFlyoutCloseButton')).not.toBeNull();
});

Expand All @@ -688,7 +691,7 @@ describe('When on the Trusted Apps Page', () => {
).toBe(false);
});

it('should show API errors in the form', async () => {
it('should show API errors in the form', () => {
expect(renderResult.container.querySelector('.euiForm__errors')).not.toBeNull();
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ import React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
import { OverviewEmpty } from '.';
import { useIngestEnabledCheck } from '../../../common/hooks/endpoint/ingest_enabled';

const endpointPackageVersion = '0.19.1';

jest.mock('../../../common/lib/kibana');
jest.mock('../../../management/pages/endpoint_hosts/view/hooks', () => ({
useIngestUrl: jest
.fn()
.mockReturnValue({ appId: 'ingestAppId', appPath: 'ingestPath', url: 'ingestUrl' }),
useEndpointSelector: jest.fn().mockReturnValue({ endpointPackageVersion }),
}));

jest.mock('../../../common/hooks/endpoint/ingest_enabled', () => ({
Expand Down Expand Up @@ -57,7 +61,7 @@ describe('OverviewEmpty', () => {
fill: false,
label: 'Add Endpoint Security',
onClick: undefined,
url: '/app/home#/tutorial_directory/security',
url: `#/integrations/endpoint-${endpointPackageVersion}/add-integration`,
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,41 @@

import React, { useMemo } from 'react';
import { omit } from 'lodash/fp';
import { createStructuredSelector } from 'reselect';

import { FormattedMessage } from '@kbn/i18n/react';
import { EuiLink } from '@elastic/eui';
import * as i18nCommon from '../../../common/translations';
import { EmptyPage, EmptyPageActionsProps } from '../../../common/components/empty_page';
import { useKibana } from '../../../common/lib/kibana';
import { ADD_DATA_PATH } from '../../../../common/constants';
import { useIngestUrl } from '../../../management/pages/endpoint_hosts/view/hooks';
import {
useEndpointSelector,
useIngestUrl,
} from '../../../management/pages/endpoint_hosts/view/hooks';
import { useNavigateToAppEventHandler } from '../../../common/hooks/endpoint/use_navigate_to_app_event_handler';
import { useIngestEnabledCheck } from '../../../common/hooks/endpoint/ingest_enabled';
import { CreateStructuredSelector } from '../../../common/store';
import { endpointPackageVersion as useEndpointPackageVersion } from '../../../management/pages/endpoint_hosts/store/selectors';

const OverviewEmptyComponent: React.FC = () => {
const { http, docLinks } = useKibana().services;
const basePath = http.basePath.get();
const { appId: ingestAppId, appPath: ingestPath, url: ingestUrl } = useIngestUrl(
'integrations?category=security'
);
const handleOnClick = useNavigateToAppEventHandler(ingestAppId, { path: ingestPath });
const selector = (createStructuredSelector as CreateStructuredSelector)({
endpointPackageVersion: useEndpointPackageVersion,
});
const { endpointPackageVersion } = useEndpointSelector(selector);
const { url: ingestUrl } = useIngestUrl('');

const endpointIntegrationUrlPath = endpointPackageVersion
? `/endpoint-${endpointPackageVersion}/add-integration`
: '';
const endpointIntegrationUrl = `#/integrations${endpointIntegrationUrlPath}`;
const handleEndpointClick = useNavigateToAppEventHandler('fleet', {
path: endpointIntegrationUrl,
});
const { allEnabled: isIngestEnabled } = useIngestEnabledCheck();

const emptyPageActions: EmptyPageActionsProps = useMemo(
() => ({
elasticAgent: {
Expand All @@ -42,13 +58,13 @@ const OverviewEmptyComponent: React.FC = () => {
},
endpoint: {
label: i18nCommon.EMPTY_ACTION_ENDPOINT,
url: `${basePath}${ADD_DATA_PATH}`,
url: endpointIntegrationUrl,
description: i18nCommon.EMPTY_ACTION_ENDPOINT_DESCRIPTION,
onClick: handleOnClick,
onClick: handleEndpointClick,
fill: false,
},
}),
[basePath, ingestUrl, handleOnClick]
[basePath, ingestUrl, endpointIntegrationUrl, handleEndpointClick]
);

const emptyPageIngestDisabledActions = useMemo(
Expand Down

0 comments on commit 1c2d803

Please sign in to comment.