From f654e06f766394f5371dba10822f6f8f4cc40ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopyci=C5=84ski?= Date: Mon, 4 Jan 2021 13:53:23 +0100 Subject: [PATCH] [Security Solution] Fix few styling issues (#87045) --- .../components/event_details/columns.tsx | 21 +- .../plugins/timeline/plugin.tsx | 43 ++-- .../components/matrix_histogram/index.tsx | 2 +- .../components/fields_browser/header.tsx | 1 + .../selectable_timeline/index.test.tsx | 15 +- .../timeline/selectable_timeline/index.tsx | 184 +++++++----------- .../factory/hosts/overview/__mocks__/index.ts | 2 +- .../factory/hosts/overview/index.ts | 2 +- .../apis/security_solution/overview_host.ts | 2 +- 9 files changed, 130 insertions(+), 142 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx index 6bc3a4904e031d..fa0684e5593bf8 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx @@ -51,6 +51,14 @@ const HoverActionsContainer = styled(EuiPanel)` HoverActionsContainer.displayName = 'HoverActionsContainer'; +const FullWidthFlexGroup = styled(EuiFlexGroup)` + width: 100%; +`; + +const FullWidthFlexItem = styled(EuiFlexItem)` + width: 100%; +`; + export const getColumns = ({ browserFields, columnHeaders, @@ -159,10 +167,15 @@ export const getColumns = ({ sortable: true, truncateText: false, render: (values: ToStringArray | null | undefined, data: EventFieldsData) => ( - + {values != null && values.map((value, i) => ( - )} - + ))} - + ), }, { diff --git a/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/timeline/plugin.tsx b/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/timeline/plugin.tsx index 8d2488b269d76e..4b03e7e0d32c4a 100644 --- a/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/timeline/plugin.tsx +++ b/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/timeline/plugin.tsx @@ -8,6 +8,7 @@ import React, { useCallback, memo } from 'react'; import { EuiSelectableOption, EuiModalBody, + EuiModalHeader, EuiMarkdownEditorUiPlugin, EuiCodeBlock, } from '@elastic/eui'; @@ -47,24 +48,32 @@ const TimelineEditorComponent: React.FC = ({ onClosePopover [] ); + const handleTimelineChange = useCallback( + (timelineTitle, timelineId, graphEventId) => { + const url = formatUrl(getTimelineUrl(timelineId ?? '', graphEventId), { + absolute: true, + skipSearch: true, + }); + onInsert(`[${timelineTitle}](${url})`, { + block: false, + }); + }, + [formatUrl, onInsert] + ); + return ( - - { - const url = formatUrl(getTimelineUrl(timelineId ?? '', graphEventId), { - absolute: true, - skipSearch: true, - }); - onInsert(`[${timelineTitle}](${url})`, { - block: false, - }); - }} - onClosePopover={onClosePopover} - timelineType={TimelineType.default} - /> - + <> + + + + + ); }; diff --git a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx index 5f567508a40116..e71cf054c87b4f 100644 --- a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx @@ -58,7 +58,7 @@ const HeaderChildrenFlexItem = styled(EuiFlexItem)` const HistogramPanel = styled(Panel)<{ height?: number }>` display: flex; flex-direction: column; - ${({ height }) => (height != null ? `height: ${height}px;` : '')} + ${({ height }) => (height != null ? `min-height: ${height}px;` : '')} `; export const MatrixHistogramComponent: React.FC = ({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/fields_browser/header.tsx b/x-pack/plugins/security_solution/public/timelines/components/fields_browser/header.tsx index 8ab099ab78ee9e..6fd24ebca7c827 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/fields_browser/header.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/fields_browser/header.tsx @@ -156,6 +156,7 @@ export const Header = React.memo( onChange={onSearchInputChange} placeholder={i18n.FILTER_PLACEHOLDER} value={searchInput} + fullWidth /> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/selectable_timeline/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/selectable_timeline/index.test.tsx index 519372d0ac7975..6e31b822e73c2e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/selectable_timeline/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/selectable_timeline/index.test.tsx @@ -3,11 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +import { EuiSelectableProps } from '@elastic/eui'; import React from 'react'; import { shallow, ShallowWrapper, mount } from 'enzyme'; + import { TimelineType } from '../../../../../common/types/timeline'; import { SortFieldTimeline, Direction } from '../../../../graphql/types'; -import { SelectableTimeline, ORIGINAL_PAGE_SIZE, SearchProps } from './'; +import { SelectableTimeline, ORIGINAL_PAGE_SIZE } from './'; const mockFetchAllTimeline = jest.fn(); jest.mock('../../../containers/all', () => { @@ -40,10 +43,10 @@ describe('SelectableTimeline', () => { }); test('render placeholder', () => { - const searchProps: SearchProps = wrapper + const searchProps: EuiSelectableProps['searchProps'] = wrapper .find('[data-test-subj="selectable-input"]') .prop('searchProps'); - expect(searchProps.placeholder).toEqual('e.g. Timeline name or description'); + expect(searchProps!.placeholder).toEqual('e.g. Timeline name or description'); }); }); @@ -58,10 +61,10 @@ describe('SelectableTimeline', () => { }); test('render placeholder', () => { - const searchProps: SearchProps = wrapper + const searchProps: EuiSelectableProps['searchProps'] = wrapper .find('[data-test-subj="selectable-input"]') .prop('searchProps'); - expect(searchProps.placeholder).toEqual('e.g. Timeline template name or description'); + expect(searchProps!.placeholder).toEqual('e.g. Timeline template name or description'); }); }); }); @@ -89,7 +92,7 @@ describe('SelectableTimeline', () => { jest.clearAllMocks(); }); - test('shoule be called with correct args', () => { + test('should be called with correct args', () => { expect(mockFetchAllTimeline).toBeCalledWith(args); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/selectable_timeline/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/selectable_timeline/index.tsx index a80576c7237f4d..7dbc4a17f4b3bf 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/selectable_timeline/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/selectable_timeline/index.tsx @@ -12,8 +12,7 @@ import { EuiIcon, EuiTextColor, EuiSelectableOption, - EuiPortal, - EuiFilterGroup, + EuiSelectableProps, EuiFilterButton, } from '@elastic/eui'; import { isEmpty, debounce } from 'lodash/fp'; @@ -41,30 +40,9 @@ const MyEuiFlexItem = styled(EuiFlexItem)` white-space: nowrap; `; -const MyEuiFlexGroup = styled(EuiFlexGroup)` - padding 0px 4px; -`; - -const EuiSelectableContainer = styled.div<{ isLoading: boolean }>` - .euiSelectable { - .euiFormControlLayout__childrenWrapper { - display: flex; - } - ${({ isLoading }) => `${ - isLoading - ? ` - .euiFormControlLayoutIcons { - display: none; - } - .euiFormControlLayoutIcons.euiFormControlLayoutIcons--right { - display: block; - left: 12px; - top: 12px; - }` - : '' - } - `} - } +const StyledEuiFilterButton = styled(EuiFilterButton)` + border-top: 0; + border-bottom: 0; `; export const ORIGINAL_PAGE_SIZE = 50; @@ -95,15 +73,6 @@ export interface SelectableTimelineProps { timelineType: TimelineTypeLiteral; } -export interface SearchProps { - 'data-test-subj'?: string; - isLoading: boolean; - placeholder: string; - onSearch: (arg: string) => void; - incremental: boolean; - inputRef: (arg: HTMLInputElement | null) => void; -} - const SelectableTimelineComponent: React.FC = ({ hideUntitled = false, getSelectableOptions, @@ -115,7 +84,6 @@ const SelectableTimelineComponent: React.FC = ({ const [heightTrigger, setHeightTrigger] = useState(0); const [searchTimelineValue, setSearchTimelineValue] = useState(''); const [onlyFavorites, setOnlyFavorites] = useState(false); - const [searchRef, setSearchRef] = useState(null); const { fetchAllTimeline, timelines, loading, totalCount: timelineCount } = useGetAllTimeline(); const selectableListOuterRef = useRef(null); const selectableListInnerRef = useRef(null); @@ -156,8 +124,8 @@ const SelectableTimelineComponent: React.FC = ({ [heightTrigger, pageSize] ); - const renderTimelineOption = useCallback((option, searchValue) => { - return ( + const renderTimelineOption = useCallback( + (option, searchValue) => ( = ({ /> - ); - }, []); + ), + [] + ); const handleTimelineChange = useCallback( (options) => { @@ -215,39 +184,53 @@ const SelectableTimelineComponent: React.FC = ({ [onClosePopover, onTimelineChange] ); - const favoritePortal = useMemo( - () => - searchRef != null ? ( - - - - - - {i18nTimeline.ONLY_FAVORITES} - - - - - - ) : null, - [searchRef, onlyFavorites, handleOnToggleOnlyFavorites] + const EuiSelectableContent = useCallback( + (list, search) => ( + <> + {search} + {list} + + ), + [] ); - const searchProps: SearchProps = { - 'data-test-subj': 'timeline-super-select-search-box', - isLoading: loading, - placeholder: useMemo(() => i18n.SEARCH_BOX_TIMELINE_PLACEHOLDER(timelineType), [timelineType]), - onSearch: onSearchTimeline, - incremental: true, - inputRef: (node: HTMLInputElement | null) => { - setSearchRef(node); - }, - }; + const searchProps: EuiSelectableProps['searchProps'] = useMemo( + () => ({ + 'data-test-subj': 'timeline-super-select-search-box', + placeholder: i18n.SEARCH_BOX_TIMELINE_PLACEHOLDER(timelineType), + onSearch: onSearchTimeline, + incremental: true, + append: ( + + {i18nTimeline.ONLY_FAVORITES} + + ), + }), + [handleOnToggleOnlyFavorites, onSearchTimeline, onlyFavorites, timelineType] + ); + + const listProps: EuiSelectableProps['listProps'] = useMemo( + () => ({ + rowHeight: TIMELINE_ITEM_HEIGHT, + showIcons: false, + windowProps: { + onScroll: ({ scrollOffset }) => + handleOnScroll( + timelines.filter((t) => !hideUntitled || t.title !== '').length, + timelineCount, + scrollOffset + ), + outerRef: selectableListOuterRef, + innerRef: selectableListInnerRef, + }, + }), + [handleOnScroll, hideUntitled, timelineCount, timelines] + ); useEffect(() => { fetchAllTimeline({ @@ -267,46 +250,25 @@ const SelectableTimelineComponent: React.FC = ({ }, [fetchAllTimeline, onlyFavorites, pageSize, searchTimelineValue, timelineType]); return ( - - - handleOnScroll( - timelines.filter((t) => !hideUntitled || t.title !== '').length, - timelineCount, - scrollOffset - ), - outerRef: selectableListOuterRef, - innerRef: selectableListInnerRef, - }, - }} - renderOption={renderTimelineOption} - onChange={handleTimelineChange} - searchable - searchProps={searchProps} - singleSelection={true} - options={getSelectableOptions({ - timelines, - onlyFavorites, - searchTimelineValue, - timelineType, - })} - > - {(list, search) => ( - <> - {search} - {favoritePortal} - {list} - - )} - - + + {EuiSelectableContent} + ); }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/overview/__mocks__/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/overview/__mocks__/index.ts index b1f9b04daa1c10..574be4b45fe267 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/overview/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/overview/__mocks__/index.ts @@ -322,7 +322,7 @@ export const formattedSearchStrategyResponse = { endgameSecurity: 0, filebeatSystemModule: 1793, winlogbeatSecurity: 42, - winlogbeatMWSysmonOperational: null, + winlogbeatMWSysmonOperational: 1781, }, }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/overview/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/overview/index.ts index 61c228a5fd164d..4a9d4c7af103cb 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/overview/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/overview/index.ts @@ -58,7 +58,7 @@ export const hostOverview: SecuritySolutionFactory = { winlogbeatMWSysmonOperational: getOr( null, 'winlog_module.mwsysmon_operational_event_count.doc_count', - response + aggregations ), }, }; diff --git a/x-pack/test/api_integration/apis/security_solution/overview_host.ts b/x-pack/test/api_integration/apis/security_solution/overview_host.ts index f3de9a6481b8f3..6077332b3a6524 100644 --- a/x-pack/test/api_integration/apis/security_solution/overview_host.ts +++ b/x-pack/test/api_integration/apis/security_solution/overview_host.ts @@ -36,7 +36,7 @@ export default function ({ getService }: FtrProviderContext) { endgameSecurity: 4, filebeatSystemModule: 0, winlogbeatSecurity: 0, - winlogbeatMWSysmonOperational: null, + winlogbeatMWSysmonOperational: 0, }; it('Make sure that we get OverviewHost data', async () => {