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

Implement new security solution wrapper #100405

Merged
merged 48 commits into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
6bde37b
Implement new security solution wrapper
michaelolo24 May 13, 2021
7234d3b
nav changes
michaelolo24 May 25, 2021
ff22379
added ml jobs and add data to topbar
michaelolo24 May 26, 2021
4ddcdec
trying to fix/finalize styles
michaelolo24 May 27, 2021
ffb555c
got scroll working
michaelolo24 May 28, 2021
b7ebeaa
need to migrate page header and empty pages
michaelolo24 May 28, 2021
c2e1bbf
use pageHeader components
michaelolo24 May 28, 2021
51c16f4
removed temp collapse and moved nav logic
michaelolo24 Jun 1, 2021
6f5e9fd
app mount context and bug fixes
michaelolo24 Jun 2, 2021
1f3c7d3
cleanup WIP
michaelolo24 Jun 3, 2021
abdc863
cleanup wrapper page
michaelolo24 Jun 3, 2021
892d66c
cleanup wrapper page and renaming
michaelolo24 Jun 4, 2021
cfd2e63
fix background color
michaelolo24 Jun 4, 2021
5d716bf
moved files to resolve tests
michaelolo24 Jun 4, 2021
c7c602d
fix snapshot test
michaelolo24 Jun 4, 2021
c34d13d
refactor navigation a bit
michaelolo24 Jun 8, 2021
fa52c57
memoize
michaelolo24 Jun 8, 2021
10b2763
styles cleanup
michaelolo24 Jun 8, 2021
27d9fbb
additional cleanup
michaelolo24 Jun 9, 2021
5f46fee
cleanup continued
michaelolo24 Jun 9, 2021
619f34a
fix cypress test
michaelolo24 Jun 9, 2021
0228fd7
fix full screen
michaelolo24 Jun 9, 2021
c000f5a
fix bottom bar and resolver panel styles
michaelolo24 Jun 9, 2021
f12f94b
remove commented code
michaelolo24 Jun 9, 2021
f5f7f17
fix type error
michaelolo24 Jun 9, 2021
90ea02c
fix inner shadow and remove unnecessary div
michaelolo24 Jun 15, 2021
a9d786c
fix empty kql, padding, eui shadows
michaelolo24 Jun 16, 2021
63bf923
update snapshot tests
michaelolo24 Jun 16, 2021
6594561
fix fixed header, bottom of page gap,
michaelolo24 Jun 16, 2021
887c685
Merge branch 'master' into security-solution-nav-update
michaelolo24 Jun 17, 2021
1993fa1
Merge branch 'master' into security-solution-nav-update
michaelolo24 Jun 17, 2021
0a793c4
fix cypress test
michaelolo24 Jun 17, 2021
47e99dd
additional style cleanup
michaelolo24 Jun 17, 2021
7fdf8d8
Merge branch 'master' into security-solution-nav-update
michaelolo24 Jun 17, 2021
8f11d27
Change the application of some styles
Jun 17, 2021
3e89711
remove wrap
michaelolo24 Jun 17, 2021
c6ed45b
Merge branch 'security-solution-nav-update' of github.com:michaelolo2…
michaelolo24 Jun 17, 2021
6a33d8b
Merge branch 'master' into security-solution-nav-update
michaelolo24 Jun 21, 2021
7a4029c
undo url state changes
michaelolo24 Jun 21, 2021
d3a9e26
pr changes
michaelolo24 Jun 22, 2021
d1595f0
addition pr changes
michaelolo24 Jun 22, 2021
0b9a590
remove unused imports
michaelolo24 Jun 22, 2021
928eb45
Merge branch 'master' into security-solution-nav-update
michaelolo24 Jun 22, 2021
42d14d4
update cases visibility tests
michaelolo24 Jun 22, 2021
d1d992a
fix cypress test
michaelolo24 Jun 23, 2021
3815b21
remove only
michaelolo24 Jun 23, 2021
4b0847c
Merge branch 'master' into security-solution-nav-update
michaelolo24 Jun 23, 2021
f4465c0
update to use t-grid
michaelolo24 Jun 23, 2021
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
1 change: 1 addition & 0 deletions src/core/public/rendering/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
@mixin kbnAffordForHeader($headerHeight) {
@include euiHeaderAffordForFixed($headerHeight);

#securitySolutionStickyKQL,
#app-fixed-viewport {
top: $headerHeight;
}
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/cases/public/components/panel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { EuiPanel } from '@elastic/eui';
* Ref: https://www.styled-components.com/docs/faqs#why-am-i-getting-html-attribute-warnings
* Ref: https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html
*/
export const Panel = styled(({ loading, ...props }) => <EuiPanel {...props} />)`
export const Panel = styled(({ loading, ...props }) => <EuiPanel {...props} hasBorder />)`
cchaos marked this conversation as resolved.
Show resolved Hide resolved
position: relative;
${({ loading }) =>
loading &&
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/security_solution/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ export const DEFAULT_INTERVAL_VALUE = 300000; // ms
export const DEFAULT_TIMEPICKER_QUICK_RANGES = 'timepicker:quickRanges';
export const DEFAULT_TRANSFORMS = 'securitySolution:transforms';
export const SCROLLING_DISABLED_CLASS_NAME = 'scrolling-disabled';
export const GLOBAL_HEADER_HEIGHT = 98; // px
export const GLOBAL_HEADER_HEIGHT = 96; // px
export const GLOBAL_HEADER_HEIGHT_WITH_GLOBAL_BANNER = 128; // 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 @@ -129,7 +129,13 @@ describe('Alerts detection rules', () => {
});

