Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { HeaderPage } from '../../../common/components/header_page';
import { KPIsSection } from './kpis/kpis_section';
import { FiltersSection } from './filters/filters_section';
import { HeaderSection } from './header/header_section';
import { SearchBarSection } from './search_bar/search_bar_section';
import { SearchBarSection } from '../common/search_bar/search_bar_section';
import { TableSection } from './table/table_section';
import type { AssigneesIdsSelection } from '../../../common/components/assignees/types';
import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@

import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import {
DATA_VIEW_ERROR_TEST_ID,
DATA_VIEW_LOADING_PROMPT_TEST_ID,
SKELETON_TEST_ID,
Wrapper,
} from './wrapper';
import { Wrapper } from './wrapper';
import { TestProviders } from '../../../common/mock';
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
import { useSourcererDataView } from '../../../sourcerer/containers';
import { useDataView } from '../../../data_view_manager/hooks/use_data_view';
import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/common';
import { createStubDataView } from '@kbn/data-views-plugin/common/data_views/data_view.stub';
import {
DATA_VIEW_ERROR_TEST_ID,
DATA_VIEW_LOADING_PROMPT_TEST_ID,
SKELETON_TEST_ID,
} from '../common/detections_wrapper';

jest.mock('../../../sourcerer/containers');
jest.mock('../../../common/hooks/use_experimental_features');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,130 +5,29 @@
* 2.0.
*/

