Skip to content

Commit

Permalink
create detail panel hook for session view
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelolo24 committed Mar 23, 2022
1 parent c3e7708 commit d7cbe6a
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import styled from 'styled-components';
import type { Filter } from '@kbn/es-query';
import { inputsModel, State } from '../../store';
import { inputsActions } from '../../store/actions';
import { ControlColumnProps, RowRenderer, TimelineId } from '../../../../common/types/timeline';
import {
ControlColumnProps,
RowRenderer,
TimelineId,
TimelineTabs,
} from '../../../../common/types/timeline';
import { APP_ID, APP_UI_ID } from '../../../../common/constants';
import { timelineActions } from '../../../timelines/store/timeline';
import type { SubsetTimelineModel } from '../../../timelines/store/timeline/model';
Expand All @@ -33,6 +38,7 @@ import {
useFieldBrowserOptions,
FieldEditorActions,
} from '../../../timelines/components/fields_browser';
import { useLoadDetailPanel } from '../../../timelines/components/side_panel/hooks/use_load_detail_panel';

const EMPTY_CONTROL_COLUMNS: ControlColumnProps[] = [];

Expand Down Expand Up @@ -156,11 +162,22 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({

const globalFilters = useMemo(() => [...filters, ...(pageFilters ?? [])], [filters, pageFilters]);
const trailingControlColumns: ControlColumnProps[] = EMPTY_CONTROL_COLUMNS;

const { openDetailsPanel, FlyoutDetailsPanel } = useLoadDetailPanel({
isFlyoutView: true,
entityType,
sourcerScope: SourcererScopeName.timeline,
timelineId: id,
tabType: TimelineTabs.query,
});

const graphOverlay = useMemo(() => {
const shouldShowOverlay =
(graphEventId != null && graphEventId.length > 0) || sessionViewId !== null;
return shouldShowOverlay ? <GraphOverlay timelineId={id} /> : null;
}, [graphEventId, id, sessionViewId]);
return shouldShowOverlay ? (
<GraphOverlay timelineId={id} openDetailsPanel={openDetailsPanel} />
) : null;
}, [graphEventId, id, sessionViewId, openDetailsPanel]);
const setQuery = useCallback(
(inspect, loading, refetch) => {
dispatch(inputsActions.setQuery({ id, inputId: 'global', inspect, loading, refetch }));
Expand Down Expand Up @@ -240,14 +257,7 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
})}
</InspectButtonContainer>
</FullScreenContainer>
<DetailsPanel
browserFields={browserFields}
entityType={entityType}
docValueFields={docValueFields}
isFlyoutView
runtimeMappings={runtimeMappings}
timelineId={id}
/>
{FlyoutDetailsPanel}
</CasesContext>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ const ScrollableFlexItem = styled(EuiFlexItem)`
width: 100%;
`;

interface OwnProps {
interface GraphOverlayProps {
openDetailsPanel: (eventId?: string, onClose?: () => void) => void;
timelineId: TimelineId;
}

Expand Down Expand Up @@ -133,7 +134,7 @@ NavigationComponent.displayName = 'NavigationComponent';

const Navigation = React.memo(NavigationComponent);

const GraphOverlayComponent: React.FC<OwnProps> = ({ timelineId }) => {
const GraphOverlayComponent: React.FC<GraphOverlayProps> = ({ timelineId, openDetailsPanel }) => {
const dispatch = useDispatch();
const { globalFullScreen, setGlobalFullScreen } = useGlobalFullScreen();
const { timelineFullScreen, setTimelineFullScreen } = useTimelineFullScreen();
Expand All @@ -147,8 +148,13 @@ const GraphOverlayComponent: React.FC<OwnProps> = ({ timelineId }) => {
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).sessionViewId
);
const sessionViewMain = useMemo(() => {
return sessionViewId !== null ? sessionView.getSessionView(sessionViewId) : null;
}, [sessionView, sessionViewId]);
return sessionViewId !== null
? sessionView.getSessionView({
sessionEntityId: sessionViewId,
loadAlertDetails: openDetailsPanel,
})
: null;
}, [sessionView, sessionViewId, openDetailsPanel]);

const getStartSelector = useMemo(() => startSelector(), []);
const getEndSelector = useMemo(() => endSelector(), []);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* 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, { useMemo, useCallback, useRef } from 'react';
import { useDispatch } from 'react-redux';
import { timelineActions, timelineSelectors } from '../../../store/timeline';
import type { EntityType } from '../../../../../../timelines/common';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
import { activeTimeline } from '../../../containers/active_timeline_context';
import { TimelineId, TimelineTabs } from '../../../../../common/types/timeline';
import { timelineDefaults } from '../../../store/timeline/defaults';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
import { DetailsPanel } from '..';

export interface UseLoadDetailPanelConfig {
entityType?: EntityType;
isFlyoutView?: boolean;
sourcerScope: SourcererScopeName;
timelineId: TimelineId;
tabType?: TimelineTabs;
}

export interface UseLoadDetailPanelReturn {
openDetailsPanel: (eventId?: string, onClose?: () => void) => void;
handleOnDetailsPanelClosed: () => void;
FlyoutDetailsPanel: JSX.Element;
shouldShowFlyoutDetailsPanel: boolean;
}

export const useLoadDetailPanel = ({
entityType,
isFlyoutView,
sourcerScope,
timelineId,
tabType,
}: UseLoadDetailPanelConfig): UseLoadDetailPanelReturn => {
const { browserFields, docValueFields, selectedPatterns, runtimeMappings } =
useSourcererDataView(sourcerScope);
const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []);
const dispatch = useDispatch();

