Skip to content

Commit

Permalink
[SIEM] [Maps] Fixes Network Map empty tooltip (#66828) (#66945)
Browse files Browse the repository at this point in the history
## Summary

Resolves #63474, and expands `ITooltipProperty`'s `rawValue` type to include `string[]` as mentioned [here](#61264 (comment)).

![image](https://user-images.githubusercontent.com/2946766/82100568-2c0e1480-96c7-11ea-958e-5b1c6b6a3db9.png)



### Checklist

Delete any items that are not applicable to this PR.

- [X] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios
  • Loading branch information
spong committed May 19, 2020
1 parent 5655987 commit 3dbe9dc
Show file tree
Hide file tree
Showing 15 changed files with 59 additions and 112 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/public/classes/fields/es_agg_field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class ESAggField implements IESAggField {
return this._esDocField ? this._esDocField.getName() : '';
}

async createTooltipProperty(value: string | undefined): Promise<ITooltipProperty> {
async createTooltipProperty(value: string | string[] | undefined): Promise<ITooltipProperty> {
const indexPattern = await this._source.getIndexPattern();
const tooltipProperty = new TooltipProperty(this.getName(), await this.getLabel(), value);
return new ESAggTooltipProperty(tooltipProperty, indexPattern, this, this.getAggType());
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/public/classes/fields/es_doc_field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class ESDocField extends AbstractField implements IField {
: indexPatternField;
}

async createTooltipProperty(value: string | undefined): Promise<ITooltipProperty> {
async createTooltipProperty(value: string | string[] | undefined): Promise<ITooltipProperty> {
const indexPattern = await this._source.getIndexPattern();
const tooltipProperty = new TooltipProperty(this.getName(), await this.getLabel(), value);
return new ESTooltipProperty(tooltipProperty, indexPattern, this as IField);
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/maps/public/classes/fields/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface IField {
canValueBeFormatted(): boolean;
getLabel(): Promise<string>;
getDataType(): Promise<string>;
createTooltipProperty(value: string | undefined): Promise<ITooltipProperty>;
createTooltipProperty(value: string | string[] | undefined): Promise<ITooltipProperty>;
getSource(): IVectorSource;
getOrigin(): FIELD_ORIGIN;
isValid(): boolean;
Expand Down Expand Up @@ -60,7 +60,7 @@ export class AbstractField implements IField {
return this._fieldName;
}

async createTooltipProperty(value: string | undefined): Promise<ITooltipProperty> {
async createTooltipProperty(value: string | string[] | undefined): Promise<ITooltipProperty> {
const label = await this.getLabel();
return new TooltipProperty(this.getName(), label, value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class TopTermPercentageField implements IESAggField {
return 'number';
}

async createTooltipProperty(value: string | undefined): Promise<ITooltipProperty> {
async createTooltipProperty(value: string | string[] | undefined): Promise<ITooltipProperty> {
return new TooltipProperty(this.getName(), await this.getLabel(), value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class ESTooltipProperty implements ITooltipProperty {
return this._tooltipProperty.getPropertyName();
}

getRawValue(): string | undefined {
getRawValue(): string | string[] | undefined {
return this._tooltipProperty.getRawValue();
}

Expand All @@ -48,7 +48,12 @@ export class ESTooltipProperty implements ITooltipProperty {

const indexPatternField = this._getIndexPatternField();
if (!indexPatternField || !this._field.canValueBeFormatted()) {
return _.escape(this.getRawValue());
const rawValue = this.getRawValue();
if (Array.isArray(rawValue)) {
return _.escape(rawValue.join());
} else {
return _.escape(rawValue);
}
}

const htmlConverter = indexPatternField.format.getConverterFor('html');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class JoinTooltipProperty implements ITooltipProperty {
return this._tooltipProperty.getPropertyName();
}

getRawValue(): string | undefined {
getRawValue(): string | string[] | undefined {
return this._tooltipProperty.getRawValue();
}

Expand Down
10 changes: 5 additions & 5 deletions x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface ITooltipProperty {
getPropertyKey(): string;
getPropertyName(): string;
getHtmlDisplayValue(): string;
getRawValue(): string | undefined;
getRawValue(): string | string[] | undefined;
isFilterable(): boolean;
getESFilters(): Promise<Filter[]>;
}
Expand Down Expand Up @@ -41,10 +41,10 @@ export type RenderToolTipContent = (params: RenderTooltipContentParams) => JSX.E

export class TooltipProperty implements ITooltipProperty {
private readonly _propertyKey: string;
private readonly _rawValue: string | undefined;
private readonly _rawValue: string | string[] | undefined;
private readonly _propertyName: string;

constructor(propertyKey: string, propertyName: string, rawValue: string | undefined) {
constructor(propertyKey: string, propertyName: string, rawValue: string | string[] | undefined) {
this._propertyKey = propertyKey;
this._propertyName = propertyName;
this._rawValue = rawValue;
Expand All @@ -59,10 +59,10 @@ export class TooltipProperty implements ITooltipProperty {
}

getHtmlDisplayValue(): string {
return _.escape(this._rawValue);
return _.escape(Array.isArray(this._rawValue) ? this._rawValue.join() : this._rawValue);
}

getRawValue(): string | undefined {
getRawValue(): string | string[] | undefined {
return this._rawValue;
}

Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/maps/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export const plugin: PluginInitializer<MapsPluginSetup, MapsPluginStart> = () =>
};

export { MAP_SAVED_OBJECT_TYPE } from '../common/constants';
export { ITooltipProperty } from './classes/tooltips/tooltip_property';

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,24 @@
import { shallow } from 'enzyme';
import React from 'react';
import { LineToolTipContentComponent } from './line_tool_tip_content';
import { FeatureProperty } from '../types';
import {
SUM_OF_CLIENT_BYTES,
SUM_OF_DESTINATION_BYTES,
SUM_OF_SERVER_BYTES,
SUM_OF_SOURCE_BYTES,
} from '../map_config';
import { ITooltipProperty } from '../../../../../../maps/public';
import { TooltipProperty } from '../../../../../../maps/public/classes/tooltips/tooltip_property';

describe('LineToolTipContent', () => {
const mockFeatureProps: FeatureProperty[] = [
{
_propertyKey: SUM_OF_DESTINATION_BYTES,
_rawValue: 'testPropValue',
},
{
_propertyKey: SUM_OF_SOURCE_BYTES,
_rawValue: 'testPropValue',
},
const mockFeatureProps: ITooltipProperty[] = [
new TooltipProperty(SUM_OF_DESTINATION_BYTES, SUM_OF_DESTINATION_BYTES, 'testPropValue'),
new TooltipProperty(SUM_OF_SOURCE_BYTES, SUM_OF_SOURCE_BYTES, 'testPropValue'),
];

const mockClientServerFeatureProps: FeatureProperty[] = [
{
_propertyKey: SUM_OF_SERVER_BYTES,
_rawValue: 'testPropValue',
},
{
_propertyKey: SUM_OF_CLIENT_BYTES,
_rawValue: 'testPropValue',
},
const mockClientServerFeatureProps: ITooltipProperty[] = [
new TooltipProperty(SUM_OF_SERVER_BYTES, SUM_OF_SERVER_BYTES, 'testPropValue'),
new TooltipProperty(SUM_OF_CLIENT_BYTES, SUM_OF_CLIENT_BYTES, 'testPropValue'),
];

test('renders correctly against snapshot', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import {
SUM_OF_SERVER_BYTES,
SUM_OF_SOURCE_BYTES,
} from '../map_config';
import { FeatureProperty } from '../types';

import * as i18n from '../translations';
import { ITooltipProperty } from '../../../../../../maps/public';

const FlowBadge = (styled(EuiBadge)`
height: 45px;
Expand All @@ -28,20 +29,22 @@ const EuiFlexGroupStyled = styled(EuiFlexGroup)`

interface LineToolTipContentProps {
contextId: string;
featureProps: FeatureProperty[];
featureProps: ITooltipProperty[];
}

export const LineToolTipContentComponent = ({
contextId,
featureProps,
}: LineToolTipContentProps) => {
const lineProps = featureProps.reduce<Record<string, string[]>>(
(acc, f) => ({
const lineProps = featureProps.reduce<Record<string, string[]>>((acc, f) => {
const rawValue = f.getRawValue() ?? [];
return {
...acc,
...{ [f._propertyKey]: Array.isArray(f._rawValue) ? f._rawValue : [f._rawValue] },
}),
{}
);
...{
[f.getPropertyKey()]: Array.isArray(rawValue) ? rawValue : [rawValue],
},
};
}, {});

const isSrcDest = Object.keys(lineProps).includes(SUM_OF_SOURCE_BYTES);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import {
EuiLoadingSpinner,
EuiOutsideClickDetector,
} from '@elastic/eui';
import { FeatureGeometry, FeatureProperty, MapToolTipProps } from '../types';
import { FeatureGeometry, MapToolTipProps } from '../types';
import { ToolTipFooter } from './tooltip_footer';
import { LineToolTipContent } from './line_tool_tip_content';
import { PointToolTipContent } from './point_tool_tip_content';
import { Loader } from '../../../../common/components/loader';
import * as i18n from '../translations';
import { ITooltipProperty } from '../../../../../../maps/public';

export const MapToolTipComponent = ({
addFilters,
Expand All @@ -31,7 +32,7 @@ export const MapToolTipComponent = ({
const [isLoadingNextFeature, setIsLoadingNextFeature] = useState<boolean>(false);
const [isError, setIsError] = useState<boolean>(false);
const [featureIndex, setFeatureIndex] = useState<number>(0);
const [featureProps, setFeatureProps] = useState<FeatureProperty[]>([]);
const [featureProps, setFeatureProps] = useState<ITooltipProperty[]>([]);
const [featureGeometry, setFeatureGeometry] = useState<FeatureGeometry | null>(null);
const [, setLayerName] = useState<string>('');

Expand Down Expand Up @@ -64,7 +65,7 @@ export const MapToolTipComponent = ({
getLayerName(layerId),
]);

setFeatureProps((featureProperties as unknown) as FeatureProperty[]);
setFeatureProps(featureProperties);
setFeatureGeometry(featureGeo);
setLayerName(layerNameString);
} catch (e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,17 @@

import { shallow } from 'enzyme';
import React from 'react';
import { FeatureProperty } from '../types';
import { getRenderedFieldValue, PointToolTipContentComponent } from './point_tool_tip_content';
import { TestProviders } from '../../../../common/mock';
import { getEmptyStringTag } from '../../../../common/components/empty_value';
import { HostDetailsLink, IPDetailsLink } from '../../../../common/components/links';
import { useMountAppended } from '../../../../common/utils/use_mount_appended';
import { FlowTarget } from '../../../../graphql/types';
import { ITooltipProperty } from '../../../../../../maps/public';
import { TooltipProperty } from '../../../../../../maps/public/classes/tooltips/tooltip_property';

describe('PointToolTipContent', () => {
const mount = useMountAppended();

const mockFeatureProps: FeatureProperty[] = [
{
_propertyKey: 'host.name',
_rawValue: 'testPropValue',
},
];

const mockFeaturePropsArrayValue: FeatureProperty[] = [
{
_propertyKey: 'host.name',
_rawValue: ['testPropValue1', 'testPropValue2'],
},
const mockFeatureProps: ITooltipProperty[] = [
new TooltipProperty('host.name', 'host.name', 'testPropValue'),
];

test('renders correctly against snapshot', () => {
Expand All @@ -46,32 +34,6 @@ describe('PointToolTipContent', () => {
expect(wrapper.find('PointToolTipContentComponent')).toMatchSnapshot();
});

test('renders array filter correctly', () => {
const closeTooltip = jest.fn();

const wrapper = mount(
<TestProviders>
<PointToolTipContentComponent
contextId={'contextId'}
featureProps={mockFeaturePropsArrayValue}
closeTooltip={closeTooltip}
/>
</TestProviders>
);
expect(wrapper.find('[data-test-subj="add-to-kql-host.name"]').prop('filter')).toEqual({
meta: {
alias: null,
disabled: false,
key: 'host.name',
negate: false,
params: { query: 'testPropValue1' },
type: 'phrase',
value: 'testPropValue1',
},
query: { match: { 'host.name': { query: 'testPropValue1', type: 'phrase' } } },
});
});

describe('#getRenderedFieldValue', () => {
test('it returns empty tag if value is empty', () => {
expect(getRenderedFieldValue('host.name', '')).toStrictEqual(getEmptyStringTag());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,19 @@

import React from 'react';
import { sourceDestinationFieldMappings } from '../map_config';
import {
AddFilterToGlobalSearchBar,
createFilter,
} from '../../../../common/components/add_filter_to_global_search_bar';
import {
getEmptyTagValue,
getOrEmptyTagFromValue,
} from '../../../../common/components/empty_value';
import { DescriptionListStyled } from '../../../../common/components/page';
import { FeatureProperty } from '../types';
import { HostDetailsLink, IPDetailsLink } from '../../../../common/components/links';
import { DefaultFieldRenderer } from '../../../../timelines/components/field_renderers/field_renderers';
import { FlowTarget } from '../../../../graphql/types';
import { ITooltipProperty } from '../../../../../../maps/public';

interface PointToolTipContentProps {
contextId: string;
featureProps: FeatureProperty[];
featureProps: ITooltipProperty[];
closeTooltip?(): void;
}

Expand All @@ -31,15 +27,14 @@ export const PointToolTipContentComponent = ({
featureProps,
closeTooltip,
}: PointToolTipContentProps) => {
const featureDescriptionListItems = featureProps.map(
({ _propertyKey: key, _rawValue: value }) => ({
const featureDescriptionListItems = featureProps.map(featureProp => {
const key = featureProp.getPropertyKey();
const value = featureProp.getRawValue() ?? [];

return {
title: sourceDestinationFieldMappings[key],
description: (
<AddFilterToGlobalSearchBar
filter={createFilter(key, Array.isArray(value) ? value[0] : value)}
onFilterAdded={closeTooltip}
data-test-subj={`add-to-kql-${key}`}
>
<>
{value != null ? (
<DefaultFieldRenderer
rowItems={Array.isArray(value) ? value : [value]}
Expand All @@ -50,10 +45,10 @@ export const PointToolTipContentComponent = ({
) : (
getEmptyTagValue()
)}
</AddFilterToGlobalSearchBar>
</>
),
})
);
};
});

return <DescriptionListStyled listItems={featureDescriptionListItems} />;
};
Expand Down
10 changes: 0 additions & 10 deletions x-pack/plugins/siem/public/network/components/embeddables/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,6 @@ export interface MapFeature {
layerId: string;
}

export interface LoadFeatureProps {
layerId: string;
featureId: number;
}

export interface FeatureProperty {
_propertyKey: string;
_rawValue: string | string[];
}

export interface FeatureGeometry {
coordinates: [number];
type: string;
Expand Down

0 comments on commit 3dbe9dc

Please sign in to comment.