mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution] Fix few styling issues (#87045)
This commit is contained in:
parent
cd06251fc4
commit
f654e06f76
9 changed files with 130 additions and 142 deletions
|
@ -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) => (
|
||||
<EuiFlexGroup direction="column" alignItems="flexStart" component="span" gutterSize="none">
|
||||
<FullWidthFlexGroup
|
||||
direction="column"
|
||||
alignItems="flexStart"
|
||||
component="span"
|
||||
gutterSize="none"
|
||||
>
|
||||
{values != null &&
|
||||
values.map((value, i) => (
|
||||
<EuiFlexItem
|
||||
<FullWidthFlexItem
|
||||
grow={false}
|
||||
component="span"
|
||||
key={`event-details-value-flex-item-${contextId}-${eventId}-${data.field}-${i}-${value}`}
|
||||
|
@ -182,9 +195,9 @@ export const getColumns = ({
|
|||
/>
|
||||
)}
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
</FullWidthFlexItem>
|
||||
))}
|
||||
</EuiFlexGroup>
|
||||
</FullWidthFlexGroup>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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<TimelineEditorProps> = ({ 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 (
|
||||
<EuiModalBody>
|
||||
<SelectableTimeline
|
||||
hideUntitled={true}
|
||||
getSelectableOptions={handleGetSelectableOptions}
|
||||
onTimelineChange={(timelineTitle, timelineId, graphEventId) => {
|
||||
const url = formatUrl(getTimelineUrl(timelineId ?? '', graphEventId), {
|
||||
absolute: true,
|
||||
skipSearch: true,
|
||||
});
|
||||
onInsert(`[${timelineTitle}](${url})`, {
|
||||
block: false,
|
||||
});
|
||||
}}
|
||||
onClosePopover={onClosePopover}
|
||||
timelineType={TimelineType.default}
|
||||
/>
|
||||
</EuiModalBody>
|
||||
<>
|
||||
<EuiModalHeader />
|
||||
<EuiModalBody>
|
||||
<SelectableTimeline
|
||||
hideUntitled={true}
|
||||
getSelectableOptions={handleGetSelectableOptions}
|
||||
onTimelineChange={handleTimelineChange}
|
||||
onClosePopover={onClosePopover}
|
||||
timelineType={TimelineType.default}
|
||||
/>
|
||||
</EuiModalBody>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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<MatrixHistogramComponentProps> = ({
|
||||
|
|
|
@ -156,6 +156,7 @@ export const Header = React.memo<Props>(
|
|||
onChange={onSearchInputChange}
|
||||
placeholder={i18n.FILTER_PLACEHOLDER}
|
||||
value={searchInput}
|
||||
fullWidth
|
||||
/>
|
||||
</SearchContainer>
|
||||
<CountRow filteredBrowserFields={filteredBrowserFields} />
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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<SelectableTimelineProps> = ({
|
||||
hideUntitled = false,
|
||||
getSelectableOptions,
|
||||
|
@ -115,7 +84,6 @@ const SelectableTimelineComponent: React.FC<SelectableTimelineProps> = ({
|
|||
const [heightTrigger, setHeightTrigger] = useState(0);
|
||||
const [searchTimelineValue, setSearchTimelineValue] = useState<string>('');
|
||||
const [onlyFavorites, setOnlyFavorites] = useState(false);
|
||||
const [searchRef, setSearchRef] = useState<HTMLInputElement | null>(null);
|
||||
const { fetchAllTimeline, timelines, loading, totalCount: timelineCount } = useGetAllTimeline();
|
||||
const selectableListOuterRef = useRef<HTMLDivElement | null>(null);
|
||||
const selectableListInnerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
@ -156,8 +124,8 @@ const SelectableTimelineComponent: React.FC<SelectableTimelineProps> = ({
|
|||
[heightTrigger, pageSize]
|
||||
);
|
||||
|
||||
const renderTimelineOption = useCallback((option, searchValue) => {
|
||||
return (
|
||||
const renderTimelineOption = useCallback(
|
||||
(option, searchValue) => (
|
||||
<EuiFlexGroup
|
||||
gutterSize="s"
|
||||
justifyContent="spaceBetween"
|
||||
|
@ -193,8 +161,9 @@ const SelectableTimelineComponent: React.FC<SelectableTimelineProps> = ({
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}, []);
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
const handleTimelineChange = useCallback(
|
||||
(options) => {
|
||||
|
@ -215,39 +184,53 @@ const SelectableTimelineComponent: React.FC<SelectableTimelineProps> = ({
|
|||
[onClosePopover, onTimelineChange]
|
||||
);
|
||||
|
||||
const favoritePortal = useMemo(
|
||||
() =>
|
||||
searchRef != null ? (
|
||||
<EuiPortal insert={{ sibling: searchRef, position: 'after' }}>
|
||||
<MyEuiFlexGroup gutterSize="xs" justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFilterGroup>
|
||||
<EuiFilterButton
|
||||
size="l"
|
||||
data-test-subj="only-favorites-toggle"
|
||||
hasActiveFilters={onlyFavorites}
|
||||
onClick={handleOnToggleOnlyFavorites}
|
||||
>
|
||||
{i18nTimeline.ONLY_FAVORITES}
|
||||
</EuiFilterButton>
|
||||
</EuiFilterGroup>
|
||||
</EuiFlexItem>
|
||||
</MyEuiFlexGroup>
|
||||
</EuiPortal>
|
||||
) : 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: (
|
||||
<StyledEuiFilterButton
|
||||
size="l"
|
||||
data-test-subj="only-favorites-toggle"
|
||||
hasActiveFilters={onlyFavorites}
|
||||
onClick={handleOnToggleOnlyFavorites}
|
||||
>
|
||||
{i18nTimeline.ONLY_FAVORITES}
|
||||
</StyledEuiFilterButton>
|
||||
),
|
||||
}),
|
||||
[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<SelectableTimelineProps> = ({
|
|||
}, [fetchAllTimeline, onlyFavorites, pageSize, searchTimelineValue, timelineType]);
|
||||
|
||||
return (
|
||||
<EuiSelectableContainer isLoading={loading}>
|
||||
<EuiSelectable
|
||||
data-test-subj="selectable-input"
|
||||
height={POPOVER_HEIGHT}
|
||||
isLoading={loading && timelines.length === 0}
|
||||
listProps={{
|
||||
rowHeight: TIMELINE_ITEM_HEIGHT,
|
||||
showIcons: false,
|
||||
windowProps: {
|
||||
onScroll: ({ scrollOffset }) =>
|
||||
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}
|
||||
</>
|
||||
)}
|
||||
</EuiSelectable>
|
||||
</EuiSelectableContainer>
|
||||
<EuiSelectable
|
||||
data-test-subj="selectable-input"
|
||||
height={POPOVER_HEIGHT}
|
||||
isLoading={loading && timelines.length === 0}
|
||||
listProps={listProps}
|
||||
renderOption={renderTimelineOption}
|
||||
onChange={handleTimelineChange}
|
||||
searchable
|
||||
searchProps={searchProps}
|
||||
singleSelection={true}
|
||||
options={getSelectableOptions({
|
||||
timelines,
|
||||
onlyFavorites,
|
||||
searchTimelineValue,
|
||||
timelineType,
|
||||
})}
|
||||
>
|
||||
{EuiSelectableContent}
|
||||
</EuiSelectable>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -322,7 +322,7 @@ export const formattedSearchStrategyResponse = {
|
|||
endgameSecurity: 0,
|
||||
filebeatSystemModule: 1793,
|
||||
winlogbeatSecurity: 42,
|
||||
winlogbeatMWSysmonOperational: null,
|
||||
winlogbeatMWSysmonOperational: 1781,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ export const hostOverview: SecuritySolutionFactory<HostsQueries.overview> = {
|
|||
winlogbeatMWSysmonOperational: getOr(
|
||||
null,
|
||||
'winlog_module.mwsysmon_operational_event_count.doc_count',
|
||||
response
|
||||
aggregations
|
||||
),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue