Skip to content

Commit 6d0257a

Browse files
[Security Solution] Fix app layout (#76668) (#78532)
1 parent 5b58a50 commit 6d0257a

File tree

13 files changed

+133
-134
lines changed

13 files changed

+133
-134
lines changed

test/functional/services/common/browser.ts

+4
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,10 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
472472
return parseInt(scrollSize, 10);
473473
}
474474

475+
public async scrollTop() {
476+
await driver.executeScript('document.documentElement.scrollTop = 0');
477+
}
478+
475479
// return promise with REAL scroll position
476480
public async setScrollTop(scrollSize: number | string) {
477481
await driver.executeScript('document.body.scrollTop = ' + scrollSize);

x-pack/plugins/security_solution/common/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const DEFAULT_INTERVAL_TYPE = 'manual';
3434
export const DEFAULT_INTERVAL_VALUE = 300000; // ms
3535
export const DEFAULT_TIMEPICKER_QUICK_RANGES = 'timepicker:quickRanges';
3636
export const SCROLLING_DISABLED_CLASS_NAME = 'scrolling-disabled';
37+
export const GLOBAL_HEADER_HEIGHT = 98; // px
3738
export const FILTERS_GLOBAL_HEIGHT = 109; // px
3839
export const FULL_SCREEN_TOGGLED_CLASS_NAME = 'fullScreenToggled';
3940
export const NO_ALERT_INDEX = 'no-alert-index-049FC71A-4C2C-446F-9901-37XMC5024C51';

x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
FIELDS_BROWSER_SELECTED_CATEGORY_TITLE,
1111
} from '../screens/fields_browser';
1212
import {
13-
EVENTS_PAGE,
1413
HEADER_SUBTITLE,
1514
HOST_GEO_CITY_NAME_HEADER,
1615
HOST_GEO_COUNTRY_NAME_HEADER,
@@ -173,7 +172,7 @@ describe.skip('Events Viewer', () => {
173172
const expectedOrderAfterDragAndDrop =
174173
'message@timestamphost.nameevent.moduleevent.datasetevent.actionuser.namesource.ipdestination.ip';
175174

176-
cy.get(EVENTS_PAGE).scrollTo('bottom');
175+
cy.scrollTo('bottom');
177176
cy.get(HEADERS_GROUP).invoke('text').should('equal', originalColumnOrder);
178177
dragAndDropColumn({ column: 0, newPosition: 1 });
179178
cy.get(HEADERS_GROUP).invoke('text').should('equal', expectedOrderAfterDragAndDrop);

x-pack/plugins/security_solution/cypress/screens/hosts/events.ts

-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
export const CLOSE_MODAL = '[data-test-subj="modal-inspect-close"]';
88

9-
export const EVENTS_PAGE = '[data-test-subj="pageContainer"]';
10-
119
export const EVENTS_VIEWER_FIELDS_BUTTON =
1210
'[data-test-subj="events-viewer-panel"] [data-test-subj="show-field-browser"]';
1311

x-pack/plugins/security_solution/public/app/home/index.tsx

+12-12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import styled from 'styled-components';
1010
import { TimelineId } from '../../../common/types/timeline';
1111
import { DragDropContextWrapper } from '../../common/components/drag_and_drop/drag_drop_context_wrapper';
1212
import { Flyout } from '../../timelines/components/flyout';
13+
import { SecuritySolutionAppWrapper } from '../../common/components/page';
1314
import { HeaderGlobal } from '../../common/components/header_global';
1415
import { HelpMenu } from '../../common/components/help_menu';
1516
import { AutoSaveWarningMsg } from '../../timelines/components/timeline/auto_save_warning';
@@ -20,18 +21,17 @@ import { useInitSourcerer, useSourcererScope } from '../../common/containers/sou
2021
import { useKibana } from '../../common/lib/kibana';
2122
import { DETECTIONS_SUB_PLUGIN_ID } from '../../../common/constants';
2223
import { SourcererScopeName } from '../../common/store/sourcerer/model';
24+
import { useThrottledResizeObserver } from '../../common/components/utils';
2325

24-
const SecuritySolutionAppWrapper = styled.div`
26+
const Main = styled.main.attrs<{ paddingTop: number }>(({ paddingTop }) => ({
27+
style: {
28+
paddingTop: `${paddingTop}px`,
29+
},
30+
}))<{ paddingTop: number }>`
31+
overflow: auto;
2532
display: flex;
2633
flex-direction: column;
27-
height: 100%;
28-
width: 100%;
29-
`;
30-
SecuritySolutionAppWrapper.displayName = 'SecuritySolutionAppWrapper';
31-
32-
const Main = styled.main`
33-
overflow: auto;
34-
flex: 1;
34+
flex: 1 1 auto;
3535
`;
3636

3737
Main.displayName = 'Main';
@@ -45,7 +45,7 @@ interface HomePageProps {
4545
const HomePageComponent: React.FC<HomePageProps> = ({ children }) => {
4646
const { application } = useKibana().services;
4747
const subPluginId = useRef<string>('');
48-
48+
const { ref, height = 0 } = useThrottledResizeObserver(300);
4949
application.currentAppId$.subscribe((appId) => {
5050
subPluginId.current = appId ?? '';
5151
});
@@ -61,9 +61,9 @@ const HomePageComponent: React.FC<HomePageProps> = ({ children }) => {
6161

6262
return (
6363
<SecuritySolutionAppWrapper>
64-
<HeaderGlobal />
64+
<HeaderGlobal ref={ref} />
6565

66-
<Main data-test-subj="pageContainer">
66+
<Main paddingTop={height} data-test-subj="pageContainer">
6767
<DragDropContextWrapper browserFields={browserFields}>
6868
<UseUrlState indexPattern={indexPattern} navTabs={navTabs} />
6969
{indicesExist && showTimeline && (

x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ export const CaseView = React.memo(({ caseId, userCanCrud }: Props) => {
402402
}
403403
if (isLoading) {
404404
return (
405-
<MyEuiFlexGroup justifyContent="center" alignItems="center">
405+
<MyEuiFlexGroup gutterSize="none" justifyContent="center" alignItems="center">
406406
<EuiFlexItem grow={false}>
407407
<EuiLoadingSpinner data-test-subj="case-view-loading" size="xl" />
408408
</EuiFlexItem>

x-pack/plugins/security_solution/public/cases/components/wrappers/index.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import { gutterTimeline } from '../../../common/lib/helpers';
1010
export const WhitePageWrapper = styled.div`
1111
background-color: ${({ theme }) => theme.eui.euiColorEmptyShade};
1212
border-top: ${({ theme }) => theme.eui.euiBorderThin};
13-
height: 100%;
14-
min-height: 100vh;
13+
flex: 1 1 auto;
1514
`;
1615

1716
export const SectionWrapper = styled.div`

x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const DEFAULT_EVENTS_VIEWER_HEIGHT = 652;
2929

3030
const FullScreenContainer = styled.div<{ $isFullScreen: boolean }>`
3131
height: ${({ $isFullScreen }) => ($isFullScreen ? '100%' : `${DEFAULT_EVENTS_VIEWER_HEIGHT}px`)};
32+
flex: 1 1 auto;
3233
display: flex;
3334
width: 100%;
3435
`;

x-pack/plugins/security_solution/public/common/components/exit_full_screen/index.tsx

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@
66

77
import { EuiButton, EuiWindowEvent } from '@elastic/eui';
88
import React, { useCallback } from 'react';
9+
import styled from 'styled-components';
910

1011
import { useFullScreen } from '../../../common/containers/use_full_screen';
1112

1213
import * as i18n from './translations';
1314

15+
const StyledEuiButton = styled(EuiButton)`
16+
margin: ${({ theme }) => theme.eui.paddingSizes.s};
17+
`;
18+
1419
export const ExitFullScreen: React.FC = () => {
1520
const { globalFullScreen, setGlobalFullScreen } = useFullScreen();
1621

@@ -36,14 +41,14 @@ export const ExitFullScreen: React.FC = () => {
3641
return (
3742
<>
3843
<EuiWindowEvent event="keydown" handler={onKeyDown} />
39-
<EuiButton
44+
<StyledEuiButton
4045
data-test-subj="exit-full-screen"
4146
iconType="fullScreen"
4247
isDisabled={!globalFullScreen}
4348
onClick={exitFullScreen}
4449
>
4550
{i18n.EXIT_FULL_SCREEN}
46-
</EuiButton>
51+
</StyledEuiButton>
4752
</>
4853
);
4954
};

x-pack/plugins/security_solution/public/common/components/header_global/index.tsx

+80-76
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui';
88
import { pickBy } from 'lodash/fp';
9-
import React, { useCallback } from 'react';
9+
import React, { forwardRef, useCallback } from 'react';
1010
import styled from 'styled-components';
1111
import { OutPortal } from 'react-reverse-portal';
1212

@@ -24,30 +24,37 @@ import { APP_ID, ADD_DATA_PATH, APP_DETECTIONS_PATH } from '../../../../common/c
2424
import { useGlobalHeaderPortal } from '../../hooks/use_global_header_portal';
2525
import { LinkAnchor } from '../links';
2626

27-
const Wrapper = styled.header<{ $globalFullScreen: boolean }>`
28-
${({ $globalFullScreen, theme }) => `
27+
const Wrapper = styled.header`
28+
${({ theme }) => `
2929
background: ${theme.eui.euiColorEmptyShade};
3030
border-bottom: ${theme.eui.euiBorderThin};
31-
padding-top: ${$globalFullScreen ? theme.eui.paddingSizes.s : theme.eui.paddingSizes.m};
3231
width: 100%;
3332
z-index: ${theme.eui.euiZNavigation};
33+
position: fixed;
3434
`}
3535
`;
3636
Wrapper.displayName = 'Wrapper';
3737

38+
const WrapperContent = styled.div<{ $globalFullScreen: boolean }>`
39+
display: ${({ $globalFullScreen }) => ($globalFullScreen ? 'none' : 'block')};
40+
padding-top: ${({ $globalFullScreen, theme }) =>
41+
$globalFullScreen ? theme.eui.paddingSizes.s : theme.eui.paddingSizes.m};
42+
`;
43+
44+
WrapperContent.displayName = 'WrapperContent';
45+
3846
const FlexItem = styled(EuiFlexItem)`
3947
min-width: 0;
4048
`;
4149
FlexItem.displayName = 'FlexItem';
4250

43-
const FlexGroup = styled(EuiFlexGroup)<{ $globalFullScreen: boolean; $hasSibling: boolean }>`
44-
${({ $globalFullScreen, $hasSibling, theme }) => `
51+
const FlexGroup = styled(EuiFlexGroup)<{ $hasSibling: boolean }>`
52+
${({ $hasSibling, theme }) => `
4553
border-bottom: ${theme.eui.euiBorderThin};
4654
margin-bottom: 1px;
4755
padding-bottom: 4px;
4856
padding-left: ${theme.eui.paddingSizes.l};
4957
padding-right: ${gutterTimeline};
50-
${$globalFullScreen ? 'display: none;' : ''}
5158
${$hasSibling ? `border-bottom: ${theme.eui.euiBorderThin};` : 'border-bottom-width: 0px;'}
5259
`}
5360
`;
@@ -56,77 +63,74 @@ FlexGroup.displayName = 'FlexGroup';
5663
interface HeaderGlobalProps {
5764
hideDetectionEngine?: boolean;
5865
}
59-
export const HeaderGlobal = React.memo<HeaderGlobalProps>(({ hideDetectionEngine = false }) => {
60-
const { globalHeaderPortalNode } = useGlobalHeaderPortal();
61-
const { globalFullScreen } = useFullScreen();
62-
const search = useGetUrlSearch(navTabs.overview);
63-
const { application, http } = useKibana().services;
64-
const { navigateToApp } = application;
65-
const basePath = http.basePath.get();
66-
const goToOverview = useCallback(
67-
(ev) => {
68-
ev.preventDefault();
69-
navigateToApp(`${APP_ID}:${SecurityPageName.overview}`, { path: search });
70-
},
71-
[navigateToApp, search]
72-
);
73-
74-
return (
75-
<Wrapper className="siemHeaderGlobal" $globalFullScreen={globalFullScreen}>
76-
<FlexGroup
77-
alignItems="center"
78-
$globalFullScreen={globalFullScreen}
79-
$hasSibling={globalHeaderPortalNode.hasChildNodes()}
80-
justifyContent="spaceBetween"
81-
wrap
82-
>
83-
<>
84-
<FlexItem>
85-
<EuiFlexGroup alignItems="center" responsive={false}>
86-
<FlexItem grow={false}>
87-
<LinkAnchor onClick={goToOverview} href={getAppOverviewUrl(search)}>
88-
<EuiIcon aria-label={i18n.SECURITY_SOLUTION} type="logoSecurity" size="l" />
89-
</LinkAnchor>
90-
</FlexItem>
66+
export const HeaderGlobal = React.memo(
67+
forwardRef<HTMLDivElement, HeaderGlobalProps>(({ hideDetectionEngine = false }, ref) => {
68+
const { globalHeaderPortalNode } = useGlobalHeaderPortal();
69+
const { globalFullScreen } = useFullScreen();
70+
const search = useGetUrlSearch(navTabs.overview);
71+
const { application, http } = useKibana().services;
72+
const { navigateToApp } = application;
73+
const basePath = http.basePath.get();
74+
const goToOverview = useCallback(
75+
(ev) => {
76+
ev.preventDefault();
77+
navigateToApp(`${APP_ID}:${SecurityPageName.overview}`, { path: search });
78+
},
79+
[navigateToApp, search]
80+
);
81+
return (
82+
<Wrapper ref={ref} className="siemHeaderGlobal">
83+
<WrapperContent $globalFullScreen={globalFullScreen}>
84+
<FlexGroup
85+
alignItems="center"
86+
$hasSibling={globalHeaderPortalNode.hasChildNodes()}
87+
justifyContent="spaceBetween"
88+
wrap
89+
>
90+
<FlexItem>
91+
<EuiFlexGroup alignItems="center" responsive={false}>
92+
<FlexItem grow={false}>
93+
<LinkAnchor onClick={goToOverview} href={getAppOverviewUrl(search)}>
94+
<EuiIcon aria-label={i18n.SECURITY_SOLUTION} type="logoSecurity" size="l" />
95+
</LinkAnchor>
96+
</FlexItem>
9197

92-
<FlexItem component="nav">
93-
<SiemNavigation
94-
display="condensed"
95-
navTabs={
96-
hideDetectionEngine
97-
? pickBy((_, key) => key !== SecurityPageName.detections, navTabs)
98-
: navTabs
99-
}
100-
/>
101-
</FlexItem>
102-
</EuiFlexGroup>
103-
</FlexItem>
98+
<FlexItem component="nav">
99+
<SiemNavigation
100+
display="condensed"
101+
navTabs={
102+
hideDetectionEngine
103+
? pickBy((_, key) => key !== SecurityPageName.detections, navTabs)
104+
: navTabs
105+
}
106+
/>
107+
</FlexItem>
108+
</EuiFlexGroup>
109+
</FlexItem>
110+
<FlexItem grow={false}>
111+
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap>
112+
{window.location.pathname.includes(APP_DETECTIONS_PATH) && (
113+
<FlexItem grow={false}>
114+
<MlPopover />
115+
</FlexItem>
116+
)}
104117

105-
<FlexItem grow={false}>
106-
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap>
107-
{window.location.pathname.includes(APP_DETECTIONS_PATH) && (
108118
<FlexItem grow={false}>
109-
<MlPopover />
119+
<EuiButtonEmpty
120+
data-test-subj="add-data"
121+
href={`${basePath}${ADD_DATA_PATH}`}
122+
iconType="plusInCircle"
123+
>
124+
{i18n.BUTTON_ADD_DATA}
125+
</EuiButtonEmpty>
110126
</FlexItem>
111-
)}
112-
113-
<FlexItem grow={false}>
114-
<EuiButtonEmpty
115-
data-test-subj="add-data"
116-
href={`${basePath}${ADD_DATA_PATH}`}
117-
iconType="plusInCircle"
118-
>
119-
{i18n.BUTTON_ADD_DATA}
120-
</EuiButtonEmpty>
121-
</FlexItem>
122-
</EuiFlexGroup>
123-
</FlexItem>
124-
</>
125-
</FlexGroup>
126-
<div>
127-
<OutPortal node={globalHeaderPortalNode} />
128-
</div>
129-
</Wrapper>
130-
);
131-
});
127+
</EuiFlexGroup>
128+
</FlexItem>
129+
</FlexGroup>
130+
<OutPortal node={globalHeaderPortalNode} />
131+
</WrapperContent>
132+
</Wrapper>
133+
);
134+
})
135+
);
132136
HeaderGlobal.displayName = 'HeaderGlobal';

0 commit comments

Comments
 (0)