[Security Solution] add timeline id to context (#111435)

* add timeline context

* remove an unused file
This commit is contained in:
Angela Chuang 2021-09-09 12:44:52 +01:00 committed by GitHub
parent c1697a1163
commit dd69697517
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 165 additions and 198 deletions

View file

@ -1,37 +0,0 @@
/*
* 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 React, { useEffect, useState } from 'react';
import { SELECTOR_TIMELINE_GLOBAL_CONTAINER } from '../../../timelines/components/timeline/styles';
export const useGetTimelineId = function (
elem: React.MutableRefObject<Element | null>,
getTimelineId: boolean = false
) {
const [timelineId, setTimelineId] = useState<string | null>(null);
useEffect(() => {
let startElem: Element | (Node & ParentNode) | null = elem.current;
if (startElem != null && getTimelineId) {
for (; startElem && startElem !== document; startElem = startElem.parentNode) {
const myElem: Element = startElem as Element;
if (
myElem != null &&
myElem.classList != null &&
myElem.classList.contains(SELECTOR_TIMELINE_GLOBAL_CONTAINER) &&
myElem.hasAttribute('data-timeline-id')
) {
setTimelineId(myElem.getAttribute('data-timeline-id'));
break;
}
}
}
}, [elem, getTimelineId]);
return timelineId;
};

View file

@ -5,13 +5,13 @@
* 2.0.
*/
import React, { useCallback, useState, useRef } from 'react';
import React, { useCallback, useState, useContext } from 'react';
import { HoverActions } from '../../hover_actions';
import { useActionCellDataProvider } from './use_action_cell_data_provider';
import { EventFieldsData, FieldsData } from '../types';
import { useGetTimelineId } from '../../drag_and_drop/use_get_timeline_id_from_dom';
import { ColumnHeaderOptions } from '../../../../../common/types/timeline';
import { BrowserField } from '../../../containers/source';
import { TimelineContext } from '../../../../../../timelines/public';
interface Props {
contextId: string;
@ -52,12 +52,9 @@ export const ActionCell: React.FC<Props> = React.memo(
values,
});
const draggableRef = useRef<HTMLDivElement | null>(null);
const [showTopN, setShowTopN] = useState<boolean>(false);
const [goGetTimelineId, setGoGetTimelineId] = useState(false);
const timelineIdFind = useGetTimelineId(draggableRef, goGetTimelineId);
const { timelineId: timelineIdFind } = useContext(TimelineContext);
const [hoverActionsOwnFocus] = useState<boolean>(false);
const toggleTopN = useCallback(() => {
setShowTopN((prevShowTopN) => {
const newShowTopN = !prevShowTopN;
@ -76,7 +73,6 @@ export const ActionCell: React.FC<Props> = React.memo(
dataProvider={actionCellConfig?.dataProvider}
enableOverflowButton={true}
field={data.field}
goGetTimelineId={setGoGetTimelineId}
isObjectArray={data.isObjectArray}
onFilterAdded={onFilterAdded}
ownFocus={hoverActionsOwnFocus}

View file

@ -52,6 +52,7 @@ import { SELECTOR_TIMELINE_GLOBAL_CONTAINER } from '../../../timelines/component
import { timelineSelectors, timelineActions } from '../../../timelines/store/timeline';
import { useDeepEqualSelector } from '../../hooks/use_selector';
import { defaultControlColumn } from '../../../timelines/components/timeline/body/control_columns';
import { TimelineContext } from '../../../../../timelines/public';
export const EVENTS_VIEWER_HEADER_HEIGHT = 90; // px
const UTILITY_BAR_HEIGHT = 19; // px
@ -287,7 +288,7 @@ const EventsViewerComponent: React.FC<Props> = ({
const leadingControlColumns: ControlColumnProps[] = [defaultControlColumn];
const trailingControlColumns: ControlColumnProps[] = [];
const timelineContext = useMemo(() => ({ timelineId: id }), [id]);
return (
<StyledEuiPanel
data-test-subj="events-viewer-panel"
@ -309,57 +310,59 @@ const EventsViewerComponent: React.FC<Props> = ({
{utilityBar && !resolverIsShowing(graphEventId) && (
<UtilityBar>{utilityBar?.(refetch, totalCountMinusDeleted)}</UtilityBar>
)}
<EventsContainerLoading
data-timeline-id={id}
data-test-subj={`events-container-loading-${loading}`}
>
<TimelineRefetch
id={id}
inputId="global"
inspect={inspect}
loading={loading}
refetch={refetch}
/>
<TimelineContext.Provider value={timelineContext}>
<EventsContainerLoading
data-timeline-id={id}
data-test-subj={`events-container-loading-${loading}`}
>
<TimelineRefetch
id={id}
inputId="global"
inspect={inspect}
loading={loading}
refetch={refetch}
/>
{graphEventId && <GraphOverlay timelineId={id} />}
<FullWidthFlexGroup $visible={!graphEventId} gutterSize="none">
<ScrollableFlexItem grow={1}>
<StatefulBody
activePage={pageInfo.activePage}
browserFields={browserFields}
data={nonDeletedEvents}
id={id}
isEventViewer={true}
onRuleChange={onRuleChange}
refetch={refetch}
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
sort={sort}
tabType={TimelineTabs.query}
totalPages={calculateTotalPages({
itemsCount: totalCountMinusDeleted,
itemsPerPage,
})}
leadingControlColumns={leadingControlColumns}
trailingControlColumns={trailingControlColumns}
/>
<Footer
activePage={pageInfo.activePage}
data-test-subj="events-viewer-footer"
updatedAt={updatedAt}
height={footerHeight}
id={id}
isLive={isLive}
isLoading={loading}
itemsCount={nonDeletedEvents.length}
itemsPerPage={itemsPerPage}
itemsPerPageOptions={itemsPerPageOptions}
onChangePage={loadPage}
totalCount={totalCountMinusDeleted}
/>
</ScrollableFlexItem>
</FullWidthFlexGroup>
</EventsContainerLoading>
{graphEventId && <GraphOverlay timelineId={id} />}
<FullWidthFlexGroup $visible={!graphEventId} gutterSize="none">
<ScrollableFlexItem grow={1}>
<StatefulBody
activePage={pageInfo.activePage}
browserFields={browserFields}
data={nonDeletedEvents}
id={id}
isEventViewer={true}
onRuleChange={onRuleChange}
refetch={refetch}
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
sort={sort}
tabType={TimelineTabs.query}
totalPages={calculateTotalPages({
itemsCount: totalCountMinusDeleted,
itemsPerPage,
})}
leadingControlColumns={leadingControlColumns}
trailingControlColumns={trailingControlColumns}
/>
<Footer
activePage={pageInfo.activePage}
data-test-subj="events-viewer-footer"
updatedAt={updatedAt}
height={footerHeight}
id={id}
isLive={isLive}
isLoading={loading}
itemsCount={nonDeletedEvents.length}
itemsPerPage={itemsPerPage}
itemsPerPageOptions={itemsPerPageOptions}
onChangePage={loadPage}
totalCount={totalCountMinusDeleted}
/>
</ScrollableFlexItem>
</FullWidthFlexGroup>
</EventsContainerLoading>
</TimelineContext.Provider>
</>
</EventDetailsWidthProvider>
) : null}

View file

@ -5,14 +5,14 @@
* 2.0.
*/
import React, { useCallback, useMemo, useState, useRef } from 'react';
import React, { useCallback, useMemo, useState, useRef, useContext } from 'react';
import { DraggableProvided, DraggableStateSnapshot } from 'react-beautiful-dnd';
import { HoverActions } from '.';
import { TimelineContext } from '../../../../../timelines/public';
import { DataProvider } from '../../../../common/types';
import { ProviderContentWrapper } from '../drag_and_drop/draggable_wrapper';
import { getDraggableId } from '../drag_and_drop/helpers';
import { useGetTimelineId } from '../drag_and_drop/use_get_timeline_id_from_dom';
const draggableContainsLinks = (draggableElement: HTMLDivElement | null) => {
const links = draggableElement?.querySelectorAll('.euiLink') ?? [];
@ -50,8 +50,7 @@ export const useHoverActions = ({
const [closePopOverTrigger, setClosePopOverTrigger] = useState(false);
const [showTopN, setShowTopN] = useState<boolean>(false);
const [hoverActionsOwnFocus, setHoverActionsOwnFocus] = useState<boolean>(false);
const [goGetTimelineId, setGoGetTimelineId] = useState(false);
const timelineIdFind = useGetTimelineId(containerRef, goGetTimelineId);
const { timelineId: timelineIdFind } = useContext(TimelineContext);
const handleClosePopOverTrigger = useCallback(() => {
setClosePopOverTrigger((prevClosePopOverTrigger) => !prevClosePopOverTrigger);
@ -105,7 +104,6 @@ export const useHoverActions = ({
field={dataProvider.queryMatch.field}
hideTopN={hideTopN}
isObjectArray={false}
goGetTimelineId={setGoGetTimelineId}
onFilterAdded={onFilterAdded}
ownFocus={hoverActionsOwnFocus}
showOwnFocus={false}

View file

@ -6,14 +6,14 @@
*/
import { EuiHighlight, EuiText } from '@elastic/eui';
import React, { useCallback, useState, useMemo, useRef } from 'react';
import React, { useCallback, useState, useMemo, useRef, useContext } from 'react';
import styled from 'styled-components';
import { OnUpdateColumns } from '../timeline/events';
import { WithHoverActions } from '../../../common/components/with_hover_actions';
import { useGetTimelineId } from '../../../common/components/drag_and_drop/use_get_timeline_id_from_dom';
import { ColumnHeaderOptions } from '../../../../common';
import { HoverActions } from '../../../common/components/hover_actions';
import { TimelineContext } from '../../../../../timelines/public';
/**
* The name of a (draggable) field
@ -95,8 +95,7 @@ export const FieldName = React.memo<{
}) => {
const containerRef = useRef<HTMLDivElement | null>(null);
const [showTopN, setShowTopN] = useState<boolean>(false);
const [goGetTimelineId, setGoGetTimelineId] = useState(false);
const timelineIdFind = useGetTimelineId(containerRef, goGetTimelineId);
const { timelineId: timelineIdFind } = useContext(TimelineContext);
const toggleTopN = useCallback(() => {
setShowTopN((prevShowTopN) => {
@ -122,7 +121,6 @@ export const FieldName = React.memo<{
ownFocus={hoverActionsOwnFocus}
showTopN={showTopN}
toggleTopN={toggleTopN}
goGetTimelineId={setGoGetTimelineId}
timelineId={timelineIdFind}
/>
),

View file

@ -11,7 +11,7 @@ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { isTab } from '../../../../../timelines/public';
import { isTab, TimelineContext } from '../../../../../timelines/public';
import { timelineActions, timelineSelectors } from '../../store/timeline';
import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
import { defaultHeaders } from './body/column_headers/default_headers';
@ -118,38 +118,41 @@ const StatefulTimelineComponent: React.FC<Props> = ({
},
[containerElement, onSkipFocusBeforeEventsTable, onSkipFocusAfterEventsTable]
);
const timelineContext = useMemo(() => ({ timelineId }), [timelineId]);
return (
<TimelineContainer
data-test-subj="timeline"
data-timeline-id={timelineId}
onKeyDown={onKeyDown}
ref={containerElement}
>
<TimelineSavingProgress timelineId={timelineId} />
{timelineType === TimelineType.template && (
<TimelineTemplateBadge>{i18n.TIMELINE_TEMPLATE}</TimelineTemplateBadge>
)}
<HideShowContainer
$isVisible={!timelineFullScreen}
data-test-subj="timeline-hide-show-container"
<TimelineContext.Provider value={timelineContext}>
<TimelineContainer
data-test-subj="timeline"
data-timeline-id={timelineId}
onKeyDown={onKeyDown}
ref={containerElement}
>
<FlyoutHeaderPanel timelineId={timelineId} />
<FlyoutHeader timelineId={timelineId} />
</HideShowContainer>
<TimelineSavingProgress timelineId={timelineId} />
{timelineType === TimelineType.template && (
<TimelineTemplateBadge>{i18n.TIMELINE_TEMPLATE}</TimelineTemplateBadge>
)}
<TabsContent
graphEventId={graphEventId}
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
setTimelineFullScreen={setTimelineFullScreen}
timelineId={timelineId}
timelineType={timelineType}
timelineDescription={description}
timelineFullScreen={timelineFullScreen}
/>
</TimelineContainer>
<HideShowContainer
$isVisible={!timelineFullScreen}
data-test-subj="timeline-hide-show-container"
>
<FlyoutHeaderPanel timelineId={timelineId} />
<FlyoutHeader timelineId={timelineId} />
</HideShowContainer>
<TabsContent
graphEventId={graphEventId}
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
setTimelineFullScreen={setTimelineFullScreen}
timelineId={timelineId}
timelineType={timelineType}
timelineDescription={description}
timelineFullScreen={timelineFullScreen}
/>
</TimelineContainer>
</TimelineContext.Provider>
);
};

View file

@ -46,7 +46,7 @@ import { SELECTOR_TIMELINE_GLOBAL_CONTAINER, UpdatedFlexGroup, UpdatedFlexItem }
import { Sort } from '../body/sort';
import { InspectButton, InspectButtonContainer } from '../../inspect';
import { SummaryViewSelector, ViewSelection } from '../event_rendered_view/selector';
import { TGridLoading, TGridEmpty } from '../shared';
import { TGridLoading, TGridEmpty, TimelineContext } from '../shared';
const AlertConsumers: typeof AlertConsumersTyped = AlertConsumersNonTyped;
@ -286,6 +286,7 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
useEffect(() => {
setQuery(inspect, loading, refetch);
}, [inspect, loading, refetch, setQuery]);
const timelineContext = useMemo(() => ({ timelineId: id }), [id]);
return (
<InspectButtonContainer>
@ -301,65 +302,66 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
{graphOverlay}
{canQueryTimeline && (
<EventsContainerLoading
data-timeline-id={id}
data-test-subj={`events-container-loading-${loading}`}
>
<UpdatedFlexGroup gutterSize="m" justifyContent="flexEnd" alignItems={alignItems}>
<UpdatedFlexItem grow={false} $show={!loading}>
<InspectButton title={justTitle} inspect={inspect} loading={loading} />
</UpdatedFlexItem>
<UpdatedFlexItem grow={false} $show={!loading}>
{!resolverIsShowing(graphEventId) && additionalFilters}
</UpdatedFlexItem>
{tGridEventRenderedViewEnabled &&
['detections-page', 'detections-rules-details-page'].includes(id) && (
<UpdatedFlexItem grow={false} $show={!loading}>
<SummaryViewSelector viewSelected={tableView} onViewChange={setTableView} />
</UpdatedFlexItem>
)}
</UpdatedFlexGroup>
{!graphEventId && graphOverlay == null && (
<>
{!hasAlerts && !loading && <TGridEmpty height="short" />}
{hasAlerts && (
<FullWidthFlexGroup
$visible={!graphEventId && graphOverlay == null}
gutterSize="none"
>
<ScrollableFlexItem grow={1}>
<StatefulBody
hasAlertsCrud={hasAlertsCrud}
activePage={pageInfo.activePage}
browserFields={browserFields}
filterQuery={filterQuery}
data={nonDeletedEvents}
defaultCellActions={defaultCellActions}
id={id}
isEventViewer={true}
itemsPerPageOptions={itemsPerPageOptions}
loadPage={loadPage}
onRuleChange={onRuleChange}
pageSize={itemsPerPage}
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
tabType={TimelineTabs.query}
tableView={tableView}
totalItems={totalCountMinusDeleted}
unit={unit}
filterStatus={filterStatus}
leadingControlColumns={leadingControlColumns}
trailingControlColumns={trailingControlColumns}
refetch={refetch}
indexNames={indexNames}
/>
</ScrollableFlexItem>
</FullWidthFlexGroup>
)}
</>
)}
</EventsContainerLoading>
<TimelineContext.Provider value={timelineContext}>
<EventsContainerLoading
data-timeline-id={id}
data-test-subj={`events-container-loading-${loading}`}
>
<UpdatedFlexGroup gutterSize="m" justifyContent="flexEnd" alignItems={alignItems}>
<UpdatedFlexItem grow={false} $show={!loading}>
<InspectButton title={justTitle} inspect={inspect} loading={loading} />
</UpdatedFlexItem>
<UpdatedFlexItem grow={false} $show={!loading}>
{!resolverIsShowing(graphEventId) && additionalFilters}
</UpdatedFlexItem>
{tGridEventRenderedViewEnabled &&
['detections-page', 'detections-rules-details-page'].includes(id) && (
<UpdatedFlexItem grow={false} $show={!loading}>
<SummaryViewSelector viewSelected={tableView} onViewChange={setTableView} />
</UpdatedFlexItem>
)}
</UpdatedFlexGroup>
{!graphEventId && graphOverlay == null && (
<>
{!hasAlerts && !loading && <TGridEmpty height="short" />}
{hasAlerts && (
<FullWidthFlexGroup
$visible={!graphEventId && graphOverlay == null}
gutterSize="none"
>
<ScrollableFlexItem grow={1}>
<StatefulBody
hasAlertsCrud={hasAlertsCrud}
activePage={pageInfo.activePage}
browserFields={browserFields}
filterQuery={filterQuery}
data={nonDeletedEvents}
defaultCellActions={defaultCellActions}
id={id}
isEventViewer={true}
itemsPerPageOptions={itemsPerPageOptions}
loadPage={loadPage}
onRuleChange={onRuleChange}
pageSize={itemsPerPage}
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
tabType={TimelineTabs.query}
tableView={tableView}
totalItems={totalCountMinusDeleted}
unit={unit}
filterStatus={filterStatus}
leadingControlColumns={leadingControlColumns}
trailingControlColumns={trailingControlColumns}
refetch={refetch}
indexNames={indexNames}
/>
</ScrollableFlexItem>
</FullWidthFlexGroup>
)}
</>
)}
</EventsContainerLoading>
</TimelineContext.Provider>
)}
</StyledEuiPanel>
</InspectButtonContainer>

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React from 'react';
import React, { createContext } from 'react';
import {
EuiPanel,
EuiFlexGroup,
@ -24,6 +24,8 @@ const heights = {
short: 250,
};
export const TimelineContext = createContext<{ timelineId: string | null }>({ timelineId: null });
export const TGridLoading: React.FC<{ height?: keyof typeof heights }> = ({ height = 'tall' }) => {
return (
<EuiPanel color="subdued">

View file

@ -47,7 +47,7 @@ import {
import { InspectButton, InspectButtonContainer } from '../../inspect';
import { useFetchIndex } from '../../../container/source';
import { AddToCaseAction } from '../../actions/timeline/cases/add_to_case_action';
import { TGridLoading, TGridEmpty } from '../shared';
import { TGridLoading, TGridEmpty, TimelineContext } from '../shared';
export const EVENTS_VIEWER_HEADER_HEIGHT = 90; // px
const STANDALONE_ID = 'standalone-t-grid';
@ -335,13 +335,14 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
isFirstUpdate.current = false;
}
}, [loading]);
const timelineContext = { timelineId: STANDALONE_ID };
return (
<InspectButtonContainer data-test-subj="events-viewer-panel">
<AlertsTableWrapper>
{isFirstUpdate.current && <TGridLoading />}
{canQueryTimeline ? (
<>
<TimelineContext.Provider value={timelineContext}>
<EventsContainerLoading
data-timeline-id={STANDALONE_ID}
data-test-subj={`events-container-loading-${loading}`}
@ -391,7 +392,7 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
</FullWidthFlexGroup>
)}
</EventsContainerLoading>
</>
</TimelineContext.Provider>
) : null}
<AddToCaseAction {...addToCaseActionProps} disableAlerts />
</AlertsTableWrapper>

View file

@ -68,3 +68,4 @@ export function plugin(initializerContext: PluginInitializerContext) {
}
export const StatefulEventContext = createContext<StatefulEventContextType | null>(null);
export { TimelineContext } from './components/t_grid/shared';