const expandedDetail = useDeepEqualSelector(
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).expandedDetail
);
const onFlyoutClose = useRef(() => {});

const shouldShowFlyoutDetailsPanel = useMemo(() => {
if (
tabType &&
expandedDetail &&
expandedDetail[tabType] &&
!!expandedDetail[tabType]?.panelView
) {
return true;
}
return false;
}, [expandedDetail, tabType]);

const loadDetailsPanel = useCallback(
(eventId?: string) => {
if (eventId) {
dispatch(
timelineActions.toggleDetailPanel({
panelView: 'eventDetail',
tabType,
timelineId,
params: {
eventId,
indexName: selectedPatterns.join(','),
},
})
);
}
},
[dispatch, selectedPatterns, tabType, timelineId]
);

const openDetailsPanel = useCallback(
(eventId?: string, onClose?: () => void) => {
loadDetailsPanel(eventId);
onFlyoutClose.current = onClose ?? (() => {});
},
[loadDetailsPanel]
);

const handleOnDetailsPanelClosed = useCallback(() => {
if (onFlyoutClose.current) onFlyoutClose.current();
dispatch(timelineActions.toggleDetailPanel({ tabType, timelineId }));

if (
tabType &&
expandedDetail[tabType]?.panelView &&
timelineId === TimelineId.active &&
shouldShowFlyoutDetailsPanel
) {
activeTimeline.toggleExpandedDetail({});
}
}, [dispatch, timelineId, expandedDetail, tabType, shouldShowFlyoutDetailsPanel]);

const FlyoutDetailsPanel = useMemo(
() => (
<DetailsPanel
browserFields={browserFields}
docValueFields={docValueFields}
entityType={entityType}
handleOnPanelClosed={handleOnDetailsPanelClosed}
isFlyoutView={isFlyoutView}
runtimeMappings={runtimeMappings}
tabType={tabType}
timelineId={timelineId}
/>
),
[
browserFields,
docValueFields,
entityType,
handleOnDetailsPanelClosed,
isFlyoutView,
runtimeMappings,
tabType,
timelineId,
]
);

return {
openDetailsPanel,
handleOnDetailsPanelClosed,
shouldShowFlyoutDetailsPanel,
FlyoutDetailsPanel,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import React, { useMemo } from 'react';
import styled from 'styled-components';
import { timelineSelectors } from '../../../store/timeline';
import { useKibana } from '../../../../common/lib/kibana';
import { TimelineId } from '../../../../../common/types/timeline';
import { TimelineId, TimelineTabs } from '../../../../../common/types/timeline';
import { timelineDefaults } from '../../../../timelines/store/timeline/defaults';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
import { useLoadDetailPanel } from '../../side_panel/hooks/use_load_detail_panel';
import { SourcererScopeName } from '../../../../common/store/sourcerer/model';

const FullWidthFlexGroup = styled(EuiFlexGroup)`
margin: 0;
Expand All @@ -25,23 +27,50 @@ const ScrollableFlexItem = styled(EuiFlexItem)`
overflow: hidden;
`;

const VerticalRule = styled.div`
width: 2px;
height: 100%;
background: ${({ theme }) => theme.eui.euiColorLightShade};
`;

interface Props {
timelineId: TimelineId;
}

const SessionTabContent: React.FC<Props> = ({ timelineId }) => {
const { sessionView } = useKibana().services;

const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []);

const sessionViewId = useDeepEqualSelector(
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).sessionViewId
);
const { openDetailsPanel, shouldShowFlyoutDetailsPanel, FlyoutDetailsPanel } = useLoadDetailPanel(
{
sourcerScope: SourcererScopeName.timeline,
timelineId,
tabType: TimelineTabs.session,
}
);
const sessionViewMain = useMemo(() => {
return sessionViewId !== null ? sessionView.getSessionView(sessionViewId) : null;
}, [sessionView, sessionViewId]);
return sessionViewId !== null
? sessionView.getSessionView({
sessionEntityId: sessionViewId,
loadAlertDetails: openDetailsPanel,
})
: null;
}, [openDetailsPanel, sessionView, sessionViewId]);

return <ScrollableFlexItem grow={2}>{sessionViewMain}</ScrollableFlexItem>;
return (
<FullWidthFlexGroup gutterSize="none">
<ScrollableFlexItem grow={2}>{sessionViewMain}</ScrollableFlexItem>
{shouldShowFlyoutDetailsPanel && (
<>
<VerticalRule />
<ScrollableFlexItem grow={1}>{FlyoutDetailsPanel}</ScrollableFlexItem>
</>
)}
</FullWidthFlexGroup>
);
};

// eslint-disable-next-line import/no-default-export
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export function ProcessTreeNode({
const shouldRenderChildren = childrenExpanded && children && children.length > 0;
const childrenTreeDepth = depth + 1;

const showUserEscalation = user.id !== parent.user.id;
const showUserEscalation = user?.id !== parent?.user?.id;
const interactiveSession = !!tty;
const sessionIcon = interactiveSession ? 'consoleApp' : 'compute';
const hasExec = process.hasExec();
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/session_view/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,5 @@ export interface SessionViewStart {
}: {
onOpenSessionView: (eventId: string) => void;
}) => JSX.Element;
getSessionView: (sessionEntityId: string) => JSX.Element;
getSessionView: (sessionDeps: SessionViewDeps) => JSX.Element;
}
1 change: 1 addition & 0 deletions x-pack/plugins/timelines/common/types/timeline/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ export enum TimelineTabs {
graph = 'graph',
notes = 'notes',
pinned = 'pinned',
session = 'session',
eql = 'eql',
}

Expand Down

0 comments on commit d7cbe6a

Please sign in to comment.