it('Auto refreshes rules', () => {
cy.clock(Date.now());
/**
* Ran into the error: timer created with setInterval() but cleared with cancelAnimationFrame()
* There are no cancelAnimationFrames in the codebase that are used to clear a setInterval so
* explicitly set the below overrides. see https://docs.cypress.io/api/commands/clock#Function-names
*/

cy.clock(Date.now(), ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'Date']);

goToManageAlertsDetectionRules();
waitForRulesTableToBeLoaded();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
TIMELINE_DATA_PROVIDERS_ACTION_MENU,
IS_DRAGGING_DATA_PROVIDERS,
TIMELINE_FLYOUT_HEADER,
TIMELINE_BOTTOM_BAR_CONTAINER,
} from '../../screens/timeline';
import { HOSTS_NAMES_DRAGGABLE } from '../../screens/hosts/all_hosts';

Expand Down Expand Up @@ -46,7 +47,7 @@ describe('timeline data providers', () => {
it('renders the data provider of a host dragged from the All Hosts widget on the hosts page', () => {
dragAndDropFirstHostToTimeline();
openTimelineUsingToggle();
cy.get(TIMELINE_DROPPED_DATA_PROVIDERS)
cy.get(`${TIMELINE_BOTTOM_BAR_CONTAINER} ${TIMELINE_DROPPED_DATA_PROVIDERS}`)
.first()
.invoke('text')
.then((dataProviderText) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import {
TIMELINE_BOTTOM_BAR_CONTAINER,
TIMELINE_EVENT,
TIMELINE_EVENTS_COUNT_NEXT_PAGE,
TIMELINE_EVENTS_COUNT_PER_PAGE,
Expand Down Expand Up @@ -50,10 +51,10 @@ describe('Pagination', () => {

it('should be able to go to next / previous page', () => {
cy.intercept('POST', '/internal/bsearch').as('refetch');
cy.get(TIMELINE_EVENTS_COUNT_NEXT_PAGE).first().click();
cy.get(`${TIMELINE_BOTTOM_BAR_CONTAINER} ${TIMELINE_EVENTS_COUNT_NEXT_PAGE}`).first().click();
cy.wait('@refetch').its('response.statusCode').should('eq', 200);

cy.get(TIMELINE_EVENTS_COUNT_PREV_PAGE).first().click();
cy.get(`${TIMELINE_BOTTOM_BAR_CONTAINER} ${TIMELINE_EVENTS_COUNT_PREV_PAGE}`).first().click();
cy.wait('@refetch').its('response.statusCode').should('eq', 200);
});
});
2 changes: 2 additions & 0 deletions x-pack/plugins/security_solution/cypress/screens/timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export const TIMELINE_CORRELATION_TAB = '[data-test-subj="timelineTabs-eql"]';

export const IS_DRAGGING_DATA_PROVIDERS = '.is-dragging';

export const TIMELINE_BOTTOM_BAR_CONTAINER = '[data-test-subj="timeline-bottom-bar-container"]';

export const TIMELINE_DATA_PROVIDERS = '[data-test-subj="dataProviders"]';

export const TIMELINE_DATA_PROVIDERS_ACTION_MENU = '[data-test-subj="providerActions"]';
Expand Down
6 changes: 3 additions & 3 deletions x-pack/plugins/security_solution/public/app/404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';

import { WrapperPage } from '../common/components/wrapper_page';
import { SecuritySolutionPageWrapper } from '../common/components/page_wrapper';

export const NotFoundPage = React.memo(() => (
<WrapperPage>
<SecuritySolutionPageWrapper>
<FormattedMessage
id="xpack.securitySolution.pages.fourohfour.noContentFoundDescription"
defaultMessage="No content found"
/>
</WrapperPage>
</SecuritySolutionPageWrapper>
));

NotFoundPage.displayName = 'NotFoundPage';
26 changes: 22 additions & 4 deletions x-pack/plugins/security_solution/public/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Store, Action } from 'redux';
import { Provider as ReduxStoreProvider } from 'react-redux';

import { EuiErrorBoundary } from '@elastic/eui';
import { AppLeaveHandler } from '../../../../../src/core/public';
import { AppLeaveHandler, AppMountParameters } from '../../../../../src/core/public';

import { ManageUserInfo } from '../detections/components/user_info';
import { DEFAULT_DARK_MODE, APP_NAME } from '../../common/constants';
Expand All @@ -30,10 +30,17 @@ interface StartAppComponent {
children: React.ReactNode;
history: History;
onAppLeave: (handler: AppLeaveHandler) => void;
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
store: Store<State, Action>;
}

const StartAppComponent: FC<StartAppComponent> = ({ children, history, onAppLeave, store }) => {
const StartAppComponent: FC<StartAppComponent> = ({
children,
history,
setHeaderActionMenu,
onAppLeave,
store,
}) => {
const { i18n } = useKibana().services;
const [darkMode] = useUiSetting$<boolean>(DEFAULT_DARK_MODE);

Expand All @@ -46,7 +53,11 @@ const StartAppComponent: FC<StartAppComponent> = ({ children, history, onAppLeav
<MlCapabilitiesProvider>
<UserPrivilegesProvider>
<ManageUserInfo>
<PageRouter history={history} onAppLeave={onAppLeave}>
<PageRouter
history={history}
onAppLeave={onAppLeave}
setHeaderActionMenu={setHeaderActionMenu}
>
{children}
</PageRouter>
</ManageUserInfo>
Expand All @@ -69,6 +80,7 @@ interface SecurityAppComponentProps {
history: History;
onAppLeave: (handler: AppLeaveHandler) => void;
services: StartServices;
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
store: Store<State, Action>;
}

Expand All @@ -77,6 +89,7 @@ const SecurityAppComponent: React.FC<SecurityAppComponentProps> = ({
history,
onAppLeave,
services,
setHeaderActionMenu,
store,
}) => (
<KibanaContextProvider
Expand All @@ -85,7 +98,12 @@ const SecurityAppComponent: React.FC<SecurityAppComponentProps> = ({
...services,
}}
>
<StartApp history={history} onAppLeave={onAppLeave} store={store}>
<StartApp
history={history}
onAppLeave={onAppLeave}
setHeaderActionMenu={setHeaderActionMenu}
store={store}
>
{children}
</StartApp>
</KibanaContextProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 {
EuiHeaderSection,
EuiHeaderLinks,
EuiHeaderLink,
EuiHeaderSectionItem,
} from '@elastic/eui';
import React, { useEffect, useMemo } from 'react';
import { createPortalNode, OutPortal, InPortal } from 'react-reverse-portal';
import { i18n } from '@kbn/i18n';

import { AppMountParameters } from '../../../../../../../src/core/public';
import { toMountPoint } from '../../../../../../../src/plugins/kibana_react/public';
import { MlPopover } from '../../../common/components/ml_popover/ml_popover';
import { useKibana } from '../../../common/lib/kibana';
import { ADD_DATA_PATH, APP_DETECTIONS_PATH } from '../../../../common/constants';

const BUTTON_ADD_DATA = i18n.translate('xpack.securitySolution.globalHeader.buttonAddData', {
defaultMessage: 'Add data',
});

/**
* This component uses the reverse portal to add the Add Data and ML job settings buttons on the
* right hand side of the Kibana global header
*/
export const GlobalHeader = React.memo(
({ setHeaderActionMenu }: { setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'] }) => {
const portalNode = useMemo(() => createPortalNode(), []);
const { http } = useKibana().services;

useEffect(() => {
let unmount = () => {};

setHeaderActionMenu((element) => {
const mount = toMountPoint(<OutPortal node={portalNode} />);
unmount = mount(element);
return unmount;
});

return () => {
portalNode.unmount();
unmount();
};
}, [portalNode, setHeaderActionMenu]);

return (
<InPortal node={portalNode}>
<EuiHeaderSection side="right">
{window.location.pathname.includes(APP_DETECTIONS_PATH) && (
<EuiHeaderSectionItem>
<MlPopover />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible at all to change this from a popover to a flyout? It's so tall 😆
Screen Shot 2021-06-15 at 16 40 30 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lol, that's a conversation I'll need to have with the PM's. We do already have a side panel flyout component, but not sure if they'd prefer it there. Personally, I think a modal would be perfect here. 🤷🏾‍♂️

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean it can just be an EuiFlyout directly too in stead of a popover? I even think there's too much content for a modal.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for highlighting this @cchaos! 🙂 This has been on our radar for a bit but hasn't been prioritized just yet. I've created #102837 to capture this effort and for us to find a better dedicated home for the Security Solution ML Job management UI.

cc @MikePaquette, @paulewing and @yiyangliu9286

</EuiHeaderSectionItem>
)}
<EuiHeaderSectionItem>
<EuiHeaderLinks>
<EuiHeaderLink
color="primary"
data-test-subj="add-data"
href={http.basePath.prepend(ADD_DATA_PATH)}
iconType="indexOpen"
>
{BUTTON_ADD_DATA}
</EuiHeaderLink>
</EuiHeaderLinks>
</EuiHeaderSectionItem>
</EuiHeaderSection>
</InPortal>
);
}
);
GlobalHeader.displayName = 'GlobalHeader';
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import * as i18n from './translations';
import * as i18n from '../translations';
import { SecurityPageName } from '../types';
import { SiemNavTab } from '../../common/components/navigation/types';
import {
Expand Down
71 changes: 20 additions & 51 deletions x-pack/plugins/security_solution/public/app/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,35 @@
* 2.0.
*/

import React, { useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import React, { useRef } from 'react';

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 { AppLeaveHandler, AppMountParameters } from '../../../../../../src/core/public';
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';
import { UseUrlState } from '../../common/components/url_state';
import { useShowTimeline } from '../../common/utils/timeline/use_show_timeline';
import { navTabs } from './home_navigations';
import { useInitSourcerer, useSourcererScope } from '../../common/containers/sourcerer';
import { useKibana } from '../../common/lib/kibana';
import { DETECTIONS_SUB_PLUGIN_ID } from '../../../common/constants';
import { SourcererScopeName } from '../../common/store/sourcerer/model';
import { useUpgradeEndpointPackage } from '../../common/hooks/endpoint/upgrade';
import { useThrottledResizeObserver } from '../../common/components/utils';
import { AppLeaveHandler } from '../../../../../../src/core/public';

const Main = styled.main.attrs<{ paddingTop: number }>(({ paddingTop }) => ({
style: {
paddingTop: `${paddingTop}px`,
},
}))<{ paddingTop: number }>`
overflow: auto;
display: flex;
flex-direction: column;
flex: 1 1 auto;
`;

Main.displayName = 'Main';
import { GlobalHeader } from './global_header';
import { SecuritySolutionTemplateWrapper } from './template_wrapper';

interface HomePageProps {
children: React.ReactNode;
onAppLeave: (handler: AppLeaveHandler) => void;
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
}

const HomePageComponent: React.FC<HomePageProps> = ({ children, onAppLeave }) => {
const { application, overlays } = useKibana().services;
const HomePageComponent: React.FC<HomePageProps> = ({
children,
onAppLeave,
setHeaderActionMenu,
}) => {
const { application } = useKibana().services;
const subPluginId = useRef<string>('');
const { ref, height = 0 } = useThrottledResizeObserver(300);
const banners$ = overlays.banners.get$();
const [headerFixed, setHeaderFixed] = useState<boolean>(true);
const mainPaddingTop = headerFixed ? height : 0;

useEffect(() => {
const subscription = banners$.subscribe((banners) => setHeaderFixed(!banners.length));
return () => subscription.unsubscribe();
}, [banners$]); // Only un/re-subscribe if the Observable changes

application.currentAppId$.subscribe((appId) => {
subPluginId.current = appId ?? '';
Expand All @@ -66,13 +44,13 @@ const HomePageComponent: React.FC<HomePageProps> = ({ children, onAppLeave }) =>
? SourcererScopeName.detections
: SourcererScopeName.default
);
const [showTimeline] = useShowTimeline();

const { browserFields, indexPattern, indicesExist } = useSourcererScope(
const { browserFields, indexPattern } = useSourcererScope(
subPluginId.current === DETECTIONS_SUB_PLUGIN_ID
? SourcererScopeName.detections
: SourcererScopeName.default
);

// side effect: this will attempt to upgrade the endpoint package if it is not up to date
// this will run when a user navigates to the Security Solution app and when they navigate between
// tabs in the app. This is useful for keeping the endpoint package as up to date as possible until
Expand All @@ -81,23 +59,14 @@ const HomePageComponent: React.FC<HomePageProps> = ({ children, onAppLeave }) =>
useUpgradeEndpointPackage();

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

<Main paddingTop={mainPaddingTop} data-test-subj="pageContainer">
<DragDropContextWrapper browserFields={browserFields}>
<UseUrlState indexPattern={indexPattern} navTabs={navTabs} />
{indicesExist && showTimeline && (
<>
<AutoSaveWarningMsg />
<Flyout timelineId={TimelineId.active} onAppLeave={onAppLeave} />
</>
)}

<SecuritySolutionAppWrapper className="kbnAppWrapper">
<GlobalHeader setHeaderActionMenu={setHeaderActionMenu} />
<DragDropContextWrapper browserFields={browserFields}>
<UseUrlState indexPattern={indexPattern} navTabs={navTabs} />
<SecuritySolutionTemplateWrapper onAppLeave={onAppLeave}>
{children}
</DragDropContextWrapper>
</Main>

</SecuritySolutionTemplateWrapper>
</DragDropContextWrapper>
<HelpMenu />
</SecuritySolutionAppWrapper>
);
Expand Down
Loading