import React, { memo, useMemo } from 'react';
import {
EuiEmptyPrompt,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiSkeletonLoading,
EuiSkeletonRectangle,
EuiSpacer,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy';
import { HeaderPage } from '../../../common/components/header_page';
import { useSourcererDataView } from '../../../sourcerer/containers';
import React, { memo } from 'react';

import { SourcererScopeName } from '../../../sourcerer/store/model';
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
import { useDataView } from '../../../data_view_manager/hooks/use_data_view';
import { AlertsPageContent } from './content';
import { PAGE_TITLE } from '../../pages/alerts/translations';

export const DATA_VIEW_LOADING_PROMPT_TEST_ID = 'alerts-page-data-view-loading-prompt';
export const DATA_VIEW_ERROR_TEST_ID = 'alerts-page-data-view-error';
export const SKELETON_TEST_ID = 'alerts-page-skeleton';

const DATAVIEW_ERROR = i18n.translate('xpack.securitySolution.alertsPage.dataViewError', {
defaultMessage: 'Unable to retrieve the data view',
});
import { DetectionsWrapper } from '../common/detections_wrapper';

/**
* Retrieves the dataView for the alerts page then renders the alerts page when the dataView is valid.
* Shows a loading skeleton while retrieving.
* Shows an error message if the dataView is invalid.
*/
export const Wrapper = memo(() => {
const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');

const { sourcererDataView: oldSourcererDataViewSpec, loading: oldSourcererDataViewIsLoading } =
useSourcererDataView(SourcererScopeName.detections);
// TODO rename to just dataView and status once we remove the newDataViewPickerEnabled feature flag
const { dataView: experimentalDataView, status: experimentalDataViewStatus } = useDataView(
SourcererScopeName.detections
);

const isLoading: boolean = useMemo(
() =>
newDataViewPickerEnabled
? experimentalDataViewStatus === 'loading' || experimentalDataViewStatus === 'pristine'
: oldSourcererDataViewIsLoading,
[experimentalDataViewStatus, newDataViewPickerEnabled, oldSourcererDataViewIsLoading]
);

// TODO this will not be needed anymore once we remove the newDataViewPickerEnabled feature flag.
// We currently only need the runtimeMappings in the KPIsSection, so we can just pass down the dataView
// and extract the runtimeMappings from it there using experimentalDataView.getRuntimeMappings()
const runtimeMappings: RunTimeMappings = useMemo(
() =>
newDataViewPickerEnabled
? (experimentalDataView?.getRuntimeMappings() as RunTimeMappings) ?? {} // TODO remove the ? as the dataView should never be undefined
: (oldSourcererDataViewSpec?.runtimeFieldMap as RunTimeMappings) ?? {},
[newDataViewPickerEnabled, experimentalDataView, oldSourcererDataViewSpec?.runtimeFieldMap]
);

const isDataViewInvalid: boolean = useMemo(
() =>
newDataViewPickerEnabled
? experimentalDataViewStatus === 'error' ||
(experimentalDataViewStatus === 'ready' && !experimentalDataView.hasMatchedIndices())
: !oldSourcererDataViewSpec ||
!oldSourcererDataViewSpec.id ||
!oldSourcererDataViewSpec.title,
[
experimentalDataView,
experimentalDataViewStatus,
newDataViewPickerEnabled,
oldSourcererDataViewSpec,
]
);

return (
<EuiSkeletonLoading
data-test-subj={DATA_VIEW_LOADING_PROMPT_TEST_ID}
isLoading={isLoading}
loadingContent={
<div data-test-subj={SKELETON_TEST_ID}>
<EuiSkeletonRectangle height={40} width="100%" />
<EuiSpacer />
<HeaderPage title={PAGE_TITLE}>
<EuiFlexGroup gutterSize="m">
<EuiFlexItem>
<EuiSkeletonRectangle height={40} width={110} />
</EuiFlexItem>
<EuiFlexItem>
<EuiSkeletonRectangle height={40} width={110} />
</EuiFlexItem>
</EuiFlexGroup>
</HeaderPage>
<EuiHorizontalRule margin="none" />
<EuiSpacer size="l" />
<EuiSkeletonRectangle height={32} width="100%" />
<EuiSpacer />
<EuiSkeletonRectangle height={375} width="100%" />
<EuiSpacer />
<EuiSkeletonRectangle height={600} width="100%" />
</div>
}
loadedContent={
<>
{isDataViewInvalid ? (
<EuiEmptyPrompt
color="danger"
data-test-subj={DATA_VIEW_ERROR_TEST_ID}
iconType="error"
title={<h2>{DATAVIEW_ERROR}</h2>}
/>
) : (
<AlertsPageContent
dataView={experimentalDataView}
oldSourcererDataViewSpec={oldSourcererDataViewSpec}
runtimeMappings={runtimeMappings}
/>
)}
</>
}
/>
<DetectionsWrapper scope={SourcererScopeName.detections} title={PAGE_TITLE}>
{({ dataView, oldSourcererDataViewSpec, runtimeMappings }) => (
<AlertsPageContent
dataView={dataView}
oldSourcererDataViewSpec={oldSourcererDataViewSpec}
runtimeMappings={runtimeMappings}
/>
)}
</DetectionsWrapper>
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@

import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/common';
import { createStubDataView } from '@kbn/data-views-plugin/common/data_views/data_view.stub';

import { TestProviders } from '../../../common/mock';
import { AttacksPageContent, SECURITY_SOLUTION_PAGE_WRAPPER_TEST_ID } from './content';

const dataView: DataView = createStubDataView({ spec: {} });
const dataViewSpec: DataViewSpec = createStubDataView({ spec: {} }).toSpec();

describe('AttacksPageContent', () => {
it('should render correctly', async () => {
render(
<TestProviders>
<AttacksPageContent />
<AttacksPageContent dataView={dataView} oldSourcererDataViewSpec={dataViewSpec} />
</TestProviders>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import { EuiHorizontalRule, EuiSpacer, EuiWindowEvent } from '@elastic/eui';
import styled from '@emotion/styled';
import { noop } from 'lodash/fp';
import React, { memo, useRef } from 'react';
import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/common';
import { PAGE_TITLE } from '../../pages/attacks/translations';
import { HeaderPage } from '../../../common/components/header_page';
import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper';
import { useGlobalFullScreen } from '../../../common/containers/use_full_screen';
import { Display } from '../../../explore/hosts/pages/display';
import { SearchBarSection } from '../common/search_bar/search_bar_section';

export const CONTENT_TEST_ID = 'attacks-page-content';
export const SECURITY_SOLUTION_PAGE_WRAPPER_TEST_ID = 'attacks-page-security-solution-page-wrapper';
Expand All @@ -27,29 +29,44 @@ const StyledFullHeightContainer = styled.div`
flex: 1 1 auto;
`;

export interface AttacksPageContentProps {
/**
* DataView for the alerts page
*/
dataView: DataView;
// TODO remove when we remove the newDataViewPickerEnabled feature flag
/**
* DataViewSpec used to fetch the alerts data when the newDataViewPickerEnabled feature flag is false
*/
oldSourcererDataViewSpec: DataViewSpec;
}

/**
* Renders the content of the attacks page: search bar, header, filters, KPIs, and table sections.
*/
export const AttacksPageContent = memo(() => {
const containerElement = useRef<HTMLDivElement | null>(null);

const { globalFullScreen } = useGlobalFullScreen();

return (
<StyledFullHeightContainer data-test-subj={CONTENT_TEST_ID} ref={containerElement}>
<EuiWindowEvent event="resize" handler={noop} />
<SecuritySolutionPageWrapper
noPadding={globalFullScreen}
data-test-subj={SECURITY_SOLUTION_PAGE_WRAPPER_TEST_ID}
>
<Display show={!globalFullScreen}>
<HeaderPage title={PAGE_TITLE} />
<EuiHorizontalRule margin="none" />
<EuiSpacer size="l" />
</Display>
</SecuritySolutionPageWrapper>
</StyledFullHeightContainer>
);
});
export const AttacksPageContent = memo(
({ dataView, oldSourcererDataViewSpec }: AttacksPageContentProps) => {
const containerElement = useRef<HTMLDivElement | null>(null);

const { globalFullScreen } = useGlobalFullScreen();

return (
<StyledFullHeightContainer data-test-subj={CONTENT_TEST_ID} ref={containerElement}>
<EuiWindowEvent event="resize" handler={noop} />
<SearchBarSection dataView={dataView} sourcererDataViewSpec={oldSourcererDataViewSpec} />
<SecuritySolutionPageWrapper
noPadding={globalFullScreen}
data-test-subj={SECURITY_SOLUTION_PAGE_WRAPPER_TEST_ID}
>
<Display show={!globalFullScreen}>
<HeaderPage title={PAGE_TITLE} />
<EuiHorizontalRule margin="none" />
<EuiSpacer size="l" />
</Display>
</SecuritySolutionPageWrapper>
</StyledFullHeightContainer>
);
}
);

AttacksPageContent.displayName = 'AttacksPageContent';
Loading