diff --git a/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.test.ts b/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.test.ts index 2006c3eed6c2a..48cd66c47b53d 100644 --- a/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.test.ts @@ -42,6 +42,7 @@ describe('createLayerDescriptor', () => { label: 'apm-*-transaction* | Source Point', maxZoom: 24, minZoom: 0, + parent: '12345', disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, @@ -119,6 +120,7 @@ describe('createLayerDescriptor', () => { label: 'apm-*-transaction* | Destination point', maxZoom: 24, minZoom: 0, + parent: '12345', disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, @@ -196,6 +198,7 @@ describe('createLayerDescriptor', () => { label: 'apm-*-transaction* | Line', maxZoom: 24, minZoom: 0, + parent: '12345', disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, @@ -248,6 +251,13 @@ describe('createLayerDescriptor', () => { type: 'GEOJSON_VECTOR', visible: true, }, + { + id: '12345', + label: 'apm-*-transaction*', + sourceDescriptor: null, + type: 'LAYER_GROUP', + visible: true, + }, ]); }); @@ -262,6 +272,7 @@ describe('createLayerDescriptor', () => { label: 'filebeat-* | Source Point', maxZoom: 24, minZoom: 0, + parent: '12345', disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, @@ -339,6 +350,7 @@ describe('createLayerDescriptor', () => { label: 'filebeat-* | Destination point', maxZoom: 24, minZoom: 0, + parent: '12345', disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, @@ -410,6 +422,7 @@ describe('createLayerDescriptor', () => { label: 'filebeat-* | Line', maxZoom: 24, minZoom: 0, + parent: '12345', disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, @@ -462,6 +475,13 @@ describe('createLayerDescriptor', () => { type: 'GEOJSON_VECTOR', visible: true, }, + { + id: '12345', + label: 'filebeat-*', + sourceDescriptor: null, + type: 'LAYER_GROUP', + visible: true, + }, ]); }); @@ -476,6 +496,7 @@ describe('createLayerDescriptor', () => { label: 'traces-apm-opbean-node | Source Point', maxZoom: 24, minZoom: 0, + parent: '12345', disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, @@ -553,6 +574,7 @@ describe('createLayerDescriptor', () => { label: 'traces-apm-opbean-node | Destination point', maxZoom: 24, minZoom: 0, + parent: '12345', disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, @@ -624,6 +646,7 @@ describe('createLayerDescriptor', () => { label: 'traces-apm-opbean-node | Line', maxZoom: 24, minZoom: 0, + parent: '12345', disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, @@ -676,6 +699,13 @@ describe('createLayerDescriptor', () => { type: 'GEOJSON_VECTOR', visible: true, }, + { + id: '12345', + label: 'traces-apm-opbean-node', + sourceDescriptor: null, + type: 'LAYER_GROUP', + visible: true, + }, ]); }); }); diff --git a/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.ts b/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.ts index f295464126c96..792d61b08b9b4 100644 --- a/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.ts +++ b/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.ts @@ -23,6 +23,7 @@ import { VECTOR_STYLES, } from '../../../../../../common/constants'; import { GeoJsonVectorLayer } from '../../../vector_layer'; +import { LayerGroup } from '../../../layer_group'; import { VectorStyle } from '../../../../styles/vector/vector_style'; import { ESSearchSource } from '../../../../sources/es_search_source'; import { ESPewPewSource } from '../../../../sources/es_pew_pew_source'; @@ -48,7 +49,11 @@ function getDestinationField(indexPatternTitle: string) { return isApmIndex(indexPatternTitle) ? 'server.geo.location' : 'destination.geo.location'; } -function createSourceLayerDescriptor(indexPatternId: string, indexPatternTitle: string) { +function createSourceLayerDescriptor( + indexPatternId: string, + indexPatternTitle: string, + parentId: string +) { const sourceDescriptor = ESSearchSource.createDescriptor({ indexPatternId, geoField: getSourceField(indexPatternTitle), @@ -96,12 +101,17 @@ function createSourceLayerDescriptor(indexPatternId: string, indexPatternTitle: defaultMessage: '{indexPatternTitle} | Source Point', values: { indexPatternTitle }, }), + parent: parentId, sourceDescriptor, style: VectorStyle.createDescriptor(styleProperties), }); } -function createDestinationLayerDescriptor(indexPatternId: string, indexPatternTitle: string) { +function createDestinationLayerDescriptor( + indexPatternId: string, + indexPatternTitle: string, + parentId: string +) { const sourceDescriptor = ESSearchSource.createDescriptor({ indexPatternId, geoField: getDestinationField(indexPatternTitle), @@ -149,12 +159,17 @@ function createDestinationLayerDescriptor(indexPatternId: string, indexPatternTi defaultMessage: '{indexPatternTitle} | Destination point', values: { indexPatternTitle }, }), + parent: parentId, sourceDescriptor, style: VectorStyle.createDescriptor(styleProperties), }); } -function createLineLayerDescriptor(indexPatternId: string, indexPatternTitle: string) { +function createLineLayerDescriptor( + indexPatternId: string, + indexPatternTitle: string, + parentId: string +) { const sourceDescriptor = ESPewPewSource.createDescriptor({ indexPatternId, sourceGeoField: getSourceField(indexPatternTitle), @@ -195,6 +210,7 @@ function createLineLayerDescriptor(indexPatternId: string, indexPatternTitle: st defaultMessage: '{indexPatternTitle} | Line', values: { indexPatternTitle }, }), + parent: parentId, sourceDescriptor, style: VectorStyle.createDescriptor(styleProperties), }); @@ -204,9 +220,11 @@ export function createSecurityLayerDescriptors( indexPatternId: string, indexPatternTitle: string ): LayerDescriptor[] { + const layerGroupDescriptor = LayerGroup.createDescriptor({ label: indexPatternTitle }); return [ - createSourceLayerDescriptor(indexPatternId, indexPatternTitle), - createDestinationLayerDescriptor(indexPatternId, indexPatternTitle), - createLineLayerDescriptor(indexPatternId, indexPatternTitle), + createSourceLayerDescriptor(indexPatternId, indexPatternTitle, layerGroupDescriptor.id), + createDestinationLayerDescriptor(indexPatternId, indexPatternTitle, layerGroupDescriptor.id), + createLineLayerDescriptor(indexPatternId, indexPatternTitle, layerGroupDescriptor.id), + layerGroupDescriptor, ]; } diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/__mocks__/mock.ts b/x-pack/plugins/security_solution/public/network/components/embeddables/__mocks__/mock.ts index abcaa079d3b20..e63fff5009152 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/__mocks__/mock.ts +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/__mocks__/mock.ts @@ -18,6 +18,14 @@ export const mockAPMIndexPatternIds: IndexPatternMapping[] = [ { title: 'traces-apm*,logs-apm*,metrics-apm*,apm-*', id: '8c7323ac-97ad-4b53-ac0a-40f8f691a918' }, ]; +export const mockLayerGroup = { + id: 'uuid.v4()', + label: 'filebeat-*', + sourceDescriptor: null, + type: LAYER_TYPE.LAYER_GROUP, + visible: true, +}; + export const mockSourceLayer = { sourceDescriptor: { id: 'uuid.v4()', @@ -64,6 +72,7 @@ export const mockSourceLayer = { }, }, id: 'uuid.v4()', + parent: 'uuid.v4()', label: `filebeat-* | Source Point`, minZoom: 0, maxZoom: 24, @@ -121,6 +130,7 @@ export const mockDestinationLayer = { }, }, id: 'uuid.v4()', + parent: 'uuid.v4()', label: `filebeat-* | Destination Point`, minZoom: 0, maxZoom: 24, @@ -176,6 +186,7 @@ export const mockClientLayer = { }, }, id: 'uuid.v4()', + parent: 'uuid.v4()', label: `apm-* | Client Point`, minZoom: 0, maxZoom: 24, @@ -238,6 +249,7 @@ export const mockServerLayer = { }, }, id: 'uuid.v4()', + parent: 'uuid.v4()', label: `apm-* | Server Point`, minZoom: 0, maxZoom: 24, @@ -307,6 +319,7 @@ export const mockLineLayer = { }, }, id: 'uuid.v4()', + parent: 'uuid.v4()', label: `filebeat-* | Line`, minZoom: 0, maxZoom: 24, @@ -371,6 +384,7 @@ export const mockClientServerLineLayer = { }, }, id: 'uuid.v4()', + parent: 'uuid.v4()', label: `apm-* | Line`, minZoom: 0, maxZoom: 24, @@ -399,6 +413,7 @@ export const mockLayerList = [ mockLineLayer, mockDestinationLayer, mockSourceLayer, + mockLayerGroup, ]; export const mockLayerListDouble = [ @@ -416,9 +431,11 @@ export const mockLayerListDouble = [ mockLineLayer, mockDestinationLayer, mockSourceLayer, + mockLayerGroup, mockLineLayer, mockDestinationLayer, mockSourceLayer, + mockLayerGroup, ]; export const mockLayerListMixed = [ @@ -436,12 +453,21 @@ export const mockLayerListMixed = [ mockLineLayer, mockDestinationLayer, mockSourceLayer, + mockLayerGroup, mockClientServerLineLayer, mockServerLayer, mockClientLayer, + { + ...mockLayerGroup, + label: 'apm-*', + }, mockApmDataStreamClientServerLineLayer, mockApmDataStreamServerLayer, mockApmDataStreamClientLayer, + { + ...mockLayerGroup, + label: 'traces-apm*,logs-apm*,metrics-apm*,apm-*', + }, ]; export const mockAPMIndexPattern: IndexPatternSavedObject = { diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/map_config.test.ts b/x-pack/plugins/security_solution/public/network/components/embeddables/map_config.test.ts index f122d0a93ce90..d476840e91063 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/map_config.test.ts +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/map_config.test.ts @@ -15,6 +15,7 @@ import { mockLayerList, mockLayerListDouble, mockLayerListMixed, + mockLayerGroup, mockLineLayer, mockServerLayer, mockSourceLayer, @@ -50,6 +51,7 @@ describe('map_config', () => { const layerList = getSourceLayer( mockIndexPatternIds[0].title, mockIndexPatternIds[0].id, + mockLayerGroup.id, lmc.default.source ); expect(layerList).toStrictEqual(mockSourceLayer); @@ -59,6 +61,7 @@ describe('map_config', () => { const layerList = getSourceLayer( mockAPMIndexPatternIds[0].title, mockAPMIndexPatternIds[0].id, + mockLayerGroup.id, lmc[mockAPMIndexPatternIds[0].title].source ); expect(layerList).toStrictEqual(mockClientLayer); @@ -70,6 +73,7 @@ describe('map_config', () => { const layerList = getDestinationLayer( mockIndexPatternIds[0].title, mockIndexPatternIds[0].id, + mockLayerGroup.id, lmc.default.destination ); expect(layerList).toStrictEqual(mockDestinationLayer); @@ -79,6 +83,7 @@ describe('map_config', () => { const layerList = getDestinationLayer( mockAPMIndexPatternIds[0].title, mockAPMIndexPatternIds[0].id, + mockLayerGroup.id, lmc[mockAPMIndexPatternIds[0].title].destination ); expect(layerList).toStrictEqual(mockServerLayer); @@ -90,6 +95,7 @@ describe('map_config', () => { const layerList = getLineLayer( mockIndexPatternIds[0].title, mockIndexPatternIds[0].id, + mockLayerGroup.id, lmc.default ); expect(layerList).toStrictEqual(mockLineLayer); @@ -99,6 +105,7 @@ describe('map_config', () => { const layerList = getLineLayer( mockAPMIndexPatternIds[0].title, mockAPMIndexPatternIds[0].id, + mockLayerGroup.id, lmc[mockAPMIndexPatternIds[0].title] ); expect(layerList).toStrictEqual(mockClientServerLineLayer); diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/map_config.ts b/x-pack/plugins/security_solution/public/network/components/embeddables/map_config.ts index 0a0e926840035..701631d585169 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/map_config.ts +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/map_config.ts @@ -117,11 +117,29 @@ export const getLayerList = (indexPatternIds: IndexPatternMapping[]) => { type: LAYER_TYPE.EMS_VECTOR_TILE, }, ...indexPatternIds.reduce((acc: object[], { title, id }) => { + const layerGroupDescriptor = { + id: uuid.v4(), + label: title, + sourceDescriptor: null, + type: LAYER_TYPE.LAYER_GROUP, + visible: true, + }; return [ ...acc, - getLineLayer(title, id, lmc[title] ?? lmc.default), - getDestinationLayer(title, id, lmc[title]?.destination ?? lmc.default.destination), - getSourceLayer(title, id, lmc[title]?.source ?? lmc.default.source), + getLineLayer(title, id, layerGroupDescriptor.id, lmc[title] ?? lmc.default), + getDestinationLayer( + title, + id, + layerGroupDescriptor.id, + lmc[title]?.destination ?? lmc.default.destination + ), + getSourceLayer( + title, + id, + layerGroupDescriptor.id, + lmc[title]?.source ?? lmc.default.source + ), + layerGroupDescriptor, ]; }, []), ]; @@ -133,11 +151,13 @@ export const getLayerList = (indexPatternIds: IndexPatternMapping[]) => { * * @param indexPatternTitle used as layer name in LayerToC UI: "${indexPatternTitle} | Source point" * @param indexPatternId used as layer's indexPattern to query for data + * @param parentId * @param layerDetails layer-specific field details */ export const getSourceLayer = ( indexPatternTitle: string, indexPatternId: string, + parentId: string, layerDetails: LayerMappingDetails ) => ({ sourceDescriptor: { @@ -179,6 +199,7 @@ export const getSourceLayer = ( }, }, id: uuid.v4(), + parent: parentId, label: `${indexPatternTitle} | ${layerDetails.label}`, minZoom: 0, maxZoom: 24, @@ -195,12 +216,14 @@ export const getSourceLayer = ( * * @param indexPatternTitle used as layer name in LayerToC UI: "${indexPatternTitle} | Destination point" * @param indexPatternId used as layer's indexPattern to query for data + * @param parentId used as layer's indexPattern to query for data * @param layerDetails layer-specific field details * */ export const getDestinationLayer = ( indexPatternTitle: string, indexPatternId: string, + parentId: string, layerDetails: LayerMappingDetails ) => ({ sourceDescriptor: { @@ -243,6 +266,7 @@ export const getDestinationLayer = ( }, }, id: uuid.v4(), + parent: parentId, label: `${indexPatternTitle} | ${layerDetails.label}`, minZoom: 0, maxZoom: 24, @@ -258,11 +282,13 @@ export const getDestinationLayer = ( * * @param indexPatternTitle used as layer name in LayerToC UI: "${indexPatternTitle} | Line" * @param indexPatternId used as layer's indexPattern to query for data + * @param parentId * @param layerDetails layer-specific field details */ export const getLineLayer = ( indexPatternTitle: string, indexPatternId: string, + parentId: string, layerDetails: LayerMapping ) => ({ sourceDescriptor: { @@ -327,6 +353,7 @@ export const getLineLayer = ( }, }, id: uuid.v4(), + parent: parentId, label: `${indexPatternTitle} | ${i18n.LINE_LAYER}`, minZoom: 0, maxZoom: 24,