Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] [Security Solution] Fix app layout (#76668) #78532

Merged
Merged
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
4 changes: 4 additions & 0 deletions test/functional/services/common/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,10 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
return parseInt(scrollSize, 10);
}

public async scrollTop() {
await driver.executeScript('document.documentElement.scrollTop = 0');
}

// return promise with REAL scroll position
public async setScrollTop(scrollSize: number | string) {
await driver.executeScript('document.body.scrollTop = ' + scrollSize);
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/security_solution/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const DEFAULT_INTERVAL_TYPE = 'manual';
export const DEFAULT_INTERVAL_VALUE = 300000; // ms
export const DEFAULT_TIMEPICKER_QUICK_RANGES = 'timepicker:quickRanges';
export const SCROLLING_DISABLED_CLASS_NAME = 'scrolling-disabled';
export const GLOBAL_HEADER_HEIGHT = 98; // px
export const FILTERS_GLOBAL_HEIGHT = 109; // px
export const FULL_SCREEN_TOGGLED_CLASS_NAME = 'fullScreenToggled';
export const NO_ALERT_INDEX = 'no-alert-index-049FC71A-4C2C-446F-9901-37XMC5024C51';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
FIELDS_BROWSER_SELECTED_CATEGORY_TITLE,
} from '../screens/fields_browser';
import {
EVENTS_PAGE,
HEADER_SUBTITLE,
HOST_GEO_CITY_NAME_HEADER,
HOST_GEO_COUNTRY_NAME_HEADER,
Expand Down Expand Up @@ -173,7 +172,7 @@ describe.skip('Events Viewer', () => {
const expectedOrderAfterDragAndDrop =
'message@timestamphost.nameevent.moduleevent.datasetevent.actionuser.namesource.ipdestination.ip';

cy.get(EVENTS_PAGE).scrollTo('bottom');
cy.scrollTo('bottom');
cy.get(HEADERS_GROUP).invoke('text').should('equal', originalColumnOrder);
dragAndDropColumn({ column: 0, newPosition: 1 });
cy.get(HEADERS_GROUP).invoke('text').should('equal', expectedOrderAfterDragAndDrop);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

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

export const EVENTS_PAGE = '[data-test-subj="pageContainer"]';

export const EVENTS_VIEWER_FIELDS_BUTTON =
'[data-test-subj="events-viewer-panel"] [data-test-subj="show-field-browser"]';

Expand Down
24 changes: 12 additions & 12 deletions x-pack/plugins/security_solution/public/app/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import styled from 'styled-components';
import { TimelineId } from '../../../common/types/timeline';
import { DragDropContextWrapper } from '../../common/components/drag_and_drop/drag_drop_context_wrapper';
import { Flyout } from '../../timelines/components/flyout';
import { SecuritySolutionAppWrapper } from '../../common/components/page';
import { HeaderGlobal } from '../../common/components/header_global';
import { HelpMenu } from '../../common/components/help_menu';
import { AutoSaveWarningMsg } from '../../timelines/components/timeline/auto_save_warning';
Expand All @@ -20,18 +21,17 @@ import { useInitSourcerer, useSourcererScope } from '../../common/containers/sou
import { useKibana } from '../../common/lib/kibana';
import { DETECTIONS_SUB_PLUGIN_ID } from '../../../common/constants';
import { SourcererScopeName } from '../../common/store/sourcerer/model';
import { useThrottledResizeObserver } from '../../common/components/utils';

const SecuritySolutionAppWrapper = styled.div`
const Main = styled.main.attrs<{ paddingTop: number }>(({ paddingTop }) => ({
style: {
paddingTop: `${paddingTop}px`,
},
}))<{ paddingTop: number }>`
overflow: auto;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
`;
SecuritySolutionAppWrapper.displayName = 'SecuritySolutionAppWrapper';

const Main = styled.main`
overflow: auto;
flex: 1;
flex: 1 1 auto;
`;

Main.displayName = 'Main';
Expand All @@ -45,7 +45,7 @@ interface HomePageProps {
const HomePageComponent: React.FC<HomePageProps> = ({ children }) => {
const { application } = useKibana().services;
const subPluginId = useRef<string>('');

const { ref, height = 0 } = useThrottledResizeObserver(300);
application.currentAppId$.subscribe((appId) => {
subPluginId.current = appId ?? '';
});
Expand All @@ -61,9 +61,9 @@ const HomePageComponent: React.FC<HomePageProps> = ({ children }) => {

return (
<SecuritySolutionAppWrapper>
<HeaderGlobal />
<HeaderGlobal ref={ref} />

<Main data-test-subj="pageContainer">
<Main paddingTop={height} data-test-subj="pageContainer">
<DragDropContextWrapper browserFields={browserFields}>
<UseUrlState indexPattern={indexPattern} navTabs={navTabs} />
{indicesExist && showTimeline && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ export const CaseView = React.memo(({ caseId, userCanCrud }: Props) => {
}
if (isLoading) {
return (
<MyEuiFlexGroup justifyContent="center" alignItems="center">
<MyEuiFlexGroup gutterSize="none" justifyContent="center" alignItems="center">
<EuiFlexItem grow={false}>
<EuiLoadingSpinner data-test-subj="case-view-loading" size="xl" />
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import { gutterTimeline } from '../../../common/lib/helpers';
export const WhitePageWrapper = styled.div`
background-color: ${({ theme }) => theme.eui.euiColorEmptyShade};
border-top: ${({ theme }) => theme.eui.euiBorderThin};
height: 100%;
min-height: 100vh;
flex: 1 1 auto;
`;

export const SectionWrapper = styled.div`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const DEFAULT_EVENTS_VIEWER_HEIGHT = 652;

const FullScreenContainer = styled.div<{ $isFullScreen: boolean }>`
height: ${({ $isFullScreen }) => ($isFullScreen ? '100%' : `${DEFAULT_EVENTS_VIEWER_HEIGHT}px`)};
flex: 1 1 auto;
display: flex;
width: 100%;
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@

import { EuiButton, EuiWindowEvent } from '@elastic/eui';
import React, { useCallback } from 'react';
import styled from 'styled-components';

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

import * as i18n from './translations';

const StyledEuiButton = styled(EuiButton)`
margin: ${({ theme }) => theme.eui.paddingSizes.s};
`;

export const ExitFullScreen: React.FC = () => {
const { globalFullScreen, setGlobalFullScreen } = useFullScreen();

Expand All @@ -36,14 +41,14 @@ export const ExitFullScreen: React.FC = () => {
return (
<>
<EuiWindowEvent event="keydown" handler={onKeyDown} />
<EuiButton
<StyledEuiButton
data-test-subj="exit-full-screen"
iconType="fullScreen"
isDisabled={!globalFullScreen}
onClick={exitFullScreen}
>
{i18n.EXIT_FULL_SCREEN}
</EuiButton>
</StyledEuiButton>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

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

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

const Wrapper = styled.header<{ $globalFullScreen: boolean }>`
${({ $globalFullScreen, theme }) => `
const Wrapper = styled.header`
${({ theme }) => `
background: ${theme.eui.euiColorEmptyShade};
border-bottom: ${theme.eui.euiBorderThin};
padding-top: ${$globalFullScreen ? theme.eui.paddingSizes.s : theme.eui.paddingSizes.m};
width: 100%;
z-index: ${theme.eui.euiZNavigation};
position: fixed;
`}
`;
Wrapper.displayName = 'Wrapper';

const WrapperContent = styled.div<{ $globalFullScreen: boolean }>`
display: ${({ $globalFullScreen }) => ($globalFullScreen ? 'none' : 'block')};
padding-top: ${({ $globalFullScreen, theme }) =>
$globalFullScreen ? theme.eui.paddingSizes.s : theme.eui.paddingSizes.m};
`;

WrapperContent.displayName = 'WrapperContent';

const FlexItem = styled(EuiFlexItem)`
min-width: 0;
`;
FlexItem.displayName = 'FlexItem';

const FlexGroup = styled(EuiFlexGroup)<{ $globalFullScreen: boolean; $hasSibling: boolean }>`
${({ $globalFullScreen, $hasSibling, theme }) => `
const FlexGroup = styled(EuiFlexGroup)<{ $hasSibling: boolean }>`
${({ $hasSibling, theme }) => `
border-bottom: ${theme.eui.euiBorderThin};
margin-bottom: 1px;
padding-bottom: 4px;
padding-left: ${theme.eui.paddingSizes.l};
padding-right: ${gutterTimeline};
${$globalFullScreen ? 'display: none;' : ''}
${$hasSibling ? `border-bottom: ${theme.eui.euiBorderThin};` : 'border-bottom-width: 0px;'}
`}
`;
Expand All @@ -56,77 +63,74 @@ FlexGroup.displayName = 'FlexGroup';
interface HeaderGlobalProps {
hideDetectionEngine?: boolean;
}
export const HeaderGlobal = React.memo<HeaderGlobalProps>(({ hideDetectionEngine = false }) => {
const { globalHeaderPortalNode } = useGlobalHeaderPortal();
const { globalFullScreen } = useFullScreen();
const search = useGetUrlSearch(navTabs.overview);
const { application, http } = useKibana().services;
const { navigateToApp } = application;
const basePath = http.basePath.get();
const goToOverview = useCallback(
(ev) => {
ev.preventDefault();
navigateToApp(`${APP_ID}:${SecurityPageName.overview}`, { path: search });
},
[navigateToApp, search]
);

return (
<Wrapper className="siemHeaderGlobal" $globalFullScreen={globalFullScreen}>
<FlexGroup
alignItems="center"
$globalFullScreen={globalFullScreen}
$hasSibling={globalHeaderPortalNode.hasChildNodes()}
justifyContent="spaceBetween"
wrap
>
<>
<FlexItem>
<EuiFlexGroup alignItems="center" responsive={false}>
<FlexItem grow={false}>
<LinkAnchor onClick={goToOverview} href={getAppOverviewUrl(search)}>
<EuiIcon aria-label={i18n.SECURITY_SOLUTION} type="logoSecurity" size="l" />
</LinkAnchor>
</FlexItem>
export const HeaderGlobal = React.memo(
forwardRef<HTMLDivElement, HeaderGlobalProps>(({ hideDetectionEngine = false }, ref) => {
const { globalHeaderPortalNode } = useGlobalHeaderPortal();
const { globalFullScreen } = useFullScreen();
const search = useGetUrlSearch(navTabs.overview);
const { application, http } = useKibana().services;
const { navigateToApp } = application;
const basePath = http.basePath.get();
const goToOverview = useCallback(
(ev) => {
ev.preventDefault();
navigateToApp(`${APP_ID}:${SecurityPageName.overview}`, { path: search });
},
[navigateToApp, search]
);
return (
<Wrapper ref={ref} className="siemHeaderGlobal">
<WrapperContent $globalFullScreen={globalFullScreen}>
<FlexGroup
alignItems="center"
$hasSibling={globalHeaderPortalNode.hasChildNodes()}
justifyContent="spaceBetween"
wrap
>
<FlexItem>
<EuiFlexGroup alignItems="center" responsive={false}>
<FlexItem grow={false}>
<LinkAnchor onClick={goToOverview} href={getAppOverviewUrl(search)}>
<EuiIcon aria-label={i18n.SECURITY_SOLUTION} type="logoSecurity" size="l" />
</LinkAnchor>
</FlexItem>

<FlexItem component="nav">
<SiemNavigation
display="condensed"
navTabs={
hideDetectionEngine
? pickBy((_, key) => key !== SecurityPageName.detections, navTabs)
: navTabs
}
/>
</FlexItem>
</EuiFlexGroup>
</FlexItem>
<FlexItem component="nav">
<SiemNavigation
display="condensed"
navTabs={
hideDetectionEngine
? pickBy((_, key) => key !== SecurityPageName.detections, navTabs)
: navTabs
}
/>
</FlexItem>
</EuiFlexGroup>
</FlexItem>
<FlexItem grow={false}>
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap>
{window.location.pathname.includes(APP_DETECTIONS_PATH) && (
<FlexItem grow={false}>
<MlPopover />
</FlexItem>
)}

<FlexItem grow={false}>
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap>
{window.location.pathname.includes(APP_DETECTIONS_PATH) && (
<FlexItem grow={false}>
<MlPopover />
<EuiButtonEmpty
data-test-subj="add-data"
href={`${basePath}${ADD_DATA_PATH}`}
iconType="plusInCircle"
>
{i18n.BUTTON_ADD_DATA}
</EuiButtonEmpty>
</FlexItem>
)}

<FlexItem grow={false}>
<EuiButtonEmpty
data-test-subj="add-data"
href={`${basePath}${ADD_DATA_PATH}`}
iconType="plusInCircle"
>
{i18n.BUTTON_ADD_DATA}
</EuiButtonEmpty>
</FlexItem>
</EuiFlexGroup>
</FlexItem>
</>
</FlexGroup>
<div>
<OutPortal node={globalHeaderPortalNode} />
</div>
</Wrapper>
);
});
</EuiFlexGroup>
</FlexItem>
</FlexGroup>
<OutPortal node={globalHeaderPortalNode} />
</WrapperContent>
</Wrapper>
);
})
);
HeaderGlobal.displayName = 'HeaderGlobal';
Loading