[ENDPOINT] Hide the Timeline Flyout while on the Management Pages (#69998)
* hide timeline on Management pages * adjust managment page view styles * Added additional tests for validating no timeline button on management views * centralize API Path responses and reuse across some tests * Fix state being reset incorrectly
This commit is contained in:
parent
6808903d57
commit
0bdff15297
|
@ -2,11 +2,11 @@
|
|||
|
||||
exports[`PageView component should display body header custom element 1`] = `
|
||||
.c0.endpoint--isListView {
|
||||
padding: 0 70px 0 24px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.c0.endpoint--isListView .endpoint-header {
|
||||
padding: 24px 0;
|
||||
padding: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ exports[`PageView component should display body header custom element 1`] = `
|
|||
}
|
||||
|
||||
.c0 .endpoint-navTabs {
|
||||
margin-left: 24px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
<PageView
|
||||
|
@ -97,11 +97,11 @@ exports[`PageView component should display body header custom element 1`] = `
|
|||
|
||||
exports[`PageView component should display body header wrapped in EuiTitle 1`] = `
|
||||
.c0.endpoint--isListView {
|
||||
padding: 0 70px 0 24px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.c0.endpoint--isListView .endpoint-header {
|
||||
padding: 24px 0;
|
||||
padding: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ exports[`PageView component should display body header wrapped in EuiTitle 1`] =
|
|||
}
|
||||
|
||||
.c0 .endpoint-navTabs {
|
||||
margin-left: 24px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
<PageView
|
||||
|
@ -195,11 +195,11 @@ exports[`PageView component should display body header wrapped in EuiTitle 1`] =
|
|||
|
||||
exports[`PageView component should display header left and right 1`] = `
|
||||
.c0.endpoint--isListView {
|
||||
padding: 0 70px 0 24px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.c0.endpoint--isListView .endpoint-header {
|
||||
padding: 24px 0;
|
||||
padding: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ exports[`PageView component should display header left and right 1`] = `
|
|||
}
|
||||
|
||||
.c0 .endpoint-navTabs {
|
||||
margin-left: 24px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
<PageView
|
||||
|
@ -308,11 +308,11 @@ exports[`PageView component should display header left and right 1`] = `
|
|||
|
||||
exports[`PageView component should display only body if not header props used 1`] = `
|
||||
.c0.endpoint--isListView {
|
||||
padding: 0 70px 0 24px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.c0.endpoint--isListView .endpoint-header {
|
||||
padding: 24px 0;
|
||||
padding: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
@ -328,7 +328,7 @@ exports[`PageView component should display only body if not header props used 1`
|
|||
}
|
||||
|
||||
.c0 .endpoint-navTabs {
|
||||
margin-left: 24px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
<PageView
|
||||
|
@ -380,11 +380,11 @@ exports[`PageView component should display only body if not header props used 1`
|
|||
|
||||
exports[`PageView component should display only header left 1`] = `
|
||||
.c0.endpoint--isListView {
|
||||
padding: 0 70px 0 24px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.c0.endpoint--isListView .endpoint-header {
|
||||
padding: 24px 0;
|
||||
padding: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
@ -400,7 +400,7 @@ exports[`PageView component should display only header left 1`] = `
|
|||
}
|
||||
|
||||
.c0 .endpoint-navTabs {
|
||||
margin-left: 24px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
<PageView
|
||||
|
@ -482,11 +482,11 @@ exports[`PageView component should display only header left 1`] = `
|
|||
|
||||
exports[`PageView component should display only header right but include an empty left side 1`] = `
|
||||
.c0.endpoint--isListView {
|
||||
padding: 0 70px 0 24px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.c0.endpoint--isListView .endpoint-header {
|
||||
padding: 24px 0;
|
||||
padding: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
@ -502,7 +502,7 @@ exports[`PageView component should display only header right but include an empt
|
|||
}
|
||||
|
||||
.c0 .endpoint-navTabs {
|
||||
margin-left: 24px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
<PageView
|
||||
|
@ -581,11 +581,11 @@ exports[`PageView component should display only header right but include an empt
|
|||
|
||||
exports[`PageView component should pass through EuiPage props 1`] = `
|
||||
.c0.endpoint--isListView {
|
||||
padding: 0 70px 0 24px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.c0.endpoint--isListView .endpoint-header {
|
||||
padding: 24px 0;
|
||||
padding: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
@ -601,7 +601,7 @@ exports[`PageView component should pass through EuiPage props 1`] = `
|
|||
}
|
||||
|
||||
.c0 .endpoint-navTabs {
|
||||
margin-left: 24px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
<PageView
|
||||
|
@ -670,11 +670,11 @@ exports[`PageView component should pass through EuiPage props 1`] = `
|
|||
|
||||
exports[`PageView component should use custom element for header left and not wrap in EuiTitle 1`] = `
|
||||
.c0.endpoint--isListView {
|
||||
padding: 0 70px 0 24px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.c0.endpoint--isListView .endpoint-header {
|
||||
padding: 24px 0;
|
||||
padding: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
@ -690,7 +690,7 @@ exports[`PageView component should use custom element for header left and not wr
|
|||
}
|
||||
|
||||
.c0 .endpoint-navTabs {
|
||||
margin-left: 24px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
<PageView
|
||||
|
|
|
@ -21,14 +21,13 @@ import {
|
|||
import React, { memo, MouseEventHandler, ReactNode, useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { EuiTabProps } from '@elastic/eui/src/components/tabs/tab';
|
||||
import { gutterTimeline } from '../../lib/helpers';
|
||||
|
||||
const StyledEuiPage = styled(EuiPage)`
|
||||
&.endpoint--isListView {
|
||||
padding: 0 ${gutterTimeline} 0 ${(props) => props.theme.eui.euiSizeL};
|
||||
padding: 0 ${(props) => props.theme.eui.euiSizeL};
|
||||
|
||||
.endpoint-header {
|
||||
padding: ${(props) => props.theme.eui.euiSizeL} 0;
|
||||
padding: ${(props) => props.theme.eui.euiSizeL};
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.endpoint-page-content {
|
||||
|
@ -44,7 +43,7 @@ const StyledEuiPage = styled(EuiPage)`
|
|||
}
|
||||
}
|
||||
.endpoint-navTabs {
|
||||
margin-left: ${(props) => props.theme.eui.euiSizeL};
|
||||
margin-left: ${(props) => props.theme.eui.euiSizeM};
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { useRouteSpy } from '../route/use_route_spy';
|
||||
|
||||
const hideTimelineForRoutes = [`/cases/configure`];
|
||||
const hideTimelineForRoutes = [`/cases/configure`, '/management'];
|
||||
|
||||
export const useShowTimeline = () => {
|
||||
const [{ pageName, pathName }] = useRouteSpy();
|
||||
|
|
|
@ -34,6 +34,12 @@ describe('when on the hosts page', () => {
|
|||
render = () => mockedContext.render(<HostList />);
|
||||
});
|
||||
|
||||
it('should NOT display timeline', async () => {
|
||||
const renderResult = render();
|
||||
const timelineFlyout = await renderResult.queryByTestId('flyoutOverlay');
|
||||
expect(timelineFlyout).toBeNull();
|
||||
});
|
||||
|
||||
it('should show a table', async () => {
|
||||
const renderResult = render();
|
||||
const table = await renderResult.findByTestId('hostListTable');
|
||||
|
|
|
@ -78,13 +78,20 @@ export const policyDetailsReducer: ImmutableReducer<PolicyDetailsState, AppActio
|
|||
const isCurrentlyOnDetailsPage = isOnPolicyDetailsPage(newState);
|
||||
const wasPreviouslyOnDetailsPage = isOnPolicyDetailsPage(state);
|
||||
|
||||
// Did user just enter the Detail page? if so, then set the loading indicator and return new state
|
||||
if (isCurrentlyOnDetailsPage && !wasPreviouslyOnDetailsPage) {
|
||||
if (isCurrentlyOnDetailsPage) {
|
||||
// Did user just enter the Detail page? if so, then
|
||||
// set the loading indicator and return new state
|
||||
if (!wasPreviouslyOnDetailsPage) {
|
||||
return {
|
||||
...newState,
|
||||
isLoading: true,
|
||||
};
|
||||
}
|
||||
// Else, user was already on the details page,
|
||||
// just return the updated state with new location data
|
||||
return newState;
|
||||
}
|
||||
|
||||
return {
|
||||
...initialPolicyDetailsState(),
|
||||
location: action.payload,
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
INGEST_API_EPM_PACKAGES,
|
||||
sendGetDatasource,
|
||||
sendGetEndpointSecurityPackage,
|
||||
sendGetEndpointSpecificDatasources,
|
||||
} from './ingest';
|
||||
import { httpServiceMock } from '../../../../../../../../../../src/core/public/mocks';
|
||||
import { DATASOURCE_SAVED_OBJECT_TYPE } from '../../../../../../../../ingest_manager/common';
|
||||
import { apiPathMockResponseProviders } from '../test_mock_utils';
|
||||
|
||||
describe('ingest service', () => {
|
||||
let http: ReturnType<typeof httpServiceMock.createStartContract>;
|
||||
|
@ -59,76 +61,7 @@ describe('ingest service', () => {
|
|||
|
||||
describe('sendGetEndpointSecurityPackage()', () => {
|
||||
it('should query EPM with category=security', async () => {
|
||||
http.get.mockResolvedValue({
|
||||
response: [
|
||||
{
|
||||
name: 'endpoint',
|
||||
title: 'Elastic Endpoint',
|
||||
version: '0.5.0',
|
||||
description: 'This is the Elastic Endpoint package.',
|
||||
type: 'solution',
|
||||
download: '/epr/endpoint/endpoint-0.5.0.tar.gz',
|
||||
path: '/package/endpoint/0.5.0',
|
||||
icons: [
|
||||
{
|
||||
src: '/package/endpoint/0.5.0/img/logo-endpoint-64-color.svg',
|
||||
size: '16x16',
|
||||
type: 'image/svg+xml',
|
||||
},
|
||||
],
|
||||
status: 'installed',
|
||||
savedObject: {
|
||||
type: 'epm-packages',
|
||||
id: 'endpoint',
|
||||
attributes: {
|
||||
installed: [
|
||||
{ id: '826759f0-7074-11ea-9bc8-6b38f4d29a16', type: 'dashboard' },
|
||||
{ id: '1cfceda0-728b-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
|
||||
{ id: '1e525190-7074-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
|
||||
{ id: '55387750-729c-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
|
||||
{ id: '92b1edc0-706a-11ea-9bc8-6b38f4d29a16', type: 'visualization' },
|
||||
{ id: 'a3a3bd10-706b-11ea-9bc8-6b38f4d29a16', type: 'map' },
|
||||
{ id: 'logs-endpoint.alerts', type: 'index-template' },
|
||||
{ id: 'events-endpoint', type: 'index-template' },
|
||||
{ id: 'logs-endpoint.events.file', type: 'index-template' },
|
||||
{ id: 'logs-endpoint.events.library', type: 'index-template' },
|
||||
{ id: 'metrics-endpoint.metadata', type: 'index-template' },
|
||||
{ id: 'metrics-endpoint.metadata_mirror', type: 'index-template' },
|
||||
{ id: 'logs-endpoint.events.network', type: 'index-template' },
|
||||
{ id: 'metrics-endpoint.policy', type: 'index-template' },
|
||||
{ id: 'logs-endpoint.events.process', type: 'index-template' },
|
||||
{ id: 'logs-endpoint.events.registry', type: 'index-template' },
|
||||
{ id: 'logs-endpoint.events.security', type: 'index-template' },
|
||||
{ id: 'metrics-endpoint.telemetry', type: 'index-template' },
|
||||
],
|
||||
es_index_patterns: {
|
||||
alerts: 'logs-endpoint.alerts-*',
|
||||
events: 'events-endpoint-*',
|
||||
file: 'logs-endpoint.events.file-*',
|
||||
library: 'logs-endpoint.events.library-*',
|
||||
metadata: 'metrics-endpoint.metadata-*',
|
||||
metadata_mirror: 'metrics-endpoint.metadata_mirror-*',
|
||||
network: 'logs-endpoint.events.network-*',
|
||||
policy: 'metrics-endpoint.policy-*',
|
||||
process: 'logs-endpoint.events.process-*',
|
||||
registry: 'logs-endpoint.events.registry-*',
|
||||
security: 'logs-endpoint.events.security-*',
|
||||
telemetry: 'metrics-endpoint.telemetry-*',
|
||||
},
|
||||
name: 'endpoint',
|
||||
version: '0.5.0',
|
||||
internal: false,
|
||||
removable: false,
|
||||
},
|
||||
references: [],
|
||||
updated_at: '2020-06-24T14:41:23.098Z',
|
||||
version: 'Wzc0LDFd',
|
||||
score: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
success: true,
|
||||
});
|
||||
http.get.mockReturnValue(apiPathMockResponseProviders[INGEST_API_EPM_PACKAGES]());
|
||||
await sendGetEndpointSecurityPackage(http);
|
||||
expect(http.get).toHaveBeenCalledWith('/api/ingest_manager/epm/packages', {
|
||||
query: { category: 'security' },
|
||||
|
|
|
@ -17,29 +17,11 @@ import {
|
|||
const generator = new EndpointDocGenerator('policy-list');
|
||||
|
||||
/**
|
||||
* It sets the mock implementation on the necessary http methods to support the policy list view
|
||||
* @param mockedHttpService
|
||||
* @param responseItems
|
||||
* a list of API paths response mock providers
|
||||
*/
|
||||
export const setPolicyListApiMockImplementation = (
|
||||
mockedHttpService: jest.Mocked<HttpStart>,
|
||||
responseItems: GetPolicyListResponse['items'] = [generator.generatePolicyDatasource()]
|
||||
): void => {
|
||||
mockedHttpService.get.mockImplementation((...args) => {
|
||||
const [path] = args;
|
||||
if (typeof path === 'string') {
|
||||
if (path === INGEST_API_DATASOURCES) {
|
||||
return Promise.resolve<GetPolicyListResponse>({
|
||||
items: responseItems,
|
||||
total: 10,
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
success: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (path === INGEST_API_EPM_PACKAGES) {
|
||||
return Promise.resolve<GetPackagesResponse>({
|
||||
export const apiPathMockResponseProviders = {
|
||||
[INGEST_API_EPM_PACKAGES]: () =>
|
||||
Promise.resolve<GetPackagesResponse>({
|
||||
response: [
|
||||
{
|
||||
name: 'endpoint',
|
||||
|
@ -107,8 +89,34 @@ export const setPolicyListApiMockImplementation = (
|
|||
},
|
||||
],
|
||||
success: true,
|
||||
}),
|
||||
};
|
||||
|
||||
/**
|
||||
* It sets the mock implementation on the necessary http methods to support the policy list view
|
||||
* @param mockedHttpService
|
||||
* @param responseItems
|
||||
*/
|
||||
export const setPolicyListApiMockImplementation = (
|
||||
mockedHttpService: jest.Mocked<HttpStart>,
|
||||
responseItems: GetPolicyListResponse['items'] = [generator.generatePolicyDatasource()]
|
||||
): void => {
|
||||
mockedHttpService.get.mockImplementation((...args) => {
|
||||
const [path] = args;
|
||||
if (typeof path === 'string') {
|
||||
if (path === INGEST_API_DATASOURCES) {
|
||||
return Promise.resolve<GetPolicyListResponse>({
|
||||
items: responseItems,
|
||||
total: 10,
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
success: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (apiPathMockResponseProviders[path]) {
|
||||
return apiPathMockResponseProviders[path]();
|
||||
}
|
||||
}
|
||||
return Promise.reject(new Error(`MOCK: unknown policy list api: ${path}`));
|
||||
});
|
||||
|
|
|
@ -9,8 +9,9 @@ import { mount } from 'enzyme';
|
|||
|
||||
import { PolicyDetails } from './policy_details';
|
||||
import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data';
|
||||
import { createAppRootMockRenderer } from '../../../../common/mock/endpoint';
|
||||
import { AppContextTestRender, createAppRootMockRenderer } from '../../../../common/mock/endpoint';
|
||||
import { getPolicyDetailPath, getPoliciesPath } from '../../../common/routing';
|
||||
import { apiPathMockResponseProviders } from '../store/policy_list/test_mock_utils';
|
||||
|
||||
describe('Policy Details', () => {
|
||||
type FindReactWrapperResponse = ReturnType<ReturnType<typeof render>['find']>;
|
||||
|
@ -19,29 +20,50 @@ describe('Policy Details', () => {
|
|||
const policyListPathUrl = getPoliciesPath();
|
||||
const sleep = (ms = 100) => new Promise((wakeup) => setTimeout(wakeup, ms));
|
||||
const generator = new EndpointDocGenerator();
|
||||
const { history, AppWrapper, coreStart } = createAppRootMockRenderer();
|
||||
const http = coreStart.http;
|
||||
const render = (ui: Parameters<typeof mount>[0]) => mount(ui, { wrappingComponent: AppWrapper });
|
||||
let history: AppContextTestRender['history'];
|
||||
let coreStart: AppContextTestRender['coreStart'];
|
||||
let middlewareSpy: AppContextTestRender['middlewareSpy'];
|
||||
let http: typeof coreStart.http;
|
||||
let render: (ui: Parameters<typeof mount>[0]) => ReturnType<typeof mount>;
|
||||
let policyDatasource: ReturnType<typeof generator.generatePolicyDatasource>;
|
||||
let policyView: ReturnType<typeof render>;
|
||||
|
||||
beforeEach(() => jest.clearAllMocks());
|
||||
beforeEach(() => {
|
||||
const appContextMockRenderer = createAppRootMockRenderer();
|
||||
const AppWrapper = appContextMockRenderer.AppWrapper;
|
||||
|
||||
({ history, coreStart, middlewareSpy } = appContextMockRenderer);
|
||||
render = (ui) => mount(ui, { wrappingComponent: AppWrapper });
|
||||
http = coreStart.http;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (policyView) {
|
||||
policyView.unmount();
|
||||
}
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when displayed with invalid id', () => {
|
||||
let releaseApiFailure: () => void;
|
||||
beforeEach(() => {
|
||||
http.get.mockReturnValue(Promise.reject(new Error('policy not found')));
|
||||
http.get.mockImplementationOnce(async () => {
|
||||
await new Promise((_, reject) => {
|
||||
releaseApiFailure = reject.bind(null, new Error('policy not found'));
|
||||
});
|
||||
});
|
||||
history.push(policyDetailsPathUrl);
|
||||
policyView = render(<PolicyDetails />);
|
||||
});
|
||||
|
||||
it('should show loader followed by error message', () => {
|
||||
it('should NOT display timeline', async () => {
|
||||
expect(policyView.find('flyoutOverlay')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should show loader followed by error message', async () => {
|
||||
expect(policyView.find('EuiLoadingSpinner').length).toBe(1);
|
||||
releaseApiFailure();
|
||||
await middlewareSpy.waitForAction('serverFailedToReturnPolicyDetailsData');
|
||||
policyView.update();
|
||||
const callout = policyView.find('EuiCallOut');
|
||||
expect(callout).toHaveLength(1);
|
||||
|
@ -76,14 +98,25 @@ describe('Policy Details', () => {
|
|||
success: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Get package data
|
||||
// Used in tests that route back to the list
|
||||
if (apiPathMockResponseProviders[path]) {
|
||||
asyncActions = asyncActions.then(async () => sleep());
|
||||
return apiPathMockResponseProviders[path]();
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(new Error('unknown API call!'));
|
||||
return Promise.reject(new Error(`unknown API call (not MOCKED): ${path}`));
|
||||
});
|
||||
history.push(policyDetailsPathUrl);
|
||||
policyView = render(<PolicyDetails />);
|
||||
});
|
||||
|
||||
it('should NOT display timeline', async () => {
|
||||
expect(policyView.find('flyoutOverlay')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should display back to list button and policy title', () => {
|
||||
policyView.update();
|
||||
const pageHeaderLeft = policyView.find(
|
||||
|
|
|
@ -23,6 +23,12 @@ describe('when on the policies page', () => {
|
|||
render = () => mockedContext.render(<PolicyList />);
|
||||
});
|
||||
|
||||
it('should NOT display timeline', async () => {
|
||||
const renderResult = render();
|
||||
const timelineFlyout = await renderResult.queryByTestId('flyoutOverlay');
|
||||
expect(timelineFlyout).toBeNull();
|
||||
});
|
||||
|
||||
it('should show the empty state', async () => {
|
||||
const renderResult = render();
|
||||
const table = await renderResult.findByTestId('emptyPolicyTable');
|
||||
|
|
Loading…
Reference in a new issue