Skip to content

Commit

Permalink
Merge branch 'main' into eui-v78.0.x
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored May 12, 2023
2 parents 2ba2c6f + 4371c15 commit c06f8fa
Show file tree
Hide file tree
Showing 82 changed files with 5,981 additions and 1,067 deletions.
3,938 changes: 3,925 additions & 13 deletions docs/CHANGELOG.asciidoc

Large diffs are not rendered by default.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

import { fireEvent, render } from '@testing-library/react';
import { GroupPanel } from '.';
import { createGroupFilter, getNullGroupFilter } from './helpers';
import { createGroupFilter, getNullGroupFilter } from '../../containers/query/helpers';
import React from 'react';
import { groupingBucket } from '../../mocks';

const onToggleGroup = jest.fn();
const renderChildComponent = jest.fn();
Expand All @@ -20,40 +21,10 @@ const testProps = {
isLoading: false,
isNullGroup: false,
groupBucket: {
...groupingBucket,
selectedGroup,
key: [ruleName, ruleName],
key_as_string: `${ruleName}|${ruleName}`,
doc_count: 98,
hostsCountAggregation: {
value: 5,
},
ruleTags: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [],
},
alertsCount: {
value: 98,
},
rulesCountAggregation: {
value: 1,
},
severitiesSubAggregation: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{
key: 'low',
doc_count: 98,
},
],
},
countSeveritySubAggregation: {
value: 1,
},
usersCountAggregation: {
value: 98,
},
key: [ruleName],
key_as_string: `${ruleName}`,
},
renderChildComponent,
selectedGroup,
Expand All @@ -68,7 +39,7 @@ describe('grouping accordion panel', () => {
const { getByTestId } = render(<GroupPanel {...testProps} />);
expect(getByTestId('grouping-accordion')).toBeInTheDocument();
expect(renderChildComponent).toHaveBeenCalledWith(
createGroupFilter(testProps.selectedGroup, ruleName)
createGroupFilter(testProps.selectedGroup, [ruleName])
);
});
it('creates the query for the selectedGroup attribute when the group is null', () => {
Expand All @@ -82,8 +53,7 @@ describe('grouping accordion panel', () => {
{...testProps}
groupBucket={{
...testProps.groupBucket,
// @ts-expect-error
key: null,
selectedGroup: 'wrong-group',
}}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
import { EuiAccordion, EuiFlexGroup, EuiFlexItem, EuiTitle, EuiIconTip } from '@elastic/eui';
import type { Filter } from '@kbn/es-query';
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { firstNonNullValue } from '../../helpers';
import type { GroupingBucket } from '../types';
import { createGroupFilter, getNullGroupFilter } from './helpers';
import { createGroupFilter, getNullGroupFilter } from '../../containers/query/helpers';

interface GroupPanelProps<T> {
customAccordionButtonClassName?: string;
Expand Down Expand Up @@ -41,9 +40,11 @@ const DefaultGroupPanelRenderer = ({
}) => (
<div>
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
<EuiFlexItem grow={false}>
<EuiFlexItem grow={false} className="eui-textTruncate">
<EuiTitle size="xs" className="euiAccordionForm__title">
<h4 className="eui-textTruncate">{title}</h4>
<h4 className="eui-textTruncate" title={title}>
{title}
</h4>
</EuiTitle>
</EuiFlexItem>
{isNullGroup && nullGroupMessage && (
Expand Down Expand Up @@ -81,17 +82,23 @@ const GroupPanelComponent = <T,>({
lastForceState.current = 'open';
}
}, [onGroupClose, forceState, selectedGroup]);
const groupFieldValue = useMemo(
() => (groupBucket.selectedGroup === selectedGroup ? firstNonNullValue(groupBucket.key) : null),
[groupBucket.key, groupBucket.selectedGroup, selectedGroup]
const groupFieldValue = useMemo<{ asString: string | null; asArray: string[] | null }>(
() =>
groupBucket.selectedGroup === selectedGroup
? {
asString: groupBucket.key_as_string,
asArray: groupBucket.key,
}
: { asString: null, asArray: null },
[groupBucket.key, groupBucket.key_as_string, groupBucket.selectedGroup, selectedGroup]
);

const groupFilters = useMemo(
() =>
isNullGroup
? getNullGroupFilter(selectedGroup)
: createGroupFilter(selectedGroup, groupFieldValue),
[groupFieldValue, isNullGroup, selectedGroup]
: createGroupFilter(selectedGroup, groupFieldValue.asArray),
[groupFieldValue.asArray, isNullGroup, selectedGroup]
);

const onToggle = useCallback(
Expand All @@ -103,14 +110,14 @@ const GroupPanelComponent = <T,>({
[groupBucket, onToggleGroup]
);

return !groupFieldValue ? null : (
return !groupFieldValue.asString ? null : (
<EuiAccordion
buttonClassName={customAccordionButtonClassName}
buttonContent={
<div data-test-subj="group-panel-toggle" className="groupingPanelRenderer">
{groupPanelRenderer ?? (
<DefaultGroupPanelRenderer
title={groupFieldValue}
title={groupFieldValue.asString}
isNullGroup={isNullGroup}
nullGroupMessage={nullGroupMessage}
/>
Expand All @@ -123,7 +130,7 @@ const GroupPanelComponent = <T,>({
extraAction={extraAction}
forceState={forceState}
isLoading={isLoading}
id={`group${groupingLevel}-${groupFieldValue}`}
id={`group${groupingLevel}-${groupFieldValue.asString}`}
onToggle={onToggle}
paddingSize="m"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { fireEvent, render, within } from '@testing-library/react';
import React from 'react';
import { I18nProvider } from '@kbn/i18n-react';
import { Grouping } from './grouping';
import { createGroupFilter, getNullGroupFilter } from './accordion_panel/helpers';
import { createGroupFilter, getNullGroupFilter } from '../containers/query/helpers';
import { METRIC_TYPE } from '@kbn/analytics';
import { getTelemetryEvent } from '../telemetry/const';

Expand Down Expand Up @@ -79,12 +79,12 @@ describe('grouping container', () => {
fireEvent.click(group1);
expect(renderChildComponent).toHaveBeenNthCalledWith(
1,
createGroupFilter(testProps.selectedGroup, host1Name)
createGroupFilter(testProps.selectedGroup, [host1Name])
);
fireEvent.click(group2);
expect(renderChildComponent).toHaveBeenNthCalledWith(
2,
createGroupFilter(testProps.selectedGroup, host2Name)
createGroupFilter(testProps.selectedGroup, [host2Name])
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ import type { Filter } from '@kbn/es-query';
import React, { useMemo, useState } from 'react';
import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics';
import { defaultUnit, firstNonNullValue } from '../helpers';
import { createGroupFilter, getNullGroupFilter } from './accordion_panel/helpers';
import { createGroupFilter, getNullGroupFilter } from '../containers/query/helpers';
import { GroupPanel } from './accordion_panel';
import { GroupStats } from './accordion_panel/group_stats';
import { EmptyGroupingComponent } from './empty_results_panel';
import { countCss, groupingContainerCss, groupingContainerCssLevel } from './styles';
import { GROUPS_UNIT, NULL_GROUP } from './translations';
import type { GroupingAggregation, GroupPanelRenderer } from './types';
import { GroupStatsRenderer, OnGroupToggle } from './types';
import type { ParsedGroupingAggregation, GroupPanelRenderer } from './types';
import { GroupingBucket, GroupStatsRenderer, OnGroupToggle } from './types';
import { getTelemetryEvent } from '../telemetry/const';

export interface GroupingProps<T> {
activePage: number;
data?: GroupingAggregation<T>;
data?: ParsedGroupingAggregation<T>;
groupPanelRenderer?: GroupPanelRenderer<T>;
groupSelector?: JSX.Element;
// list of custom UI components which correspond to your custom rendered metrics aggregations
Expand Down Expand Up @@ -92,7 +92,7 @@ const GroupingComponent = <T,>({

const groupPanels = useMemo(
() =>
data?.groupByFields?.buckets?.map((groupBucket, groupNumber) => {
data?.groupByFields?.buckets?.map((groupBucket: GroupingBucket<T>, groupNumber) => {
const group = firstNonNullValue(groupBucket.key);
const groupKey = `group-${groupNumber}-${group}`;
const isNullGroup = groupBucket.isNullGroup ?? false;
Expand All @@ -112,7 +112,10 @@ const GroupingComponent = <T,>({
groupFilter={
isNullGroup
? getNullGroupFilter(selectedGroup)
: createGroupFilter(selectedGroup, group)
: createGroupFilter(
selectedGroup,
Array.isArray(groupBucket.key) ? groupBucket.key : [groupBucket.key]
)
}
groupNumber={groupNumber}
statRenderers={
Expand Down
14 changes: 11 additions & 3 deletions packages/kbn-securitysolution-grouping/src/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
* Side Public License, v 1.
*/

// copied from common/search_strategy/common
export interface GenericBuckets {
key: string | string[];
key_as_string?: string; // contains, for example, formatted dates
Expand All @@ -17,15 +16,16 @@ export const NONE_GROUP_KEY = 'none';
export type RawBucket<T> = GenericBuckets & T;

export type GroupingBucket<T> = RawBucket<T> & {
key: string[];
key_as_string: string;
selectedGroup: string;
isNullGroup?: boolean;
};

/** Defines the shape of the aggregation returned by Elasticsearch */
// TODO: write developer docs for these fields
export interface RootAggregation<T> {
groupByFields?: {
buckets?: Array<GroupingBucket<T>>;
buckets?: Array<RawBucket<T>>;
};
groupsCount?: {
value?: number | null;
Expand All @@ -38,6 +38,12 @@ export interface RootAggregation<T> {
};
}

export type ParsedRootAggregation<T> = RootAggregation<T> & {
groupByFields?: {
buckets?: Array<GroupingBucket<T>>;
};
};

export type GroupingFieldTotalAggregation<T> = Record<
string,
{
Expand All @@ -47,6 +53,8 @@ export type GroupingFieldTotalAggregation<T> = Record<
>;

export type GroupingAggregation<T> = RootAggregation<T> & GroupingFieldTotalAggregation<T>;
export type ParsedGroupingAggregation<T> = ParsedRootAggregation<T> &
GroupingFieldTotalAggregation<T>;

export interface BadgeMetric {
value: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { createGroupFilter } from './helpers';

const selectedGroup = 'host.name';
describe('createGroupFilter', () => {
it('returns an array of Filter objects with correct meta and query properties when values and selectedGroup are truthy', () => {
const values = ['host1', 'host2'];
const result = createGroupFilter(selectedGroup, values);
expect(result).toHaveLength(3);
expect(result[0].meta.key).toBe(selectedGroup);
expect(result[0].query.script.script.params.field).toBe(selectedGroup);
expect(result[0].query.script.script.params.size).toBe(values.length);
expect(result[1].meta.key).toBe(selectedGroup);
expect(result[1].query.match_phrase[selectedGroup].query).toBe(values[0]);
expect(result[2].meta.key).toBe(selectedGroup);
expect(result[2].query.match_phrase[selectedGroup].query).toBe(values[1]);
});

it('returns an empty array when values is an empty array and selectedGroup is truthy', () => {
const result = createGroupFilter(selectedGroup, []);
expect(result).toHaveLength(0);
});

it('returns an empty array when values is null and selectedGroup is truthy', () => {
const result = createGroupFilter(selectedGroup, null);
expect(result).toHaveLength(0);
});
});
Loading

0 comments on commit c06f8fa

Please sign in to comment.