Skip to content

Commit

Permalink
Adds building block filter UI and queries
Browse files Browse the repository at this point in the history
  • Loading branch information
spong committed Jul 11, 2020
1 parent e1253ed commit 3c82c83
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export { UtilityBar } from './utility_bar';
export { UtilityBarAction } from './utility_bar_action';
export { UtilityBarGroup } from './utility_bar_group';
export { UtilityBarSection } from './utility_bar_section';
export { UtilityBarSpacer } from './utility_bar_spacer';
export { UtilityBarText } from './utility_bar_text';
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ export interface BarProps {
border?: boolean;
}

export interface BarSectionProps {
grow?: boolean;
}

export interface BarGroupProps {
grow?: boolean;
}

export const Bar = styled.aside.attrs({
className: 'siemUtilityBar',
})<BarProps>`
Expand All @@ -36,8 +44,8 @@ Bar.displayName = 'Bar';

export const BarSection = styled.div.attrs({
className: 'siemUtilityBar__section',
})`
${({ theme }) => css`
})<BarSectionProps>`
${({ grow, theme }) => css`
& + & {
margin-top: ${theme.eui.euiSizeS};
}
Expand All @@ -53,14 +61,18 @@ export const BarSection = styled.div.attrs({
margin-left: ${theme.eui.euiSize};
}
}
${grow &&
css`
flex: 1;
`}
`}
`;
BarSection.displayName = 'BarSection';

export const BarGroup = styled.div.attrs({
className: 'siemUtilityBar__group',
})`
${({ theme }) => css`
})<BarGroupProps>`
${({ grow, theme }) => css`
align-items: flex-start;
display: flex;
flex-wrap: wrap;
Expand Down Expand Up @@ -93,6 +105,10 @@ export const BarGroup = styled.div.attrs({
margin-right: 0;
}
}
${grow &&
css`
flex: 1;
`}
`}
`;
BarGroup.displayName = 'BarGroup';
Expand All @@ -118,3 +134,12 @@ export const BarAction = styled.div.attrs({
`}
`;
BarAction.displayName = 'BarAction';

export const BarSpacer = styled.div.attrs({
className: 'siemUtilityBar__spacer',
})`
${() => css`
flex: 1;
`}
`;
BarSpacer.displayName = 'BarSpacer';
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

import React from 'react';

import { BarGroup } from './styles';
import { BarGroup, BarGroupProps } from './styles';

export interface UtilityBarGroupProps {
export interface UtilityBarGroupProps extends BarGroupProps {
children: React.ReactNode;
}

export const UtilityBarGroup = React.memo<UtilityBarGroupProps>(({ children }) => (
<BarGroup>{children}</BarGroup>
export const UtilityBarGroup = React.memo<UtilityBarGroupProps>(({ grow, children }) => (
<BarGroup grow={grow}>{children}</BarGroup>
));

UtilityBarGroup.displayName = 'UtilityBarGroup';
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

import React from 'react';

import { BarSection } from './styles';
import { BarSection, BarSectionProps } from './styles';

export interface UtilityBarSectionProps {
export interface UtilityBarSectionProps extends BarSectionProps {
children: React.ReactNode;
}

export const UtilityBarSection = React.memo<UtilityBarSectionProps>(({ children }) => (
<BarSection>{children}</BarSection>
export const UtilityBarSection = React.memo<UtilityBarSectionProps>(({ grow, children }) => (
<BarSection grow={grow}>{children}</BarSection>
));

UtilityBarSection.displayName = 'UtilityBarSection';
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';

import { BarSpacer } from './styles';

export interface UtilityBarSpacerProps {
dataTestSubj?: string;
}

export const UtilityBarSpacer = React.memo<UtilityBarSpacerProps>(({ dataTestSubj }) => (
<BarSpacer data-test-subj={dataTestSubj} />
));

UtilityBarSpacer.displayName = 'UtilityBarSpacer';
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { isEmpty } from 'lodash/fp';
import React, { useCallback } from 'react';
import numeral from '@elastic/numeral';

import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiCheckbox } from '@elastic/eui';
import styled from 'styled-components';

import { Status } from '../../../../../common/detection_engine/schemas/common/schemas';
import { Link } from '../../../../common/components/link_icon';
import { DEFAULT_NUMBER_FORMAT } from '../../../../../common/constants';
Expand All @@ -18,6 +19,7 @@ import {
UtilityBarAction,
UtilityBarGroup,
UtilityBarSection,
UtilityBarSpacer,
UtilityBarText,
} from '../../../../common/components/utility_bar';
import * as i18n from './translations';
Expand All @@ -34,6 +36,8 @@ interface AlertsUtilityBarProps {
currentFilter: Status;
selectAll: () => void;
selectedEventIds: Readonly<Record<string, TimelineNonEcsData[]>>;
showBuildingBlockAlerts: boolean;
onShowBuildingBlockAlertsChanged: (showBuildingBlockAlerts: boolean) => void;
showClearSelection: boolean;
totalCount: number;
updateAlertsStatus: UpdateAlertsStatus;
Expand All @@ -52,6 +56,8 @@ const AlertsUtilityBarComponent: React.FC<AlertsUtilityBarProps> = ({
selectedEventIds,
currentFilter,
selectAll,
showBuildingBlockAlerts,
onShowBuildingBlockAlertsChanged,
showClearSelection,
updateAlertsStatus,
}) => {
Expand Down Expand Up @@ -125,17 +131,36 @@ const AlertsUtilityBarComponent: React.FC<AlertsUtilityBarProps> = ({
</UtilityBarFlexGroup>
);

const UtilityBarAdditionalFiltersContent = (closePopover: () => void) => (
<UtilityBarFlexGroup direction="column">
<EuiFlexItem>
<EuiCheckbox
id="showBuildingBlockAlertsCheckbox"
aria-label="showBuildingBlockAlerts"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
closePopover();
onShowBuildingBlockAlertsChanged(e.target.checked);
}}
checked={showBuildingBlockAlerts}
color="text"
data-test-subj="showBuildingBlockAlertsCheckbox"
label={i18n.ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK}
/>
</EuiFlexItem>
</UtilityBarFlexGroup>
);

return (
<>
<UtilityBar>
<UtilityBarSection>
<UtilityBarSection grow={true}>
<UtilityBarGroup>
<UtilityBarText dataTestSubj="showingAlerts">
{i18n.SHOWING_ALERTS(formattedTotalCount, totalCount)}
</UtilityBarText>
</UtilityBarGroup>

<UtilityBarGroup>
<UtilityBarGroup grow={true}>
{canUserCRUD && hasIndexWrite && (
<>
<UtilityBarText dataTestSubj="selectedAlerts">
Expand Down Expand Up @@ -174,6 +199,17 @@ const AlertsUtilityBarComponent: React.FC<AlertsUtilityBarProps> = ({
</UtilityBarAction>
</>
)}
<UtilityBarSpacer />
<UtilityBarAction
dataTestSubj="additionalFilters"
disabled={areEventsLoading}
iconType="arrowDown"
iconSide="right"
ownFocus={false}
popoverContent={UtilityBarAdditionalFiltersContent}
>
{i18n.ADDITIONAL_FILTERS_ACTIONS}
</UtilityBarAction>
</UtilityBarGroup>
</UtilityBarSection>
</UtilityBar>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ export const SELECT_ALL_ALERTS = (totalAlertsFormatted: string, totalAlerts: num
'Select all {totalAlertsFormatted} {totalAlerts, plural, =1 {alert} other {alerts}}',
});

export const ADDITIONAL_FILTERS_ACTIONS = i18n.translate(
'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle',
{
defaultMessage: 'Additional filters',
}
);

export const ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK = i18n.translate(
'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle',
{
defaultMessage: 'Include building block alerts',
}
);

export const CLEAR_SELECTION = i18n.translate(
'xpack.securitySolution.detectionEngine.alerts.utilityBar.clearSelectionTitle',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,25 @@ export const buildAlertsRuleIdFilter = (ruleId: string): Filter[] => [
},
];

export const buildShowBuildingBlockFilter = (showBuildingBlockAlerts: boolean): Filter[] => [
...(showBuildingBlockAlerts
? []
: [
{
meta: {
alias: null,
negate: true,
disabled: false,
type: 'exists',
key: 'signal.rule.building_block_type',
value: 'exists',
},
// @ts-ignore TODO: Rework parent typings to support ExistsFilter[]
exists: { field: 'signal.rule.building_block_type' },
},
]),
];

export const alertsHeaders: ColumnHeaderOptions[] = [
{
columnHeaderType: defaultColumnHeaderType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ interface OwnProps {
hasIndexWrite: boolean;
from: number;
loading: boolean;
showBuildingBlockAlerts: boolean;
onShowBuildingBlockAlertsChanged: (showBuildingBlockAlerts: boolean) => void;
signalsIndex: string;
to: number;
}
Expand Down Expand Up @@ -94,6 +96,8 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
selectedEventIds,
setEventsDeleted,
setEventsLoading,
showBuildingBlockAlerts,
onShowBuildingBlockAlertsChanged,
signalsIndex,
to,
updateTimeline,
Expand Down Expand Up @@ -302,6 +306,8 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
currentFilter={filterGroup}
selectAll={selectAllCallback}
selectedEventIds={selectedEventIds}
showBuildingBlockAlerts={showBuildingBlockAlerts}
onShowBuildingBlockAlertsChanged={onShowBuildingBlockAlertsChanged}
showClearSelection={showClearSelectionAction}
totalCount={totalCount}
updateAlertsStatus={updateAlertsStatusCallback.bind(null, refetchQuery)}
Expand All @@ -313,6 +319,8 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
hasIndexWrite,
clearSelectionCallback,
filterGroup,
showBuildingBlockAlerts,
onShowBuildingBlockAlertsChanged,
loadingEventIds.length,
selectAllCallback,
selectedEventIds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import { EuiSpacer } from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import { StickyContainer } from 'react-sticky';
import { connect, ConnectedProps } from 'react-redux';

Expand Down Expand Up @@ -38,6 +38,7 @@ import { DetectionEngineUserUnauthenticated } from './detection_engine_user_unau
import * as i18n from './translations';
import { LinkButton } from '../../../common/components/links';
import { useFormatUrl } from '../../../common/components/link_to';
import { buildShowBuildingBlockFilter } from '../../components/alerts_table/default_config';

export const DetectionEnginePageComponent: React.FC<PropsFromRedux> = ({
filters,
Expand All @@ -57,6 +58,7 @@ export const DetectionEnginePageComponent: React.FC<PropsFromRedux> = ({
const history = useHistory();
const [lastAlerts] = useAlertInfo({});
const { formatUrl } = useFormatUrl(SecurityPageName.detections);
const [showBuildingBlockAlerts, setShowBuildingBlockAlerts] = useState(false);

const updateDateRangeCallback = useCallback<UpdateDateRange>(
({ x }) => {
Expand All @@ -77,6 +79,24 @@ export const DetectionEnginePageComponent: React.FC<PropsFromRedux> = ({
[history]
);

const alertsHistogramDefaultFilters = useMemo(
() => [...filters, ...buildShowBuildingBlockFilter(showBuildingBlockAlerts)],
[filters, showBuildingBlockAlerts]
);

// AlertsTable manages global filters itself, so not including `filters`
const alertsTableDefaultFilters = useMemo(
() => buildShowBuildingBlockFilter(showBuildingBlockAlerts),
[showBuildingBlockAlerts]
);

const onShowBuildingBlockAlertsChangedCallback = useCallback(
(newShowBuildingBlockAlerts: boolean) => {
setShowBuildingBlockAlerts(newShowBuildingBlockAlerts);
},
[setShowBuildingBlockAlerts]
);

const indexToAdd = useMemo(() => (signalIndexName == null ? [] : [signalIndexName]), [
signalIndexName,
]);
Expand Down Expand Up @@ -134,7 +154,7 @@ export const DetectionEnginePageComponent: React.FC<PropsFromRedux> = ({

<AlertsHistogramPanel
deleteQuery={deleteQuery}
filters={filters}
filters={alertsHistogramDefaultFilters}
from={from}
query={query}
setQuery={setQuery}
Expand All @@ -151,6 +171,9 @@ export const DetectionEnginePageComponent: React.FC<PropsFromRedux> = ({
hasIndexWrite={hasIndexWrite ?? false}
canUserCRUD={(canUserCRUD ?? false) && (hasEncryptionKey ?? false)}
from={from}
defaultFilters={alertsTableDefaultFilters}
showBuildingBlockAlerts={showBuildingBlockAlerts}
onShowBuildingBlockAlertsChanged={onShowBuildingBlockAlertsChangedCallback}
signalsIndex={signalIndexName ?? ''}
to={to}
/>
Expand Down
Loading

0 comments on commit 3c82c83

Please sign in to comment.