Skip to content

Commit

Permalink
[Security Solution] Fixes scroll issues related to the sticky header (#…
Browse files Browse the repository at this point in the history
…74062)

## [Security Solution] Fixes scroll issues related to the sticky header

Fixes scrolling issues related to the sticky header.

The Security solution hid the app navigation links (e.g. `Overview`, `Detections`, `Hosts` ...) in the sticky header when the page was scrolled (to maximize the available vertical space), but in recent `7.9` BCs, sometimes this [created issues while scrolling](#73882).

With the introduction of Full Screen mode in Timeline-based views, it's no longer necessary to hide the app navigation links while scrolling. (The navigation links are hidden when Timeline-based views are placed into full screen mode.)

Fixes: #73882

## Desk testing

Desk tested in:
- Chrome `84.0.4147.105`
- Firefox `79.0`
- Safari `13.1.2`
  • Loading branch information
andrew-goldstein authored Aug 4, 2020
1 parent 64126b4 commit 4031f55
Show file tree
Hide file tree
Showing 35 changed files with 264 additions and 460 deletions.
49 changes: 16 additions & 33 deletions x-pack/plugins/security_solution/public/app/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import React, { useMemo } from 'react';
import styled from 'styled-components';

import { useThrottledResizeObserver } from '../../common/components/utils';
import { DragDropContextWrapper } from '../../common/components/drag_and_drop/drag_drop_context_wrapper';
import { Flyout } from '../../timelines/components/flyout';
import { HeaderGlobal } from '../../common/components/header_global';
Expand All @@ -19,43 +18,29 @@ import { useShowTimeline } from '../../common/utils/timeline/use_show_timeline';
import { navTabs } from './home_navigations';
import { useSignalIndex } from '../../detections/containers/detection_engine/alerts/use_signal_index';

const WrappedByAutoSizer = styled.div`
const SecuritySolutionAppWrapper = styled.div`
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
`;
WrappedByAutoSizer.displayName = 'WrappedByAutoSizer';
SecuritySolutionAppWrapper.displayName = 'SecuritySolutionAppWrapper';

const Main = styled.main`
height: 100%;
position: relative;
overflow: auto;
flex: 1;
`;

Main.displayName = 'Main';

const usersViewing = ['elastic']; // TODO: get the users viewing this timeline from Elasticsearch (persistance)

/** the global Kibana navigation at the top of every page */
export const globalHeaderHeightPx = 48;

const calculateFlyoutHeight = ({
globalHeaderSize,
windowHeight,
}: {
globalHeaderSize: number;
windowHeight: number;
}): number => Math.max(0, windowHeight - globalHeaderSize);

interface HomePageProps {
children: React.ReactNode;
}

export const HomePage: React.FC<HomePageProps> = ({ children }) => {
const { ref: measureRef, height: windowHeight = 0 } = useThrottledResizeObserver();
const flyoutHeight = useMemo(
() =>
calculateFlyoutHeight({
globalHeaderSize: globalHeaderHeightPx,
windowHeight,
}),
[windowHeight]
);
const HomePageComponent: React.FC<HomePageProps> = ({ children }) => {
const { signalIndexExists, signalIndexName } = useSignalIndex();

const indexToAdd = useMemo<string[] | null>(() => {
Expand All @@ -69,7 +54,7 @@ export const HomePage: React.FC<HomePageProps> = ({ children }) => {
const { browserFields, indexPattern, indicesExist } = useWithSource('default', indexToAdd);

return (
<WrappedByAutoSizer data-test-subj="wrapped-by-auto-sizer" ref={measureRef}>
<SecuritySolutionAppWrapper>
<HeaderGlobal />

<Main data-test-subj="pageContainer">
Expand All @@ -78,11 +63,7 @@ export const HomePage: React.FC<HomePageProps> = ({ children }) => {
{indicesExist && showTimeline && (
<>
<AutoSaveWarningMsg />
<Flyout
flyoutHeight={flyoutHeight}
timelineId="timeline-1"
usersViewing={usersViewing}
/>
<Flyout timelineId="timeline-1" usersViewing={usersViewing} />
</>
)}

Expand All @@ -91,8 +72,10 @@ export const HomePage: React.FC<HomePageProps> = ({ children }) => {
</Main>

<HelpMenu />
</WrappedByAutoSizer>
</SecuritySolutionAppWrapper>
);
};

HomePage.displayName = 'HomePage';
HomePageComponent.displayName = 'HomePage';

export const HomePage = React.memo(HomePageComponent);
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,13 @@ const defaultAlertsFilters: Filter[] = [
interface Props {
timelineId: TimelineIdLiteral;
endDate: string;
eventsViewerBodyHeight?: number;
startDate: string;
pageFilters?: Filter[];
}

const AlertsTableComponent: React.FC<Props> = ({
timelineId,
endDate,
eventsViewerBodyHeight,
startDate,
pageFilters = [],
}) => {
Expand All @@ -93,7 +91,6 @@ const AlertsTableComponent: React.FC<Props> = ({
pageFilters={alertsFilter}
defaultModel={alertsDefaultModel}
end={endDate}
height={eventsViewerBodyHeight}
id={timelineId}
start={startDate}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,9 @@
*/
import React, { useEffect, useCallback, useMemo } from 'react';
import numeral from '@elastic/numeral';
import { useWindowSize } from 'react-use';

import { globalHeaderHeightPx } from '../../../app/home';
import { DEFAULT_NUMBER_FORMAT, FILTERS_GLOBAL_HEIGHT } from '../../../../common/constants';
import { DEFAULT_NUMBER_FORMAT } from '../../../../common/constants';
import { useFullScreen } from '../../containers/use_full_screen';
import { EVENTS_VIEWER_HEADER_HEIGHT } from '../events_viewer/events_viewer';
import {
getEventsViewerBodyHeight,
MIN_EVENTS_VIEWER_BODY_HEIGHT,
} from '../../../timelines/components/timeline/body/helpers';
import { footerHeight } from '../../../timelines/components/timeline/footer';

import { AlertsComponentsProps } from './types';
import { AlertsTable } from './alerts_table';
Expand Down Expand Up @@ -45,7 +37,6 @@ export const AlertsView = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
const { height: windowHeight } = useWindowSize();
const { globalFullScreen } = useFullScreen();
const alertsHistogramConfigs: MatrixHisrogramConfigs = useMemo(
() => ({
Expand Down Expand Up @@ -79,17 +70,6 @@ export const AlertsView = ({
<AlertsTable
timelineId={timelineId}
endDate={endDate}
eventsViewerBodyHeight={
globalFullScreen
? getEventsViewerBodyHeight({
footerHeight,
headerHeight: EVENTS_VIEWER_HEADER_HEIGHT,
kibanaChromeHeight: globalHeaderHeightPx,
otherContentHeight: FILTERS_GLOBAL_HEIGHT,
windowHeight,
})
: MIN_EVENTS_VIEWER_BODY_HEIGHT
}
startDate={startDate}
pageFilters={pageFilters}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui';
import { getOr, isEmpty, union } from 'lodash/fp';
import React, { useEffect, useMemo, useState } from 'react';
import styled, { css } from 'styled-components';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';

import { BrowserFields, DocValueFields } from '../../containers/source';
Expand Down Expand Up @@ -50,18 +50,18 @@ const TitleText = styled.span`
margin-right: 12px;
`;

const DEFAULT_EVENTS_VIEWER_HEIGHT = 500;

const StyledEuiPanel = styled(EuiPanel)<{ $isFullScreen: boolean }>`
display: flex;
flex-direction: column;
${({ $isFullScreen }) =>
$isFullScreen &&
css`
`
border: 0;
box-shadow: none;
padding-top: 0;
padding-bottom: 0;
`}
max-width: 100%;
`}
`;

const TitleFlexGroup = styled(EuiFlexGroup)`
Expand All @@ -70,17 +70,18 @@ const TitleFlexGroup = styled(EuiFlexGroup)`

const EventsContainerLoading = styled.div`
width: 100%;
overflow: auto;
overflow: hidden;
flex: 1;
display: flex;
flex-direction: column;
`;

/**
* Hides stateful headerFilterGroup implementations, but prevents the component
* from being unmounted, to preserve the state of the component
*/
const HeaderFilterGroupWrapper = styled.header<{ show: boolean }>`
${({ show }) => css`
${show ? '' : 'visibility: hidden;'};
`}
${({ show }) => (show ? '' : 'visibility: hidden;')}
`;

interface Props {
Expand Down Expand Up @@ -119,7 +120,6 @@ const EventsViewerComponent: React.FC<Props> = ({
end,
filters,
headerFilterGroup,
height = DEFAULT_EVENTS_VIEWER_HEIGHT,
id,
indexPattern,
isLive,
Expand Down Expand Up @@ -277,7 +277,6 @@ const EventsViewerComponent: React.FC<Props> = ({
docValueFields={docValueFields}
id={id}
isEventViewer={true}
height={height}
sort={sort}
toggleColumn={toggleColumn}
/>
Expand Down Expand Up @@ -326,7 +325,6 @@ export const EventsViewer = React.memo(
prevProps.end === nextProps.end &&
deepEqual(prevProps.filters, nextProps.filters) &&
prevProps.headerFilterGroup === nextProps.headerFilterGroup &&
prevProps.height === nextProps.height &&
prevProps.id === nextProps.id &&
deepEqual(prevProps.indexPattern, nextProps.indexPattern) &&
prevProps.isLive === nextProps.isLive &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import React, { useCallback, useMemo, useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import styled from 'styled-components';

import { DEFAULT_INDEX_KEY } from '../../../../common/constants';
import { inputsModel, inputsSelectors, State } from '../../store';
Expand All @@ -23,12 +24,20 @@ import { useUiSetting } from '../../lib/kibana';
import { EventsViewer } from './events_viewer';
import { useFetchIndexPatterns } from '../../../detections/containers/detection_engine/rules/fetch_index_patterns';
import { InspectButtonContainer } from '../inspect';
import { useFullScreen } from '../../containers/use_full_screen';

const DEFAULT_EVENTS_VIEWER_HEIGHT = 652;

const FullScreenContainer = styled.div<{ $isFullScreen: boolean }>`
height: ${({ $isFullScreen }) => ($isFullScreen ? '100%' : `${DEFAULT_EVENTS_VIEWER_HEIGHT}px`)};
display: flex;
width: 100%;
`;

export interface OwnProps {
defaultIndices?: string[];
defaultModel: SubsetTimelineModel;
end: string;
height?: number;
id: string;
start: string;
headerFilterGroup?: React.ReactNode;
Expand All @@ -49,7 +58,6 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
excludedRowRendererIds,
filters,
headerFilterGroup,
height,
id,
isLive,
itemsPerPage,
Expand All @@ -74,6 +82,8 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
'events_viewer'
);

const { globalFullScreen } = useFullScreen();

useEffect(() => {
if (createTimeline != null) {
createTimeline({
Expand Down Expand Up @@ -121,33 +131,34 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
const globalFilters = useMemo(() => [...filters, ...(pageFilters ?? [])], [filters, pageFilters]);

return (
<InspectButtonContainer>
<EventsViewer
browserFields={browserFields}
columns={columns}
docValueFields={docValueFields}
id={id}
dataProviders={dataProviders!}
deletedEventIds={deletedEventIds}
end={end}
isLoadingIndexPattern={isLoadingIndexPattern}
filters={globalFilters}
headerFilterGroup={headerFilterGroup}
height={height}
indexPattern={indexPatterns}
isLive={isLive}
itemsPerPage={itemsPerPage!}
itemsPerPageOptions={itemsPerPageOptions!}
kqlMode={kqlMode}
onChangeItemsPerPage={onChangeItemsPerPage}
query={query}
start={start}
sort={sort}
toggleColumn={toggleColumn}
utilityBar={utilityBar}
graphEventId={graphEventId}
/>
</InspectButtonContainer>
<FullScreenContainer $isFullScreen={globalFullScreen}>
<InspectButtonContainer>
<EventsViewer
browserFields={browserFields}
columns={columns}
docValueFields={docValueFields}
id={id}
dataProviders={dataProviders!}
deletedEventIds={deletedEventIds}
end={end}
isLoadingIndexPattern={isLoadingIndexPattern}
filters={globalFilters}
headerFilterGroup={headerFilterGroup}
indexPattern={indexPatterns}
isLive={isLive}
itemsPerPage={itemsPerPage!}
itemsPerPageOptions={itemsPerPageOptions!}
kqlMode={kqlMode}
onChangeItemsPerPage={onChangeItemsPerPage}
query={query}
start={start}
sort={sort}
toggleColumn={toggleColumn}
utilityBar={utilityBar}
graphEventId={graphEventId}
/>
</InspectButtonContainer>
</FullScreenContainer>
);
};

Expand Down Expand Up @@ -219,7 +230,6 @@ export const StatefulEventsViewer = connector(
prevProps.deletedEventIds === nextProps.deletedEventIds &&
prevProps.end === nextProps.end &&
deepEqual(prevProps.filters, nextProps.filters) &&
prevProps.height === nextProps.height &&
prevProps.isLive === nextProps.isLive &&
prevProps.itemsPerPage === nextProps.itemsPerPage &&
deepEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) &&
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 4031f55

Please sign in to comment.