diff --git a/test/functional/services/common/browser.ts b/test/functional/services/common/browser.ts index c52e68581cf9f2..b0a07eeaebf358 100644 --- a/test/functional/services/common/browser.ts +++ b/test/functional/services/common/browser.ts @@ -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); diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index a93d2817fbbb3e..2910f02a187f48 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -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'; diff --git a/x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts b/x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts index d193330dc54ff4..4e2edcb282cfc4 100644 --- a/x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts @@ -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, @@ -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); diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/events.ts b/x-pack/plugins/security_solution/cypress/screens/hosts/events.ts index 05f517b5de6624..4b1ca19bd96fef 100644 --- a/x-pack/plugins/security_solution/cypress/screens/hosts/events.ts +++ b/x-pack/plugins/security_solution/cypress/screens/hosts/events.ts @@ -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"]'; diff --git a/x-pack/plugins/security_solution/public/app/home/index.tsx b/x-pack/plugins/security_solution/public/app/home/index.tsx index e0dea199e78ff4..24e25470feb3b3 100644 --- a/x-pack/plugins/security_solution/public/app/home/index.tsx +++ b/x-pack/plugins/security_solution/public/app/home/index.tsx @@ -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'; @@ -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'; @@ -45,7 +45,7 @@ interface HomePageProps { const HomePageComponent: React.FC = ({ children }) => { const { application } = useKibana().services; const subPluginId = useRef(''); - + const { ref, height = 0 } = useThrottledResizeObserver(300); application.currentAppId$.subscribe((appId) => { subPluginId.current = appId ?? ''; }); @@ -61,9 +61,9 @@ const HomePageComponent: React.FC = ({ children }) => { return ( - + -
+
{indicesExist && showTimeline && ( diff --git a/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx b/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx index ad113d3e7e7372..750ff49cd700cd 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx @@ -402,7 +402,7 @@ export const CaseView = React.memo(({ caseId, userCanCrud }: Props) => { } if (isLoading) { return ( - + diff --git a/x-pack/plugins/security_solution/public/cases/components/wrappers/index.tsx b/x-pack/plugins/security_solution/public/cases/components/wrappers/index.tsx index 06715514e01bf6..b89a7e8eefec32 100644 --- a/x-pack/plugins/security_solution/public/cases/components/wrappers/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/wrappers/index.tsx @@ -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` diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx index cd43c7e4930657..c53d311dc1361c 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -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%; `; diff --git a/x-pack/plugins/security_solution/public/common/components/exit_full_screen/index.tsx b/x-pack/plugins/security_solution/public/common/components/exit_full_screen/index.tsx index 8c5ad95a8de0e9..cd4740bc8c4649 100644 --- a/x-pack/plugins/security_solution/public/common/components/exit_full_screen/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exit_full_screen/index.tsx @@ -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(); @@ -36,14 +41,14 @@ export const ExitFullScreen: React.FC = () => { return ( <> - {i18n.EXIT_FULL_SCREEN} - + ); }; diff --git a/x-pack/plugins/security_solution/public/common/components/header_global/index.tsx b/x-pack/plugins/security_solution/public/common/components/header_global/index.tsx index 5b4dd2e9728bba..0c6a54d4434d21 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_global/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_global/index.tsx @@ -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'; @@ -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;'} `} `; @@ -56,77 +63,74 @@ FlexGroup.displayName = 'FlexGroup'; interface HeaderGlobalProps { hideDetectionEngine?: boolean; } -export const HeaderGlobal = React.memo(({ 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 ( - - - <> - - - - - - - +export const HeaderGlobal = React.memo( + forwardRef(({ 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 ( + + + + + + + + + + - - key !== SecurityPageName.detections, navTabs) - : navTabs - } - /> - - - + + key !== SecurityPageName.detections, navTabs) + : navTabs + } + /> + + + + + + {window.location.pathname.includes(APP_DETECTIONS_PATH) && ( + + + + )} - - - {window.location.pathname.includes(APP_DETECTIONS_PATH) && ( - + + {i18n.BUTTON_ADD_DATA} + - )} - - - - {i18n.BUTTON_ADD_DATA} - - - - - - -
- -
-
- ); -}); + + + + + + + ); + }) +); HeaderGlobal.displayName = 'HeaderGlobal'; diff --git a/x-pack/plugins/security_solution/public/common/components/page/index.tsx b/x-pack/plugins/security_solution/public/common/components/page/index.tsx index 140429dc4abd78..8a8eda3e20185f 100644 --- a/x-pack/plugins/security_solution/public/common/components/page/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/page/index.tsx @@ -8,27 +8,36 @@ import { EuiBadge, EuiDescriptionList, EuiFlexGroup, EuiIcon, EuiPage } from '@e import styled, { createGlobalStyle } from 'styled-components'; import { + GLOBAL_HEADER_HEIGHT, FULL_SCREEN_TOGGLED_CLASS_NAME, SCROLLING_DISABLED_CLASS_NAME, } from '../../../../common/constants'; +export const SecuritySolutionAppWrapper = styled.div` + display: flex; + flex-direction: column; + flex: 1 1 auto; + width: 100%; +`; +SecuritySolutionAppWrapper.displayName = 'SecuritySolutionAppWrapper'; + /* SIDE EFFECT: the following `createGlobalStyle` overrides default styling in angular code that was not theme-friendly and `EuiPopover`, `EuiToolTip` global styles */ export const AppGlobalStyle = createGlobalStyle<{ theme: { eui: { euiColorPrimary: string } } }>` - /* dirty hack to fix draggables with tooltip on FF */ - body#siem-app { - position: static; - } - /* end of dirty hack to fix draggables with tooltip on FF */ - div.app-wrapper { background-color: rgba(0,0,0,0); } div.application { background-color: rgba(0,0,0,0); + + // Security App wrapper + > div { + display: flex; + flex: 1 1 auto; + } } .euiPopover__panel.euiPopover__panel-isOpen { @@ -67,37 +76,8 @@ export const AppGlobalStyle = createGlobalStyle<{ theme: { eui: { euiColorPrimar ${({ theme }) => `background-color: ${theme.eui.euiColorPrimary} !important`}; } - body { - overflow-y: hidden; - } - - #kibana-body { - height: 100%; - overflow-y: hidden; - - > .content { - height: 100%; - - > .app-wrapper { - height: 100%; - - > .app-wrapper-panel { - height: 100%; - - > .application { - height: 100%; - - > div { - height: 100%; - } - } - } - } - } - } - - .${SCROLLING_DISABLED_CLASS_NAME} #kibana-body { - overflow-y: hidden; + .${SCROLLING_DISABLED_CLASS_NAME} ${SecuritySolutionAppWrapper} { + max-height: calc(100vh - ${GLOBAL_HEADER_HEIGHT}px); } `; diff --git a/x-pack/plugins/security_solution/public/common/components/wrapper_page/index.tsx b/x-pack/plugins/security_solution/public/common/components/wrapper_page/index.tsx index f3136b0a40b3e4..0908c887d25f6e 100644 --- a/x-pack/plugins/security_solution/public/common/components/wrapper_page/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/wrapper_page/index.tsx @@ -28,6 +28,9 @@ const Wrapper = styled.div` &.siemWrapperPage--fullHeight { height: 100%; + display: flex; + flex-direction: column; + flex: 1 1 auto; } &.siemWrapperPage--withTimeline { @@ -36,6 +39,9 @@ const Wrapper = styled.div` &.siemWrapperPage--noPadding { padding: 0; + display: flex; + flex-direction: column; + flex: 1 1 auto; } `; diff --git a/x-pack/test/security_solution_endpoint/page_objects/policy_page.ts b/x-pack/test/security_solution_endpoint/page_objects/policy_page.ts index d661b3097bd354..92571e5c275665 100644 --- a/x-pack/test/security_solution_endpoint/page_objects/policy_page.ts +++ b/x-pack/test/security_solution_endpoint/page_objects/policy_page.ts @@ -9,6 +9,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export function EndpointPolicyPageProvider({ getService, getPageObjects }: FtrProviderContext) { const pageObjects = getPageObjects(['common', 'header']); const testSubjects = getService('testSubjects'); + const browser = getService('browser'); return { /** @@ -88,6 +89,7 @@ export function EndpointPolicyPageProvider({ getService, getPageObjects }: FtrPr */ async confirmAndSave() { await this.ensureIsOnDetailsPage(); + await browser.scrollTop(); await (await this.findSaveButton()).click(); await testSubjects.existOrFail('policyDetailsConfirmModal'); await pageObjects.common.clickConfirmOnModal();