From 980112de1e1fae28352bb7047d553f2ec7fa8526 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 2 Feb 2021 15:51:00 -0700 Subject: [PATCH 01/14] [Maps] migrate mvt routes to use data.search service instead of directly calling elasticsearch (#89904) * [Maps] migrate mvt routes to use data.search service instead of directly calling elasticsearch * pass search session id to mvt requests * move grid tile tests to integration tests * replace getTile unit test with integration test * add comment about request param * revert total meta change * tslint fixes * update jest tests --- .../es_geo_grid_source.test.ts | 11 + .../es_geo_grid_source/es_geo_grid_source.tsx | 14 +- .../es_search_source/es_search_source.test.ts | 14 + .../es_search_source/es_search_source.tsx | 13 +- .../mvt/__fixtures__/json/0_0_0_gridagg.json | 1 - .../mvt/__fixtures__/json/0_0_0_search.json | 1 - .../mvt/__fixtures__/tile_es_responses.ts | 35 --- .../plugins/maps/server/mvt/get_tile.test.ts | 261 ------------------ x-pack/plugins/maps/server/mvt/get_tile.ts | 189 +++++++------ x-pack/plugins/maps/server/mvt/mvt_routes.ts | 27 +- .../apis/maps/get_grid_tile.js | 80 +++++- .../api_integration/apis/maps/get_tile.js | 70 ++++- 12 files changed, 304 insertions(+), 412 deletions(-) delete mode 100644 x-pack/plugins/maps/server/mvt/__fixtures__/json/0_0_0_gridagg.json delete mode 100644 x-pack/plugins/maps/server/mvt/__fixtures__/json/0_0_0_search.json delete mode 100644 x-pack/plugins/maps/server/mvt/__fixtures__/tile_es_responses.ts delete mode 100644 x-pack/plugins/maps/server/mvt/get_tile.test.ts diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts index 8ac014c820ac..73d3bcb1eea0 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts @@ -278,6 +278,17 @@ describe('ESGeoGridSource', () => { "rootdir/api/maps/mvt/getGridTile;?x={x}&y={y}&z={z}&geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!((geo_bounding_box:(bar:(bottom_right:!(180,-82.67628),top_left:!(-180,82.67628)))))),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point" ); }); + + it('should include searchSourceId in urlTemplateWithMeta', async () => { + const urlTemplateWithMeta = await geogridSource.getUrlTemplateWithMeta({ + ...vectorSourceRequestMeta, + searchSessionId: '1', + }); + + expect(urlTemplateWithMeta.urlTemplate).toBe( + "rootdir/api/maps/mvt/getGridTile;?x={x}&y={y}&z={z}&geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!((geo_bounding_box:(bar:(bottom_right:!(180,-82.67628),top_left:!(-180,82.67628)))))),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point&searchSessionId=1" + ); + }); }); describe('Gold+ usage', () => { diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx index 24b7e0dec519..8e82a60a802c 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx @@ -443,12 +443,22 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle ); const geoField = await this._getGeoField(); - const urlTemplate = `${mvtUrlServicePath}?x={x}&y={y}&z={z}&geometryFieldName=${this._descriptor.geoField}&index=${indexPattern.title}&requestBody=${risonDsl}&requestType=${this._descriptor.requestType}&geoFieldType=${geoField.type}`; + const urlTemplate = `${mvtUrlServicePath}\ +?x={x}\ +&y={y}\ +&z={z}\ +&geometryFieldName=${this._descriptor.geoField}\ +&index=${indexPattern.title}\ +&requestBody=${risonDsl}\ +&requestType=${this._descriptor.requestType}\ +&geoFieldType=${geoField.type}`; return { layerName: this.getLayerName(), minSourceZoom: this.getMinZoom(), maxSourceZoom: this.getMaxZoom(), - urlTemplate, + urlTemplate: searchFilters.searchSessionId + ? urlTemplate + `&searchSessionId=${searchFilters.searchSessionId}` + : urlTemplate, }; } diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts index 3f8b9d3e28e1..61b3ee348b46 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts @@ -116,6 +116,20 @@ describe('ESSearchSource', () => { `rootdir/api/maps/mvt/getTile;?x={x}&y={y}&z={z}&geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))&geoFieldType=geo_shape` ); }); + + it('should include searchSourceId in urlTemplateWithMeta', async () => { + const esSearchSource = new ESSearchSource({ + geoField: geoFieldName, + indexPatternId: 'ipId', + }); + const urlTemplateWithMeta = await esSearchSource.getUrlTemplateWithMeta({ + ...searchFilters, + searchSessionId: '1', + }); + expect(urlTemplateWithMeta.urlTemplate).toBe( + `rootdir/api/maps/mvt/getTile;?x={x}&y={y}&z={z}&geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))&geoFieldType=geo_shape&searchSessionId=1` + ); + }); }); }); diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx index b70a433f2c72..8c5c63931db2 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx @@ -729,12 +729,21 @@ export class ESSearchSource extends AbstractESSource implements ITiledSingleLaye const geoField = await this._getGeoField(); - const urlTemplate = `${mvtUrlServicePath}?x={x}&y={y}&z={z}&geometryFieldName=${this._descriptor.geoField}&index=${indexPattern.title}&requestBody=${risonDsl}&geoFieldType=${geoField.type}`; + const urlTemplate = `${mvtUrlServicePath}\ +?x={x}\ +&y={y}\ +&z={z}\ +&geometryFieldName=${this._descriptor.geoField}\ +&index=${indexPattern.title}\ +&requestBody=${risonDsl}\ +&geoFieldType=${geoField.type}`; return { layerName: this.getLayerName(), minSourceZoom: this.getMinZoom(), maxSourceZoom: this.getMaxZoom(), - urlTemplate, + urlTemplate: searchFilters.searchSessionId + ? urlTemplate + `&searchSessionId=${searchFilters.searchSessionId}` + : urlTemplate, }; } } diff --git a/x-pack/plugins/maps/server/mvt/__fixtures__/json/0_0_0_gridagg.json b/x-pack/plugins/maps/server/mvt/__fixtures__/json/0_0_0_gridagg.json deleted file mode 100644 index 0945dc57fa51..000000000000 --- a/x-pack/plugins/maps/server/mvt/__fixtures__/json/0_0_0_gridagg.json +++ /dev/null @@ -1 +0,0 @@ -{"took":2,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":10000,"relation":"gte"},"max_score":null,"hits":[]},"aggregations":{"gridSplit":{"buckets":[{"key":"7/37/48","doc_count":42637,"avg_of_TOTAL_AV":{"value":5398920.390458991},"gridCentroid":{"location":{"lat":40.77936432658204,"lon":-73.96795676049909},"count":42637}}]}}} diff --git a/x-pack/plugins/maps/server/mvt/__fixtures__/json/0_0_0_search.json b/x-pack/plugins/maps/server/mvt/__fixtures__/json/0_0_0_search.json deleted file mode 100644 index 0fc99ffd811f..000000000000 --- a/x-pack/plugins/maps/server/mvt/__fixtures__/json/0_0_0_search.json +++ /dev/null @@ -1 +0,0 @@ -{"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":1,"relation":"eq"},"max_score":0,"hits":[{"_index":"poly","_id":"G7PRMXQBgyyZ-h5iYibj","_score":0,"_source":{"coordinates":{"coordinates":[[[-106.171875,36.59788913307022],[-50.625,-22.91792293614603],[4.921875,42.8115217450979],[-33.046875,63.54855223203644],[-66.796875,63.860035895395306],[-106.171875,36.59788913307022]]],"type":"polygon"}}}]}} diff --git a/x-pack/plugins/maps/server/mvt/__fixtures__/tile_es_responses.ts b/x-pack/plugins/maps/server/mvt/__fixtures__/tile_es_responses.ts deleted file mode 100644 index 9fbaba21e71d..000000000000 --- a/x-pack/plugins/maps/server/mvt/__fixtures__/tile_es_responses.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 * as path from 'path'; -import * as fs from 'fs'; - -export const TILE_SEARCHES = { - '0.0.0': { - countResponse: { - count: 1, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - }, - searchResponse: loadJson('./json/0_0_0_search.json'), - }, -}; - -export const TILE_GRIDAGGS = { - '0.0.0': { - gridAggResponse: loadJson('./json/0_0_0_gridagg.json'), - }, -}; - -function loadJson(filePath: string) { - const absolutePath = path.resolve(__dirname, filePath); - const rawContents = fs.readFileSync(absolutePath); - return JSON.parse((rawContents as unknown) as string); -} diff --git a/x-pack/plugins/maps/server/mvt/get_tile.test.ts b/x-pack/plugins/maps/server/mvt/get_tile.test.ts deleted file mode 100644 index c959d03c6ef8..000000000000 --- a/x-pack/plugins/maps/server/mvt/get_tile.test.ts +++ /dev/null @@ -1,261 +0,0 @@ -/* - * 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 { getGridTile, getTile } from './get_tile'; -import { TILE_GRIDAGGS, TILE_SEARCHES } from './__fixtures__/tile_es_responses'; -import { Logger } from 'src/core/server'; -import { - ES_GEO_FIELD_TYPE, - KBN_IS_CENTROID_FEATURE, - MVT_SOURCE_LAYER_NAME, - RENDER_AS, -} from '../../common/constants'; - -// @ts-expect-error -import { VectorTile, VectorTileLayer } from '@mapbox/vector-tile'; -// @ts-expect-error -import Protobuf from 'pbf'; - -interface ITileLayerJsonExpectation { - version: number; - name: string; - extent: number; - features: Array<{ - id: string | number | undefined; - type: number; - properties: object; - extent: number; - pointArrays: object; - }>; -} - -describe('getTile', () => { - const mockCallElasticsearch = jest.fn(); - - const requestBody = { - _source: { excludes: [] }, - docvalue_fields: [], - query: { bool: { filter: [{ match_all: {} }], must: [], must_not: [], should: [] } }, - script_fields: {}, - size: 10000, - stored_fields: ['*'], - }; - const geometryFieldName = 'coordinates'; - - beforeEach(() => { - mockCallElasticsearch.mockReset(); - }); - - test('0.0.0 - under limit', async () => { - mockCallElasticsearch.mockImplementation((type) => { - if (type === 'count') { - return TILE_SEARCHES['0.0.0'].countResponse; - } else if (type === 'search') { - return TILE_SEARCHES['0.0.0'].searchResponse; - } else { - throw new Error(`${type} not recognized`); - } - }); - - const pbfTile = await getTile({ - x: 0, - y: 0, - z: 0, - index: 'world_countries', - requestBody, - geometryFieldName, - logger: ({ - info: () => {}, - } as unknown) as Logger, - callElasticsearch: mockCallElasticsearch, - geoFieldType: ES_GEO_FIELD_TYPE.GEO_SHAPE, - }); - - const jsonTile = new VectorTile(new Protobuf(pbfTile)); - compareJsonTiles(jsonTile, { - version: 2, - name: 'source_layer', - extent: 4096, - features: [ - { - id: undefined, - type: 3, - properties: { - __kbn__feature_id__: 'poly:G7PRMXQBgyyZ-h5iYibj:0', - _id: 'G7PRMXQBgyyZ-h5iYibj', - _index: 'poly', - }, - extent: 4096, - pointArrays: [ - [ - { x: 840, y: 1600 }, - { x: 1288, y: 1096 }, - { x: 1672, y: 1104 }, - { x: 2104, y: 1508 }, - { x: 1472, y: 2316 }, - { x: 840, y: 1600 }, - ], - ], - }, - { - id: undefined, - type: 1, - properties: { - __kbn__feature_id__: 'poly:G7PRMXQBgyyZ-h5iYibj:0', - _id: 'G7PRMXQBgyyZ-h5iYibj', - _index: 'poly', - [KBN_IS_CENTROID_FEATURE]: true, - }, - extent: 4096, - pointArrays: [[{ x: 1470, y: 1702 }]], - }, - ], - }); - }); -}); - -describe('getGridTile', () => { - const mockCallElasticsearch = jest.fn(); - - const geometryFieldName = 'geometry'; - - // For mock-purposes only. The ES-call response is mocked in 0_0_0_gridagg.json file - const requestBody = { - _source: { excludes: [] }, - aggs: { - gridSplit: { - aggs: { - // eslint-disable-next-line @typescript-eslint/naming-convention - avg_of_TOTAL_AV: { avg: { field: 'TOTAL_AV' } }, - gridCentroid: { geo_centroid: { field: geometryFieldName } }, - }, - geotile_grid: { - bounds: null, - field: geometryFieldName, - precision: null, - shard_size: 65535, - size: 65535, - }, - }, - }, - docvalue_fields: [], - query: { - bool: { - filter: [], - }, - }, - script_fields: {}, - size: 0, - stored_fields: ['*'], - }; - - beforeEach(() => { - mockCallElasticsearch.mockReset(); - mockCallElasticsearch.mockImplementation((type) => { - return TILE_GRIDAGGS['0.0.0'].gridAggResponse; - }); - }); - - const defaultParams = { - x: 0, - y: 0, - z: 0, - index: 'manhattan', - requestBody, - geometryFieldName, - logger: ({ - info: () => {}, - } as unknown) as Logger, - callElasticsearch: mockCallElasticsearch, - requestType: RENDER_AS.POINT, - geoFieldType: ES_GEO_FIELD_TYPE.GEO_POINT, - }; - - test('0.0.0 tile (clusters)', async () => { - const pbfTile = await getGridTile(defaultParams); - const jsonTile = new VectorTile(new Protobuf(pbfTile)); - compareJsonTiles(jsonTile, { - version: 2, - name: 'source_layer', - extent: 4096, - features: [ - { - id: undefined, - type: 1, - properties: { - ['avg_of_TOTAL_AV']: 5398920.390458991, - doc_count: 42637, - }, - extent: 4096, - pointArrays: [[{ x: 1206, y: 1539 }]], - }, - ], - }); - }); - - test('0.0.0 tile (grids)', async () => { - const pbfTile = await getGridTile({ ...defaultParams, requestType: RENDER_AS.GRID }); - const jsonTile = new VectorTile(new Protobuf(pbfTile)); - compareJsonTiles(jsonTile, { - version: 2, - name: 'source_layer', - extent: 4096, - features: [ - { - id: undefined, - type: 3, - properties: { - ['avg_of_TOTAL_AV']: 5398920.390458991, - doc_count: 42637, - }, - extent: 4096, - pointArrays: [ - [ - { x: 1216, y: 1536 }, - { x: 1216, y: 1568 }, - { x: 1184, y: 1568 }, - { x: 1184, y: 1536 }, - { x: 1216, y: 1536 }, - ], - ], - }, - { - id: undefined, - type: 1, - properties: { - ['avg_of_TOTAL_AV']: 5398920.390458991, - doc_count: 42637, - [KBN_IS_CENTROID_FEATURE]: true, - }, - extent: 4096, - pointArrays: [[{ x: 1200, y: 1552 }]], - }, - ], - }); - }); -}); - -/** - * Verifies JSON-representation of tile-contents - * @param actualTileJson - * @param expectedLayer - */ -function compareJsonTiles(actualTileJson: VectorTile, expectedLayer: ITileLayerJsonExpectation) { - const actualLayer: VectorTileLayer = actualTileJson.layers[MVT_SOURCE_LAYER_NAME]; - expect(actualLayer.version).toEqual(expectedLayer.version); - expect(actualLayer.extent).toEqual(expectedLayer.extent); - expect(actualLayer.name).toEqual(expectedLayer.name); - expect(actualLayer.length).toEqual(expectedLayer.features.length); - - expectedLayer.features.forEach((expectedFeature, index) => { - const actualFeature = actualLayer.feature(index); - expect(actualFeature.type).toEqual(expectedFeature.type); - expect(actualFeature.extent).toEqual(expectedFeature.extent); - expect(actualFeature.id).toEqual(expectedFeature.id); - expect(actualFeature.properties).toEqual(expectedFeature.properties); - expect(actualFeature.loadGeometry()).toEqual(expectedFeature.pointArrays); - }); -} diff --git a/x-pack/plugins/maps/server/mvt/get_tile.ts b/x-pack/plugins/maps/server/mvt/get_tile.ts index ee4584904271..fb2b1b675dde 100644 --- a/x-pack/plugins/maps/server/mvt/get_tile.ts +++ b/x-pack/plugins/maps/server/mvt/get_tile.ts @@ -8,7 +8,8 @@ import geojsonvt from 'geojson-vt'; // @ts-expect-error import vtpbf from 'vt-pbf'; -import { Logger } from 'src/core/server'; +import { Logger, RequestHandlerContext } from 'src/core/server'; +import type { DataApiRequestHandlerContext } from 'src/plugins/data/server'; import { Feature, FeatureCollection, Polygon } from 'geojson'; import { ES_GEO_FIELD_TYPE, @@ -28,7 +29,7 @@ import { getCentroidFeatures } from '../../common/get_centroid_features'; export async function getGridTile({ logger, - callElasticsearch, + context, index, geometryFieldName, x, @@ -37,17 +38,19 @@ export async function getGridTile({ requestBody = {}, requestType = RENDER_AS.POINT, geoFieldType = ES_GEO_FIELD_TYPE.GEO_POINT, + searchSessionId, }: { x: number; y: number; z: number; geometryFieldName: string; index: string; - callElasticsearch: (type: string, ...args: any[]) => Promise; + context: RequestHandlerContext & { search: DataApiRequestHandlerContext }; logger: Logger; requestBody: any; requestType: RENDER_AS; geoFieldType: ES_GEO_FIELD_TYPE; + searchSessionId?: string; }): Promise { const esBbox: ESBounds = tileToESBbox(x, y, z); try { @@ -79,13 +82,20 @@ export async function getGridTile({ ); requestBody.aggs[GEOTILE_GRID_AGG_NAME].geotile_grid.bounds = esBbox; - const esGeotileGridQuery = { - index, - body: requestBody, - }; - - const gridAggResult = await callElasticsearch('search', esGeotileGridQuery); - const features: Feature[] = convertRegularRespToGeoJson(gridAggResult, requestType); + const response = await context + .search!.search( + { + params: { + index, + body: requestBody, + }, + }, + { + sessionId: searchSessionId, + } + ) + .toPromise(); + const features: Feature[] = convertRegularRespToGeoJson(response.rawResponse, requestType); const featureCollection: FeatureCollection = { features, type: 'FeatureCollection', @@ -100,7 +110,7 @@ export async function getGridTile({ export async function getTile({ logger, - callElasticsearch, + context, index, geometryFieldName, x, @@ -108,112 +118,121 @@ export async function getTile({ z, requestBody = {}, geoFieldType, + searchSessionId, }: { x: number; y: number; z: number; geometryFieldName: string; index: string; - callElasticsearch: (type: string, ...args: any[]) => Promise; + context: RequestHandlerContext & { search: DataApiRequestHandlerContext }; logger: Logger; requestBody: any; geoFieldType: ES_GEO_FIELD_TYPE; + searchSessionId?: string; }): Promise { - const geojsonBbox = tileToGeoJsonPolygon(x, y, z); - - let resultFeatures: Feature[]; + let features: Feature[]; try { - let result; - try { - const geoShapeFilter = { - geo_shape: { - [geometryFieldName]: { - shape: geojsonBbox, - relation: 'INTERSECTS', - }, + requestBody.query.bool.filter.push({ + geo_shape: { + [geometryFieldName]: { + shape: tileToGeoJsonPolygon(x, y, z), + relation: 'INTERSECTS', }, - }; - requestBody.query.bool.filter.push(geoShapeFilter); + }, + }); - const esSearchQuery = { - index, - body: requestBody, - }; + const searchOptions = { + sessionId: searchSessionId, + }; - const esCountQuery = { - index, - body: { - query: requestBody.query, + const countResponse = await context + .search!.search( + { + params: { + index, + body: { + size: 0, + query: requestBody.query, + }, + }, }, - }; - - const countResult = await callElasticsearch('count', esCountQuery); + searchOptions + ) + .toPromise(); - // @ts-expect-error - if (countResult.count > requestBody.size) { - // Generate "too many features"-bounds - const bboxAggName = 'data_bounds'; - const bboxQuery = { - index, - body: { - size: 0, - query: requestBody.query, - aggs: { - [bboxAggName]: { - geo_bounds: { - field: geometryFieldName, + if (countResponse.rawResponse.hits.total > requestBody.size) { + // Generate "too many features"-bounds + const bboxResponse = await context + .search!.search( + { + params: { + index, + body: { + size: 0, + query: requestBody.query, + aggs: { + data_bounds: { + geo_bounds: { + field: geometryFieldName, + }, + }, }, }, }, }, - }; - - const bboxResult = await callElasticsearch('search', bboxQuery); - - // @ts-expect-error - const bboxForData = esBboxToGeoJsonPolygon(bboxResult.aggregations[bboxAggName].bounds); + searchOptions + ) + .toPromise(); - resultFeatures = [ + features = [ + { + type: 'Feature', + properties: { + [KBN_TOO_MANY_FEATURES_PROPERTY]: true, + }, + geometry: esBboxToGeoJsonPolygon( + bboxResponse.rawResponse.aggregations.data_bounds.bounds + ), + }, + ]; + } else { + const documentsResponse = await context + .search!.search( { - type: 'Feature', - properties: { - [KBN_TOO_MANY_FEATURES_PROPERTY]: true, + params: { + index, + body: requestBody, }, - geometry: bboxForData, }, - ]; - } else { - result = await callElasticsearch('search', esSearchQuery); + searchOptions + ) + .toPromise(); - // Todo: pass in epochMillies-fields - const featureCollection = hitsToGeoJson( - // @ts-expect-error - result.hits.hits, - (hit: Record) => { - return flattenHit(geometryFieldName, hit); - }, - geometryFieldName, - geoFieldType, - [] - ); + // Todo: pass in epochMillies-fields + const featureCollection = hitsToGeoJson( + documentsResponse.rawResponse.hits.hits, + (hit: Record) => { + return flattenHit(geometryFieldName, hit); + }, + geometryFieldName, + geoFieldType, + [] + ); - resultFeatures = featureCollection.features; + features = featureCollection.features; - // Correct system-fields. - for (let i = 0; i < resultFeatures.length; i++) { - const props = resultFeatures[i].properties; - if (props !== null) { - props[FEATURE_ID_PROPERTY_NAME] = resultFeatures[i].id; - } + // Correct system-fields. + for (let i = 0; i < features.length; i++) { + const props = features[i].properties; + if (props !== null) { + props[FEATURE_ID_PROPERTY_NAME] = features[i].id; } } - } catch (e) { - logger.warn(e.message); - throw e; } const featureCollection: FeatureCollection = { - features: resultFeatures, + features, type: 'FeatureCollection', }; diff --git a/x-pack/plugins/maps/server/mvt/mvt_routes.ts b/x-pack/plugins/maps/server/mvt/mvt_routes.ts index fc298f73b04a..65692619b333 100644 --- a/x-pack/plugins/maps/server/mvt/mvt_routes.ts +++ b/x-pack/plugins/maps/server/mvt/mvt_routes.ts @@ -13,6 +13,7 @@ import { RequestHandlerContext, } from 'src/core/server'; import { IRouter } from 'src/core/server'; +import type { DataApiRequestHandlerContext } from 'src/plugins/data/server'; import { MVT_GETTILE_API_PATH, API_ROOT_PATH, @@ -24,7 +25,13 @@ import { getGridTile, getTile } from './get_tile'; const CACHE_TIMEOUT = 0; // Todo. determine good value. Unsure about full-implications (e.g. wrt. time-based data). -export function initMVTRoutes({ router, logger }: { logger: Logger; router: IRouter }) { +export function initMVTRoutes({ + router, + logger, +}: { + router: IRouter; + logger: Logger; +}) { router.get( { path: `${API_ROOT_PATH}/${MVT_GETTILE_API_PATH}`, @@ -37,11 +44,12 @@ export function initMVTRoutes({ router, logger }: { logger: Logger; router: IRou requestBody: schema.string(), index: schema.string(), geoFieldType: schema.string(), + searchSessionId: schema.maybe(schema.string()), }), }, }, async ( - context: RequestHandlerContext, + context: RequestHandlerContext & { search: DataApiRequestHandlerContext }, request: KibanaRequest, unknown>, response: KibanaResponseFactory ) => { @@ -50,7 +58,7 @@ export function initMVTRoutes({ router, logger }: { logger: Logger; router: IRou const tile = await getTile({ logger, - callElasticsearch: makeCallElasticsearch(context), + context, geometryFieldName: query.geometryFieldName as string, x: query.x as number, y: query.y as number, @@ -58,6 +66,7 @@ export function initMVTRoutes({ router, logger }: { logger: Logger; router: IRou index: query.index as string, requestBody: requestBodyDSL as any, geoFieldType: query.geoFieldType as ES_GEO_FIELD_TYPE, + searchSessionId: query.searchSessionId, }); return sendResponse(response, tile); @@ -77,11 +86,12 @@ export function initMVTRoutes({ router, logger }: { logger: Logger; router: IRou index: schema.string(), requestType: schema.string(), geoFieldType: schema.string(), + searchSessionId: schema.maybe(schema.string()), }), }, }, async ( - context: RequestHandlerContext, + context: RequestHandlerContext & { search: DataApiRequestHandlerContext }, request: KibanaRequest, unknown>, response: KibanaResponseFactory ) => { @@ -90,7 +100,7 @@ export function initMVTRoutes({ router, logger }: { logger: Logger; router: IRou const tile = await getGridTile({ logger, - callElasticsearch: makeCallElasticsearch(context), + context, geometryFieldName: query.geometryFieldName as string, x: query.x as number, y: query.y as number, @@ -99,6 +109,7 @@ export function initMVTRoutes({ router, logger }: { logger: Logger; router: IRou requestBody: requestBodyDSL as any, requestType: query.requestType as RENDER_AS, geoFieldType: query.geoFieldType as ES_GEO_FIELD_TYPE, + searchSessionId: query.searchSessionId, }); return sendResponse(response, tile); @@ -125,9 +136,3 @@ function sendResponse(response: KibanaResponseFactory, tile: any) { }); } } - -function makeCallElasticsearch(context: RequestHandlerContext) { - return async (type: string, ...args: any[]): Promise => { - return context.core.elasticsearch.legacy.client.callAsCurrentUser(type, ...args); - }; -} diff --git a/x-pack/test/api_integration/apis/maps/get_grid_tile.js b/x-pack/test/api_integration/apis/maps/get_grid_tile.js index 3eee56c962a2..0d499e186c70 100644 --- a/x-pack/test/api_integration/apis/maps/get_grid_tile.js +++ b/x-pack/test/api_integration/apis/maps/get_grid_tile.js @@ -4,26 +4,92 @@ * you may not use this file except in compliance with the Elastic License. */ +import { VectorTile } from '@mapbox/vector-tile'; +import Protobuf from 'pbf'; +import expect from '@kbn/expect'; +import { + KBN_IS_CENTROID_FEATURE, + MVT_SOURCE_LAYER_NAME, +} from '../../../../plugins/maps/common/constants'; + export default function ({ getService }) { const supertest = getService('supertest'); describe('getGridTile', () => { - it('should validate params', async () => { - await supertest + it('should return vector tile containing cluster features', async () => { + const resp = await supertest .get( - `/api/maps/mvt/getGridTile?x=0&y=0&z=0&geometryFieldName=coordinates&index=logstash*&requestBody=(_source:(excludes:!()),aggs:(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:coordinates))),geotile_grid:(bounds:!n,field:coordinates,precision:!n,shard_size:65535,size:65535))),docvalue_fields:!((field:%27@timestamp%27,format:date_time),(field:timestamp,format:date_time),(field:utc_time,format:date_time)),query:(bool:(filter:!((match_all:()),(range:(timestamp:(format:strict_date_optional_time,gte:%272020-09-16T13:57:36.734Z%27,lte:%272020-09-23T13:57:36.734Z%27)))),must:!(),must_not:!(),should:!())),script_fields:(hour_of_day:(script:(lang:painless,source:%27doc[!%27timestamp!%27].value.getHour()%27))),size:0,stored_fields:!(%27*%27))&requestType=point&geoFieldType=geo_point` + `/api/maps/mvt/getGridTile\ +?x=2\ +&y=3\ +&z=3\ +&geometryFieldName=geo.coordinates\ +&index=logstash-*\ +&requestBody=(_source:(excludes:!()),aggs:(gridSplit:(aggs:(avg_of_bytes:(avg:(field:bytes)),gridCentroid:(geo_centroid:(field:geo.coordinates))),geotile_grid:(bounds:!n,field:geo.coordinates,precision:!n,shard_size:65535,size:65535))),fields:!((field:%27@timestamp%27,format:date_time),(field:%27relatedContent.article:modified_time%27,format:date_time),(field:%27relatedContent.article:published_time%27,format:date_time),(field:utc_time,format:date_time)),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(hour_of_day:(script:(lang:painless,source:%27doc[!%27@timestamp!%27].value.getHour()%27))),size:0,stored_fields:!(%27*%27))\ +&requestType=point\ +&geoFieldType=geo_point` ) .set('kbn-xsrf', 'kibana') + .responseType('blob') .expect(200); + + const jsonTile = new VectorTile(new Protobuf(resp.body)); + const layer = jsonTile.layers[MVT_SOURCE_LAYER_NAME]; + expect(layer.length).to.be(1); + const clusterFeature = layer.feature(0); + expect(clusterFeature.type).to.be(1); + expect(clusterFeature.extent).to.be(4096); + expect(clusterFeature.id).to.be(undefined); + expect(clusterFeature.properties).to.eql({ doc_count: 1, avg_of_bytes: 9252 }); + expect(clusterFeature.loadGeometry()).to.eql([[{ x: 87, y: 667 }]]); }); - it('should not validate when required params are missing', async () => { - await supertest + it('should return vector tile containing grid features', async () => { + const resp = await supertest .get( - `/api/maps/mvt/getGridTile?x=0&y=0&z=0&geometryFieldName=coordinates&index=logstash*&requestBody=(_source:(excludes:!()),aggs:(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:coordinates))),geotile_grid:(bounds:!n,field:coordinates,precision:!n,shard_size:65535,size:65535))),docvalue_fields:!((field:%27@timestamp%27,format:date_time),(field:timestamp,format:date_time),(field:utc_time,format:date_time)),query:(bool:(filter:!((match_all:()),(range:(timestamp:(format:strict_date_optional_time,gte:%272020-09-16T13:57:36.734Z%27,lte:%272020-09-23T13:57:36.734Z%27)))),must:!(),must_not:!(),should:!())),script_fields:(hour_of_day:(script:(lang:painless,source:%27doc[!%27timestamp!%27].value.getHour()%27))),size:0,stored_fields:!(%27*%27))&requestType=point` + `/api/maps/mvt/getGridTile\ +?x=2\ +&y=3\ +&z=3\ +&geometryFieldName=geo.coordinates\ +&index=logstash-*\ +&requestBody=(_source:(excludes:!()),aggs:(gridSplit:(aggs:(avg_of_bytes:(avg:(field:bytes)),gridCentroid:(geo_centroid:(field:geo.coordinates))),geotile_grid:(bounds:!n,field:geo.coordinates,precision:!n,shard_size:65535,size:65535))),fields:!((field:%27@timestamp%27,format:date_time),(field:%27relatedContent.article:modified_time%27,format:date_time),(field:%27relatedContent.article:published_time%27,format:date_time),(field:utc_time,format:date_time)),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(hour_of_day:(script:(lang:painless,source:%27doc[!%27@timestamp!%27].value.getHour()%27))),size:0,stored_fields:!(%27*%27))\ +&requestType=grid\ +&geoFieldType=geo_point` ) .set('kbn-xsrf', 'kibana') - .expect(400); + .responseType('blob') + .expect(200); + + const jsonTile = new VectorTile(new Protobuf(resp.body)); + const layer = jsonTile.layers[MVT_SOURCE_LAYER_NAME]; + expect(layer.length).to.be(2); + + const gridFeature = layer.feature(0); + expect(gridFeature.type).to.be(3); + expect(gridFeature.extent).to.be(4096); + expect(gridFeature.id).to.be(undefined); + expect(gridFeature.properties).to.eql({ doc_count: 1, avg_of_bytes: 9252 }); + expect(gridFeature.loadGeometry()).to.eql([ + [ + { x: 96, y: 640 }, + { x: 96, y: 672 }, + { x: 64, y: 672 }, + { x: 64, y: 640 }, + { x: 96, y: 640 }, + ], + ]); + + const clusterFeature = layer.feature(1); + expect(clusterFeature.type).to.be(1); + expect(clusterFeature.extent).to.be(4096); + expect(clusterFeature.id).to.be(undefined); + expect(clusterFeature.properties).to.eql({ + doc_count: 1, + avg_of_bytes: 9252, + [KBN_IS_CENTROID_FEATURE]: true, + }); + expect(clusterFeature.loadGeometry()).to.eql([[{ x: 80, y: 656 }]]); }); }); } diff --git a/x-pack/test/api_integration/apis/maps/get_tile.js b/x-pack/test/api_integration/apis/maps/get_tile.js index 9dd0698b6c6e..e39f8a72ae6a 100644 --- a/x-pack/test/api_integration/apis/maps/get_tile.js +++ b/x-pack/test/api_integration/apis/maps/get_tile.js @@ -4,26 +4,82 @@ * you may not use this file except in compliance with the Elastic License. */ +import { VectorTile } from '@mapbox/vector-tile'; +import Protobuf from 'pbf'; +import expect from '@kbn/expect'; +import { MVT_SOURCE_LAYER_NAME } from '../../../../plugins/maps/common/constants'; + export default function ({ getService }) { const supertest = getService('supertest'); describe('getTile', () => { - it('should validate params', async () => { - await supertest + it('should return vector tile containing document', async () => { + const resp = await supertest .get( - `/api/maps/mvt/getTile?x=15&y=11&z=5&geometryFieldName=coordinates&index=logstash*&requestBody=(_source:(includes:!(coordinates)),docvalue_fields:!(),query:(bool:(filter:!((match_all:())),must:!(),must_not:!(),should:!())),script_fields:(),size:10000,stored_fields:!(coordinates))&geoFieldType=geo_point` + `/api/maps/mvt/getTile\ +?x=1\ +&y=1\ +&z=2\ +&geometryFieldName=geo.coordinates\ +&index=logstash-*\ +&requestBody=(_source:!f,docvalue_fields:!(bytes,geo.coordinates,machine.os.raw),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(),size:10000,stored_fields:!(bytes,geo.coordinates,machine.os.raw))\ +&geoFieldType=geo_point` ) .set('kbn-xsrf', 'kibana') + .responseType('blob') .expect(200); + + const jsonTile = new VectorTile(new Protobuf(resp.body)); + const layer = jsonTile.layers[MVT_SOURCE_LAYER_NAME]; + expect(layer.length).to.be(2); + const feature = layer.feature(0); + expect(feature.type).to.be(1); + expect(feature.extent).to.be(4096); + expect(feature.id).to.be(undefined); + expect(feature.properties).to.eql({ + __kbn__feature_id__: 'logstash-2015.09.20:AU_x3_BsGFA8no6Qjjug:0', + _id: 'AU_x3_BsGFA8no6Qjjug', + _index: 'logstash-2015.09.20', + bytes: 9252, + ['machine.os.raw']: 'ios', + }); + expect(feature.loadGeometry()).to.eql([[{ x: 44, y: 2382 }]]); }); - it('should not validate when required params are missing', async () => { - await supertest + it('should return vector tile containing bounds when count exceeds size', async () => { + const resp = await supertest + // requestBody sets size=1 to force count exceeded .get( - `/api/maps/mvt/getTile?&index=logstash*&requestBody=(_source:(includes:!(coordinates)),docvalue_fields:!(),query:(bool:(filter:!((match_all:())),must:!(),must_not:!(),should:!())),script_fields:(),size:10000,stored_fields:!(coordinates))` + `/api/maps/mvt/getTile\ +?x=1\ +&y=1\ +&z=2\ +&geometryFieldName=geo.coordinates\ +&index=logstash-*\ +&requestBody=(_source:!f,docvalue_fields:!(bytes,geo.coordinates,machine.os.raw),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(),size:1,stored_fields:!(bytes,geo.coordinates,machine.os.raw))\ +&geoFieldType=geo_point` ) .set('kbn-xsrf', 'kibana') - .expect(400); + .responseType('blob') + .expect(200); + + const jsonTile = new VectorTile(new Protobuf(resp.body)); + const layer = jsonTile.layers[MVT_SOURCE_LAYER_NAME]; + expect(layer.length).to.be(1); + const feature = layer.feature(0); + expect(feature.type).to.be(3); + expect(feature.extent).to.be(4096); + expect(feature.id).to.be(undefined); + expect(feature.properties).to.eql({ __kbn_too_many_features__: true }); + expect(feature.loadGeometry()).to.eql([ + [ + { x: 44, y: 2382 }, + { x: 44, y: 1913 }, + { x: 550, y: 1913 }, + { x: 550, y: 2382 }, + { x: 44, y: 2382 }, + ], + ]); }); }); } From 3da4c6bb2c58a2b61c1fca7afc4d3c0741de4cb5 Mon Sep 17 00:00:00 2001 From: Kevin Qualters <56408403+kqualters-elastic@users.noreply.github.com> Date: Tue, 2 Feb 2021 18:30:45 -0500 Subject: [PATCH 02/14] [Secutiy Solution] Timeline kpis (#89210) * Stub kpi component * search strategy scheleton timeline KPI * search strategy scheleton timeline KPI * Add timeline kpis component and search strategy container * Use getEmptyValue in timeline kpis * Prevent request from being made for blank timeline properly * Add kpi search strategy api integration test * Add jest tests for timeline kpis * Clear mocks in afterAll * Decouple some tests from EUI structure * Combine some selector calls, change types to be more appropriate * Simplify hook logic * Set loading and response on blank timeline * Only render kpi component when query is active tab * Use TimelineTabs enum for query tab string Co-authored-by: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../search_strategy/timeline/events/index.ts | 1 + .../timeline/events/last_event_time/index.ts | 9 ++ .../common/search_strategy/timeline/index.ts | 5 + .../components/flyout/header/index.test.tsx | 117 ++++++++++++++ .../components/flyout/header/index.tsx | 153 ++++++++++++++---- .../components/flyout/header/kpis.tsx | 68 ++++++++ .../components/flyout/header/translations.ts | 29 ++++ .../timelines/containers/kpis/index.tsx | 129 +++++++++++++++ .../timeline/factory/events/index.ts | 2 + .../timeline/factory/events/kpi/index.ts | 39 +++++ .../factory/events/kpi/query.kpi.dsl.ts | 86 ++++++++++ .../security_solution/timeline_details.ts | 27 ++++ 12 files changed, 631 insertions(+), 34 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx create mode 100644 x-pack/plugins/security_solution/public/timelines/containers/kpis/index.tsx create mode 100644 x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/kpi/index.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/kpi/query.kpi.dsl.ts diff --git a/x-pack/plugins/security_solution/common/search_strategy/timeline/events/index.ts b/x-pack/plugins/security_solution/common/search_strategy/timeline/events/index.ts index 6bb946199597..9dca1558d5a6 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/timeline/events/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/timeline/events/index.ts @@ -11,5 +11,6 @@ export * from './last_event_time'; export enum TimelineEventsQueries { all = 'eventsAll', details = 'eventsDetails', + kpi = 'eventsKpi', lastEventTime = 'eventsLastEventTime', } diff --git a/x-pack/plugins/security_solution/common/search_strategy/timeline/events/last_event_time/index.ts b/x-pack/plugins/security_solution/common/search_strategy/timeline/events/last_event_time/index.ts index 10750503fc80..d6c1be0594c0 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/timeline/events/last_event_time/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/timeline/events/last_event_time/index.ts @@ -25,6 +25,15 @@ export interface TimelineEventsLastEventTimeStrategyResponse extends IEsSearchRe inspect?: Maybe; } +export interface TimelineKpiStrategyResponse extends IEsSearchResponse { + destinationIpCount: number; + inspect?: Maybe; + hostCount: number; + processCount: number; + sourceIpCount: number; + userCount: number; +} + export interface TimelineEventsLastEventTimeRequestOptions extends Omit { indexKey: LastEventIndexKey; diff --git a/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts b/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts index d3ec2763f939..f6b937b516fd 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts @@ -13,6 +13,7 @@ import { TimelineEventsDetailsStrategyResponse, TimelineEventsLastEventTimeRequestOptions, TimelineEventsLastEventTimeStrategyResponse, + TimelineKpiStrategyResponse, } from './events'; import { DocValueFields, PaginationInputPaginated, TimerangeInput, SortField } from '../common'; @@ -44,6 +45,8 @@ export type TimelineStrategyResponseType< ? TimelineEventsAllStrategyResponse : T extends TimelineEventsQueries.details ? TimelineEventsDetailsStrategyResponse + : T extends TimelineEventsQueries.kpi + ? TimelineKpiStrategyResponse : T extends TimelineEventsQueries.lastEventTime ? TimelineEventsLastEventTimeStrategyResponse : never; @@ -54,6 +57,8 @@ export type TimelineStrategyRequestType< ? TimelineEventsAllRequestOptions : T extends TimelineEventsQueries.details ? TimelineEventsDetailsRequestOptions + : T extends TimelineEventsQueries.kpi + ? TimelineRequestBasicOptions : T extends TimelineEventsQueries.lastEventTime ? TimelineEventsLastEventTimeRequestOptions : never; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx new file mode 100644 index 000000000000..3a2f96e42025 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx @@ -0,0 +1,117 @@ +/* + * 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 { useKibana } from '../../../../common/lib/kibana'; +import { TestProviders, mockIndexNames, mockIndexPattern } from '../../../../common/mock'; +import { useTimelineKpis } from '../../../containers/kpis'; +import { FlyoutHeader } from '.'; +import { useSourcererScope } from '../../../../common/containers/sourcerer'; +import { mockBrowserFields, mockDocValueFields } from '../../../../common/containers/source/mock'; +import { useMountAppended } from '../../../../common/utils/use_mount_appended'; +import { getEmptyValue } from '../../../../common/components/empty_value'; + +const mockUseSourcererScope: jest.Mock = useSourcererScope as jest.Mock; +jest.mock('../../../../common/containers/sourcerer'); + +const mockUseTimelineKpis: jest.Mock = useTimelineKpis as jest.Mock; +jest.mock('../../../containers/kpis', () => ({ + useTimelineKpis: jest.fn(), +})); +const useKibanaMock = useKibana as jest.Mocked; +jest.mock('../../../../common/lib/kibana'); + +const mockUseTimelineKpiResponse = { + processCount: 1, + userCount: 1, + sourceIpCount: 1, + hostCount: 1, + destinationIpCount: 1, +}; +const defaultMocks = { + browserFields: mockBrowserFields, + docValueFields: mockDocValueFields, + indexPattern: mockIndexPattern, + loading: false, + selectedPatterns: mockIndexNames, +}; +describe('Timeline KPIs', () => { + const mount = useMountAppended(); + + beforeEach(() => { + // Mocking these services is required for the header component to render. + mockUseSourcererScope.mockImplementation(() => defaultMocks); + useKibanaMock().services.application.capabilities = { + navLinks: {}, + management: {}, + catalogue: {}, + actions: { show: true, crud: true }, + }; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('when the data is not loading and the response contains data', () => { + beforeEach(() => { + mockUseTimelineKpis.mockReturnValue([false, mockUseTimelineKpiResponse]); + }); + it('renders the component, labels and values succesfully', async () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="siem-timeline-kpis"]').exists()).toEqual(true); + // label + expect(wrapper.find('[data-test-subj="siem-timeline-process-kpi"]').first().text()).toEqual( + expect.stringContaining('Processes') + ); + // value + expect(wrapper.find('[data-test-subj="siem-timeline-process-kpi"]').first().text()).toEqual( + expect.stringContaining('1') + ); + }); + }); + + describe('when the data is loading', () => { + beforeEach(() => { + mockUseTimelineKpis.mockReturnValue([true, mockUseTimelineKpiResponse]); + }); + it('renders a loading indicator for values', async () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="siem-timeline-process-kpi"]').first().text()).toEqual( + expect.stringContaining('--') + ); + }); + }); + + describe('when the response is null and timeline is blank', () => { + beforeEach(() => { + mockUseTimelineKpis.mockReturnValue([false, null]); + }); + it('renders labels and the default empty string', async () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find('[data-test-subj="siem-timeline-process-kpi"]').first().text()).toEqual( + expect.stringContaining('Processes') + ); + expect(wrapper.find('[data-test-subj="siem-timeline-process-kpi"]').first().text()).toEqual( + expect.stringContaining(getEmptyValue()) + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx index 0e948afd5d7c..6e77971b8553 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx @@ -15,25 +15,42 @@ import { } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import { isEmpty, get, pick } from 'lodash/fp'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; import { FormattedRelative } from '@kbn/i18n/react'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; -import { TimelineStatus, TimelineTabs, TimelineType } from '../../../../../common/types/timeline'; +import { + TimelineStatus, + TimelineTabs, + TimelineType, + TimelineId, +} from '../../../../../common/types/timeline'; +import { State } from '../../../../common/store'; import { timelineActions, timelineSelectors } from '../../../store/timeline'; import { timelineDefaults } from '../../../../timelines/store/timeline/defaults'; import { AddToFavoritesButton } from '../../timeline/properties/helpers'; - +import { TimerangeInput } from '../../../../../common/search_strategy'; import { AddToCaseButton } from '../add_to_case_button'; import { AddTimelineButton } from '../add_timeline_button'; import { SaveTimelineButton } from '../../timeline/header/save_timeline_button'; +import { useKibana } from '../../../../common/lib/kibana'; import { InspectButton } from '../../../../common/components/inspect'; +import { useTimelineKpis } from '../../../containers/kpis'; +import { esQuery } from '../../../../../../../../src/plugins/data/public'; +import { useSourcererScope } from '../../../../common/containers/sourcerer'; +import { TimelineModel } from '../../../../timelines/store/timeline/model'; +import { + startSelector, + endSelector, +} from '../../../../common/components/super_date_picker/selectors'; +import { combineQueries, focusActiveTimelineButton } from '../../timeline/helpers'; +import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { ActiveTimelines } from './active_timelines'; import * as i18n from './translations'; import * as commonI18n from '../../timeline/properties/translations'; import { getTimelineStatusByIdSelector } from './selectors'; -import { focusActiveTimelineButton } from '../../timeline/helpers'; +import { TimelineKPIs } from './kpis'; // to hide side borders const StyledPanel = styled(EuiPanel)` @@ -227,38 +244,106 @@ const TimelineStatusInfoComponent: React.FC = ({ timelineId } const TimelineStatusInfo = React.memo(TimelineStatusInfoComponent); -const FlyoutHeaderComponent: React.FC = ({ timelineId }) => ( - - - - - - - - - - - - - - - - +const FlyoutHeaderComponent: React.FC = ({ timelineId }) => { + const { selectedPatterns, indexPattern, docValueFields, browserFields } = useSourcererScope( + SourcererScopeName.timeline + ); + const getStartSelector = useMemo(() => startSelector(), []); + const getEndSelector = useMemo(() => endSelector(), []); + const isActive = useMemo(() => timelineId === TimelineId.active, [timelineId]); + const timerange: TimerangeInput = useDeepEqualSelector((state) => { + if (isActive) { + return { + from: getStartSelector(state.inputs.timeline), + to: getEndSelector(state.inputs.timeline), + interval: '', + }; + } else { + return { + from: getStartSelector(state.inputs.global), + to: getEndSelector(state.inputs.global), + interval: '', + }; + } + }); + const { uiSettings } = useKibana().services; + const esQueryConfig = useMemo(() => esQuery.getEsQueryConfig(uiSettings), [uiSettings]); + const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); + const timeline: TimelineModel = useSelector( + (state: State) => getTimeline(state, timelineId) ?? timelineDefaults + ); + const { dataProviders, filters, timelineType, kqlMode, activeTab } = timeline; + const getKqlQueryTimeline = useMemo(() => timelineSelectors.getKqlFilterQuerySelector(), []); + const kqlQueryTimeline = useSelector((state: State) => getKqlQueryTimeline(state, timelineId)!); - {/* KPIs PLACEHOLDER */} + const kqlQueryExpression = + isEmpty(dataProviders) && isEmpty(kqlQueryTimeline) && timelineType === 'template' + ? ' ' + : kqlQueryTimeline; + const kqlQuery = useMemo(() => ({ query: kqlQueryExpression, language: 'kuery' }), [ + kqlQueryExpression, + ]); - - - - - - - - - - - -); + const isBlankTimeline: boolean = useMemo( + () => isEmpty(dataProviders) && isEmpty(filters) && isEmpty(kqlQuery.query), + [dataProviders, filters, kqlQuery] + ); + const combinedQueries = useMemo( + () => + combineQueries({ + config: esQueryConfig, + dataProviders, + indexPattern, + browserFields, + filters: filters ? filters : [], + kqlQuery, + kqlMode, + }), + [browserFields, dataProviders, esQueryConfig, filters, indexPattern, kqlMode, kqlQuery] + ); + const [loading, kpis] = useTimelineKpis({ + defaultIndex: selectedPatterns, + docValueFields, + timerange, + isBlankTimeline, + filterQuery: combinedQueries?.filterQuery ?? '', + }); + + return ( + + + + + + + + + + + + + + + + + + + {activeTab === TimelineTabs.query ? : null} + + + + + + + + + + + + + + ); +}; FlyoutHeaderComponent.displayName = 'FlyoutHeaderComponent'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx new file mode 100644 index 000000000000..b8dc10a878f8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx @@ -0,0 +1,68 @@ +/* + * 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 { EuiStat, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { TimelineKpiStrategyResponse } from '../../../../../common/search_strategy'; +import { getEmptyValue } from '../../../../common/components/empty_value'; +import * as i18n from './translations'; + +export const TimelineKPIs = React.memo( + ({ kpis, isLoading }: { kpis: TimelineKpiStrategyResponse | null; isLoading: boolean }) => { + return ( + + + + + + + + + + + + + + + + + + ); + } +); + +TimelineKPIs.displayName = 'TimelineKPIs'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/translations.ts index 6492731cdeba..8c4a0aa12ef8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/translations.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/translations.ts @@ -31,6 +31,35 @@ export const INSPECT_TIMELINE_TITLE = i18n.translate( } ); +export const PROCESS_KPI_TITLE = i18n.translate( + 'xpack.securitySolution.timeline.kpis.processKpiTitle', + { + defaultMessage: 'Processes', + } +); + +export const HOST_KPI_TITLE = i18n.translate('xpack.securitySolution.timeline.kpis.hostKpiTitle', { + defaultMessage: 'Hosts', +}); + +export const SOURCE_IP_KPI_TITLE = i18n.translate( + 'xpack.securitySolution.timeline.kpis.sourceIpKpiTitle', + { + defaultMessage: 'Source IPs', + } +); + +export const DESTINATION_IP_KPI_TITLE = i18n.translate( + 'xpack.securitySolution.timeline.kpis.destinationKpiTitle', + { + defaultMessage: 'Destination IPs', + } +); + +export const USER_KPI_TITLE = i18n.translate('xpack.securitySolution.timeline.kpis.userKpiTitle', { + defaultMessage: 'Users', +}); + export const TIMELINE_TOGGLE_BUTTON_ARIA_LABEL = ({ isOpen, title, diff --git a/x-pack/plugins/security_solution/public/timelines/containers/kpis/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/kpis/index.tsx new file mode 100644 index 000000000000..03d448f22827 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/containers/kpis/index.tsx @@ -0,0 +1,129 @@ +/* + * 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 { noop } from 'lodash/fp'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import deepEqual from 'fast-deep-equal'; + +import { inputsModel } from '../../../common/store'; +import { useKibana } from '../../../common/lib/kibana'; +import { + DocValueFields, + TimelineEventsQueries, + TimelineRequestBasicOptions, + TimelineKpiStrategyResponse, + TimerangeInput, +} from '../../../../common/search_strategy'; +import { ESQuery } from '../../../../common/typed_json'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/public'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; + +export interface UseTimelineKpiProps { + timerange: TimerangeInput; + filterQuery?: ESQuery | string | undefined; + defaultIndex: string[]; + docValueFields?: DocValueFields[]; + isBlankTimeline: boolean; +} + +export const useTimelineKpis = ({ + timerange, + filterQuery, + docValueFields, + defaultIndex, + isBlankTimeline, +}: UseTimelineKpiProps): [boolean, TimelineKpiStrategyResponse | null] => { + const { data, notifications } = useKibana().services; + const refetch = useRef(noop); + const abortCtrl = useRef(new AbortController()); + const didCancel = useRef(false); + const [loading, setLoading] = useState(false); + const [timelineKpiRequest, setTimelineKpiRequest] = useState( + null + ); + const [ + timelineKpiResponse, + setTimelineKpiResponse, + ] = useState(null); + const timelineKpiSearch = useCallback( + (request: TimelineRequestBasicOptions | null) => { + if (request == null) { + return; + } + didCancel.current = false; + const asyncSearch = async () => { + abortCtrl.current = new AbortController(); + setLoading(true); + + const searchSubscription$ = data.search + .search(request, { + strategy: 'securitySolutionTimelineSearchStrategy', + abortSignal: abortCtrl.current.signal, + }) + .subscribe({ + next: (response) => { + if (isCompleteResponse(response)) { + if (!didCancel.current) { + setLoading(false); + setTimelineKpiResponse(response); + } + searchSubscription$.unsubscribe(); + } else if (isErrorResponse(response)) { + if (!didCancel.current) { + setLoading(false); + } + notifications.toasts.addWarning('An error has occurred'); + searchSubscription$.unsubscribe(); + } + }, + error: (msg) => { + if (!didCancel.current) { + setLoading(false); + } + if (!(msg instanceof AbortError)) { + notifications.toasts.addDanger('Failed to load KPIs'); + } + }, + }); + }; + abortCtrl.current.abort(); + asyncSearch(); + refetch.current = asyncSearch; + }, + [data.search, notifications.toasts] + ); + + useEffect(() => { + setTimelineKpiRequest((prevRequest) => { + const myRequest = { + ...(prevRequest ?? {}), + docValueFields, + defaultIndex, + timerange, + filterQuery, + factoryQueryType: TimelineEventsQueries.kpi, + }; + if (!deepEqual(prevRequest, myRequest)) { + return myRequest; + } + return prevRequest; + }); + }, [docValueFields, defaultIndex, timerange, filterQuery]); + + useEffect(() => { + if (!isBlankTimeline) { + timelineKpiSearch(timelineKpiRequest); + } else { + setLoading(false); + setTimelineKpiResponse(null); + } + return () => { + didCancel.current = true; + abortCtrl.current.abort(); + }; + }, [isBlankTimeline, timelineKpiRequest, timelineKpiSearch]); + return [loading, timelineKpiResponse]; +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/index.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/index.ts index a4e2c168a41d..6d652d2721ea 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/index.ts @@ -12,6 +12,7 @@ import { import { SecuritySolutionTimelineFactory } from '../types'; import { timelineEventsAll } from './all'; import { timelineEventsDetails } from './details'; +import { timelineKpi } from './kpi'; import { timelineEventsLastEventTime } from './last_event_time'; export const timelineEventsFactory: Record< @@ -20,5 +21,6 @@ export const timelineEventsFactory: Record< > = { [TimelineEventsQueries.all]: timelineEventsAll, [TimelineEventsQueries.details]: timelineEventsDetails, + [TimelineEventsQueries.kpi]: timelineKpi, [TimelineEventsQueries.lastEventTime]: timelineEventsLastEventTime, }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/kpi/index.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/kpi/index.ts new file mode 100644 index 000000000000..ee84a0faab2c --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/kpi/index.ts @@ -0,0 +1,39 @@ +/* + * 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 { getOr } from 'lodash/fp'; + +import { IEsSearchResponse } from '../../../../../../../../../src/plugins/data/common'; +import { + TimelineEventsQueries, + TimelineRequestBasicOptions, + TimelineKpiStrategyResponse, +} from '../../../../../../common/search_strategy/timeline'; +import { inspectStringifyObject } from '../../../../../utils/build_query'; +import { SecuritySolutionTimelineFactory } from '../../types'; +import { buildTimelineKpiQuery } from './query.kpi.dsl'; + +export const timelineKpi: SecuritySolutionTimelineFactory = { + buildDsl: (options: TimelineRequestBasicOptions) => buildTimelineKpiQuery(options), + parse: async ( + options: TimelineRequestBasicOptions, + response: IEsSearchResponse + ): Promise => { + const inspect = { + dsl: [inspectStringifyObject(buildTimelineKpiQuery(options))], + }; + + return { + ...response, + destinationIpCount: getOr(0, 'aggregations.destinationIpCount.value', response.rawResponse), + inspect, + hostCount: getOr(0, 'aggregations.hostCount.value', response.rawResponse), + processCount: getOr(0, 'aggregations.processCount.value', response.rawResponse), + sourceIpCount: getOr(0, 'aggregations.sourceIpCount.value', response.rawResponse), + userCount: getOr(0, 'aggregations.userCount.value', response.rawResponse), + }; + }, +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/kpi/query.kpi.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/kpi/query.kpi.dsl.ts new file mode 100644 index 000000000000..b0333411bdee --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/kpi/query.kpi.dsl.ts @@ -0,0 +1,86 @@ +/* + * 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 { isEmpty } from 'lodash/fp'; + +import { + TimerangeFilter, + TimerangeInput, + TimelineRequestBasicOptions, +} from '../../../../../../common/search_strategy'; +import { createQueryFilterClauses } from '../../../../../utils/build_query'; + +export const buildTimelineKpiQuery = ({ + defaultIndex, + filterQuery, + timerange, +}: TimelineRequestBasicOptions) => { + const filterClause = [...createQueryFilterClauses(filterQuery)]; + + const getTimerangeFilter = (timerangeOption: TimerangeInput | undefined): TimerangeFilter[] => { + if (timerangeOption) { + const { to, from } = timerangeOption; + return !isEmpty(to) && !isEmpty(from) + ? [ + { + range: { + '@timestamp': { + gte: from, + lte: to, + format: 'strict_date_optional_time', + }, + }, + }, + ] + : []; + } + return []; + }; + + const filter = [...filterClause, ...getTimerangeFilter(timerange), { match_all: {} }]; + + const dslQuery = { + allowNoIndices: true, + index: defaultIndex, + ignoreUnavailable: true, + body: { + aggs: { + userCount: { + cardinality: { + field: 'user.id', + }, + }, + destinationIpCount: { + cardinality: { + field: 'destination.ip', + }, + }, + hostCount: { + cardinality: { + field: 'host.id', + }, + }, + processCount: { + cardinality: { + field: 'process.entity_id', + }, + }, + sourceIpCount: { + cardinality: { + field: 'source.ip', + }, + }, + }, + query: { + bool: { + filter, + }, + }, + track_total_hits: true, + }, + }; + + return dslQuery; +}; diff --git a/x-pack/test/api_integration/apis/security_solution/timeline_details.ts b/x-pack/test/api_integration/apis/security_solution/timeline_details.ts index aec9a896afc7..da104e5124b3 100644 --- a/x-pack/test/api_integration/apis/security_solution/timeline_details.ts +++ b/x-pack/test/api_integration/apis/security_solution/timeline_details.ts @@ -558,6 +558,14 @@ const EXPECTED_DATA = [ }, ]; +const EXPECTED_KPI_COUNTS = { + destinationIpCount: 154, + hostCount: 1, + processCount: 0, + sourceIpCount: 121, + userCount: 0, +}; + export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); @@ -587,5 +595,24 @@ export default function ({ getService }: FtrProviderContext) { }) ).to.eql(sortBy(EXPECTED_DATA, 'name')); }); + + it('Make sure that we get kpi data', async () => { + const { + body: { destinationIpCount, hostCount, processCount, sourceIpCount, userCount }, + } = await supertest + .post('/internal/search/securitySolutionTimelineSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: TimelineEventsQueries.kpi, + docValueFields: [], + indexName: INDEX_NAME, + inspect: false, + eventId: ID, + }) + .expect(200); + expect({ destinationIpCount, hostCount, processCount, sourceIpCount, userCount }).to.eql( + EXPECTED_KPI_COUNTS + ); + }); }); } From 9246f398ea116df796a33aa499983bdfbd23c685 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 2 Feb 2021 16:55:41 -0700 Subject: [PATCH 03/14] [esArchiver] upgrade to new ES client (#89874) Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- package.json | 1 + .../src/actions/empty_kibana_index.ts | 2 +- packages/kbn-es-archiver/src/actions/load.ts | 4 +- packages/kbn-es-archiver/src/actions/save.ts | 2 +- .../kbn-es-archiver/src/actions/unload.ts | 2 +- packages/kbn-es-archiver/src/cli.ts | 7 +- packages/kbn-es-archiver/src/es_archiver.ts | 2 +- .../src/lib/docs/__mocks__/stubs.ts | 67 - .../docs/generate_doc_records_stream.test.ts | 269 ++-- .../lib/docs/generate_doc_records_stream.ts | 41 +- .../lib/docs/index_doc_records_stream.test.ts | 382 +++-- .../src/lib/docs/index_doc_records_stream.ts | 39 +- .../src/lib/indices/__mocks__/stubs.ts | 33 +- .../lib/indices/create_index_stream.test.ts | 38 +- .../src/lib/indices/create_index_stream.ts | 7 +- .../src/lib/indices/delete_index.ts | 52 +- .../src/lib/indices/delete_index_stream.ts | 2 +- .../generate_index_records_stream.test.ts | 4 +- .../indices/generate_index_records_stream.ts | 40 +- .../src/lib/indices/kibana_index.ts | 89 +- packages/kbn-pm/dist/index.js | 1232 +++++++++-------- test/common/services/es_archiver.ts | 2 +- yarn.lock | 8 + 23 files changed, 1301 insertions(+), 1024 deletions(-) delete mode 100644 packages/kbn-es-archiver/src/lib/docs/__mocks__/stubs.ts diff --git a/package.json b/package.json index 920e0c8ba519..a5754e13d2a0 100644 --- a/package.json +++ b/package.json @@ -568,6 +568,7 @@ "@welldone-software/why-did-you-render": "^5.0.0", "@yarnpkg/lockfile": "^1.1.0", "abab": "^2.0.4", + "aggregate-error": "^3.1.0", "angular-aria": "^1.8.0", "angular-mocks": "^1.7.9", "angular-recursion": "^1.0.5", diff --git a/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts b/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts index 56c75c5aca41..db7c79c7dfc5 100644 --- a/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts +++ b/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts @@ -6,7 +6,7 @@ * Public License, v 1. */ -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { ToolingLog, KbnClient } from '@kbn/dev-utils'; import { migrateKibanaIndex, createStats, cleanKibanaIndices } from '../lib'; diff --git a/packages/kbn-es-archiver/src/actions/load.ts b/packages/kbn-es-archiver/src/actions/load.ts index c32496ad4269..592fb3ff90af 100644 --- a/packages/kbn-es-archiver/src/actions/load.ts +++ b/packages/kbn-es-archiver/src/actions/load.ts @@ -10,7 +10,7 @@ import { resolve } from 'path'; import { createReadStream } from 'fs'; import { Readable } from 'stream'; import { ToolingLog, KbnClient } from '@kbn/dev-utils'; -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { createPromiseFromStreams, concatStreamProviders } from '@kbn/utils'; @@ -92,7 +92,7 @@ export async function loadAction({ await client.indices.refresh({ index: '_all', - allowNoIndices: true, + allow_no_indices: true, }); // If we affected the Kibana index, we need to ensure it's migrated... diff --git a/packages/kbn-es-archiver/src/actions/save.ts b/packages/kbn-es-archiver/src/actions/save.ts index d88871f5b422..63b09ef8981a 100644 --- a/packages/kbn-es-archiver/src/actions/save.ts +++ b/packages/kbn-es-archiver/src/actions/save.ts @@ -9,7 +9,7 @@ import { resolve } from 'path'; import { createWriteStream, mkdirSync } from 'fs'; import { Readable, Writable } from 'stream'; -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { createListStream, createPromiseFromStreams } from '@kbn/utils'; diff --git a/packages/kbn-es-archiver/src/actions/unload.ts b/packages/kbn-es-archiver/src/actions/unload.ts index 07cbf2aec39f..94b8387d3df0 100644 --- a/packages/kbn-es-archiver/src/actions/unload.ts +++ b/packages/kbn-es-archiver/src/actions/unload.ts @@ -9,7 +9,7 @@ import { resolve } from 'path'; import { createReadStream } from 'fs'; import { Readable, Writable } from 'stream'; -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { ToolingLog, KbnClient } from '@kbn/dev-utils'; import { createPromiseFromStreams } from '@kbn/utils'; diff --git a/packages/kbn-es-archiver/src/cli.ts b/packages/kbn-es-archiver/src/cli.ts index e3114b4e78cf..cba2a25b9e27 100644 --- a/packages/kbn-es-archiver/src/cli.ts +++ b/packages/kbn-es-archiver/src/cli.ts @@ -19,7 +19,7 @@ import Fs from 'fs'; import { RunWithCommands, createFlagError, KbnClient, CA_CERT_PATH } from '@kbn/dev-utils'; import { readConfigFile } from '@kbn/test'; -import legacyElasticsearch from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { EsArchiver } from './es_archiver'; @@ -115,10 +115,9 @@ export function runCli() { throw createFlagError('--dir or --config must be defined'); } - const client = new legacyElasticsearch.Client({ - host: esUrl, + const client = new Client({ + node: esUrl, ssl: esCa ? { ca: esCa } : undefined, - log: flags.verbose ? 'trace' : [], }); addCleanupTask(() => client.close()); diff --git a/packages/kbn-es-archiver/src/es_archiver.ts b/packages/kbn-es-archiver/src/es_archiver.ts index f101c5d6867f..9176de60544f 100644 --- a/packages/kbn-es-archiver/src/es_archiver.ts +++ b/packages/kbn-es-archiver/src/es_archiver.ts @@ -6,7 +6,7 @@ * Public License, v 1. */ -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { ToolingLog, KbnClient } from '@kbn/dev-utils'; import { diff --git a/packages/kbn-es-archiver/src/lib/docs/__mocks__/stubs.ts b/packages/kbn-es-archiver/src/lib/docs/__mocks__/stubs.ts deleted file mode 100644 index 3cdf3e24c328..000000000000 --- a/packages/kbn-es-archiver/src/lib/docs/__mocks__/stubs.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * and the Server Side Public License, v 1; you may not use this file except in - * compliance with, at your election, the Elastic License or the Server Side - * Public License, v 1. - */ - -import { Client } from 'elasticsearch'; -import sinon from 'sinon'; -import Chance from 'chance'; -import { times } from 'lodash'; - -import { Stats } from '../../stats'; - -const chance = new Chance(); - -export const createStubStats = (): Stats => - ({ - indexedDoc: sinon.stub(), - archivedDoc: sinon.stub(), - } as any); - -export const createPersonDocRecords = (n: number) => - times(n, () => ({ - type: 'doc', - value: { - index: 'people', - type: 'person', - id: chance.natural(), - source: { - name: chance.name(), - birthday: chance.birthday(), - ssn: chance.ssn(), - }, - }, - })); - -type MockClient = Client & { - assertNoPendingResponses: () => void; -}; - -export const createStubClient = ( - responses: Array<(name: string, params: any) => any | Promise> = [] -): MockClient => { - const createStubClientMethod = (name: string) => - sinon.spy(async (params) => { - if (responses.length === 0) { - throw new Error(`unexpected client.${name} call`); - } - - const response = responses.shift(); - return await response!(name, params); - }); - - return { - search: createStubClientMethod('search'), - scroll: createStubClientMethod('scroll'), - bulk: createStubClientMethod('bulk'), - - assertNoPendingResponses() { - if (responses.length) { - throw new Error(`There are ${responses.length} unsent responses.`); - } - }, - } as any; -}; diff --git a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts index e28711ad140b..217c5aaf767f 100644 --- a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.test.ts @@ -6,128 +6,185 @@ * Public License, v 1. */ -import sinon from 'sinon'; -import { delay } from 'bluebird'; -import { createListStream, createPromiseFromStreams, createConcatStream } from '@kbn/utils'; +import { + createListStream, + createPromiseFromStreams, + createConcatStream, + createMapStream, + ToolingLog, +} from '@kbn/dev-utils'; import { createGenerateDocRecordsStream } from './generate_doc_records_stream'; import { Progress } from '../progress'; -import { createStubStats, createStubClient } from './__mocks__/stubs'; +import { createStats } from '../stats'; -describe('esArchiver: createGenerateDocRecordsStream()', () => { - it('scolls 1000 documents at a time', async () => { - const stats = createStubStats(); - const client = createStubClient([ - (name, params) => { - expect(name).toBe('search'); - expect(params).toHaveProperty('index', 'logstash-*'); - expect(params).toHaveProperty('size', 1000); - return { +const log = new ToolingLog(); + +it('transforms each input index to a stream of docs using scrollSearch helper', async () => { + const responses: any = { + foo: [ + { + body: { hits: { - total: 0, - hits: [], + total: 5, + hits: [ + { _index: 'foo', _type: '_doc', _id: '0', _source: {} }, + { _index: 'foo', _type: '_doc', _id: '1', _source: {} }, + { _index: 'foo', _type: '_doc', _id: '2', _source: {} }, + ], }, - }; + }, }, - ]); - - const progress = new Progress(); - await createPromiseFromStreams([ - createListStream(['logstash-*']), - createGenerateDocRecordsStream({ client, stats, progress }), - ]); - - expect(progress.getTotal()).toBe(0); - expect(progress.getComplete()).toBe(0); - }); - - it('uses a 1 minute scroll timeout', async () => { - const stats = createStubStats(); - const client = createStubClient([ - (name, params) => { - expect(name).toBe('search'); - expect(params).toHaveProperty('index', 'logstash-*'); - expect(params).toHaveProperty('scroll', '1m'); - expect(params).toHaveProperty('rest_total_hits_as_int', true); - return { + { + body: { hits: { - total: 0, - hits: [], + total: 5, + hits: [ + { _index: 'foo', _type: '_doc', _id: '3', _source: {} }, + { _index: 'foo', _type: '_doc', _id: '4', _source: {} }, + ], }, - }; + }, }, - ]); - - const progress = new Progress(); - await createPromiseFromStreams([ - createListStream(['logstash-*']), - createGenerateDocRecordsStream({ client, stats, progress }), - ]); + ], + bar: [ + { + body: { + hits: { + total: 2, + hits: [ + { _index: 'bar', _type: '_doc', _id: '0', _source: {} }, + { _index: 'bar', _type: '_doc', _id: '1', _source: {} }, + ], + }, + }, + }, + ], + }; - expect(progress.getTotal()).toBe(0); - expect(progress.getComplete()).toBe(0); - }); + const client: any = { + helpers: { + scrollSearch: jest.fn(function* ({ index }) { + while (responses[index] && responses[index].length) { + yield responses[index].shift()!; + } + }), + }, + }; - it('consumes index names and scrolls completely before continuing', async () => { - const stats = createStubStats(); - let checkpoint = Date.now(); - const client = createStubClient([ - async (name, params) => { - expect(name).toBe('search'); - expect(params).toHaveProperty('index', 'index1'); - await delay(200); - return { - _scroll_id: 'index1ScrollId', - hits: { total: 2, hits: [{ _id: 1, _index: '.kibana_foo' }] }, - }; - }, - async (name, params) => { - expect(name).toBe('scroll'); - expect(params).toHaveProperty('scrollId', 'index1ScrollId'); - expect(Date.now() - checkpoint).not.toBeLessThan(200); - checkpoint = Date.now(); - await delay(200); - return { hits: { total: 2, hits: [{ _id: 2, _index: 'foo' }] } }; - }, - async (name, params) => { - expect(name).toBe('search'); - expect(params).toHaveProperty('index', 'index2'); - expect(Date.now() - checkpoint).not.toBeLessThan(200); - checkpoint = Date.now(); - await delay(200); - return { hits: { total: 0, hits: [] } }; - }, - ]); + const stats = createStats('test', log); + const progress = new Progress(); - const progress = new Progress(); - const docRecords = await createPromiseFromStreams([ - createListStream(['index1', 'index2']), - createGenerateDocRecordsStream({ client, stats, progress }), - createConcatStream([]), - ]); + const results = await createPromiseFromStreams([ + createListStream(['bar', 'foo']), + createGenerateDocRecordsStream({ + client, + stats, + progress, + }), + createMapStream((record: any) => { + expect(record).toHaveProperty('type', 'doc'); + expect(record.value.source).toEqual({}); + expect(record.value.type).toBe('_doc'); + expect(record.value.index).toMatch(/^(foo|bar)$/); + expect(record.value.id).toMatch(/^\d+$/); + return `${record.value.index}:${record.value.id}`; + }), + createConcatStream([]), + ]); - expect(docRecords).toEqual([ - { - type: 'doc', - value: { - index: '.kibana_1', - type: undefined, - id: 1, - source: undefined, + expect(client.helpers.scrollSearch).toMatchInlineSnapshot(` + [MockFunction] { + "calls": Array [ + Array [ + Object { + "_source": "true", + "body": Object { + "query": undefined, + }, + "index": "bar", + "rest_total_hits_as_int": true, + "scroll": "1m", + "size": 1000, + }, + ], + Array [ + Object { + "_source": "true", + "body": Object { + "query": undefined, + }, + "index": "foo", + "rest_total_hits_as_int": true, + "scroll": "1m", + "size": 1000, + }, + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Object {}, + }, + Object { + "type": "return", + "value": Object {}, + }, + ], + } + `); + expect(results).toMatchInlineSnapshot(` + Array [ + "bar:0", + "bar:1", + "foo:0", + "foo:1", + "foo:2", + "foo:3", + "foo:4", + ] + `); + expect(progress).toMatchInlineSnapshot(` + Progress { + "complete": 7, + "loggingInterval": undefined, + "total": 7, + } + `); + expect(stats).toMatchInlineSnapshot(` + Object { + "bar": Object { + "archived": false, + "configDocs": Object { + "tagged": 0, + "upToDate": 0, + "upgraded": 0, }, + "created": false, + "deleted": false, + "docs": Object { + "archived": 2, + "indexed": 0, + }, + "skipped": false, + "waitForSnapshot": 0, }, - { - type: 'doc', - value: { - index: 'foo', - type: undefined, - id: 2, - source: undefined, + "foo": Object { + "archived": false, + "configDocs": Object { + "tagged": 0, + "upToDate": 0, + "upgraded": 0, + }, + "created": false, + "deleted": false, + "docs": Object { + "archived": 5, + "indexed": 0, }, + "skipped": false, + "waitForSnapshot": 0, }, - ]); - sinon.assert.calledTwice(stats.archivedDoc as any); - expect(progress.getTotal()).toBe(2); - expect(progress.getComplete()).toBe(2); - }); + } + `); }); diff --git a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts index 7c236214fb03..a375753628e4 100644 --- a/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/docs/generate_doc_records_stream.ts @@ -7,7 +7,7 @@ */ import { Transform } from 'stream'; -import { Client, SearchParams, SearchResponse } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { Stats } from '../stats'; import { Progress } from '../progress'; @@ -30,31 +30,26 @@ export function createGenerateDocRecordsStream({ readableObjectMode: true, async transform(index, enc, callback) { try { - let remainingHits = 0; - let resp: SearchResponse | null = null; + const interator = client.helpers.scrollSearch({ + index, + scroll: SCROLL_TIMEOUT, + size: SCROLL_SIZE, + _source: 'true', + body: { + query, + }, + rest_total_hits_as_int: true, + }); - while (!resp || remainingHits > 0) { - if (!resp) { - resp = await client.search({ - index, - scroll: SCROLL_TIMEOUT, - size: SCROLL_SIZE, - _source: true, - body: { - query, - }, - rest_total_hits_as_int: true, // not declared on SearchParams type - } as SearchParams); - remainingHits = resp.hits.total; + let remainingHits: number | null = null; + + for await (const resp of interator) { + if (remainingHits === null) { + remainingHits = resp.body.hits.total as number; progress.addToTotal(remainingHits); - } else { - resp = await client.scroll({ - scrollId: resp._scroll_id!, - scroll: SCROLL_TIMEOUT, - }); } - for (const hit of resp.hits.hits) { + for (const hit of resp.body.hits.hits) { remainingHits -= 1; stats.archivedDoc(hit._index); this.push({ @@ -70,7 +65,7 @@ export function createGenerateDocRecordsStream({ }); } - progress.addToComplete(resp.hits.hits.length); + progress.addToComplete(resp.body.hits.hits.length); } callback(undefined); diff --git a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.test.ts b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.test.ts index b2b8d9d310ab..a86359262bd4 100644 --- a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.test.ts @@ -6,170 +6,278 @@ * Public License, v 1. */ -import { delay } from 'bluebird'; -import { createListStream, createPromiseFromStreams } from '@kbn/utils'; +import { + createListStream, + createPromiseFromStreams, + ToolingLog, + createRecursiveSerializer, +} from '@kbn/dev-utils'; import { Progress } from '../progress'; import { createIndexDocRecordsStream } from './index_doc_records_stream'; -import { createStubStats, createStubClient, createPersonDocRecords } from './__mocks__/stubs'; - -const recordsToBulkBody = (records: any[]) => { - return records.reduce((acc, record) => { - const { index, id, source } = record.value; - - return [...acc, { index: { _index: index, _id: id } }, source]; - }, [] as any[]); -}; - -describe('esArchiver: createIndexDocRecordsStream()', () => { - it('consumes doc records and sends to `_bulk` api', async () => { - const records = createPersonDocRecords(1); - const client = createStubClient([ - async (name, params) => { - expect(name).toBe('bulk'); - expect(params).toEqual({ - body: recordsToBulkBody(records), - requestTimeout: 120000, - }); - return { ok: true }; - }, - ]); - const stats = createStubStats(); - const progress = new Progress(); +import { createStats } from '../stats'; - await createPromiseFromStreams([ - createListStream(records), - createIndexDocRecordsStream(client, stats, progress), - ]); +const AT_LINE_RE = /^\s+at /m; - client.assertNoPendingResponses(); - expect(progress.getComplete()).toBe(1); - expect(progress.getTotal()).toBe(undefined); - }); +expect.addSnapshotSerializer( + createRecursiveSerializer( + (v) => typeof v === 'string' && AT_LINE_RE.test(v), + (v: string) => { + const lines = v.split('\n'); + const withoutStack: string[] = []; - it('consumes multiple doc records and sends to `_bulk` api together', async () => { - const records = createPersonDocRecords(10); - const client = createStubClient([ - async (name, params) => { - expect(name).toBe('bulk'); - expect(params).toEqual({ - body: recordsToBulkBody(records.slice(0, 1)), - requestTimeout: 120000, - }); - return { ok: true }; + // move source lines to withoutStack, filtering out stacktrace lines + while (lines.length) { + const line = lines.shift()!; + + if (!AT_LINE_RE.test(line)) { + withoutStack.push(line); + } else { + // push in representation of stack trace indented to match "at" + withoutStack.push(`${' '.repeat(line.indexOf('at'))}`); + + // shift off all subsequent `at ...` lines + while (lines.length && AT_LINE_RE.test(lines[0])) { + lines.shift(); + } + } + } + + return withoutStack.join('\n'); + } + ) +); + +const log = new ToolingLog(); + +class MockClient { + helpers = { + bulk: jest.fn(), + }; +} + +const testRecords = [ + { + type: 'doc', + value: { + index: 'foo', + id: '0', + source: { + hello: 'world', }, - async (name, params) => { - expect(name).toBe('bulk'); - expect(params).toEqual({ - body: recordsToBulkBody(records.slice(1)), - requestTimeout: 120000, - }); - return { ok: true }; + }, + }, + { + type: 'doc', + value: { + index: 'foo', + id: '1', + source: { + hello: 'world', }, - ]); - const stats = createStubStats(); - const progress = new Progress(); + }, + }, + { + type: 'doc', + value: { + index: 'foo', + id: '2', + source: { + hello: 'world', + }, + }, + }, + { + type: 'doc', + value: { + index: 'foo', + id: '3', + source: { + hello: 'world', + }, + }, + }, +]; - await createPromiseFromStreams([ - createListStream(records), - createIndexDocRecordsStream(client, stats, progress), - ]); +it('indexes documents using the bulk client helper', async () => { + const client = new MockClient(); + client.helpers.bulk.mockImplementation(async () => {}); - client.assertNoPendingResponses(); - expect(progress.getComplete()).toBe(10); - expect(progress.getTotal()).toBe(undefined); - }); + const progress = new Progress(); + const stats = createStats('test', log); - it('waits until request is complete before sending more', async () => { - const records = createPersonDocRecords(10); - const stats = createStubStats(); - const start = Date.now(); - const delayMs = 1234; - const client = createStubClient([ - async (name, params) => { - expect(name).toBe('bulk'); - expect(params).toEqual({ - body: recordsToBulkBody(records.slice(0, 1)), - requestTimeout: 120000, - }); - await delay(delayMs); - return { ok: true }; + await createPromiseFromStreams([ + createListStream(testRecords), + createIndexDocRecordsStream(client as any, stats, progress), + ]); + + expect(stats).toMatchInlineSnapshot(` + Object { + "foo": Object { + "archived": false, + "configDocs": Object { + "tagged": 0, + "upToDate": 0, + "upgraded": 0, + }, + "created": false, + "deleted": false, + "docs": Object { + "archived": 0, + "indexed": 4, + }, + "skipped": false, + "waitForSnapshot": 0, }, - async (name, params) => { - expect(name).toBe('bulk'); - expect(params).toEqual({ - body: recordsToBulkBody(records.slice(1)), - requestTimeout: 120000, + } + `); + expect(progress).toMatchInlineSnapshot(` + Progress { + "complete": 4, + "loggingInterval": undefined, + "total": undefined, + } + `); + expect(client.helpers.bulk).toMatchInlineSnapshot(` + [MockFunction] { + "calls": Array [ + Array [ + Object { + "datasource": Array [ + Object { + "hello": "world", + }, + ], + "onDocument": [Function], + "onDrop": [Function], + "retries": 5, + }, + ], + Array [ + Object { + "datasource": Array [ + Object { + "hello": "world", + }, + Object { + "hello": "world", + }, + Object { + "hello": "world", + }, + ], + "onDocument": [Function], + "onDrop": [Function], + "retries": 5, + }, + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + Object { + "type": "return", + "value": Promise {}, + }, + ], + } + `); +}); + +describe('bulk helper onDocument param', () => { + it('returns index ops for each doc', async () => { + expect.assertions(testRecords.length); + + const client = new MockClient(); + client.helpers.bulk.mockImplementation(async ({ datasource, onDocument }) => { + for (const d of datasource) { + const op = onDocument(d); + expect(op).toEqual({ + index: { + _index: 'foo', + _id: expect.stringMatching(/^\d$/), + }, }); - expect(Date.now() - start).not.toBeLessThan(delayMs); - return { ok: true }; - }, - ]); + } + }); + + const stats = createStats('test', log); const progress = new Progress(); await createPromiseFromStreams([ - createListStream(records), - createIndexDocRecordsStream(client, stats, progress), + createListStream(testRecords), + createIndexDocRecordsStream(client as any, stats, progress), ]); - - client.assertNoPendingResponses(); - expect(progress.getComplete()).toBe(10); - expect(progress.getTotal()).toBe(undefined); }); - it('sends a maximum of 300 documents at a time', async () => { - const records = createPersonDocRecords(301); - const stats = createStubStats(); - const client = createStubClient([ - async (name, params) => { - expect(name).toBe('bulk'); - expect(params.body.length).toEqual(1 * 2); - return { ok: true }; - }, - async (name, params) => { - expect(name).toBe('bulk'); - expect(params.body.length).toEqual(299 * 2); - return { ok: true }; - }, - async (name, params) => { - expect(name).toBe('bulk'); - expect(params.body.length).toEqual(1 * 2); - return { ok: true }; - }, - ]); + it('returns create ops for each doc when instructed', async () => { + expect.assertions(testRecords.length); + + const client = new MockClient(); + client.helpers.bulk.mockImplementation(async ({ datasource, onDocument }) => { + for (const d of datasource) { + const op = onDocument(d); + expect(op).toEqual({ + create: { + _index: 'foo', + _id: expect.stringMatching(/^\d$/), + }, + }); + } + }); + + const stats = createStats('test', log); const progress = new Progress(); await createPromiseFromStreams([ - createListStream(records), - createIndexDocRecordsStream(client, stats, progress), + createListStream(testRecords), + createIndexDocRecordsStream(client as any, stats, progress, true), ]); - - client.assertNoPendingResponses(); - expect(progress.getComplete()).toBe(301); - expect(progress.getTotal()).toBe(undefined); }); +}); - it('emits an error if any request fails', async () => { - const records = createPersonDocRecords(2); - const stats = createStubStats(); - const client = createStubClient([ - async () => ({ ok: true }), - async () => ({ errors: true, forcedError: true }), - ]); +describe('bulk helper onDrop param', () => { + it('throws an error reporting any docs which failed all retry attempts', async () => { + const client = new MockClient(); + let counter = -1; + client.helpers.bulk.mockImplementation(async ({ datasource, onDrop }) => { + for (const d of datasource) { + counter++; + if (counter > 0) { + onDrop({ + document: d, + error: { + reason: `${counter} conflicts with something`, + }, + }); + } + } + }); + + const stats = createStats('test', log); const progress = new Progress(); - try { - await createPromiseFromStreams([ - createListStream(records), - createIndexDocRecordsStream(client, stats, progress), - ]); - throw new Error('expected stream to emit error'); - } catch (err) { - expect(err.message).toMatch(/"forcedError":\s*true/); - } + const promise = createPromiseFromStreams([ + createListStream(testRecords), + createIndexDocRecordsStream(client as any, stats, progress), + ]); - client.assertNoPendingResponses(); - expect(progress.getComplete()).toBe(1); - expect(progress.getTotal()).toBe(undefined); + await expect(promise).rejects.toThrowErrorMatchingInlineSnapshot(` + " + Error: Bulk doc failure [operation=index]: + doc: {\\"hello\\":\\"world\\"} + error: {\\"reason\\":\\"1 conflicts with something\\"} + + Error: Bulk doc failure [operation=index]: + doc: {\\"hello\\":\\"world\\"} + error: {\\"reason\\":\\"2 conflicts with something\\"} + + Error: Bulk doc failure [operation=index]: + doc: {\\"hello\\":\\"world\\"} + error: {\\"reason\\":\\"3 conflicts with something\\"} + " + `); }); }); diff --git a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts index 873ea881382b..75e96fbbc922 100644 --- a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts @@ -6,7 +6,8 @@ * Public License, v 1. */ -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; +import AggregateError from 'aggregate-error'; import { Writable } from 'stream'; import { Stats } from '../stats'; import { Progress } from '../progress'; @@ -18,24 +19,38 @@ export function createIndexDocRecordsStream( useCreate: boolean = false ) { async function indexDocs(docs: any[]) { - const body: any[] = []; const operation = useCreate === true ? 'create' : 'index'; - docs.forEach((doc) => { - stats.indexedDoc(doc.index); - body.push( - { + const ops = new WeakMap(); + const errors: string[] = []; + + await client.helpers.bulk({ + retries: 5, + datasource: docs.map((doc) => { + const body = doc.source; + ops.set(body, { [operation]: { _index: doc.index, _id: doc.id, }, - }, - doc.source - ); + }); + return body; + }), + onDocument(doc) { + return ops.get(doc); + }, + onDrop(dropped) { + const dj = JSON.stringify(dropped.document); + const ej = JSON.stringify(dropped.error); + errors.push(`Bulk doc failure [operation=${operation}]:\n doc: ${dj}\n error: ${ej}`); + }, }); - const resp = await client.bulk({ requestTimeout: 2 * 60 * 1000, body }); - if (resp.errors) { - throw new Error(`Failed to index all documents: ${JSON.stringify(resp, null, 2)}`); + if (errors.length) { + throw new AggregateError(errors); + } + + for (const doc of docs) { + stats.indexedDoc(doc.index); } } diff --git a/packages/kbn-es-archiver/src/lib/indices/__mocks__/stubs.ts b/packages/kbn-es-archiver/src/lib/indices/__mocks__/stubs.ts index 4d42daa71ef2..de5fbd15c1f6 100644 --- a/packages/kbn-es-archiver/src/lib/indices/__mocks__/stubs.ts +++ b/packages/kbn-es-archiver/src/lib/indices/__mocks__/stubs.ts @@ -6,7 +6,7 @@ * Public License, v 1. */ -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import sinon from 'sinon'; import { ToolingLog } from '@kbn/dev-utils'; import { Stats } from '../../stats'; @@ -54,9 +54,11 @@ export const createStubDocRecord = (index: string, id: number) => ({ const createEsClientError = (errorType: string) => { const err = new Error(`ES Client Error Stub "${errorType}"`); - (err as any).body = { - error: { - type: errorType, + (err as any).meta = { + body: { + error: { + type: errorType, + }, }, }; return err; @@ -79,26 +81,25 @@ export const createStubClient = ( } return { - [index]: { - mappings: {}, - settings: {}, + body: { + [index]: { + mappings: {}, + settings: {}, + }, }, }; }), - existsAlias: sinon.spy(({ name }) => { - return Promise.resolve(aliases.hasOwnProperty(name)); - }), getAlias: sinon.spy(async ({ index, name }) => { if (index && existingIndices.indexOf(index) >= 0) { const result = indexAlias(aliases, index); - return { [index]: { aliases: result ? { [result]: {} } : {} } }; + return { body: { [index]: { aliases: result ? { [result]: {} } : {} } } }; } if (name && aliases[name]) { - return { [aliases[name]]: { aliases: { [name]: {} } } }; + return { body: { [aliases[name]]: { aliases: { [name]: {} } } } }; } - return { status: 404 }; + return { statusCode: 404 }; }), updateAliases: sinon.spy(async ({ body }) => { body.actions.forEach( @@ -110,14 +111,14 @@ export const createStubClient = ( } ); - return { ok: true }; + return { body: { ok: true } }; }), create: sinon.spy(async ({ index }) => { if (existingIndices.includes(index) || aliases.hasOwnProperty(index)) { throw createEsClientError('resource_already_exists_exception'); } else { existingIndices.push(index); - return { ok: true }; + return { body: { ok: true } }; } }), delete: sinon.spy(async ({ index }) => { @@ -131,7 +132,7 @@ export const createStubClient = ( } }); indices.forEach((ix) => existingIndices.splice(existingIndices.indexOf(ix), 1)); - return { ok: true }; + return { body: { ok: true } }; } else { throw createEsClientError('index_not_found_exception'); } diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts index cf6a64306835..57c1efdbb712 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts @@ -56,15 +56,35 @@ describe('esArchiver: createCreateIndexStream()', () => { createCreateIndexStream({ client, stats, log }), ]); - expect((client.indices.getAlias as sinon.SinonSpy).calledOnce).toBe(true); - expect((client.indices.getAlias as sinon.SinonSpy).args[0][0]).toEqual({ - name: 'existing-index', - ignore: [404], - }); - expect((client.indices.delete as sinon.SinonSpy).calledOnce).toBe(true); - expect((client.indices.delete as sinon.SinonSpy).args[0][0]).toEqual({ - index: ['actual-index'], - }); + expect((client.indices.getAlias as sinon.SinonSpy).args).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "name": Array [ + "existing-index", + ], + }, + Object { + "ignore": Array [ + 404, + ], + }, + ], + ] + `); + + expect((client.indices.delete as sinon.SinonSpy).args).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "index": Array [ + "actual-index", + ], + }, + ], + ] + `); + sinon.assert.callCount(client.indices.create as sinon.SinonSpy, 3); // one failed create because of existing }); diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts index 362e92c5dd76..ba70a8dc2dfb 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts @@ -9,7 +9,7 @@ import { Transform, Readable } from 'stream'; import { inspect } from 'util'; -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { Stats } from '../stats'; @@ -88,7 +88,10 @@ export function createCreateIndexStream({ return; } - if (err?.body?.error?.type !== 'resource_already_exists_exception' || attemptNumber >= 3) { + if ( + err?.meta?.body?.error?.type !== 'resource_already_exists_exception' || + attemptNumber >= 3 + ) { throw err; } diff --git a/packages/kbn-es-archiver/src/lib/indices/delete_index.ts b/packages/kbn-es-archiver/src/lib/indices/delete_index.ts index e42928da2566..597db5a980de 100644 --- a/packages/kbn-es-archiver/src/lib/indices/delete_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/delete_index.ts @@ -6,8 +6,7 @@ * Public License, v 1. */ -import { get } from 'lodash'; -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { Stats } from '../stats'; @@ -17,35 +16,45 @@ const PENDING_SNAPSHOT_STATUSES = ['INIT', 'STARTED', 'WAITING']; export async function deleteIndex(options: { client: Client; stats: Stats; - index: string; + index: string | string[]; log: ToolingLog; retryIfSnapshottingCount?: number; }): Promise { - const { client, stats, index, log, retryIfSnapshottingCount = 10 } = options; + const { client, stats, log, retryIfSnapshottingCount = 10 } = options; + const indices = [options.index].flat(); const getIndicesToDelete = async () => { - const aliasInfo = await client.indices.getAlias({ name: index, ignore: [404] }); - return aliasInfo.status === 404 ? [index] : Object.keys(aliasInfo); + const resp = await client.indices.getAlias( + { + name: indices, + }, + { + ignore: [404], + } + ); + + return resp.statusCode === 404 ? indices : Object.keys(resp.body); }; try { const indicesToDelete = await getIndicesToDelete(); await client.indices.delete({ index: indicesToDelete }); - for (let i = 0; i < indicesToDelete.length; i++) { - const indexToDelete = indicesToDelete[i]; - stats.deletedIndex(indexToDelete); + for (const index of indices) { + stats.deletedIndex(index); } } catch (error) { if (retryIfSnapshottingCount > 0 && isDeleteWhileSnapshotInProgressError(error)) { - stats.waitingForInProgressSnapshot(index); - await waitForSnapshotCompletion(client, index, log); + for (const index of indices) { + stats.waitingForInProgressSnapshot(index); + } + await waitForSnapshotCompletion(client, indices, log); return await deleteIndex({ ...options, retryIfSnapshottingCount: retryIfSnapshottingCount - 1, }); } - if (get(error, 'body.error.type') !== 'index_not_found_exception') { + if (error?.meta?.body?.error?.type !== 'index_not_found_exception') { throw error; } } @@ -57,8 +66,8 @@ export async function deleteIndex(options: { * @param {Error} error * @return {Boolean} */ -export function isDeleteWhileSnapshotInProgressError(error: object) { - return get(error, 'body.error.reason', '').startsWith( +export function isDeleteWhileSnapshotInProgressError(error: any) { + return (error?.meta?.body?.error?.reason ?? '').startsWith( 'Cannot delete indices that are being snapshotted' ); } @@ -67,10 +76,16 @@ export function isDeleteWhileSnapshotInProgressError(error: object) { * Wait for the any snapshot in any repository that is * snapshotting this index to complete. */ -export async function waitForSnapshotCompletion(client: Client, index: string, log: ToolingLog) { +export async function waitForSnapshotCompletion( + client: Client, + index: string | string[], + log: ToolingLog +) { const isSnapshotPending = async (repository: string, snapshot: string) => { const { - snapshots: [status], + body: { + snapshots: [status], + }, } = await client.snapshot.status({ repository, snapshot, @@ -81,10 +96,13 @@ export async function waitForSnapshotCompletion(client: Client, index: string, l }; const getInProgressSnapshots = async (repository: string) => { - const { snapshots: inProgressSnapshots } = await client.snapshot.get({ + const { + body: { snapshots: inProgressSnapshots }, + } = await client.snapshot.get({ repository, snapshot: '_current', }); + return inProgressSnapshots; }; diff --git a/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts index 1b3b09afb783..95633740032f 100644 --- a/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts @@ -7,7 +7,7 @@ */ import { Transform } from 'stream'; -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { Stats } from '../stats'; diff --git a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.test.ts b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.test.ts index e60e6b6d4771..a526039df45d 100644 --- a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.test.ts @@ -44,8 +44,8 @@ describe('esArchiver: createGenerateIndexRecordsStream()', () => { ]); const params = (client.indices.get as sinon.SinonSpy).args[0][0]; - expect(params).toHaveProperty('filterPath'); - const filters: string[] = params.filterPath; + expect(params).toHaveProperty('filter_path'); + const filters: string[] = params.filter_path; expect(filters.some((path) => path.includes('index.creation_date'))).toBe(true); expect(filters.some((path) => path.includes('index.uuid'))).toBe(true); expect(filters.some((path) => path.includes('index.version'))).toBe(true); diff --git a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts index c1ff48e19744..2e624ef7adba 100644 --- a/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/generate_index_records_stream.ts @@ -7,7 +7,7 @@ */ import { Transform } from 'stream'; -import { Client } from 'elasticsearch'; +import { Client } from '@elastic/elasticsearch'; import { Stats } from '../stats'; export function createGenerateIndexRecordsStream(client: Client, stats: Stats) { @@ -16,26 +16,30 @@ export function createGenerateIndexRecordsStream(client: Client, stats: Stats) { readableObjectMode: true, async transform(indexOrAlias, enc, callback) { try { - const resp = (await client.indices.get({ - index: indexOrAlias, - filterPath: [ - '*.settings', - '*.mappings', - // remove settings that aren't really settings - '-*.settings.index.creation_date', - '-*.settings.index.uuid', - '-*.settings.index.version', - '-*.settings.index.provided_name', - '-*.settings.index.frozen', - '-*.settings.index.search.throttled', - '-*.settings.index.query', - '-*.settings.index.routing', - ], - })) as Record; + const resp = ( + await client.indices.get({ + index: indexOrAlias, + filter_path: [ + '*.settings', + '*.mappings', + // remove settings that aren't really settings + '-*.settings.index.creation_date', + '-*.settings.index.uuid', + '-*.settings.index.version', + '-*.settings.index.provided_name', + '-*.settings.index.frozen', + '-*.settings.index.search.throttled', + '-*.settings.index.query', + '-*.settings.index.routing', + ], + }) + ).body as Record; for (const [index, { settings, mappings }] of Object.entries(resp)) { const { - [index]: { aliases }, + body: { + [index]: { aliases }, + }, } = await client.indices.getAlias({ index }); stats.archivedIndex(index, { settings, mappings }); diff --git a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts index 0459a4301cf6..d370e49d0bca 100644 --- a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts @@ -6,7 +6,9 @@ * Public License, v 1. */ -import { Client, CreateDocumentParams } from 'elasticsearch'; +import { inspect } from 'util'; + +import { Client } from '@elastic/elasticsearch'; import { ToolingLog, KbnClient } from '@kbn/dev-utils'; import { Stats } from '../stats'; import { deleteIndex } from './delete_index'; @@ -57,13 +59,17 @@ export async function migrateKibanaIndex({ }) { // we allow dynamic mappings on the index, as some interceptors are accessing documents before // the migration is actually performed. The migrator will put the value back to `strict` after migration. - await client.indices.putMapping({ - index: '.kibana', - body: { - dynamic: true, + await client.indices.putMapping( + { + index: '.kibana', + body: { + dynamic: true, + }, }, - ignore: [404], - } as any); + { + ignore: [404], + } + ); await kbnClient.savedObjects.migrate(); } @@ -75,9 +81,14 @@ export async function migrateKibanaIndex({ * index (e.g. we don't want to remove .kibana_task_manager or the like). */ async function fetchKibanaIndices(client: Client) { - const kibanaIndices = await client.cat.indices({ index: '.kibana*', format: 'json' }); + const resp = await client.cat.indices({ index: '.kibana*', format: 'json' }); const isKibanaIndex = (index: string) => /^\.kibana(:?_\d*)?$/.test(index); - return kibanaIndices.map((x: { index: string }) => x.index).filter(isKibanaIndex); + + if (!Array.isArray(resp.body)) { + throw new Error(`expected response to be an array ${inspect(resp.body)}`); + } + + return resp.body.map((x: { index: string }) => x.index).filter(isKibanaIndex); } const delay = (delayInMs: number) => new Promise((resolve) => setTimeout(resolve, delayInMs)); @@ -102,27 +113,31 @@ export async function cleanKibanaIndices({ } while (true) { - const resp = await client.deleteByQuery({ - index: `.kibana`, - body: { - query: { - bool: { - must_not: { - ids: { - values: ['space:default'], + const resp = await client.deleteByQuery( + { + index: `.kibana`, + body: { + query: { + bool: { + must_not: { + ids: { + values: ['space:default'], + }, }, }, }, }, }, - ignore: [409], - }); + { + ignore: [409], + } + ); - if (resp.total !== resp.deleted) { + if (resp.body.total !== resp.body.deleted) { log.warning( 'delete by query deleted %d of %d total documents, trying again', - resp.deleted, - resp.total + resp.body.deleted, + resp.body.total ); await delay(200); continue; @@ -140,19 +155,23 @@ export async function cleanKibanaIndices({ } export async function createDefaultSpace({ index, client }: { index: string; client: Client }) { - await client.create({ - index, - id: 'space:default', - ignore: 409, - body: { - type: 'space', - updated_at: new Date().toISOString(), - space: { - name: 'Default Space', - description: 'This is the default space', - disabledFeatures: [], - _reserved: true, + await client.create( + { + index, + id: 'space:default', + body: { + type: 'space', + updated_at: new Date().toISOString(), + space: { + name: 'Default Space', + description: 'This is the default space', + disabledFeatures: [], + _reserved: true, + }, }, }, - } as CreateDocumentParams); + { + ignore: [409], + } + ); } diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index e8c6fa4d5a01..d641b50537d5 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -59495,12 +59495,12 @@ const path = __webpack_require__(4); const os = __webpack_require__(121); const pMap = __webpack_require__(515); const arrify = __webpack_require__(510); -const globby = __webpack_require__(516); -const hasGlob = __webpack_require__(712); -const cpFile = __webpack_require__(714); -const junk = __webpack_require__(724); -const pFilter = __webpack_require__(725); -const CpyError = __webpack_require__(727); +const globby = __webpack_require__(518); +const hasGlob = __webpack_require__(714); +const cpFile = __webpack_require__(716); +const junk = __webpack_require__(726); +const pFilter = __webpack_require__(727); +const CpyError = __webpack_require__(729); const defaultOptions = { ignoreJunk: true @@ -59656,7 +59656,7 @@ module.exports = (source, destination, { "use strict"; -const AggregateError = __webpack_require__(242); +const AggregateError = __webpack_require__(516); module.exports = async ( iterable, @@ -59744,12 +59744,108 @@ module.exports = async ( "use strict"; +const indentString = __webpack_require__(517); +const cleanStack = __webpack_require__(244); + +const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); + +class AggregateError extends Error { + constructor(errors) { + if (!Array.isArray(errors)) { + throw new TypeError(`Expected input to be an Array, got ${typeof errors}`); + } + + errors = [...errors].map(error => { + if (error instanceof Error) { + return error; + } + + if (error !== null && typeof error === 'object') { + // Handle plain error objects with message property and/or possibly other metadata + return Object.assign(new Error(error.message), error); + } + + return new Error(error); + }); + + let message = errors + .map(error => { + // The `stack` property is not standardized, so we can't assume it exists + return typeof error.stack === 'string' ? cleanInternalStack(cleanStack(error.stack)) : String(error); + }) + .join('\n'); + message = '\n' + indentString(message, 4); + super(message); + + this.name = 'AggregateError'; + + Object.defineProperty(this, '_errors', {value: errors}); + } + + * [Symbol.iterator]() { + for (const error of this._errors) { + yield error; + } + } +} + +module.exports = AggregateError; + + +/***/ }), +/* 517 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = (string, count = 1, options) => { + options = { + indent: ' ', + includeEmptyLines: false, + ...options + }; + + if (typeof string !== 'string') { + throw new TypeError( + `Expected \`input\` to be a \`string\`, got \`${typeof string}\`` + ); + } + + if (typeof count !== 'number') { + throw new TypeError( + `Expected \`count\` to be a \`number\`, got \`${typeof count}\`` + ); + } + + if (typeof options.indent !== 'string') { + throw new TypeError( + `Expected \`options.indent\` to be a \`string\`, got \`${typeof options.indent}\`` + ); + } + + if (count === 0) { + return string; + } + + const regex = options.includeEmptyLines ? /^/gm : /^(?!\s*$)/gm; + + return string.replace(regex, options.indent.repeat(count)); +}; + + +/***/ }), +/* 518 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + const fs = __webpack_require__(134); -const arrayUnion = __webpack_require__(517); +const arrayUnion = __webpack_require__(519); const glob = __webpack_require__(147); -const fastGlob = __webpack_require__(519); -const dirGlob = __webpack_require__(705); -const gitignore = __webpack_require__(708); +const fastGlob = __webpack_require__(521); +const dirGlob = __webpack_require__(707); +const gitignore = __webpack_require__(710); const DEFAULT_FILTER = () => false; @@ -59894,12 +59990,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 517 */ +/* 519 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(518); +var arrayUniq = __webpack_require__(520); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -59907,7 +60003,7 @@ module.exports = function () { /***/ }), -/* 518 */ +/* 520 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59976,10 +60072,10 @@ if ('Set' in global) { /***/ }), -/* 519 */ +/* 521 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(520); +const pkg = __webpack_require__(522); module.exports = pkg.async; module.exports.default = pkg.async; @@ -59992,19 +60088,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 520 */ +/* 522 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(521); -var taskManager = __webpack_require__(522); -var reader_async_1 = __webpack_require__(676); -var reader_stream_1 = __webpack_require__(700); -var reader_sync_1 = __webpack_require__(701); -var arrayUtils = __webpack_require__(703); -var streamUtils = __webpack_require__(704); +var optionsManager = __webpack_require__(523); +var taskManager = __webpack_require__(524); +var reader_async_1 = __webpack_require__(678); +var reader_stream_1 = __webpack_require__(702); +var reader_sync_1 = __webpack_require__(703); +var arrayUtils = __webpack_require__(705); +var streamUtils = __webpack_require__(706); /** * Synchronous API. */ @@ -60070,7 +60166,7 @@ function isString(source) { /***/ }), -/* 521 */ +/* 523 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60108,13 +60204,13 @@ exports.prepare = prepare; /***/ }), -/* 522 */ +/* 524 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(523); +var patternUtils = __webpack_require__(525); /** * Generate tasks based on parent directory of each pattern. */ @@ -60205,16 +60301,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 523 */ +/* 525 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var globParent = __webpack_require__(524); +var globParent = __webpack_require__(526); var isGlob = __webpack_require__(172); -var micromatch = __webpack_require__(527); +var micromatch = __webpack_require__(529); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -60360,15 +60456,15 @@ exports.matchAny = matchAny; /***/ }), -/* 524 */ +/* 526 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(4); -var isglob = __webpack_require__(525); -var pathDirname = __webpack_require__(526); +var isglob = __webpack_require__(527); +var pathDirname = __webpack_require__(528); var isWin32 = __webpack_require__(121).platform() === 'win32'; module.exports = function globParent(str) { @@ -60391,7 +60487,7 @@ module.exports = function globParent(str) { /***/ }), -/* 525 */ +/* 527 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -60422,7 +60518,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 526 */ +/* 528 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60572,7 +60668,7 @@ module.exports.win32 = win32; /***/ }), -/* 527 */ +/* 529 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60583,18 +60679,18 @@ module.exports.win32 = win32; */ var util = __webpack_require__(112); -var braces = __webpack_require__(528); -var toRegex = __webpack_require__(529); -var extend = __webpack_require__(642); +var braces = __webpack_require__(530); +var toRegex = __webpack_require__(531); +var extend = __webpack_require__(644); /** * Local dependencies */ -var compilers = __webpack_require__(644); -var parsers = __webpack_require__(671); -var cache = __webpack_require__(672); -var utils = __webpack_require__(673); +var compilers = __webpack_require__(646); +var parsers = __webpack_require__(673); +var cache = __webpack_require__(674); +var utils = __webpack_require__(675); var MAX_LENGTH = 1024 * 64; /** @@ -61456,7 +61552,7 @@ module.exports = micromatch; /***/ }), -/* 528 */ +/* 530 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61466,18 +61562,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(529); -var unique = __webpack_require__(551); -var extend = __webpack_require__(552); +var toRegex = __webpack_require__(531); +var unique = __webpack_require__(553); +var extend = __webpack_require__(554); /** * Local dependencies */ -var compilers = __webpack_require__(554); -var parsers = __webpack_require__(567); -var Braces = __webpack_require__(571); -var utils = __webpack_require__(555); +var compilers = __webpack_require__(556); +var parsers = __webpack_require__(569); +var Braces = __webpack_require__(573); +var utils = __webpack_require__(557); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -61781,16 +61877,16 @@ module.exports = braces; /***/ }), -/* 529 */ +/* 531 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(530); -var define = __webpack_require__(536); -var extend = __webpack_require__(544); -var not = __webpack_require__(548); +var safe = __webpack_require__(532); +var define = __webpack_require__(538); +var extend = __webpack_require__(546); +var not = __webpack_require__(550); var MAX_LENGTH = 1024 * 64; /** @@ -61943,10 +62039,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 530 */ +/* 532 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(531); +var parse = __webpack_require__(533); var types = parse.types; module.exports = function (re, opts) { @@ -61992,13 +62088,13 @@ function isRegExp (x) { /***/ }), -/* 531 */ +/* 533 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(532); -var types = __webpack_require__(533); -var sets = __webpack_require__(534); -var positions = __webpack_require__(535); +var util = __webpack_require__(534); +var types = __webpack_require__(535); +var sets = __webpack_require__(536); +var positions = __webpack_require__(537); module.exports = function(regexpStr) { @@ -62280,11 +62376,11 @@ module.exports.types = types; /***/ }), -/* 532 */ +/* 534 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(533); -var sets = __webpack_require__(534); +var types = __webpack_require__(535); +var sets = __webpack_require__(536); // All of these are private and only used by randexp. @@ -62397,7 +62493,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 533 */ +/* 535 */ /***/ (function(module, exports) { module.exports = { @@ -62413,10 +62509,10 @@ module.exports = { /***/ }), -/* 534 */ +/* 536 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(533); +var types = __webpack_require__(535); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -62501,10 +62597,10 @@ exports.anyChar = function() { /***/ }), -/* 535 */ +/* 537 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(533); +var types = __webpack_require__(535); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -62524,7 +62620,7 @@ exports.end = function() { /***/ }), -/* 536 */ +/* 538 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62537,8 +62633,8 @@ exports.end = function() { -var isobject = __webpack_require__(537); -var isDescriptor = __webpack_require__(538); +var isobject = __webpack_require__(539); +var isDescriptor = __webpack_require__(540); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -62569,7 +62665,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 537 */ +/* 539 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62588,7 +62684,7 @@ module.exports = function isObject(val) { /***/ }), -/* 538 */ +/* 540 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62601,9 +62697,9 @@ module.exports = function isObject(val) { -var typeOf = __webpack_require__(539); -var isAccessor = __webpack_require__(540); -var isData = __webpack_require__(542); +var typeOf = __webpack_require__(541); +var isAccessor = __webpack_require__(542); +var isData = __webpack_require__(544); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -62617,7 +62713,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 539 */ +/* 541 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -62752,7 +62848,7 @@ function isBuffer(val) { /***/ }), -/* 540 */ +/* 542 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62765,7 +62861,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(541); +var typeOf = __webpack_require__(543); // accessor descriptor properties var accessor = { @@ -62828,7 +62924,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 541 */ +/* 543 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -62963,7 +63059,7 @@ function isBuffer(val) { /***/ }), -/* 542 */ +/* 544 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62976,7 +63072,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(543); +var typeOf = __webpack_require__(545); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -63019,7 +63115,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 543 */ +/* 545 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -63154,14 +63250,14 @@ function isBuffer(val) { /***/ }), -/* 544 */ +/* 546 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(545); -var assignSymbols = __webpack_require__(547); +var isExtendable = __webpack_require__(547); +var assignSymbols = __webpack_require__(549); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -63221,7 +63317,7 @@ function isEnum(obj, key) { /***/ }), -/* 545 */ +/* 547 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63234,7 +63330,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(546); +var isPlainObject = __webpack_require__(548); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -63242,7 +63338,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 546 */ +/* 548 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63255,7 +63351,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(537); +var isObject = __webpack_require__(539); function isObjectObject(o) { return isObject(o) === true @@ -63286,7 +63382,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 547 */ +/* 549 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63333,14 +63429,14 @@ module.exports = function(receiver, objects) { /***/ }), -/* 548 */ +/* 550 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(549); -var safe = __webpack_require__(530); +var extend = __webpack_require__(551); +var safe = __webpack_require__(532); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -63412,14 +63508,14 @@ module.exports = toRegex; /***/ }), -/* 549 */ +/* 551 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(550); -var assignSymbols = __webpack_require__(547); +var isExtendable = __webpack_require__(552); +var assignSymbols = __webpack_require__(549); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -63479,7 +63575,7 @@ function isEnum(obj, key) { /***/ }), -/* 550 */ +/* 552 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63492,7 +63588,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(546); +var isPlainObject = __webpack_require__(548); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -63500,7 +63596,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 551 */ +/* 553 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63550,13 +63646,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 552 */ +/* 554 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(553); +var isObject = __webpack_require__(555); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -63590,7 +63686,7 @@ function hasOwn(obj, key) { /***/ }), -/* 553 */ +/* 555 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63610,13 +63706,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 554 */ +/* 556 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(555); +var utils = __webpack_require__(557); module.exports = function(braces, options) { braces.compiler @@ -63899,25 +63995,25 @@ function hasQueue(node) { /***/ }), -/* 555 */ +/* 557 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(556); +var splitString = __webpack_require__(558); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(552); -utils.flatten = __webpack_require__(559); -utils.isObject = __webpack_require__(537); -utils.fillRange = __webpack_require__(560); -utils.repeat = __webpack_require__(566); -utils.unique = __webpack_require__(551); +utils.extend = __webpack_require__(554); +utils.flatten = __webpack_require__(561); +utils.isObject = __webpack_require__(539); +utils.fillRange = __webpack_require__(562); +utils.repeat = __webpack_require__(568); +utils.unique = __webpack_require__(553); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -64249,7 +64345,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 556 */ +/* 558 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64262,7 +64358,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(557); +var extend = __webpack_require__(559); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -64427,14 +64523,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 557 */ +/* 559 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(558); -var assignSymbols = __webpack_require__(547); +var isExtendable = __webpack_require__(560); +var assignSymbols = __webpack_require__(549); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -64494,7 +64590,7 @@ function isEnum(obj, key) { /***/ }), -/* 558 */ +/* 560 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64507,7 +64603,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(546); +var isPlainObject = __webpack_require__(548); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -64515,7 +64611,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 559 */ +/* 561 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64544,7 +64640,7 @@ function flat(arr, res) { /***/ }), -/* 560 */ +/* 562 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64558,10 +64654,10 @@ function flat(arr, res) { var util = __webpack_require__(112); -var isNumber = __webpack_require__(561); -var extend = __webpack_require__(552); -var repeat = __webpack_require__(564); -var toRegex = __webpack_require__(565); +var isNumber = __webpack_require__(563); +var extend = __webpack_require__(554); +var repeat = __webpack_require__(566); +var toRegex = __webpack_require__(567); /** * Return a range of numbers or letters. @@ -64759,7 +64855,7 @@ module.exports = fillRange; /***/ }), -/* 561 */ +/* 563 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64772,7 +64868,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(562); +var typeOf = __webpack_require__(564); module.exports = function isNumber(num) { var type = typeOf(num); @@ -64788,10 +64884,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 562 */ +/* 564 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(563); +var isBuffer = __webpack_require__(565); var toString = Object.prototype.toString; /** @@ -64910,7 +65006,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 563 */ +/* 565 */ /***/ (function(module, exports) { /*! @@ -64937,7 +65033,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 564 */ +/* 566 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65014,7 +65110,7 @@ function repeat(str, num) { /***/ }), -/* 565 */ +/* 567 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65027,8 +65123,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(564); -var isNumber = __webpack_require__(561); +var repeat = __webpack_require__(566); +var isNumber = __webpack_require__(563); var cache = {}; function toRegexRange(min, max, options) { @@ -65315,7 +65411,7 @@ module.exports = toRegexRange; /***/ }), -/* 566 */ +/* 568 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65340,14 +65436,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 567 */ +/* 569 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(568); -var utils = __webpack_require__(555); +var Node = __webpack_require__(570); +var utils = __webpack_require__(557); /** * Braces parsers @@ -65707,15 +65803,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 568 */ +/* 570 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(537); -var define = __webpack_require__(569); -var utils = __webpack_require__(570); +var isObject = __webpack_require__(539); +var define = __webpack_require__(571); +var utils = __webpack_require__(572); var ownNames; /** @@ -66206,7 +66302,7 @@ exports = module.exports = Node; /***/ }), -/* 569 */ +/* 571 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66219,7 +66315,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(538); +var isDescriptor = __webpack_require__(540); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -66244,13 +66340,13 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 570 */ +/* 572 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(562); +var typeOf = __webpack_require__(564); var utils = module.exports; /** @@ -67270,17 +67366,17 @@ function assert(val, message) { /***/ }), -/* 571 */ +/* 573 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(552); -var Snapdragon = __webpack_require__(572); -var compilers = __webpack_require__(554); -var parsers = __webpack_require__(567); -var utils = __webpack_require__(555); +var extend = __webpack_require__(554); +var Snapdragon = __webpack_require__(574); +var compilers = __webpack_require__(556); +var parsers = __webpack_require__(569); +var utils = __webpack_require__(557); /** * Customize Snapdragon parser and renderer @@ -67381,17 +67477,17 @@ module.exports = Braces; /***/ }), -/* 572 */ +/* 574 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(573); -var define = __webpack_require__(600); -var Compiler = __webpack_require__(610); -var Parser = __webpack_require__(639); -var utils = __webpack_require__(619); +var Base = __webpack_require__(575); +var define = __webpack_require__(602); +var Compiler = __webpack_require__(612); +var Parser = __webpack_require__(641); +var utils = __webpack_require__(621); var regexCache = {}; var cache = {}; @@ -67562,20 +67658,20 @@ module.exports.Parser = Parser; /***/ }), -/* 573 */ +/* 575 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var define = __webpack_require__(574); -var CacheBase = __webpack_require__(575); -var Emitter = __webpack_require__(576); -var isObject = __webpack_require__(537); -var merge = __webpack_require__(594); -var pascal = __webpack_require__(597); -var cu = __webpack_require__(598); +var define = __webpack_require__(576); +var CacheBase = __webpack_require__(577); +var Emitter = __webpack_require__(578); +var isObject = __webpack_require__(539); +var merge = __webpack_require__(596); +var pascal = __webpack_require__(599); +var cu = __webpack_require__(600); /** * Optionally define a custom `cache` namespace to use. @@ -68004,7 +68100,7 @@ module.exports.namespace = namespace; /***/ }), -/* 574 */ +/* 576 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68017,7 +68113,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(538); +var isDescriptor = __webpack_require__(540); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -68042,21 +68138,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 575 */ +/* 577 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(537); -var Emitter = __webpack_require__(576); -var visit = __webpack_require__(577); -var toPath = __webpack_require__(580); -var union = __webpack_require__(581); -var del = __webpack_require__(585); -var get = __webpack_require__(583); -var has = __webpack_require__(590); -var set = __webpack_require__(593); +var isObject = __webpack_require__(539); +var Emitter = __webpack_require__(578); +var visit = __webpack_require__(579); +var toPath = __webpack_require__(582); +var union = __webpack_require__(583); +var del = __webpack_require__(587); +var get = __webpack_require__(585); +var has = __webpack_require__(592); +var set = __webpack_require__(595); /** * Create a `Cache` constructor that when instantiated will @@ -68310,7 +68406,7 @@ module.exports.namespace = namespace; /***/ }), -/* 576 */ +/* 578 */ /***/ (function(module, exports, __webpack_require__) { @@ -68479,7 +68575,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 577 */ +/* 579 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68492,8 +68588,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(578); -var mapVisit = __webpack_require__(579); +var visit = __webpack_require__(580); +var mapVisit = __webpack_require__(581); module.exports = function(collection, method, val) { var result; @@ -68516,7 +68612,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 578 */ +/* 580 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68529,7 +68625,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(537); +var isObject = __webpack_require__(539); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -68556,14 +68652,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 579 */ +/* 581 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var visit = __webpack_require__(578); +var visit = __webpack_require__(580); /** * Map `visit` over an array of objects. @@ -68600,7 +68696,7 @@ function isObject(val) { /***/ }), -/* 580 */ +/* 582 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68613,7 +68709,7 @@ function isObject(val) { -var typeOf = __webpack_require__(562); +var typeOf = __webpack_require__(564); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -68640,16 +68736,16 @@ function filter(arr) { /***/ }), -/* 581 */ +/* 583 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(553); -var union = __webpack_require__(582); -var get = __webpack_require__(583); -var set = __webpack_require__(584); +var isObject = __webpack_require__(555); +var union = __webpack_require__(584); +var get = __webpack_require__(585); +var set = __webpack_require__(586); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -68677,7 +68773,7 @@ function arrayify(val) { /***/ }), -/* 582 */ +/* 584 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68713,7 +68809,7 @@ module.exports = function union(init) { /***/ }), -/* 583 */ +/* 585 */ /***/ (function(module, exports) { /*! @@ -68769,7 +68865,7 @@ function toString(val) { /***/ }), -/* 584 */ +/* 586 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68782,10 +68878,10 @@ function toString(val) { -var split = __webpack_require__(556); -var extend = __webpack_require__(552); -var isPlainObject = __webpack_require__(546); -var isObject = __webpack_require__(553); +var split = __webpack_require__(558); +var extend = __webpack_require__(554); +var isPlainObject = __webpack_require__(548); +var isObject = __webpack_require__(555); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -68831,7 +68927,7 @@ function isValidKey(key) { /***/ }), -/* 585 */ +/* 587 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68844,8 +68940,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(537); -var has = __webpack_require__(586); +var isObject = __webpack_require__(539); +var has = __webpack_require__(588); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -68870,7 +68966,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 586 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68883,9 +68979,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(587); -var hasValues = __webpack_require__(589); -var get = __webpack_require__(583); +var isObject = __webpack_require__(589); +var hasValues = __webpack_require__(591); +var get = __webpack_require__(585); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -68896,7 +68992,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 587 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68909,7 +69005,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(588); +var isArray = __webpack_require__(590); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -68917,7 +69013,7 @@ module.exports = function isObject(val) { /***/ }), -/* 588 */ +/* 590 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -68928,7 +69024,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 589 */ +/* 591 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68971,7 +69067,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 590 */ +/* 592 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68984,9 +69080,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(537); -var hasValues = __webpack_require__(591); -var get = __webpack_require__(583); +var isObject = __webpack_require__(539); +var hasValues = __webpack_require__(593); +var get = __webpack_require__(585); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -68994,7 +69090,7 @@ module.exports = function(val, prop) { /***/ }), -/* 591 */ +/* 593 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69007,8 +69103,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(592); -var isNumber = __webpack_require__(561); +var typeOf = __webpack_require__(594); +var isNumber = __webpack_require__(563); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -69061,10 +69157,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 592 */ +/* 594 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(563); +var isBuffer = __webpack_require__(565); var toString = Object.prototype.toString; /** @@ -69186,7 +69282,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 593 */ +/* 595 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69199,10 +69295,10 @@ module.exports = function kindOf(val) { -var split = __webpack_require__(556); -var extend = __webpack_require__(552); -var isPlainObject = __webpack_require__(546); -var isObject = __webpack_require__(553); +var split = __webpack_require__(558); +var extend = __webpack_require__(554); +var isPlainObject = __webpack_require__(548); +var isObject = __webpack_require__(555); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -69248,14 +69344,14 @@ function isValidKey(key) { /***/ }), -/* 594 */ +/* 596 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(595); -var forIn = __webpack_require__(596); +var isExtendable = __webpack_require__(597); +var forIn = __webpack_require__(598); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -69319,7 +69415,7 @@ module.exports = mixinDeep; /***/ }), -/* 595 */ +/* 597 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69332,7 +69428,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(546); +var isPlainObject = __webpack_require__(548); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -69340,7 +69436,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 596 */ +/* 598 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69363,7 +69459,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 597 */ +/* 599 */ /***/ (function(module, exports) { /*! @@ -69390,14 +69486,14 @@ module.exports = pascalcase; /***/ }), -/* 598 */ +/* 600 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var utils = __webpack_require__(599); +var utils = __webpack_require__(601); /** * Expose class utils @@ -69762,7 +69858,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 599 */ +/* 601 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69776,10 +69872,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(582); -utils.define = __webpack_require__(600); -utils.isObj = __webpack_require__(537); -utils.staticExtend = __webpack_require__(607); +utils.union = __webpack_require__(584); +utils.define = __webpack_require__(602); +utils.isObj = __webpack_require__(539); +utils.staticExtend = __webpack_require__(609); /** @@ -69790,7 +69886,7 @@ module.exports = utils; /***/ }), -/* 600 */ +/* 602 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69803,7 +69899,7 @@ module.exports = utils; -var isDescriptor = __webpack_require__(601); +var isDescriptor = __webpack_require__(603); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -69828,7 +69924,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 601 */ +/* 603 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69841,9 +69937,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(602); -var isAccessor = __webpack_require__(603); -var isData = __webpack_require__(605); +var typeOf = __webpack_require__(604); +var isAccessor = __webpack_require__(605); +var isData = __webpack_require__(607); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -69857,7 +69953,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 602 */ +/* 604 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -70010,7 +70106,7 @@ function isBuffer(val) { /***/ }), -/* 603 */ +/* 605 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70023,7 +70119,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(604); +var typeOf = __webpack_require__(606); // accessor descriptor properties var accessor = { @@ -70086,10 +70182,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 604 */ +/* 606 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(563); +var isBuffer = __webpack_require__(565); var toString = Object.prototype.toString; /** @@ -70208,7 +70304,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 605 */ +/* 607 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70221,7 +70317,7 @@ module.exports = function kindOf(val) { -var typeOf = __webpack_require__(606); +var typeOf = __webpack_require__(608); // data descriptor properties var data = { @@ -70270,10 +70366,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 606 */ +/* 608 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(563); +var isBuffer = __webpack_require__(565); var toString = Object.prototype.toString; /** @@ -70392,7 +70488,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 607 */ +/* 609 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70405,8 +70501,8 @@ module.exports = function kindOf(val) { -var copy = __webpack_require__(608); -var define = __webpack_require__(600); +var copy = __webpack_require__(610); +var define = __webpack_require__(602); var util = __webpack_require__(112); /** @@ -70489,15 +70585,15 @@ module.exports = extend; /***/ }), -/* 608 */ +/* 610 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(562); -var copyDescriptor = __webpack_require__(609); -var define = __webpack_require__(600); +var typeOf = __webpack_require__(564); +var copyDescriptor = __webpack_require__(611); +var define = __webpack_require__(602); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -70670,7 +70766,7 @@ module.exports.has = has; /***/ }), -/* 609 */ +/* 611 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70758,16 +70854,16 @@ function isObject(val) { /***/ }), -/* 610 */ +/* 612 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(611); -var define = __webpack_require__(600); -var debug = __webpack_require__(613)('snapdragon:compiler'); -var utils = __webpack_require__(619); +var use = __webpack_require__(613); +var define = __webpack_require__(602); +var debug = __webpack_require__(615)('snapdragon:compiler'); +var utils = __webpack_require__(621); /** * Create a new `Compiler` with the given `options`. @@ -70921,7 +71017,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(638); + var sourcemaps = __webpack_require__(640); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -70942,7 +71038,7 @@ module.exports = Compiler; /***/ }), -/* 611 */ +/* 613 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70955,7 +71051,7 @@ module.exports = Compiler; -var utils = __webpack_require__(612); +var utils = __webpack_require__(614); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -71070,7 +71166,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 612 */ +/* 614 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71084,8 +71180,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(600); -utils.isObject = __webpack_require__(537); +utils.define = __webpack_require__(602); +utils.isObject = __webpack_require__(539); utils.isString = function(val) { @@ -71100,7 +71196,7 @@ module.exports = utils; /***/ }), -/* 613 */ +/* 615 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -71109,14 +71205,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(614); + module.exports = __webpack_require__(616); } else { - module.exports = __webpack_require__(617); + module.exports = __webpack_require__(619); } /***/ }), -/* 614 */ +/* 616 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -71125,7 +71221,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(615); +exports = module.exports = __webpack_require__(617); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -71307,7 +71403,7 @@ function localstorage() { /***/ }), -/* 615 */ +/* 617 */ /***/ (function(module, exports, __webpack_require__) { @@ -71323,7 +71419,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(616); +exports.humanize = __webpack_require__(618); /** * The currently active debug mode names, and names to skip. @@ -71515,7 +71611,7 @@ function coerce(val) { /***/ }), -/* 616 */ +/* 618 */ /***/ (function(module, exports) { /** @@ -71673,7 +71769,7 @@ function plural(ms, n, name) { /***/ }), -/* 617 */ +/* 619 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -71689,7 +71785,7 @@ var util = __webpack_require__(112); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(615); +exports = module.exports = __webpack_require__(617); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -71868,7 +71964,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(618); + var net = __webpack_require__(620); stream = new net.Socket({ fd: fd, readable: false, @@ -71927,13 +72023,13 @@ exports.enable(load()); /***/ }), -/* 618 */ +/* 620 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 619 */ +/* 621 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71943,9 +72039,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(552); -exports.SourceMap = __webpack_require__(620); -exports.sourceMapResolve = __webpack_require__(631); +exports.extend = __webpack_require__(554); +exports.SourceMap = __webpack_require__(622); +exports.sourceMapResolve = __webpack_require__(633); /** * Convert backslash in the given string to forward slashes @@ -71988,7 +72084,7 @@ exports.last = function(arr, n) { /***/ }), -/* 620 */ +/* 622 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -71996,13 +72092,13 @@ exports.last = function(arr, n) { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(621).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(627).SourceMapConsumer; -exports.SourceNode = __webpack_require__(630).SourceNode; +exports.SourceMapGenerator = __webpack_require__(623).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(629).SourceMapConsumer; +exports.SourceNode = __webpack_require__(632).SourceNode; /***/ }), -/* 621 */ +/* 623 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -72012,10 +72108,10 @@ exports.SourceNode = __webpack_require__(630).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(622); -var util = __webpack_require__(624); -var ArraySet = __webpack_require__(625).ArraySet; -var MappingList = __webpack_require__(626).MappingList; +var base64VLQ = __webpack_require__(624); +var util = __webpack_require__(626); +var ArraySet = __webpack_require__(627).ArraySet; +var MappingList = __webpack_require__(628).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -72424,7 +72520,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 622 */ +/* 624 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -72464,7 +72560,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(623); +var base64 = __webpack_require__(625); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -72570,7 +72666,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 623 */ +/* 625 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -72643,7 +72739,7 @@ exports.decode = function (charCode) { /***/ }), -/* 624 */ +/* 626 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73066,7 +73162,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 625 */ +/* 627 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73076,7 +73172,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(624); +var util = __webpack_require__(626); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -73193,7 +73289,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 626 */ +/* 628 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73203,7 +73299,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(624); +var util = __webpack_require__(626); /** * Determine whether mappingB is after mappingA with respect to generated @@ -73278,7 +73374,7 @@ exports.MappingList = MappingList; /***/ }), -/* 627 */ +/* 629 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73288,11 +73384,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(624); -var binarySearch = __webpack_require__(628); -var ArraySet = __webpack_require__(625).ArraySet; -var base64VLQ = __webpack_require__(622); -var quickSort = __webpack_require__(629).quickSort; +var util = __webpack_require__(626); +var binarySearch = __webpack_require__(630); +var ArraySet = __webpack_require__(627).ArraySet; +var base64VLQ = __webpack_require__(624); +var quickSort = __webpack_require__(631).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -74366,7 +74462,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 628 */ +/* 630 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74483,7 +74579,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 629 */ +/* 631 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74603,7 +74699,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 630 */ +/* 632 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74613,8 +74709,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(621).SourceMapGenerator; -var util = __webpack_require__(624); +var SourceMapGenerator = __webpack_require__(623).SourceMapGenerator; +var util = __webpack_require__(626); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -75022,17 +75118,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 631 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(632) -var resolveUrl = __webpack_require__(633) -var decodeUriComponent = __webpack_require__(634) -var urix = __webpack_require__(636) -var atob = __webpack_require__(637) +var sourceMappingURL = __webpack_require__(634) +var resolveUrl = __webpack_require__(635) +var decodeUriComponent = __webpack_require__(636) +var urix = __webpack_require__(638) +var atob = __webpack_require__(639) @@ -75330,7 +75426,7 @@ module.exports = { /***/ }), -/* 632 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -75393,7 +75489,7 @@ void (function(root, factory) { /***/ }), -/* 633 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -75411,13 +75507,13 @@ module.exports = resolveUrl /***/ }), -/* 634 */ +/* 636 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(635) +var decodeUriComponent = __webpack_require__(637) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -75428,7 +75524,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 635 */ +/* 637 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75529,7 +75625,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 636 */ +/* 638 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -75552,7 +75648,7 @@ module.exports = urix /***/ }), -/* 637 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75566,7 +75662,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 638 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75574,8 +75670,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(134); var path = __webpack_require__(4); -var define = __webpack_require__(600); -var utils = __webpack_require__(619); +var define = __webpack_require__(602); +var utils = __webpack_require__(621); /** * Expose `mixin()`. @@ -75718,19 +75814,19 @@ exports.comment = function(node) { /***/ }), -/* 639 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(611); +var use = __webpack_require__(613); var util = __webpack_require__(112); -var Cache = __webpack_require__(640); -var define = __webpack_require__(600); -var debug = __webpack_require__(613)('snapdragon:parser'); -var Position = __webpack_require__(641); -var utils = __webpack_require__(619); +var Cache = __webpack_require__(642); +var define = __webpack_require__(602); +var debug = __webpack_require__(615)('snapdragon:parser'); +var Position = __webpack_require__(643); +var utils = __webpack_require__(621); /** * Create a new `Parser` with the given `input` and `options`. @@ -76258,7 +76354,7 @@ module.exports = Parser; /***/ }), -/* 640 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76365,13 +76461,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 641 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(600); +var define = __webpack_require__(602); /** * Store position for a node @@ -76386,14 +76482,14 @@ module.exports = function Position(start, parser) { /***/ }), -/* 642 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(643); -var assignSymbols = __webpack_require__(547); +var isExtendable = __webpack_require__(645); +var assignSymbols = __webpack_require__(549); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -76453,7 +76549,7 @@ function isEnum(obj, key) { /***/ }), -/* 643 */ +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76466,7 +76562,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(546); +var isPlainObject = __webpack_require__(548); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -76474,14 +76570,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 644 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(645); -var extglob = __webpack_require__(660); +var nanomatch = __webpack_require__(647); +var extglob = __webpack_require__(662); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -76558,7 +76654,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 645 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76569,17 +76665,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(112); -var toRegex = __webpack_require__(529); -var extend = __webpack_require__(646); +var toRegex = __webpack_require__(531); +var extend = __webpack_require__(648); /** * Local dependencies */ -var compilers = __webpack_require__(648); -var parsers = __webpack_require__(649); -var cache = __webpack_require__(652); -var utils = __webpack_require__(654); +var compilers = __webpack_require__(650); +var parsers = __webpack_require__(651); +var cache = __webpack_require__(654); +var utils = __webpack_require__(656); var MAX_LENGTH = 1024 * 64; /** @@ -77403,14 +77499,14 @@ module.exports = nanomatch; /***/ }), -/* 646 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(647); -var assignSymbols = __webpack_require__(547); +var isExtendable = __webpack_require__(649); +var assignSymbols = __webpack_require__(549); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -77470,7 +77566,7 @@ function isEnum(obj, key) { /***/ }), -/* 647 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77483,7 +77579,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(546); +var isPlainObject = __webpack_require__(548); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -77491,7 +77587,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 648 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77837,15 +77933,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 649 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(548); -var toRegex = __webpack_require__(529); -var isOdd = __webpack_require__(650); +var regexNot = __webpack_require__(550); +var toRegex = __webpack_require__(531); +var isOdd = __webpack_require__(652); /** * Characters to use in negation regex (we want to "not" match @@ -78231,7 +78327,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 650 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78244,7 +78340,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(651); +var isNumber = __webpack_require__(653); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -78258,7 +78354,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 651 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78286,14 +78382,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 652 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(653))(); +module.exports = new (__webpack_require__(655))(); /***/ }), -/* 653 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78306,7 +78402,7 @@ module.exports = new (__webpack_require__(653))(); -var MapCache = __webpack_require__(640); +var MapCache = __webpack_require__(642); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -78428,7 +78524,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 654 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78441,14 +78537,14 @@ var path = __webpack_require__(4); * Module dependencies */ -var isWindows = __webpack_require__(655)(); -var Snapdragon = __webpack_require__(572); -utils.define = __webpack_require__(656); -utils.diff = __webpack_require__(657); -utils.extend = __webpack_require__(646); -utils.pick = __webpack_require__(658); -utils.typeOf = __webpack_require__(659); -utils.unique = __webpack_require__(551); +var isWindows = __webpack_require__(657)(); +var Snapdragon = __webpack_require__(574); +utils.define = __webpack_require__(658); +utils.diff = __webpack_require__(659); +utils.extend = __webpack_require__(648); +utils.pick = __webpack_require__(660); +utils.typeOf = __webpack_require__(661); +utils.unique = __webpack_require__(553); /** * Returns true if the given value is effectively an empty string @@ -78814,7 +78910,7 @@ utils.unixify = function(options) { /***/ }), -/* 655 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -78842,7 +78938,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 656 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78855,8 +78951,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(537); -var isDescriptor = __webpack_require__(538); +var isobject = __webpack_require__(539); +var isDescriptor = __webpack_require__(540); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -78887,7 +78983,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 657 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78941,7 +79037,7 @@ function diffArray(one, two) { /***/ }), -/* 658 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78954,7 +79050,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(537); +var isObject = __webpack_require__(539); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -78983,7 +79079,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 659 */ +/* 661 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -79118,7 +79214,7 @@ function isBuffer(val) { /***/ }), -/* 660 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79128,18 +79224,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(552); -var unique = __webpack_require__(551); -var toRegex = __webpack_require__(529); +var extend = __webpack_require__(554); +var unique = __webpack_require__(553); +var toRegex = __webpack_require__(531); /** * Local dependencies */ -var compilers = __webpack_require__(661); -var parsers = __webpack_require__(667); -var Extglob = __webpack_require__(670); -var utils = __webpack_require__(669); +var compilers = __webpack_require__(663); +var parsers = __webpack_require__(669); +var Extglob = __webpack_require__(672); +var utils = __webpack_require__(671); var MAX_LENGTH = 1024 * 64; /** @@ -79456,13 +79552,13 @@ module.exports = extglob; /***/ }), -/* 661 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(662); +var brackets = __webpack_require__(664); /** * Extglob compilers @@ -79632,7 +79728,7 @@ module.exports = function(extglob) { /***/ }), -/* 662 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79642,17 +79738,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(663); -var parsers = __webpack_require__(665); +var compilers = __webpack_require__(665); +var parsers = __webpack_require__(667); /** * Module dependencies */ -var debug = __webpack_require__(613)('expand-brackets'); -var extend = __webpack_require__(552); -var Snapdragon = __webpack_require__(572); -var toRegex = __webpack_require__(529); +var debug = __webpack_require__(615)('expand-brackets'); +var extend = __webpack_require__(554); +var Snapdragon = __webpack_require__(574); +var toRegex = __webpack_require__(531); /** * Parses the given POSIX character class `pattern` and returns a @@ -79850,13 +79946,13 @@ module.exports = brackets; /***/ }), -/* 663 */ +/* 665 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(664); +var posix = __webpack_require__(666); module.exports = function(brackets) { brackets.compiler @@ -79944,7 +80040,7 @@ module.exports = function(brackets) { /***/ }), -/* 664 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79973,14 +80069,14 @@ module.exports = { /***/ }), -/* 665 */ +/* 667 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(666); -var define = __webpack_require__(600); +var utils = __webpack_require__(668); +var define = __webpack_require__(602); /** * Text regex @@ -80199,14 +80295,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 666 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(529); -var regexNot = __webpack_require__(548); +var toRegex = __webpack_require__(531); +var regexNot = __webpack_require__(550); var cached; /** @@ -80240,15 +80336,15 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 667 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(662); -var define = __webpack_require__(668); -var utils = __webpack_require__(669); +var brackets = __webpack_require__(664); +var define = __webpack_require__(670); +var utils = __webpack_require__(671); /** * Characters to use in text regex (we want to "not" match @@ -80403,7 +80499,7 @@ module.exports = parsers; /***/ }), -/* 668 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80416,7 +80512,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(538); +var isDescriptor = __webpack_require__(540); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -80441,14 +80537,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 669 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(548); -var Cache = __webpack_require__(653); +var regex = __webpack_require__(550); +var Cache = __webpack_require__(655); /** * Utils @@ -80517,7 +80613,7 @@ utils.createRegex = function(str) { /***/ }), -/* 670 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80527,16 +80623,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(572); -var define = __webpack_require__(668); -var extend = __webpack_require__(552); +var Snapdragon = __webpack_require__(574); +var define = __webpack_require__(670); +var extend = __webpack_require__(554); /** * Local dependencies */ -var compilers = __webpack_require__(661); -var parsers = __webpack_require__(667); +var compilers = __webpack_require__(663); +var parsers = __webpack_require__(669); /** * Customize Snapdragon parser and renderer @@ -80602,16 +80698,16 @@ module.exports = Extglob; /***/ }), -/* 671 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(660); -var nanomatch = __webpack_require__(645); -var regexNot = __webpack_require__(548); -var toRegex = __webpack_require__(529); +var extglob = __webpack_require__(662); +var nanomatch = __webpack_require__(647); +var regexNot = __webpack_require__(550); +var toRegex = __webpack_require__(531); var not; /** @@ -80692,14 +80788,14 @@ function textRegex(pattern) { /***/ }), -/* 672 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(653))(); +module.exports = new (__webpack_require__(655))(); /***/ }), -/* 673 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80712,13 +80808,13 @@ var path = __webpack_require__(4); * Module dependencies */ -var Snapdragon = __webpack_require__(572); -utils.define = __webpack_require__(674); -utils.diff = __webpack_require__(657); -utils.extend = __webpack_require__(642); -utils.pick = __webpack_require__(658); -utils.typeOf = __webpack_require__(675); -utils.unique = __webpack_require__(551); +var Snapdragon = __webpack_require__(574); +utils.define = __webpack_require__(676); +utils.diff = __webpack_require__(659); +utils.extend = __webpack_require__(644); +utils.pick = __webpack_require__(660); +utils.typeOf = __webpack_require__(677); +utils.unique = __webpack_require__(553); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -81015,7 +81111,7 @@ utils.unixify = function(options) { /***/ }), -/* 674 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81028,8 +81124,8 @@ utils.unixify = function(options) { -var isobject = __webpack_require__(537); -var isDescriptor = __webpack_require__(538); +var isobject = __webpack_require__(539); +var isDescriptor = __webpack_require__(540); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -81060,7 +81156,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 675 */ +/* 677 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -81195,7 +81291,7 @@ function isBuffer(val) { /***/ }), -/* 676 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81214,9 +81310,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(677); -var reader_1 = __webpack_require__(690); -var fs_stream_1 = __webpack_require__(694); +var readdir = __webpack_require__(679); +var reader_1 = __webpack_require__(692); +var fs_stream_1 = __webpack_require__(696); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -81277,15 +81373,15 @@ exports.default = ReaderAsync; /***/ }), -/* 677 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(678); -const readdirAsync = __webpack_require__(686); -const readdirStream = __webpack_require__(689); +const readdirSync = __webpack_require__(680); +const readdirAsync = __webpack_require__(688); +const readdirStream = __webpack_require__(691); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -81369,7 +81465,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 678 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81377,11 +81473,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(679); +const DirectoryReader = __webpack_require__(681); let syncFacade = { - fs: __webpack_require__(684), - forEach: __webpack_require__(685), + fs: __webpack_require__(686), + forEach: __webpack_require__(687), sync: true }; @@ -81410,7 +81506,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 679 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81419,9 +81515,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(138).Readable; const EventEmitter = __webpack_require__(156).EventEmitter; const path = __webpack_require__(4); -const normalizeOptions = __webpack_require__(680); -const stat = __webpack_require__(682); -const call = __webpack_require__(683); +const normalizeOptions = __webpack_require__(682); +const stat = __webpack_require__(684); +const call = __webpack_require__(685); /** * Asynchronously reads the contents of a directory and streams the results @@ -81797,14 +81893,14 @@ module.exports = DirectoryReader; /***/ }), -/* 680 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const globToRegExp = __webpack_require__(681); +const globToRegExp = __webpack_require__(683); module.exports = normalizeOptions; @@ -81981,7 +82077,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 681 */ +/* 683 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -82118,13 +82214,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 682 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(683); +const call = __webpack_require__(685); module.exports = stat; @@ -82199,7 +82295,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 683 */ +/* 685 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82260,14 +82356,14 @@ function callOnce (fn) { /***/ }), -/* 684 */ +/* 686 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const call = __webpack_require__(683); +const call = __webpack_require__(685); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -82331,7 +82427,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 685 */ +/* 687 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82360,7 +82456,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 686 */ +/* 688 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82368,12 +82464,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(687); -const DirectoryReader = __webpack_require__(679); +const maybe = __webpack_require__(689); +const DirectoryReader = __webpack_require__(681); let asyncFacade = { fs: __webpack_require__(134), - forEach: __webpack_require__(688), + forEach: __webpack_require__(690), async: true }; @@ -82415,7 +82511,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 687 */ +/* 689 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82442,7 +82538,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 688 */ +/* 690 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82478,7 +82574,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 689 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82486,11 +82582,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(679); +const DirectoryReader = __webpack_require__(681); let streamFacade = { fs: __webpack_require__(134), - forEach: __webpack_require__(688), + forEach: __webpack_require__(690), async: true }; @@ -82510,16 +82606,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 690 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var deep_1 = __webpack_require__(691); -var entry_1 = __webpack_require__(693); -var pathUtil = __webpack_require__(692); +var deep_1 = __webpack_require__(693); +var entry_1 = __webpack_require__(695); +var pathUtil = __webpack_require__(694); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -82585,14 +82681,14 @@ exports.default = Reader; /***/ }), -/* 691 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(692); -var patternUtils = __webpack_require__(523); +var pathUtils = __webpack_require__(694); +var patternUtils = __webpack_require__(525); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -82675,7 +82771,7 @@ exports.default = DeepFilter; /***/ }), -/* 692 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82706,14 +82802,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 693 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(692); -var patternUtils = __webpack_require__(523); +var pathUtils = __webpack_require__(694); +var patternUtils = __webpack_require__(525); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -82798,7 +82894,7 @@ exports.default = EntryFilter; /***/ }), -/* 694 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82818,8 +82914,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(138); -var fsStat = __webpack_require__(695); -var fs_1 = __webpack_require__(699); +var fsStat = __webpack_require__(697); +var fs_1 = __webpack_require__(701); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -82869,14 +82965,14 @@ exports.default = FileSystemStream; /***/ }), -/* 695 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(696); -const statProvider = __webpack_require__(698); +const optionsManager = __webpack_require__(698); +const statProvider = __webpack_require__(700); /** * Asynchronous API. */ @@ -82907,13 +83003,13 @@ exports.statSync = statSync; /***/ }), -/* 696 */ +/* 698 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(697); +const fsAdapter = __webpack_require__(699); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -82926,7 +83022,7 @@ exports.prepare = prepare; /***/ }), -/* 697 */ +/* 699 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82949,7 +83045,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 698 */ +/* 700 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83001,7 +83097,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 699 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83032,7 +83128,7 @@ exports.default = FileSystem; /***/ }), -/* 700 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83052,9 +83148,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(138); -var readdir = __webpack_require__(677); -var reader_1 = __webpack_require__(690); -var fs_stream_1 = __webpack_require__(694); +var readdir = __webpack_require__(679); +var reader_1 = __webpack_require__(692); +var fs_stream_1 = __webpack_require__(696); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -83122,7 +83218,7 @@ exports.default = ReaderStream; /***/ }), -/* 701 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83141,9 +83237,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(677); -var reader_1 = __webpack_require__(690); -var fs_sync_1 = __webpack_require__(702); +var readdir = __webpack_require__(679); +var reader_1 = __webpack_require__(692); +var fs_sync_1 = __webpack_require__(704); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -83203,7 +83299,7 @@ exports.default = ReaderSync; /***/ }), -/* 702 */ +/* 704 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83222,8 +83318,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(695); -var fs_1 = __webpack_require__(699); +var fsStat = __webpack_require__(697); +var fs_1 = __webpack_require__(701); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -83269,7 +83365,7 @@ exports.default = FileSystemSync; /***/ }), -/* 703 */ +/* 705 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83285,7 +83381,7 @@ exports.flatten = flatten; /***/ }), -/* 704 */ +/* 706 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83306,13 +83402,13 @@ exports.merge = merge; /***/ }), -/* 705 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(706); +const pathType = __webpack_require__(708); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -83378,13 +83474,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 706 */ +/* 708 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const pify = __webpack_require__(707); +const pify = __webpack_require__(709); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -83427,7 +83523,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 707 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83518,17 +83614,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 708 */ +/* 710 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(519); -const gitIgnore = __webpack_require__(709); -const pify = __webpack_require__(710); -const slash = __webpack_require__(711); +const fastGlob = __webpack_require__(521); +const gitIgnore = __webpack_require__(711); +const pify = __webpack_require__(712); +const slash = __webpack_require__(713); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -83626,7 +83722,7 @@ module.exports.sync = options => { /***/ }), -/* 709 */ +/* 711 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -84095,7 +84191,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 710 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84170,7 +84266,7 @@ module.exports = (input, options) => { /***/ }), -/* 711 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84188,7 +84284,7 @@ module.exports = input => { /***/ }), -/* 712 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84201,7 +84297,7 @@ module.exports = input => { -var isGlob = __webpack_require__(713); +var isGlob = __webpack_require__(715); module.exports = function hasGlob(val) { if (val == null) return false; @@ -84221,7 +84317,7 @@ module.exports = function hasGlob(val) { /***/ }), -/* 713 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -84252,17 +84348,17 @@ module.exports = function isGlob(str) { /***/ }), -/* 714 */ +/* 716 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); const {constants: fsConstants} = __webpack_require__(134); -const pEvent = __webpack_require__(715); -const CpFileError = __webpack_require__(718); -const fs = __webpack_require__(720); -const ProgressEmitter = __webpack_require__(723); +const pEvent = __webpack_require__(717); +const CpFileError = __webpack_require__(720); +const fs = __webpack_require__(722); +const ProgressEmitter = __webpack_require__(725); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -84376,12 +84472,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 715 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(716); +const pTimeout = __webpack_require__(718); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -84672,12 +84768,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 716 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(717); +const pFinally = __webpack_require__(719); class TimeoutError extends Error { constructor(message) { @@ -84723,7 +84819,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 717 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84745,12 +84841,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 718 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(719); +const NestedError = __webpack_require__(721); class CpFileError extends NestedError { constructor(message, nested) { @@ -84764,7 +84860,7 @@ module.exports = CpFileError; /***/ }), -/* 719 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(112).inherits; @@ -84820,16 +84916,16 @@ module.exports = NestedError; /***/ }), -/* 720 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(112); const fs = __webpack_require__(133); -const makeDir = __webpack_require__(721); -const pEvent = __webpack_require__(715); -const CpFileError = __webpack_require__(718); +const makeDir = __webpack_require__(723); +const pEvent = __webpack_require__(717); +const CpFileError = __webpack_require__(720); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -84926,7 +85022,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 721 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84934,7 +85030,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(134); const path = __webpack_require__(4); const {promisify} = __webpack_require__(112); -const semver = __webpack_require__(722); +const semver = __webpack_require__(724); const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0'); @@ -85089,7 +85185,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 722 */ +/* 724 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -86691,7 +86787,7 @@ function coerce (version, options) { /***/ }), -/* 723 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86732,7 +86828,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 724 */ +/* 726 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86778,12 +86874,12 @@ exports.default = module.exports; /***/ }), -/* 725 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pMap = __webpack_require__(726); +const pMap = __webpack_require__(728); const pFilter = async (iterable, filterer, options) => { const values = await pMap( @@ -86800,7 +86896,7 @@ module.exports.default = pFilter; /***/ }), -/* 726 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86879,12 +86975,12 @@ module.exports.default = pMap; /***/ }), -/* 727 */ +/* 729 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(719); +const NestedError = __webpack_require__(721); class CpyError extends NestedError { constructor(message, nested) { diff --git a/test/common/services/es_archiver.ts b/test/common/services/es_archiver.ts index e1b85ddf8bc9..e6d4a8a56af2 100644 --- a/test/common/services/es_archiver.ts +++ b/test/common/services/es_archiver.ts @@ -14,7 +14,7 @@ import * as KibanaServer from './kibana_server'; export function EsArchiverProvider({ getService }: FtrProviderContext): EsArchiver { const config = getService('config'); - const client = getService('legacyEs'); + const client = getService('es'); const log = getService('log'); const kibanaServer = getService('kibanaServer'); const retry = getService('retry'); diff --git a/yarn.lock b/yarn.lock index 734173756ae2..c51ff54800c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7355,6 +7355,14 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +aggregate-error@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + airbnb-js-shims@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz#db481102d682b98ed1daa4c5baa697a05ce5c040" From cf846bdddf59333c22794f2e2e23ca08dcfa90b5 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 2 Feb 2021 16:56:40 -0700 Subject: [PATCH 04/14] [Metrics UI][Logs UI] Completely remove GraphQL and Apollo (#89036) --- .../infra/common/graphql/root/index.ts | 7 - .../infra/common/graphql/root/schema.gql.ts | 18 - .../graphql/shared/fragments.gql_query.ts | 81 - .../infra/common/graphql/shared/index.ts | 8 - .../infra/common/graphql/shared/schema.gql.ts | 38 - x-pack/plugins/infra/common/graphql/types.ts | 780 ----- .../infra/common/http_api/node_details_api.ts | 6 +- .../infra/common/http_api/source_api.ts | 52 +- .../infra/common/log_entry/log_entry.ts | 1 - x-pack/plugins/infra/docs/arch.md | 4 +- x-pack/plugins/infra/docs/arch_client.md | 2 +- x-pack/plugins/infra/docs/graphql.md | 53 - .../infra/public/apps/common_providers.tsx | 21 +- x-pack/plugins/infra/public/apps/logs_app.tsx | 8 +- .../plugins/infra/public/apps/metrics_app.tsx | 8 +- .../source_configuration_form_state.tsx | 4 +- .../source/create_source.gql_query.ts | 36 - .../source/query_source.gql_query.ts | 31 - .../infra/public/containers/source/source.tsx | 102 +- .../source_fields_fragment.gql_query.ts | 58 - .../source/update_source.gql_query.ts | 33 - .../containers/source/use_source_via_http.ts | 4 +- .../containers/with_source/with_source.tsx | 11 +- .../infra/public/graphql/introspection.json | 2713 ----------------- x-pack/plugins/infra/public/graphql/types.ts | 786 ----- x-pack/plugins/infra/public/lib/lib.ts | 4 +- .../infra/public/pages/metrics/index.tsx | 4 +- .../metric_detail/components/helpers.ts | 8 +- .../metric_detail/components/page_error.tsx | 2 - .../metric_detail/components/series_chart.tsx | 6 +- .../metrics_explorer/components/chart.tsx | 4 +- .../components/chart_context_menu.tsx | 6 +- .../metrics_explorer/components/charts.tsx | 4 +- .../components/helpers/create_tsvb_link.ts | 8 +- .../hooks/use_metric_explorer_state.ts | 4 +- .../hooks/use_metrics_explorer_data.test.tsx | 4 +- .../hooks/use_metrics_explorer_data.ts | 4 +- .../pages/metrics/metrics_explorer/index.tsx | 4 +- .../infra/public/utils/apollo_client.ts | 86 - .../infra/public/utils/apollo_context.ts | 26 - .../public/utils/source_configuration.ts | 17 +- .../plugins/infra/scripts/combined_schema.ts | 16 - .../scripts/generate_types_from_graphql.js | 75 - x-pack/plugins/infra/server/graphql/index.ts | 12 - .../server/graphql/source_status/index.ts | 7 - .../server/graphql/source_status/resolvers.ts | 90 - .../graphql/source_status/schema.gql.ts | 40 - .../infra/server/graphql/sources/index.ts | 8 - .../infra/server/graphql/sources/resolvers.ts | 202 -- .../server/graphql/sources/schema.gql.ts | 209 -- x-pack/plugins/infra/server/graphql/types.ts | 1111 ------- x-pack/plugins/infra/server/infra_server.ts | 14 - .../framework/kibana_framework_adapter.ts | 79 +- .../server/lib/adapters/metrics/lib/errors.ts | 15 - .../infra/server/lib/domains/fields_domain.ts | 11 +- .../plugins/infra/server/lib/infra_types.ts | 9 +- .../infra/server/routes/log_sources/status.ts | 3 +- .../infra/server/routes/source/index.ts | 92 +- .../infra/server/utils/serialized_query.ts | 7 +- .../infra/server/utils/typed_resolvers.ts | 97 - .../plugins/infra/types/graphql_fields.d.ts | 11 - .../apis/metrics_ui/feature_controls.ts | 252 -- .../apis/metrics_ui/http_source.ts | 12 +- .../api_integration/apis/metrics_ui/index.js | 1 - .../apis/metrics_ui/metadata.ts | 13 +- .../apis/metrics_ui/metrics.ts | 14 +- .../apis/metrics_ui/snapshot.ts | 60 +- .../apis/metrics_ui/sources.ts | 457 +-- x-pack/test/api_integration/services/index.ts | 6 - .../services/infraops_graphql_client.ts | 68 - .../services/infraops_source_configuration.ts | 65 +- 71 files changed, 406 insertions(+), 7706 deletions(-) delete mode 100644 x-pack/plugins/infra/common/graphql/root/index.ts delete mode 100644 x-pack/plugins/infra/common/graphql/root/schema.gql.ts delete mode 100644 x-pack/plugins/infra/common/graphql/shared/fragments.gql_query.ts delete mode 100644 x-pack/plugins/infra/common/graphql/shared/index.ts delete mode 100644 x-pack/plugins/infra/common/graphql/shared/schema.gql.ts delete mode 100644 x-pack/plugins/infra/common/graphql/types.ts delete mode 100644 x-pack/plugins/infra/docs/graphql.md delete mode 100644 x-pack/plugins/infra/public/containers/source/create_source.gql_query.ts delete mode 100644 x-pack/plugins/infra/public/containers/source/query_source.gql_query.ts delete mode 100644 x-pack/plugins/infra/public/containers/source/source_fields_fragment.gql_query.ts delete mode 100644 x-pack/plugins/infra/public/containers/source/update_source.gql_query.ts delete mode 100644 x-pack/plugins/infra/public/graphql/introspection.json delete mode 100644 x-pack/plugins/infra/public/graphql/types.ts delete mode 100644 x-pack/plugins/infra/public/utils/apollo_client.ts delete mode 100644 x-pack/plugins/infra/public/utils/apollo_context.ts delete mode 100644 x-pack/plugins/infra/scripts/combined_schema.ts delete mode 100644 x-pack/plugins/infra/scripts/generate_types_from_graphql.js delete mode 100644 x-pack/plugins/infra/server/graphql/index.ts delete mode 100644 x-pack/plugins/infra/server/graphql/source_status/index.ts delete mode 100644 x-pack/plugins/infra/server/graphql/source_status/resolvers.ts delete mode 100644 x-pack/plugins/infra/server/graphql/source_status/schema.gql.ts delete mode 100644 x-pack/plugins/infra/server/graphql/sources/index.ts delete mode 100644 x-pack/plugins/infra/server/graphql/sources/resolvers.ts delete mode 100644 x-pack/plugins/infra/server/graphql/sources/schema.gql.ts delete mode 100644 x-pack/plugins/infra/server/graphql/types.ts delete mode 100644 x-pack/plugins/infra/server/lib/adapters/metrics/lib/errors.ts delete mode 100644 x-pack/plugins/infra/server/utils/typed_resolvers.ts delete mode 100644 x-pack/plugins/infra/types/graphql_fields.d.ts delete mode 100644 x-pack/test/api_integration/apis/metrics_ui/feature_controls.ts delete mode 100644 x-pack/test/api_integration/services/infraops_graphql_client.ts diff --git a/x-pack/plugins/infra/common/graphql/root/index.ts b/x-pack/plugins/infra/common/graphql/root/index.ts deleted file mode 100644 index 47417b637630..000000000000 --- a/x-pack/plugins/infra/common/graphql/root/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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. - */ - -export { rootSchema } from './schema.gql'; diff --git a/x-pack/plugins/infra/common/graphql/root/schema.gql.ts b/x-pack/plugins/infra/common/graphql/root/schema.gql.ts deleted file mode 100644 index 1665334827e8..000000000000 --- a/x-pack/plugins/infra/common/graphql/root/schema.gql.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 gql from 'graphql-tag'; - -export const rootSchema = gql` - schema { - query: Query - mutation: Mutation - } - - type Query - - type Mutation -`; diff --git a/x-pack/plugins/infra/common/graphql/shared/fragments.gql_query.ts b/x-pack/plugins/infra/common/graphql/shared/fragments.gql_query.ts deleted file mode 100644 index c324813b65ef..000000000000 --- a/x-pack/plugins/infra/common/graphql/shared/fragments.gql_query.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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 gql from 'graphql-tag'; - -export const sharedFragments = { - InfraTimeKey: gql` - fragment InfraTimeKeyFields on InfraTimeKey { - time - tiebreaker - } - `, - InfraSourceFields: gql` - fragment InfraSourceFields on InfraSource { - id - version - updatedAt - origin - } - `, - InfraLogEntryFields: gql` - fragment InfraLogEntryFields on InfraLogEntry { - gid - key { - time - tiebreaker - } - columns { - ... on InfraLogEntryTimestampColumn { - columnId - timestamp - } - ... on InfraLogEntryMessageColumn { - columnId - message { - ... on InfraLogMessageFieldSegment { - field - value - } - ... on InfraLogMessageConstantSegment { - constant - } - } - } - ... on InfraLogEntryFieldColumn { - columnId - field - value - } - } - } - `, - InfraLogEntryHighlightFields: gql` - fragment InfraLogEntryHighlightFields on InfraLogEntry { - gid - key { - time - tiebreaker - } - columns { - ... on InfraLogEntryMessageColumn { - columnId - message { - ... on InfraLogMessageFieldSegment { - field - highlights - } - } - } - ... on InfraLogEntryFieldColumn { - columnId - field - highlights - } - } - } - `, -}; diff --git a/x-pack/plugins/infra/common/graphql/shared/index.ts b/x-pack/plugins/infra/common/graphql/shared/index.ts deleted file mode 100644 index 56c8675e76ca..000000000000 --- a/x-pack/plugins/infra/common/graphql/shared/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * 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. - */ - -export { sharedFragments } from './fragments.gql_query'; -export { sharedSchema } from './schema.gql'; diff --git a/x-pack/plugins/infra/common/graphql/shared/schema.gql.ts b/x-pack/plugins/infra/common/graphql/shared/schema.gql.ts deleted file mode 100644 index 071313817eff..000000000000 --- a/x-pack/plugins/infra/common/graphql/shared/schema.gql.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 gql from 'graphql-tag'; - -export const sharedSchema = gql` - "A representation of the log entry's position in the event stream" - type InfraTimeKey { - "The timestamp of the event that the log entry corresponds to" - time: Float! - "The tiebreaker that disambiguates events with the same timestamp" - tiebreaker: Float! - } - - input InfraTimeKeyInput { - time: Float! - tiebreaker: Float! - } - - enum InfraIndexType { - ANY - LOGS - METRICS - } - - enum InfraNodeType { - pod - container - host - awsEC2 - awsS3 - awsRDS - awsSQS - } -`; diff --git a/x-pack/plugins/infra/common/graphql/types.ts b/x-pack/plugins/infra/common/graphql/types.ts deleted file mode 100644 index ee536feb1ce6..000000000000 --- a/x-pack/plugins/infra/common/graphql/types.ts +++ /dev/null @@ -1,780 +0,0 @@ -/* tslint:disable */ - -// ==================================================== -// START: Typescript template -// ==================================================== - -// ==================================================== -// Types -// ==================================================== - -export interface Query { - /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source that doesn't exist doesn't error out,but returns the configured or hardcoded defaults. */ - source: InfraSource; - /** Get a list of all infrastructure data sources */ - allSources: InfraSource[]; -} -/** A source of infrastructure data */ -export interface InfraSource { - /** The id of the source */ - id: string; - /** The version number the source configuration was last persisted with */ - version?: string | null; - /** The timestamp the source configuration was last persisted at */ - updatedAt?: number | null; - /** The origin of the source (one of 'fallback', 'internal', 'stored') */ - origin: string; - /** The raw configuration of the source */ - configuration: InfraSourceConfiguration; - /** The status of the source */ - status: InfraSourceStatus; - - /** A snapshot of nodes */ - snapshot?: InfraSnapshotResponse | null; - - metrics: InfraMetricData[]; -} -/** A set of configuration options for an infrastructure data source */ -export interface InfraSourceConfiguration { - /** The name of the data source */ - name: string; - /** A description of the data source */ - description: string; - /** The alias to read metric data from */ - metricAlias: string; - /** The alias to read log data from */ - logAlias: string; - /** The field mapping to use for this source */ - fields: InfraSourceFields; - /** The columns to use for log display */ - logColumns: InfraSourceLogColumn[]; -} -/** A mapping of semantic fields to their document counterparts */ -export interface InfraSourceFields { - /** The field to identify a container by */ - container: string; - /** The fields to identify a host by */ - host: string; - /** The fields to use as the log message */ - message: string[]; - /** The field to identify a pod by */ - pod: string; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker: string; - /** The field to use as a timestamp for metrics and logs */ - timestamp: string; -} -/** The built-in timestamp log column */ -export interface InfraSourceTimestampLogColumn { - timestampColumn: InfraSourceTimestampLogColumnAttributes; -} - -export interface InfraSourceTimestampLogColumnAttributes { - /** A unique id for the column */ - id: string; -} -/** The built-in message log column */ -export interface InfraSourceMessageLogColumn { - messageColumn: InfraSourceMessageLogColumnAttributes; -} - -export interface InfraSourceMessageLogColumnAttributes { - /** A unique id for the column */ - id: string; -} -/** A log column containing a field value */ -export interface InfraSourceFieldLogColumn { - fieldColumn: InfraSourceFieldLogColumnAttributes; -} - -export interface InfraSourceFieldLogColumnAttributes { - /** A unique id for the column */ - id: string; - /** The field name this column refers to */ - field: string; -} -/** The status of an infrastructure data source */ -export interface InfraSourceStatus { - /** Whether the configured metric alias exists */ - metricAliasExists: boolean; - /** Whether the configured log alias exists */ - logAliasExists: boolean; - /** Whether the configured alias or wildcard pattern resolve to any metric indices */ - metricIndicesExist: boolean; - /** Whether the configured alias or wildcard pattern resolve to any log indices */ - logIndicesExist: boolean; - /** The list of indices in the metric alias */ - metricIndices: string[]; - /** The list of indices in the log alias */ - logIndices: string[]; - /** The list of fields defined in the index mappings */ - indexFields: InfraIndexField[]; -} -/** A descriptor of a field in an index */ -export interface InfraIndexField { - /** The name of the field */ - name: string; - /** The type of the field's values as recognized by Kibana */ - type: string; - /** Whether the field's values can be efficiently searched for */ - searchable: boolean; - /** Whether the field's values can be aggregated */ - aggregatable: boolean; - /** Whether the field should be displayed based on event.module and a ECS allowed list */ - displayable: boolean; -} - -export interface InfraSnapshotResponse { - /** Nodes of type host, container or pod grouped by 0, 1 or 2 terms */ - nodes: InfraSnapshotNode[]; -} - -export interface InfraSnapshotNode { - path: InfraSnapshotNodePath[]; - - metric: InfraSnapshotNodeMetric; -} - -export interface InfraSnapshotNodePath { - value: string; - - label: string; - - ip?: string | null; -} - -export interface InfraSnapshotNodeMetric { - name: InfraSnapshotMetricType; - - value?: number | null; - - avg?: number | null; - - max?: number | null; -} - -export interface InfraMetricData { - id?: InfraMetric | null; - - series: InfraDataSeries[]; -} - -export interface InfraDataSeries { - id: string; - - label: string; - - data: InfraDataPoint[]; -} - -export interface InfraDataPoint { - timestamp: number; - - value?: number | null; -} - -export interface Mutation { - /** Create a new source of infrastructure data */ - createSource: UpdateSourceResult; - /** Modify an existing source */ - updateSource: UpdateSourceResult; - /** Delete a source of infrastructure data */ - deleteSource: DeleteSourceResult; -} -/** The result of a successful source update */ -export interface UpdateSourceResult { - /** The source that was updated */ - source: InfraSource; -} -/** The result of a source deletion operations */ -export interface DeleteSourceResult { - /** The id of the source that was deleted */ - id: string; -} - -// ==================================================== -// InputTypes -// ==================================================== - -export interface InfraTimerangeInput { - /** The interval string to use for last bucket. The format is '{value}{unit}'. For example '5m' would return the metrics for the last 5 minutes of the timespan. */ - interval: string; - /** The end of the timerange */ - to: number; - /** The beginning of the timerange */ - from: number; -} - -export interface InfraSnapshotGroupbyInput { - /** The label to use in the results for the group by for the terms group by */ - label?: string | null; - /** The field to group by from a terms aggregation, this is ignored by the filter type */ - field?: string | null; -} - -export interface InfraSnapshotMetricInput { - /** The type of metric */ - type: InfraSnapshotMetricType; -} - -export interface InfraNodeIdsInput { - nodeId: string; - - cloudId?: string | null; -} -/** The properties to update the source with */ -export interface UpdateSourceInput { - /** The name of the data source */ - name?: string | null; - /** A description of the data source */ - description?: string | null; - /** The alias to read metric data from */ - metricAlias?: string | null; - /** The alias to read log data from */ - logAlias?: string | null; - /** The field mapping to use for this source */ - fields?: UpdateSourceFieldsInput | null; - /** Default view for inventory */ - inventoryDefaultView?: string | null; - /** Default view for Metrics Explorer */ - metricsExplorerDefaultView?: string | null; - /** The log columns to display for this source */ - logColumns?: UpdateSourceLogColumnInput[] | null; -} -/** The mapping of semantic fields of the source to be created */ -export interface UpdateSourceFieldsInput { - /** The field to identify a container by */ - container?: string | null; - /** The fields to identify a host by */ - host?: string | null; - /** The field to identify a pod by */ - pod?: string | null; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker?: string | null; - /** The field to use as a timestamp for metrics and logs */ - timestamp?: string | null; -} -/** One of the log column types to display for this source */ -export interface UpdateSourceLogColumnInput { - /** A custom field log column */ - fieldColumn?: UpdateSourceFieldLogColumnInput | null; - /** A built-in message log column */ - messageColumn?: UpdateSourceMessageLogColumnInput | null; - /** A built-in timestamp log column */ - timestampColumn?: UpdateSourceTimestampLogColumnInput | null; -} - -export interface UpdateSourceFieldLogColumnInput { - id: string; - - field: string; -} - -export interface UpdateSourceMessageLogColumnInput { - id: string; -} - -export interface UpdateSourceTimestampLogColumnInput { - id: string; -} - -// ==================================================== -// Arguments -// ==================================================== - -export interface SourceQueryArgs { - /** The id of the source */ - id: string; -} -export interface SnapshotInfraSourceArgs { - timerange: InfraTimerangeInput; - - filterQuery?: string | null; -} -export interface MetricsInfraSourceArgs { - nodeIds: InfraNodeIdsInput; - - nodeType: InfraNodeType; - - timerange: InfraTimerangeInput; - - metrics: InfraMetric[]; -} -export interface IndexFieldsInfraSourceStatusArgs { - indexType?: InfraIndexType | null; -} -export interface NodesInfraSnapshotResponseArgs { - type: InfraNodeType; - - groupBy: InfraSnapshotGroupbyInput[]; - - metric: InfraSnapshotMetricInput; -} -export interface CreateSourceMutationArgs { - /** The id of the source */ - id: string; - - sourceProperties: UpdateSourceInput; -} -export interface UpdateSourceMutationArgs { - /** The id of the source */ - id: string; - /** The properties to update the source with */ - sourceProperties: UpdateSourceInput; -} -export interface DeleteSourceMutationArgs { - /** The id of the source */ - id: string; -} - -// ==================================================== -// Enums -// ==================================================== - -export enum InfraIndexType { - ANY = 'ANY', - LOGS = 'LOGS', - METRICS = 'METRICS', -} - -export enum InfraNodeType { - pod = 'pod', - container = 'container', - host = 'host', - awsEC2 = 'awsEC2', - awsS3 = 'awsS3', - awsRDS = 'awsRDS', - awsSQS = 'awsSQS', -} - -export enum InfraSnapshotMetricType { - count = 'count', - cpu = 'cpu', - load = 'load', - memory = 'memory', - tx = 'tx', - rx = 'rx', - logRate = 'logRate', - diskIOReadBytes = 'diskIOReadBytes', - diskIOWriteBytes = 'diskIOWriteBytes', - s3TotalRequests = 's3TotalRequests', - s3NumberOfObjects = 's3NumberOfObjects', - s3BucketSize = 's3BucketSize', - s3DownloadBytes = 's3DownloadBytes', - s3UploadBytes = 's3UploadBytes', - rdsConnections = 'rdsConnections', - rdsQueriesExecuted = 'rdsQueriesExecuted', - rdsActiveTransactions = 'rdsActiveTransactions', - rdsLatency = 'rdsLatency', - sqsMessagesVisible = 'sqsMessagesVisible', - sqsMessagesDelayed = 'sqsMessagesDelayed', - sqsMessagesSent = 'sqsMessagesSent', - sqsMessagesEmpty = 'sqsMessagesEmpty', - sqsOldestMessage = 'sqsOldestMessage', -} - -export enum InfraMetric { - hostSystemOverview = 'hostSystemOverview', - hostCpuUsage = 'hostCpuUsage', - hostFilesystem = 'hostFilesystem', - hostK8sOverview = 'hostK8sOverview', - hostK8sCpuCap = 'hostK8sCpuCap', - hostK8sDiskCap = 'hostK8sDiskCap', - hostK8sMemoryCap = 'hostK8sMemoryCap', - hostK8sPodCap = 'hostK8sPodCap', - hostLoad = 'hostLoad', - hostMemoryUsage = 'hostMemoryUsage', - hostNetworkTraffic = 'hostNetworkTraffic', - hostDockerOverview = 'hostDockerOverview', - hostDockerInfo = 'hostDockerInfo', - hostDockerTop5ByCpu = 'hostDockerTop5ByCpu', - hostDockerTop5ByMemory = 'hostDockerTop5ByMemory', - podOverview = 'podOverview', - podCpuUsage = 'podCpuUsage', - podMemoryUsage = 'podMemoryUsage', - podLogUsage = 'podLogUsage', - podNetworkTraffic = 'podNetworkTraffic', - containerOverview = 'containerOverview', - containerCpuKernel = 'containerCpuKernel', - containerCpuUsage = 'containerCpuUsage', - containerDiskIOOps = 'containerDiskIOOps', - containerDiskIOBytes = 'containerDiskIOBytes', - containerMemory = 'containerMemory', - containerNetworkTraffic = 'containerNetworkTraffic', - nginxHits = 'nginxHits', - nginxRequestRate = 'nginxRequestRate', - nginxActiveConnections = 'nginxActiveConnections', - nginxRequestsPerConnection = 'nginxRequestsPerConnection', - awsOverview = 'awsOverview', - awsCpuUtilization = 'awsCpuUtilization', - awsNetworkBytes = 'awsNetworkBytes', - awsNetworkPackets = 'awsNetworkPackets', - awsDiskioBytes = 'awsDiskioBytes', - awsDiskioOps = 'awsDiskioOps', - awsEC2CpuUtilization = 'awsEC2CpuUtilization', - awsEC2DiskIOBytes = 'awsEC2DiskIOBytes', - awsEC2NetworkTraffic = 'awsEC2NetworkTraffic', - awsS3TotalRequests = 'awsS3TotalRequests', - awsS3NumberOfObjects = 'awsS3NumberOfObjects', - awsS3BucketSize = 'awsS3BucketSize', - awsS3DownloadBytes = 'awsS3DownloadBytes', - awsS3UploadBytes = 'awsS3UploadBytes', - awsRDSCpuTotal = 'awsRDSCpuTotal', - awsRDSConnections = 'awsRDSConnections', - awsRDSQueriesExecuted = 'awsRDSQueriesExecuted', - awsRDSActiveTransactions = 'awsRDSActiveTransactions', - awsRDSLatency = 'awsRDSLatency', - awsSQSMessagesVisible = 'awsSQSMessagesVisible', - awsSQSMessagesDelayed = 'awsSQSMessagesDelayed', - awsSQSMessagesSent = 'awsSQSMessagesSent', - awsSQSMessagesEmpty = 'awsSQSMessagesEmpty', - awsSQSOldestMessage = 'awsSQSOldestMessage', - custom = 'custom', -} - -// ==================================================== -// Unions -// ==================================================== - -/** All known log column types */ -export type InfraSourceLogColumn = - | InfraSourceTimestampLogColumn - | InfraSourceMessageLogColumn - | InfraSourceFieldLogColumn; - -// ==================================================== -// END: Typescript template -// ==================================================== - -// ==================================================== -// Documents -// ==================================================== - -export namespace MetricsQuery { - export type Variables = { - sourceId: string; - timerange: InfraTimerangeInput; - metrics: InfraMetric[]; - nodeId: string; - cloudId?: string | null; - nodeType: InfraNodeType; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - id: string; - - metrics: Metrics[]; - }; - - export type Metrics = { - __typename?: 'InfraMetricData'; - - id?: InfraMetric | null; - - series: Series[]; - }; - - export type Series = { - __typename?: 'InfraDataSeries'; - - id: string; - - label: string; - - data: Data[]; - }; - - export type Data = { - __typename?: 'InfraDataPoint'; - - timestamp: number; - - value?: number | null; - }; -} - -export namespace CreateSourceConfigurationMutation { - export type Variables = { - sourceId: string; - sourceProperties: UpdateSourceInput; - }; - - export type Mutation = { - __typename?: 'Mutation'; - - createSource: CreateSource; - }; - - export type CreateSource = { - __typename?: 'UpdateSourceResult'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - configuration: Configuration; - - status: Status; - } & InfraSourceFields.Fragment; - - export type Configuration = SourceConfigurationFields.Fragment; - - export type Status = SourceStatusFields.Fragment; -} - -export namespace SourceQuery { - export type Variables = { - sourceId?: string | null; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - configuration: Configuration; - - status: Status; - } & InfraSourceFields.Fragment; - - export type Configuration = SourceConfigurationFields.Fragment; - - export type Status = SourceStatusFields.Fragment; -} - -export namespace UpdateSourceMutation { - export type Variables = { - sourceId?: string | null; - sourceProperties: UpdateSourceInput; - }; - - export type Mutation = { - __typename?: 'Mutation'; - - updateSource: UpdateSource; - }; - - export type UpdateSource = { - __typename?: 'UpdateSourceResult'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - configuration: Configuration; - - status: Status; - } & InfraSourceFields.Fragment; - - export type Configuration = SourceConfigurationFields.Fragment; - - export type Status = SourceStatusFields.Fragment; -} - -export namespace WaffleNodesQuery { - export type Variables = { - sourceId: string; - timerange: InfraTimerangeInput; - filterQuery?: string | null; - metric: InfraSnapshotMetricInput; - groupBy: InfraSnapshotGroupbyInput[]; - type: InfraNodeType; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - id: string; - - snapshot?: Snapshot | null; - }; - - export type Snapshot = { - __typename?: 'InfraSnapshotResponse'; - - nodes: Nodes[]; - }; - - export type Nodes = { - __typename?: 'InfraSnapshotNode'; - - path: Path[]; - - metric: Metric; - }; - - export type Path = { - __typename?: 'InfraSnapshotNodePath'; - - value: string; - - label: string; - - ip?: string | null; - }; - - export type Metric = { - __typename?: 'InfraSnapshotNodeMetric'; - - name: InfraSnapshotMetricType; - - value?: number | null; - - avg?: number | null; - - max?: number | null; - }; -} - -export namespace SourceConfigurationFields { - export type Fragment = { - __typename?: 'InfraSourceConfiguration'; - - name: string; - - description: string; - - logAlias: string; - - metricAlias: string; - - fields: Fields; - - logColumns: LogColumns[]; - - inventoryDefaultView: string; - - metricsExplorerDefaultView: string; - }; - - export type Fields = { - __typename?: 'InfraSourceFields'; - - container: string; - - host: string; - - message: string[]; - - pod: string; - - tiebreaker: string; - - timestamp: string; - }; - - export type LogColumns = - | InfraSourceTimestampLogColumnInlineFragment - | InfraSourceMessageLogColumnInlineFragment - | InfraSourceFieldLogColumnInlineFragment; - - export type InfraSourceTimestampLogColumnInlineFragment = { - __typename?: 'InfraSourceTimestampLogColumn'; - - timestampColumn: TimestampColumn; - }; - - export type TimestampColumn = { - __typename?: 'InfraSourceTimestampLogColumnAttributes'; - - id: string; - }; - - export type InfraSourceMessageLogColumnInlineFragment = { - __typename?: 'InfraSourceMessageLogColumn'; - - messageColumn: MessageColumn; - }; - - export type MessageColumn = { - __typename?: 'InfraSourceMessageLogColumnAttributes'; - - id: string; - }; - - export type InfraSourceFieldLogColumnInlineFragment = { - __typename?: 'InfraSourceFieldLogColumn'; - - fieldColumn: FieldColumn; - }; - - export type FieldColumn = { - __typename?: 'InfraSourceFieldLogColumnAttributes'; - - id: string; - - field: string; - }; -} - -export namespace SourceStatusFields { - export type Fragment = { - __typename?: 'InfraSourceStatus'; - - indexFields: IndexFields[]; - - logIndicesExist: boolean; - - metricIndicesExist: boolean; - }; - - export type IndexFields = { - __typename?: 'InfraIndexField'; - - name: string; - - type: string; - - searchable: boolean; - - aggregatable: boolean; - - displayable: boolean; - }; -} - -export namespace InfraTimeKeyFields { - export type Fragment = { - __typename?: 'InfraTimeKey'; - - time: number; - - tiebreaker: number; - }; -} - -export namespace InfraSourceFields { - export type Fragment = { - __typename?: 'InfraSource'; - - id: string; - - version?: string | null; - - updatedAt?: number | null; - - origin: string; - }; -} diff --git a/x-pack/plugins/infra/common/http_api/node_details_api.ts b/x-pack/plugins/infra/common/http_api/node_details_api.ts index 0ef5ae82baeb..6de21da53c36 100644 --- a/x-pack/plugins/infra/common/http_api/node_details_api.ts +++ b/x-pack/plugins/infra/common/http_api/node_details_api.ts @@ -17,18 +17,20 @@ const NodeDetailsDataPointRT = rt.intersection([ }), ]); -const NodeDetailsDataSeries = rt.type({ +const NodeDetailsDataSeriesRT = rt.type({ id: rt.string, label: rt.string, data: rt.array(NodeDetailsDataPointRT), }); +export type NodeDetailsDataSeries = rt.TypeOf; + export const NodeDetailsMetricDataRT = rt.intersection([ rt.partial({ id: rt.union([InventoryMetricRT, rt.null]), }), rt.type({ - series: rt.array(NodeDetailsDataSeries), + series: rt.array(NodeDetailsDataSeriesRT), }), ]); diff --git a/x-pack/plugins/infra/common/http_api/source_api.ts b/x-pack/plugins/infra/common/http_api/source_api.ts index be50989358c7..52a8d43da53b 100644 --- a/x-pack/plugins/infra/common/http_api/source_api.ts +++ b/x-pack/plugins/infra/common/http_api/source_api.ts @@ -39,18 +39,30 @@ const SavedSourceConfigurationFieldsRuntimeType = rt.partial({ timestamp: rt.string, }); +export type InfraSavedSourceConfigurationFields = rt.TypeOf< + typeof SavedSourceConfigurationFieldColumnRuntimeType +>; + export const SavedSourceConfigurationTimestampColumnRuntimeType = rt.type({ timestampColumn: rt.type({ id: rt.string, }), }); +export type InfraSourceConfigurationTimestampColumn = rt.TypeOf< + typeof SavedSourceConfigurationTimestampColumnRuntimeType +>; + export const SavedSourceConfigurationMessageColumnRuntimeType = rt.type({ messageColumn: rt.type({ id: rt.string, }), }); +export type InfraSourceConfigurationMessageColumn = rt.TypeOf< + typeof SavedSourceConfigurationMessageColumnRuntimeType +>; + export const SavedSourceConfigurationFieldColumnRuntimeType = rt.type({ fieldColumn: rt.type({ id: rt.string, @@ -64,6 +76,10 @@ export const SavedSourceConfigurationColumnRuntimeType = rt.union([ SavedSourceConfigurationFieldColumnRuntimeType, ]); +export type InfraSavedSourceConfigurationColumn = rt.TypeOf< + typeof SavedSourceConfigurationColumnRuntimeType +>; + export const SavedSourceConfigurationRuntimeType = rt.partial({ name: rt.string, description: rt.string, @@ -136,12 +152,30 @@ const SourceConfigurationFieldsRuntimeType = rt.type({ ...StaticSourceConfigurationFieldsRuntimeType.props, }); +export type InfraSourceConfigurationFields = rt.TypeOf; + export const SourceConfigurationRuntimeType = rt.type({ ...SavedSourceConfigurationRuntimeType.props, fields: SourceConfigurationFieldsRuntimeType, logColumns: rt.array(SavedSourceConfigurationColumnRuntimeType), }); +const SourceStatusFieldRuntimeType = rt.type({ + name: rt.string, + type: rt.string, + searchable: rt.boolean, + aggregatable: rt.boolean, + displayable: rt.boolean, +}); + +export type InfraSourceIndexField = rt.TypeOf; + +const SourceStatusRuntimeType = rt.type({ + logIndicesExist: rt.boolean, + metricIndicesExist: rt.boolean, + indexFields: rt.array(SourceStatusFieldRuntimeType), +}); + export const SourceRuntimeType = rt.intersection([ rt.type({ id: rt.string, @@ -155,31 +189,19 @@ export const SourceRuntimeType = rt.intersection([ rt.partial({ version: rt.string, updatedAt: rt.number, + status: SourceStatusRuntimeType, }), ]); +export interface InfraSourceStatus extends rt.TypeOf {} + export interface InfraSourceConfiguration extends rt.TypeOf {} export interface InfraSource extends rt.TypeOf {} -const SourceStatusFieldRuntimeType = rt.type({ - name: rt.string, - type: rt.string, - searchable: rt.boolean, - aggregatable: rt.boolean, - displayable: rt.boolean, -}); - -const SourceStatusRuntimeType = rt.type({ - logIndicesExist: rt.boolean, - metricIndicesExist: rt.boolean, - indexFields: rt.array(SourceStatusFieldRuntimeType), -}); - export const SourceResponseRuntimeType = rt.type({ source: SourceRuntimeType, - status: SourceStatusRuntimeType, }); export type SourceResponse = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/log_entry/log_entry.ts b/x-pack/plugins/infra/common/log_entry/log_entry.ts index bf3f9ceb0b08..837249b65b2e 100644 --- a/x-pack/plugins/infra/common/log_entry/log_entry.ts +++ b/x-pack/plugins/infra/common/log_entry/log_entry.ts @@ -14,7 +14,6 @@ export type LogEntryTime = TimeKey; /** * message parts */ - export const logMessageConstantPartRT = rt.type({ constant: rt.string, }); diff --git a/x-pack/plugins/infra/docs/arch.md b/x-pack/plugins/infra/docs/arch.md index f3d7312a3491..89b00cd19d1d 100644 --- a/x-pack/plugins/infra/docs/arch.md +++ b/x-pack/plugins/infra/docs/arch.md @@ -7,7 +7,7 @@ In this arch, we use 3 main terms to describe the code: - **Libs / Domain Libs** - Business logic & data formatting (though complex formatting might call utils) - **Adapters** - code that directly calls 3rd party APIs and data sources, exposing clean easy to stub APIs - **Composition Files** - composes adapters into libs based on where the code is running -- **Implementation layer** - The API such as rest endpoints or graphql schema on the server, and the state management / UI on the client +- **Implementation layer** - The API such as rest endpoints on the server, and the state management / UI on the client ## Arch Visual Example @@ -85,7 +85,7 @@ An example structure might be... | | | | |-- kibana_angular // if an adapter has more than one file... | | | | | |-- index.html | | | | | |-- index.ts - | | | | | + | | | | | | | | | |-- ui_harness.ts | | | | | | |-- domains diff --git a/x-pack/plugins/infra/docs/arch_client.md b/x-pack/plugins/infra/docs/arch_client.md index cdc474635721..b40c9aaf1ff5 100644 --- a/x-pack/plugins/infra/docs/arch_client.md +++ b/x-pack/plugins/infra/docs/arch_client.md @@ -26,7 +26,7 @@ However, components that tweak EUI should go into `/public/components/eui/${comp If using an EUI component that has not yet been typed, types should be placed into `/types/eui.d.ts` -## Containers (Also: [see GraphQL docs](docs/graphql.md)) +## Containers - HOC's based on Apollo. - One folder per data type e.g. `host`. Folder name should be singular. diff --git a/x-pack/plugins/infra/docs/graphql.md b/x-pack/plugins/infra/docs/graphql.md deleted file mode 100644 index 5584a5ce7c0d..000000000000 --- a/x-pack/plugins/infra/docs/graphql.md +++ /dev/null @@ -1,53 +0,0 @@ -# GraphQL In Infra UI - -- The combined graphql schema collected from both the `public` and `server` directories is exported to `common/all.gql_schema.ts` for the purpose of automatic type generation only. - -## Server - -- Under `/server/graphql` there are files for each domain of data's graph schema and resolvers. - - Each file has 2 exports `${domain}Schema` e.g. `fieldsSchema`, and `create${domain}Resolvers` e.g. `createFieldResolvers` -- `/server/infra_server.ts` imports all schema and resolvers and passing the full schema to the server -- Resolvers should be used to call composed libs, rather than directly performing any meaningful amount of data processing. -- Resolvers should, however, only pass the required data into libs; that is to say all args for example would not be passed into a lib unless all were needed. - -## Client - -- Under `/public/containers/${domain}/` there is a file for each container. Each file has two exports, the query name e.g. `AllHosts` and the apollo HOC in the pattern of `with${queryName}` e.g. `withAllHosts`. This is done for two reasons: - - 1. It makes the code uniform, thus easier to reason about later. - 2. If reformatting the data using a transform, it lets us re-type the data clearly. - -- Containers should use the apollo props callback to pass ONLY the props and data needed to children. e.g. - - ```ts - import { Hosts, Pods, HostsAndPods } from '../../common/types'; - - // used to generate the `HostsAndPods` type imported above - export const hostsAndPods = gql` - # ... - `; - - type HostsAndPodsProps = { - hosts: Hosts; - pods: Pods; - } - - export const withHostsAndPods = graphql< - {}, - HostsAndPods.Query, - HostsAndPods.Variables, - HostsAndPodsProps - >(hostsAndPods, { - props: ({ data, ownProps }) => ({ - hosts: hostForMap(data && data.hosts ? data.hosts : []), -  pods: podsFromHosts(data && data.hosts ? data.hosts : []) - ...ownProps, - }), - }); - ``` - - as `ownProps` are the props passed to the wrapped component, they should just be forwarded. - -## Types - -- The command `yarn build-graphql-types` derives the schema, query and mutation types and stores them in `common/types.ts` for use on both the client and server. diff --git a/x-pack/plugins/infra/public/apps/common_providers.tsx b/x-pack/plugins/infra/public/apps/common_providers.tsx index ebfa412410dd..ad1c1e1129de 100644 --- a/x-pack/plugins/infra/public/apps/common_providers.tsx +++ b/x-pack/plugins/infra/public/apps/common_providers.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ApolloClient } from 'apollo-client'; import { AppMountParameters, CoreStart } from 'kibana/public'; import React, { useMemo } from 'react'; import { @@ -15,32 +14,28 @@ import { EuiThemeProvider } from '../../../../../src/plugins/kibana_react/common import { TriggersAndActionsUIPublicPluginStart } from '../../../triggers_actions_ui/public'; import { createKibanaContextForPlugin } from '../hooks/use_kibana'; import { InfraClientStartDeps } from '../types'; -import { ApolloClientContext } from '../utils/apollo_context'; import { HeaderActionMenuProvider } from '../utils/header_action_menu_provider'; import { NavigationWarningPromptProvider } from '../utils/navigation_warning_prompt'; import { TriggersActionsProvider } from '../utils/triggers_actions_context'; import { Storage } from '../../../../../src/plugins/kibana_utils/public'; export const CommonInfraProviders: React.FC<{ - apolloClient: ApolloClient<{}>; appName: string; storage: Storage; triggersActionsUI: TriggersAndActionsUIPublicPluginStart; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; -}> = ({ apolloClient, children, triggersActionsUI, setHeaderActionMenu, appName, storage }) => { +}> = ({ children, triggersActionsUI, setHeaderActionMenu, appName, storage }) => { const [darkMode] = useUiSetting$('theme:darkMode'); return ( - - - - - {children} - - - - + + + + {children} + + + ); }; diff --git a/x-pack/plugins/infra/public/apps/logs_app.tsx b/x-pack/plugins/infra/public/apps/logs_app.tsx index 381c75c4b9a2..8a6a2e273f2c 100644 --- a/x-pack/plugins/infra/public/apps/logs_app.tsx +++ b/x-pack/plugins/infra/public/apps/logs_app.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ApolloClient } from 'apollo-client'; import { History } from 'history'; import { CoreStart } from 'kibana/public'; import React from 'react'; @@ -17,7 +16,6 @@ import { NotFoundPage } from '../pages/404'; import { LinkToLogsPage } from '../pages/link_to/link_to_logs'; import { LogsPage } from '../pages/logs'; import { InfraClientStartDeps } from '../types'; -import { createApolloClient } from '../utils/apollo_client'; import { CommonInfraProviders, CoreProviders } from './common_providers'; import { prepareMountElement } from './common_styles'; @@ -26,14 +24,12 @@ export const renderApp = ( plugins: InfraClientStartDeps, { element, history, setHeaderActionMenu }: AppMountParameters ) => { - const apolloClient = createApolloClient(core.http.fetch); const storage = new Storage(window.localStorage); prepareMountElement(element); ReactDOM.render( ; core: CoreStart; history: History; plugins: InfraClientStartDeps; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; storage: Storage; -}> = ({ apolloClient, core, history, plugins, setHeaderActionMenu, storage }) => { +}> = ({ core, history, plugins, setHeaderActionMenu, storage }) => { const uiCapabilities = core.application.capabilities; return ( { - const apolloClient = createApolloClient(core.http.fetch); const storage = new Storage(window.localStorage); prepareMountElement(element); ReactDOM.render( ; core: CoreStart; history: History; plugins: InfraClientStartDeps; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; storage: Storage; -}> = ({ apolloClient, core, history, plugins, setHeaderActionMenu, storage }) => { +}> = ({ core, history, plugins, setHeaderActionMenu, storage }) => { const uiCapabilities = core.application.capabilities; return ( { +export const useSourceConfigurationFormState = (configuration?: InfraSourceConfiguration) => { const indicesConfigurationFormState = useIndicesConfigurationFormState({ initialFormState: useMemo( () => diff --git a/x-pack/plugins/infra/public/containers/source/create_source.gql_query.ts b/x-pack/plugins/infra/public/containers/source/create_source.gql_query.ts deleted file mode 100644 index 6727dea712f3..000000000000 --- a/x-pack/plugins/infra/public/containers/source/create_source.gql_query.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 gql from 'graphql-tag'; - -import { sharedFragments } from '../../../common/graphql/shared'; -import { - sourceConfigurationFieldsFragment, - sourceStatusFieldsFragment, -} from './source_fields_fragment.gql_query'; - -export const createSourceMutation = gql` - mutation CreateSourceConfigurationMutation( - $sourceId: ID! - $sourceProperties: UpdateSourceInput! - ) { - createSource(id: $sourceId, sourceProperties: $sourceProperties) { - source { - ...InfraSourceFields - configuration { - ...SourceConfigurationFields - } - status { - ...SourceStatusFields - } - } - } - } - - ${sharedFragments.InfraSourceFields} - ${sourceConfigurationFieldsFragment} - ${sourceStatusFieldsFragment} -`; diff --git a/x-pack/plugins/infra/public/containers/source/query_source.gql_query.ts b/x-pack/plugins/infra/public/containers/source/query_source.gql_query.ts deleted file mode 100644 index 21b5192e5725..000000000000 --- a/x-pack/plugins/infra/public/containers/source/query_source.gql_query.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 gql from 'graphql-tag'; - -import { sharedFragments } from '../../../common/graphql/shared'; -import { - sourceConfigurationFieldsFragment, - sourceStatusFieldsFragment, -} from './source_fields_fragment.gql_query'; - -export const sourceQuery = gql` - query SourceQuery($sourceId: ID = "default") { - source(id: $sourceId) { - ...InfraSourceFields - configuration { - ...SourceConfigurationFields - } - status { - ...SourceStatusFields - } - } - } - - ${sharedFragments.InfraSourceFields} - ${sourceConfigurationFieldsFragment} - ${sourceStatusFieldsFragment} -`; diff --git a/x-pack/plugins/infra/public/containers/source/source.tsx b/x-pack/plugins/infra/public/containers/source/source.tsx index 96bbd858c3a4..c84269d6b498 100644 --- a/x-pack/plugins/infra/public/containers/source/source.tsx +++ b/x-pack/plugins/infra/public/containers/source/source.tsx @@ -8,20 +8,17 @@ import createContainer from 'constate'; import { useEffect, useMemo, useState } from 'react'; import { - CreateSourceConfigurationMutation, - SourceQuery, - UpdateSourceInput, - UpdateSourceMutation, -} from '../../graphql/types'; -import { DependencyError, useApolloClient } from '../../utils/apollo_context'; + InfraSavedSourceConfiguration, + InfraSource, + SourceResponse, +} from '../../../common/http_api/source_api'; import { useTrackedPromise } from '../../utils/use_tracked_promise'; -import { createSourceMutation } from './create_source.gql_query'; -import { sourceQuery } from './query_source.gql_query'; -import { updateSourceMutation } from './update_source.gql_query'; +import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; -type Source = SourceQuery.Query['source']; - -export const pickIndexPattern = (source: Source | undefined, type: 'logs' | 'metrics' | 'both') => { +export const pickIndexPattern = ( + source: InfraSource | undefined, + type: 'logs' | 'metrics' | 'both' +) => { if (!source) { return 'unknown-index'; } @@ -34,96 +31,79 @@ export const pickIndexPattern = (source: Source | undefined, type: 'logs' | 'met return `${source.configuration.logAlias},${source.configuration.metricAlias}`; }; +const DEPENDENCY_ERROR_MESSAGE = 'Failed to load source: No fetch client available.'; + export const useSource = ({ sourceId }: { sourceId: string }) => { - const apolloClient = useApolloClient(); - const [source, setSource] = useState(undefined); + const kibana = useKibana(); + const fetchService = kibana.services.http?.fetch; + const API_URL = `/api/metrics/source/${sourceId}`; + + const [source, setSource] = useState(undefined); const [loadSourceRequest, loadSource] = useTrackedPromise( { cancelPreviousOn: 'resolution', createPromise: async () => { - if (!apolloClient) { - throw new DependencyError('Failed to load source: No apollo client available.'); + if (!fetchService) { + throw new Error(DEPENDENCY_ERROR_MESSAGE); } - return await apolloClient.query({ - fetchPolicy: 'no-cache', - query: sourceQuery, - variables: { - sourceId, - }, + return await fetchService(`${API_URL}/metrics`, { + method: 'GET', }); }, onResolve: (response) => { - setSource(response.data.source); + setSource(response.source); }, }, - [apolloClient, sourceId] + [fetchService, sourceId] ); const [createSourceConfigurationRequest, createSourceConfiguration] = useTrackedPromise( { - createPromise: async (sourceProperties: UpdateSourceInput) => { - if (!apolloClient) { - throw new DependencyError( - 'Failed to create source configuration: No apollo client available.' - ); + createPromise: async (sourceProperties: InfraSavedSourceConfiguration) => { + if (!fetchService) { + throw new Error(DEPENDENCY_ERROR_MESSAGE); } - return await apolloClient.mutate< - CreateSourceConfigurationMutation.Mutation, - CreateSourceConfigurationMutation.Variables - >({ - mutation: createSourceMutation, - fetchPolicy: 'no-cache', - variables: { - sourceId, - sourceProperties, - }, + return await fetchService(API_URL, { + method: 'PATCH', + body: JSON.stringify(sourceProperties), }); }, onResolve: (response) => { - if (response.data) { - setSource(response.data.createSource.source); + if (response) { + setSource(response.source); } }, }, - [apolloClient, sourceId] + [fetchService, sourceId] ); const [updateSourceConfigurationRequest, updateSourceConfiguration] = useTrackedPromise( { - createPromise: async (sourceProperties: UpdateSourceInput) => { - if (!apolloClient) { - throw new DependencyError( - 'Failed to update source configuration: No apollo client available.' - ); + createPromise: async (sourceProperties: InfraSavedSourceConfiguration) => { + if (!fetchService) { + throw new Error(DEPENDENCY_ERROR_MESSAGE); } - return await apolloClient.mutate< - UpdateSourceMutation.Mutation, - UpdateSourceMutation.Variables - >({ - mutation: updateSourceMutation, - fetchPolicy: 'no-cache', - variables: { - sourceId, - sourceProperties, - }, + return await fetchService(API_URL, { + method: 'PATCH', + body: JSON.stringify(sourceProperties), }); }, onResolve: (response) => { - if (response.data) { - setSource(response.data.updateSource.source); + if (response) { + setSource(response.source); } }, }, - [apolloClient, sourceId] + [fetchService, sourceId] ); const createDerivedIndexPattern = (type: 'logs' | 'metrics' | 'both') => { return { - fields: source ? source.status.indexFields : [], + fields: source?.status ? source.status.indexFields : [], title: pickIndexPattern(source, type), }; }; diff --git a/x-pack/plugins/infra/public/containers/source/source_fields_fragment.gql_query.ts b/x-pack/plugins/infra/public/containers/source/source_fields_fragment.gql_query.ts deleted file mode 100644 index 61312a0f2890..000000000000 --- a/x-pack/plugins/infra/public/containers/source/source_fields_fragment.gql_query.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 gql from 'graphql-tag'; - -export const sourceConfigurationFieldsFragment = gql` - fragment SourceConfigurationFields on InfraSourceConfiguration { - name - description - logAlias - metricAlias - inventoryDefaultView - metricsExplorerDefaultView - fields { - container - host - message - pod - tiebreaker - timestamp - } - logColumns { - ... on InfraSourceTimestampLogColumn { - timestampColumn { - id - } - } - ... on InfraSourceMessageLogColumn { - messageColumn { - id - } - } - ... on InfraSourceFieldLogColumn { - fieldColumn { - id - field - } - } - } - } -`; - -export const sourceStatusFieldsFragment = gql` - fragment SourceStatusFields on InfraSourceStatus { - indexFields { - name - type - searchable - aggregatable - displayable - } - logIndicesExist - metricIndicesExist - } -`; diff --git a/x-pack/plugins/infra/public/containers/source/update_source.gql_query.ts b/x-pack/plugins/infra/public/containers/source/update_source.gql_query.ts deleted file mode 100644 index ed52780049f6..000000000000 --- a/x-pack/plugins/infra/public/containers/source/update_source.gql_query.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 gql from 'graphql-tag'; - -import { sharedFragments } from '../../../common/graphql/shared'; -import { - sourceConfigurationFieldsFragment, - sourceStatusFieldsFragment, -} from './source_fields_fragment.gql_query'; - -export const updateSourceMutation = gql` - mutation UpdateSourceMutation($sourceId: ID = "default", $sourceProperties: UpdateSourceInput!) { - updateSource(id: $sourceId, sourceProperties: $sourceProperties) { - source { - ...InfraSourceFields - configuration { - ...SourceConfigurationFields - } - status { - ...SourceStatusFields - } - } - } - } - - ${sharedFragments.InfraSourceFields} - ${sourceConfigurationFieldsFragment} - ${sourceStatusFieldsFragment} -`; diff --git a/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts b/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts index 94e2537a67a2..33f74173bee3 100644 --- a/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts +++ b/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts @@ -72,7 +72,7 @@ export const useSourceViaHttp = ({ const createDerivedIndexPattern = useCallback( (indexType: 'logs' | 'metrics' | 'both' = type) => { return { - fields: response?.source ? response.status.indexFields : [], + fields: response?.source.status ? response.source.status.indexFields : [], title: pickIndexPattern(response?.source, indexType), }; }, @@ -80,7 +80,7 @@ export const useSourceViaHttp = ({ ); const source = useMemo(() => { - return response ? { ...response.source, status: response.status } : null; + return response ? response.source : null; }, [response]); return { diff --git a/x-pack/plugins/infra/public/containers/with_source/with_source.tsx b/x-pack/plugins/infra/public/containers/with_source/with_source.tsx index e8c609ae0bad..1681bf85f7f1 100644 --- a/x-pack/plugins/infra/public/containers/with_source/with_source.tsx +++ b/x-pack/plugins/infra/public/containers/with_source/with_source.tsx @@ -7,14 +7,17 @@ import React, { useContext } from 'react'; import { IIndexPattern } from 'src/plugins/data/public'; -import { SourceQuery, UpdateSourceInput } from '../../graphql/types'; +import { + InfraSavedSourceConfiguration, + InfraSourceConfiguration, +} from '../../../common/http_api/source_api'; import { RendererFunction } from '../../utils/typed_react'; import { Source } from '../source'; interface WithSourceProps { children: RendererFunction<{ - configuration?: SourceQuery.Query['source']['configuration']; - create: (sourceProperties: UpdateSourceInput) => Promise | undefined; + configuration?: InfraSourceConfiguration; + create: (sourceProperties: InfraSavedSourceConfiguration) => Promise | undefined; createDerivedIndexPattern: (type: 'logs' | 'metrics' | 'both') => IIndexPattern; exists?: boolean; hasFailed: boolean; @@ -25,7 +28,7 @@ interface WithSourceProps { metricAlias?: string; metricIndicesExist?: boolean; sourceId: string; - update: (sourceProperties: UpdateSourceInput) => Promise | undefined; + update: (sourceProperties: InfraSavedSourceConfiguration) => Promise | undefined; version?: string; }>; } diff --git a/x-pack/plugins/infra/public/graphql/introspection.json b/x-pack/plugins/infra/public/graphql/introspection.json deleted file mode 100644 index efdca72c1383..000000000000 --- a/x-pack/plugins/infra/public/graphql/introspection.json +++ /dev/null @@ -1,2713 +0,0 @@ -{ - "__schema": { - "queryType": { "name": "Query" }, - "mutationType": { "name": "Mutation" }, - "subscriptionType": null, - "types": [ - { - "kind": "OBJECT", - "name": "Query", - "description": "", - "fields": [ - { - "name": "source", - "description": "Get an infrastructure data source by id.\n\nThe resolution order for the source configuration attributes is as follows\nwith the first defined value winning:\n\n1. The attributes of the saved object with the given 'id'.\n2. The attributes defined in the static Kibana configuration key\n 'xpack.infra.sources.default'.\n3. The hard-coded default values.\n\nAs a consequence, querying a source that doesn't exist doesn't error out,\nbut returns the configured or hardcoded defaults.", - "args": [ - { - "name": "id", - "description": "The id of the source", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraSource", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allSources", - "description": "Get a list of all infrastructure data sources", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraSource", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSource", - "description": "A source of infrastructure data", - "fields": [ - { - "name": "id", - "description": "The id of the source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "The version number the source configuration was last persisted with", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "The timestamp the source configuration was last persisted at", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "origin", - "description": "The origin of the source (one of 'fallback', 'internal', 'stored')", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "configuration", - "description": "The raw configuration of the source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraSourceConfiguration", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "status", - "description": "The status of the source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraSourceStatus", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "snapshot", - "description": "A snapshot of nodes", - "args": [ - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "InfraTimerangeInput", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "InfraSnapshotResponse", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "metrics", - "description": "", - "args": [ - { - "name": "nodeIds", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "InfraNodeIdsInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "nodeType", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "InfraNodeType", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "InfraTimerangeInput", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "metrics", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "InfraMetric", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraMetricData", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "String", - "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSourceConfiguration", - "description": "A set of configuration options for an infrastructure data source", - "fields": [ - { - "name": "name", - "description": "The name of the data source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "A description of the data source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "metricAlias", - "description": "The alias to read metric data from", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logAlias", - "description": "The alias to read log data from", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fields", - "description": "The field mapping to use for this source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraSourceFields", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logColumns", - "description": "The columns to use for log display", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "UNION", "name": "InfraSourceLogColumn", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSourceFields", - "description": "A mapping of semantic fields to their document counterparts", - "fields": [ - { - "name": "container", - "description": "The field to identify a container by", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "host", - "description": "The fields to identify a host by", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": "The fields to use as the log message", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pod", - "description": "The field to identify a pod by", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "tiebreaker", - "description": "The field to use as a tiebreaker for log events that have identical timestamps", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timestamp", - "description": "The field to use as a timestamp for metrics and logs", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "UNION", - "name": "InfraSourceLogColumn", - "description": "All known log column types", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": [ - { "kind": "OBJECT", "name": "InfraSourceTimestampLogColumn", "ofType": null }, - { "kind": "OBJECT", "name": "InfraSourceMessageLogColumn", "ofType": null }, - { "kind": "OBJECT", "name": "InfraSourceFieldLogColumn", "ofType": null } - ] - }, - { - "kind": "OBJECT", - "name": "InfraSourceTimestampLogColumn", - "description": "The built-in timestamp log column", - "fields": [ - { - "name": "timestampColumn", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "InfraSourceTimestampLogColumnAttributes", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSourceTimestampLogColumnAttributes", - "description": "", - "fields": [ - { - "name": "id", - "description": "A unique id for the column", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSourceMessageLogColumn", - "description": "The built-in message log column", - "fields": [ - { - "name": "messageColumn", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "InfraSourceMessageLogColumnAttributes", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSourceMessageLogColumnAttributes", - "description": "", - "fields": [ - { - "name": "id", - "description": "A unique id for the column", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSourceFieldLogColumn", - "description": "A log column containing a field value", - "fields": [ - { - "name": "fieldColumn", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "InfraSourceFieldLogColumnAttributes", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSourceFieldLogColumnAttributes", - "description": "", - "fields": [ - { - "name": "id", - "description": "A unique id for the column", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "field", - "description": "The field name this column refers to", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSourceStatus", - "description": "The status of an infrastructure data source", - "fields": [ - { - "name": "metricAliasExists", - "description": "Whether the configured metric alias exists", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logAliasExists", - "description": "Whether the configured log alias exists", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "metricIndicesExist", - "description": "Whether the configured alias or wildcard pattern resolve to any metric indices", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndicesExist", - "description": "Whether the configured alias or wildcard pattern resolve to any log indices", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "metricIndices", - "description": "The list of indices in the metric alias", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logIndices", - "description": "The list of indices in the log alias", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "indexFields", - "description": "The list of fields defined in the index mappings", - "args": [ - { - "name": "indexType", - "description": "", - "type": { "kind": "ENUM", "name": "InfraIndexType", "ofType": null }, - "defaultValue": "ANY" - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraIndexField", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The `Boolean` scalar type represents `true` or `false`.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "InfraIndexType", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { "name": "ANY", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "LOGS", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "METRICS", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraIndexField", - "description": "A descriptor of a field in an index", - "fields": [ - { - "name": "name", - "description": "The name of the field", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "The type of the field's values as recognized by Kibana", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "searchable", - "description": "Whether the field's values can be efficiently searched for", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "aggregatable", - "description": "Whether the field's values can be aggregated", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "displayable", - "description": "Whether the field should be displayed based on event.module and a ECS allowed list", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Int", - "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "InfraTimerangeInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "interval", - "description": "The interval string to use for last bucket. The format is '{value}{unit}'. For example '5m' would return the metrics for the last 5 minutes of the timespan.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "to", - "description": "The end of the timerange", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "from", - "description": "The beginning of the timerange", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSnapshotResponse", - "description": "", - "fields": [ - { - "name": "nodes", - "description": "Nodes of type host, container or pod grouped by 0, 1 or 2 terms", - "args": [ - { - "name": "type", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "InfraNodeType", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "groupBy", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "InfraSnapshotGroupbyInput", - "ofType": null - } - } - } - }, - "defaultValue": null - }, - { - "name": "metric", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "InfraSnapshotMetricInput", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraSnapshotNode", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "InfraNodeType", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { "name": "pod", "description": "", "isDeprecated": false, "deprecationReason": null }, - { - "name": "container", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "host", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "awsEC2", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "InfraSnapshotGroupbyInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "label", - "description": "The label to use in the results for the group by for the terms group by", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "field", - "description": "The field to group by from a terms aggregation, this is ignored by the filter type", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "InfraSnapshotMetricInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "type", - "description": "The type of metric", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "InfraSnapshotMetricType", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "InfraSnapshotMetricType", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { "name": "count", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "cpu", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "load", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "memory", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "tx", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "rx", "description": "", "isDeprecated": false, "deprecationReason": null }, - { - "name": "logRate", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "diskIOReadBytes", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "diskIOWriteBytes", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSnapshotNode", - "description": "", - "fields": [ - { - "name": "path", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraSnapshotNodePath", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "metric", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraSnapshotNodeMetric", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSnapshotNodePath", - "description": "", - "fields": [ - { - "name": "value", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "label", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ip", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraSnapshotNodeMetric", - "description": "", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "InfraSnapshotMetricType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "value", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "avg", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "max", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "InfraNodeIdsInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "nodeId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "cloudId", - "description": "", - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "InfraMetric", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "hostSystemOverview", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostCpuUsage", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostFilesystem", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostK8sOverview", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostK8sCpuCap", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostK8sDiskCap", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostK8sMemoryCap", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostK8sPodCap", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostLoad", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostMemoryUsage", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostNetworkTraffic", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostDockerOverview", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostDockerInfo", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostDockerTop5ByCpu", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostDockerTop5ByMemory", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "podOverview", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "podCpuUsage", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "podMemoryUsage", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "podLogUsage", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "podNetworkTraffic", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "containerOverview", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "containerCpuKernel", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "containerCpuUsage", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "containerDiskIOOps", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "containerDiskIOBytes", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "containerMemory", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "containerNetworkTraffic", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "nginxHits", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "nginxRequestRate", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "nginxActiveConnections", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "nginxRequestsPerConnection", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "awsOverview", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "awsCpuUtilization", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "awsNetworkBytes", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "awsNetworkPackets", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "awsDiskioBytes", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "awsDiskioOps", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "awsEC2CpuUtilization", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "awsEC2NetworkTraffic", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "awsEC2DiskIOBytes", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "custom", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraMetricData", - "description": "", - "fields": [ - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "ENUM", "name": "InfraMetric", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "series", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraDataSeries", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraDataSeries", - "description": "", - "fields": [ - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "label", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "data", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraDataPoint", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InfraDataPoint", - "description": "", - "fields": [ - { - "name": "timestamp", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "value", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Mutation", - "description": "", - "fields": [ - { - "name": "createSource", - "description": "Create a new source of infrastructure data", - "args": [ - { - "name": "id", - "description": "The id of the source", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "sourceProperties", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateSourceInput", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UpdateSourceResult", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateSource", - "description": "Modify an existing source", - "args": [ - { - "name": "id", - "description": "The id of the source", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "sourceProperties", - "description": "The properties to update the source with", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateSourceInput", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UpdateSourceResult", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteSource", - "description": "Delete a source of infrastructure data", - "args": [ - { - "name": "id", - "description": "The id of the source", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "DeleteSourceResult", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceInput", - "description": "The properties to update the source with", - "fields": null, - "inputFields": [ - { - "name": "name", - "description": "The name of the data source", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "description", - "description": "A description of the data source", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "metricAlias", - "description": "The alias to read metric data from", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "logAlias", - "description": "The alias to read log data from", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "fields", - "description": "The field mapping to use for this source", - "type": { "kind": "INPUT_OBJECT", "name": "UpdateSourceFieldsInput", "ofType": null }, - "defaultValue": null - }, - { - "name": "logColumns", - "description": "The log columns to display for this source", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceLogColumnInput", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceFieldsInput", - "description": "The mapping of semantic fields of the source to be created", - "fields": null, - "inputFields": [ - { - "name": "container", - "description": "The field to identify a container by", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "host", - "description": "The fields to identify a host by", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "pod", - "description": "The field to identify a pod by", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "tiebreaker", - "description": "The field to use as a tiebreaker for log events that have identical timestamps", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timestamp", - "description": "The field to use as a timestamp for metrics and logs", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceLogColumnInput", - "description": "One of the log column types to display for this source", - "fields": null, - "inputFields": [ - { - "name": "fieldColumn", - "description": "A custom field log column", - "type": { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceFieldLogColumnInput", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "messageColumn", - "description": "A built-in message log column", - "type": { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceMessageLogColumnInput", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "timestampColumn", - "description": "A built-in timestamp log column", - "type": { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceTimestampLogColumnInput", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceFieldLogColumnInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "field", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceMessageLogColumnInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateSourceTimestampLogColumnInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UpdateSourceResult", - "description": "The result of a successful source update", - "fields": [ - { - "name": "source", - "description": "The source that was updated", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraSource", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "DeleteSourceResult", - "description": "The result of a source deletion operations", - "fields": [ - { - "name": "id", - "description": "The id of the source that was deleted", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Schema", - "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", - "fields": [ - { - "name": "types", - "description": "A list of all types supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "queryType", - "description": "The type that query operations will be rooted at.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mutationType", - "description": "If this server supports mutation, the type that mutation operations will be rooted at.", - "args": [], - "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subscriptionType", - "description": "If this server support subscription, the type that subscription operations will be rooted at.", - "args": [], - "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "directives", - "description": "A list of all directives supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Type", - "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", - "fields": [ - { - "name": "kind", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fields", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "interfaces", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "possibleTypes", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enumValues", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inputFields", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ofType", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__TypeKind", - "description": "An enum describing what kind of type a given `__Type` is.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "SCALAR", - "description": "Indicates this type is a scalar.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Indicates this type is a union. `possibleTypes` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Indicates this type is an enum. `enumValues` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Indicates this type is an input object. `inputFields` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LIST", - "description": "Indicates this type is a list. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NON_NULL", - "description": "Indicates this type is a non-null. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Field", - "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__InputValue", - "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "defaultValue", - "description": "A GraphQL-formatted string representing the default value for this input value.", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__EnumValue", - "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Directive", - "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "locations", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "onOperation", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - }, - { - "name": "onFragment", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - }, - { - "name": "onField", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__DirectiveLocation", - "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "QUERY", - "description": "Location adjacent to a query operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MUTATION", - "description": "Location adjacent to a mutation operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SUBSCRIPTION", - "description": "Location adjacent to a subscription operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD", - "description": "Location adjacent to a field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_DEFINITION", - "description": "Location adjacent to a fragment definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_SPREAD", - "description": "Location adjacent to a fragment spread.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INLINE_FRAGMENT", - "description": "Location adjacent to an inline fragment.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCHEMA", - "description": "Location adjacent to a schema definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCALAR", - "description": "Location adjacent to a scalar definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Location adjacent to an object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD_DEFINITION", - "description": "Location adjacent to a field definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ARGUMENT_DEFINITION", - "description": "Location adjacent to an argument definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Location adjacent to an interface definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Location adjacent to a union definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Location adjacent to an enum definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM_VALUE", - "description": "Location adjacent to an enum value definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Location adjacent to an input object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_FIELD_DEFINITION", - "description": "Location adjacent to an input object field definition.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - } - ], - "directives": [ - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", - "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], - "args": [ - { - "name": "if", - "description": "Skipped when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "defaultValue": null - } - ] - }, - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", - "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "defaultValue": null - } - ] - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "locations": ["FIELD_DEFINITION", "ENUM_VALUE"], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": "\"No longer supported\"" - } - ] - } - ] - } -} diff --git a/x-pack/plugins/infra/public/graphql/types.ts b/x-pack/plugins/infra/public/graphql/types.ts deleted file mode 100644 index eb025ee4efd7..000000000000 --- a/x-pack/plugins/infra/public/graphql/types.ts +++ /dev/null @@ -1,786 +0,0 @@ -import { SnapshotMetricType } from '../../common/inventory_models/types'; - -/* tslint:disable */ - -// ==================================================== -// START: Typescript template -// ==================================================== - -// ==================================================== -// Types -// ==================================================== - -export interface Query { - /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source that doesn't exist doesn't error out,but returns the configured or hardcoded defaults. */ - source: InfraSource; - /** Get a list of all infrastructure data sources */ - allSources: InfraSource[]; -} -/** A source of infrastructure data */ -export interface InfraSource { - /** The id of the source */ - id: string; - /** The version number the source configuration was last persisted with */ - version?: string | null; - /** The timestamp the source configuration was last persisted at */ - updatedAt?: number | null; - /** The origin of the source (one of 'fallback', 'internal', 'stored') */ - origin: string; - /** The raw configuration of the source */ - configuration: InfraSourceConfiguration; - /** The status of the source */ - status: InfraSourceStatus; - - /** A snapshot of nodes */ - snapshot?: InfraSnapshotResponse | null; - - metrics: InfraMetricData[]; -} -/** A set of configuration options for an infrastructure data source */ -export interface InfraSourceConfiguration { - /** The name of the data source */ - name: string; - /** A description of the data source */ - description: string; - /** The alias to read metric data from */ - metricAlias: string; - /** The alias to read log data from */ - logAlias: string; - /** The field mapping to use for this source */ - fields: InfraSourceFields; - /** Default view for inventory */ - inventoryDefaultView: string; - /** Default view for Metrics Explorer */ - metricsExplorerDefaultView?: string | null; - /** The columns to use for log display */ - logColumns: InfraSourceLogColumn[]; -} -/** A mapping of semantic fields to their document counterparts */ -export interface InfraSourceFields { - /** The field to identify a container by */ - container: string; - /** The fields to identify a host by */ - host: string; - /** The fields to use as the log message */ - message: string[]; - /** The field to identify a pod by */ - pod: string; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker: string; - /** The field to use as a timestamp for metrics and logs */ - timestamp: string; -} -/** The built-in timestamp log column */ -export interface InfraSourceTimestampLogColumn { - timestampColumn: InfraSourceTimestampLogColumnAttributes; -} - -export interface InfraSourceTimestampLogColumnAttributes { - /** A unique id for the column */ - id: string; -} -/** The built-in message log column */ -export interface InfraSourceMessageLogColumn { - messageColumn: InfraSourceMessageLogColumnAttributes; -} - -export interface InfraSourceMessageLogColumnAttributes { - /** A unique id for the column */ - id: string; -} -/** A log column containing a field value */ -export interface InfraSourceFieldLogColumn { - fieldColumn: InfraSourceFieldLogColumnAttributes; -} - -export interface InfraSourceFieldLogColumnAttributes { - /** A unique id for the column */ - id: string; - /** The field name this column refers to */ - field: string; -} -/** The status of an infrastructure data source */ -export interface InfraSourceStatus { - /** Whether the configured metric alias exists */ - metricAliasExists: boolean; - /** Whether the configured log alias exists */ - logAliasExists: boolean; - /** Whether the configured alias or wildcard pattern resolve to any metric indices */ - metricIndicesExist: boolean; - /** Whether the configured alias or wildcard pattern resolve to any log indices */ - logIndicesExist: boolean; - /** The list of indices in the metric alias */ - metricIndices: string[]; - /** The list of indices in the log alias */ - logIndices: string[]; - /** The list of fields defined in the index mappings */ - indexFields: InfraIndexField[]; -} -/** A descriptor of a field in an index */ -export interface InfraIndexField { - /** The name of the field */ - name: string; - /** The type of the field's values as recognized by Kibana */ - type: string; - /** Whether the field's values can be efficiently searched for */ - searchable: boolean; - /** Whether the field's values can be aggregated */ - aggregatable: boolean; - /** Whether the field should be displayed based on event.module and a ECS allowed list */ - displayable: boolean; -} - -export interface InfraSnapshotResponse { - /** Nodes of type host, container or pod grouped by 0, 1 or 2 terms */ - nodes: InfraSnapshotNode[]; -} - -export interface InfraSnapshotNode { - path: InfraSnapshotNodePath[]; - - metric: InfraSnapshotNodeMetric; -} - -export interface InfraSnapshotNodePath { - value: string; - - label: string; - - ip?: string | null; -} - -export interface InfraSnapshotNodeMetric { - name: SnapshotMetricType; - - value?: number | null; - - avg?: number | null; - - max?: number | null; -} - -export interface InfraMetricData { - id?: InfraMetric | null; - - series: InfraDataSeries[]; -} - -export interface InfraDataSeries { - id: string; - - label: string; - - data: InfraDataPoint[]; -} - -export interface InfraDataPoint { - timestamp: number; - - value?: number | null; -} - -export interface Mutation { - /** Create a new source of infrastructure data */ - createSource: UpdateSourceResult; - /** Modify an existing source */ - updateSource: UpdateSourceResult; - /** Delete a source of infrastructure data */ - deleteSource: DeleteSourceResult; -} -/** The result of a successful source update */ -export interface UpdateSourceResult { - /** The source that was updated */ - source: InfraSource; -} -/** The result of a source deletion operations */ -export interface DeleteSourceResult { - /** The id of the source that was deleted */ - id: string; -} - -// ==================================================== -// InputTypes -// ==================================================== - -export interface InfraTimerangeInput { - /** The interval string to use for last bucket. The format is '{value}{unit}'. For example '5m' would return the metrics for the last 5 minutes of the timespan. */ - interval: string; - /** The end of the timerange */ - to: number; - /** The beginning of the timerange */ - from: number; -} - -export interface InfraSnapshotGroupbyInput { - /** The label to use in the results for the group by for the terms group by */ - label?: string | null; - /** The field to group by from a terms aggregation, this is ignored by the filter type */ - field?: string | null; -} - -export interface InfraSnapshotMetricInput { - /** The type of metric */ - type: InfraSnapshotMetricType; -} - -export interface InfraNodeIdsInput { - nodeId: string; - - cloudId?: string | null; -} -/** The properties to update the source with */ -export interface UpdateSourceInput { - /** The name of the data source */ - name?: string | null; - /** A description of the data source */ - description?: string | null; - /** The alias to read metric data from */ - metricAlias?: string | null; - /** The alias to read log data from */ - logAlias?: string | null; - /** The field mapping to use for this source */ - fields?: UpdateSourceFieldsInput | null; - /** Name of default inventory view */ - inventoryDefaultView?: string | null; - /** Default view for Metrics Explorer */ - metricsExplorerDefaultView?: string | null; - /** The log columns to display for this source */ - logColumns?: UpdateSourceLogColumnInput[] | null; -} -/** The mapping of semantic fields of the source to be created */ -export interface UpdateSourceFieldsInput { - /** The field to identify a container by */ - container?: string | null; - /** The fields to identify a host by */ - host?: string | null; - /** The field to identify a pod by */ - pod?: string | null; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker?: string | null; - /** The field to use as a timestamp for metrics and logs */ - timestamp?: string | null; -} -/** One of the log column types to display for this source */ -export interface UpdateSourceLogColumnInput { - /** A custom field log column */ - fieldColumn?: UpdateSourceFieldLogColumnInput | null; - /** A built-in message log column */ - messageColumn?: UpdateSourceMessageLogColumnInput | null; - /** A built-in timestamp log column */ - timestampColumn?: UpdateSourceTimestampLogColumnInput | null; -} - -export interface UpdateSourceFieldLogColumnInput { - id: string; - - field: string; -} - -export interface UpdateSourceMessageLogColumnInput { - id: string; -} - -export interface UpdateSourceTimestampLogColumnInput { - id: string; -} - -// ==================================================== -// Arguments -// ==================================================== - -export interface SourceQueryArgs { - /** The id of the source */ - id: string; -} -export interface SnapshotInfraSourceArgs { - timerange: InfraTimerangeInput; - - filterQuery?: string | null; -} -export interface MetricsInfraSourceArgs { - nodeIds: InfraNodeIdsInput; - - nodeType: InfraNodeType; - - timerange: InfraTimerangeInput; - - metrics: InfraMetric[]; -} -export interface IndexFieldsInfraSourceStatusArgs { - indexType?: InfraIndexType | null; -} -export interface NodesInfraSnapshotResponseArgs { - type: InfraNodeType; - - groupBy: InfraSnapshotGroupbyInput[]; - - metric: InfraSnapshotMetricInput; -} -export interface CreateSourceMutationArgs { - /** The id of the source */ - id: string; - - sourceProperties: UpdateSourceInput; -} -export interface UpdateSourceMutationArgs { - /** The id of the source */ - id: string; - /** The properties to update the source with */ - sourceProperties: UpdateSourceInput; -} -export interface DeleteSourceMutationArgs { - /** The id of the source */ - id: string; -} - -// ==================================================== -// Enums -// ==================================================== - -export enum InfraIndexType { - ANY = 'ANY', - LOGS = 'LOGS', - METRICS = 'METRICS', -} - -export enum InfraNodeType { - pod = 'pod', - container = 'container', - host = 'host', - awsEC2 = 'awsEC2', - awsS3 = 'awsS3', - awsRDS = 'awsRDS', - awsSQS = 'awsSQS', -} - -export enum InfraSnapshotMetricType { - count = 'count', - cpu = 'cpu', - load = 'load', - memory = 'memory', - tx = 'tx', - rx = 'rx', - logRate = 'logRate', - diskIOReadBytes = 'diskIOReadBytes', - diskIOWriteBytes = 'diskIOWriteBytes', - s3TotalRequests = 's3TotalRequests', - s3NumberOfObjects = 's3NumberOfObjects', - s3BucketSize = 's3BucketSize', - s3DownloadBytes = 's3DownloadBytes', - s3UploadBytes = 's3UploadBytes', - rdsConnections = 'rdsConnections', - rdsQueriesExecuted = 'rdsQueriesExecuted', - rdsActiveTransactions = 'rdsActiveTransactions', - rdsLatency = 'rdsLatency', - sqsMessagesVisible = 'sqsMessagesVisible', - sqsMessagesDelayed = 'sqsMessagesDelayed', - sqsMessagesSent = 'sqsMessagesSent', - sqsMessagesEmpty = 'sqsMessagesEmpty', - sqsOldestMessage = 'sqsOldestMessage', -} - -export enum InfraMetric { - hostSystemOverview = 'hostSystemOverview', - hostCpuUsage = 'hostCpuUsage', - hostFilesystem = 'hostFilesystem', - hostK8sOverview = 'hostK8sOverview', - hostK8sCpuCap = 'hostK8sCpuCap', - hostK8sDiskCap = 'hostK8sDiskCap', - hostK8sMemoryCap = 'hostK8sMemoryCap', - hostK8sPodCap = 'hostK8sPodCap', - hostLoad = 'hostLoad', - hostMemoryUsage = 'hostMemoryUsage', - hostNetworkTraffic = 'hostNetworkTraffic', - hostDockerOverview = 'hostDockerOverview', - hostDockerInfo = 'hostDockerInfo', - hostDockerTop5ByCpu = 'hostDockerTop5ByCpu', - hostDockerTop5ByMemory = 'hostDockerTop5ByMemory', - podOverview = 'podOverview', - podCpuUsage = 'podCpuUsage', - podMemoryUsage = 'podMemoryUsage', - podLogUsage = 'podLogUsage', - podNetworkTraffic = 'podNetworkTraffic', - containerOverview = 'containerOverview', - containerCpuKernel = 'containerCpuKernel', - containerCpuUsage = 'containerCpuUsage', - containerDiskIOOps = 'containerDiskIOOps', - containerDiskIOBytes = 'containerDiskIOBytes', - containerMemory = 'containerMemory', - containerNetworkTraffic = 'containerNetworkTraffic', - nginxHits = 'nginxHits', - nginxRequestRate = 'nginxRequestRate', - nginxActiveConnections = 'nginxActiveConnections', - nginxRequestsPerConnection = 'nginxRequestsPerConnection', - awsOverview = 'awsOverview', - awsCpuUtilization = 'awsCpuUtilization', - awsNetworkBytes = 'awsNetworkBytes', - awsNetworkPackets = 'awsNetworkPackets', - awsDiskioBytes = 'awsDiskioBytes', - awsDiskioOps = 'awsDiskioOps', - awsEC2CpuUtilization = 'awsEC2CpuUtilization', - awsEC2DiskIOBytes = 'awsEC2DiskIOBytes', - awsEC2NetworkTraffic = 'awsEC2NetworkTraffic', - awsS3TotalRequests = 'awsS3TotalRequests', - awsS3NumberOfObjects = 'awsS3NumberOfObjects', - awsS3BucketSize = 'awsS3BucketSize', - awsS3DownloadBytes = 'awsS3DownloadBytes', - awsS3UploadBytes = 'awsS3UploadBytes', - awsRDSCpuTotal = 'awsRDSCpuTotal', - awsRDSConnections = 'awsRDSConnections', - awsRDSQueriesExecuted = 'awsRDSQueriesExecuted', - awsRDSActiveTransactions = 'awsRDSActiveTransactions', - awsRDSLatency = 'awsRDSLatency', - awsSQSMessagesVisible = 'awsSQSMessagesVisible', - awsSQSMessagesDelayed = 'awsSQSMessagesDelayed', - awsSQSMessagesSent = 'awsSQSMessagesSent', - awsSQSMessagesEmpty = 'awsSQSMessagesEmpty', - awsSQSOldestMessage = 'awsSQSOldestMessage', - custom = 'custom', -} - -// ==================================================== -// Unions -// ==================================================== - -/** All known log column types */ -export type InfraSourceLogColumn = - | InfraSourceTimestampLogColumn - | InfraSourceMessageLogColumn - | InfraSourceFieldLogColumn; - -// ==================================================== -// END: Typescript template -// ==================================================== - -// ==================================================== -// Documents -// ==================================================== - -export namespace MetricsQuery { - export type Variables = { - sourceId: string; - timerange: InfraTimerangeInput; - metrics: InfraMetric[]; - nodeId: string; - cloudId?: string | null; - nodeType: InfraNodeType; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - id: string; - - metrics: Metrics[]; - }; - - export type Metrics = { - __typename?: 'InfraMetricData'; - - id?: InfraMetric | null; - - series: Series[]; - }; - - export type Series = { - __typename?: 'InfraDataSeries'; - - id: string; - - label: string; - - data: Data[]; - }; - - export type Data = { - __typename?: 'InfraDataPoint'; - - timestamp: number; - - value?: number | null; - }; -} - -export namespace CreateSourceConfigurationMutation { - export type Variables = { - sourceId: string; - sourceProperties: UpdateSourceInput; - }; - - export type Mutation = { - __typename?: 'Mutation'; - - createSource: CreateSource; - }; - - export type CreateSource = { - __typename?: 'UpdateSourceResult'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - configuration: Configuration; - - status: Status; - } & InfraSourceFields.Fragment; - - export type Configuration = SourceConfigurationFields.Fragment; - - export type Status = SourceStatusFields.Fragment; -} - -export namespace SourceQuery { - export type Variables = { - sourceId?: string | null; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - configuration: Configuration; - - status: Status; - } & InfraSourceFields.Fragment; - - export type Configuration = SourceConfigurationFields.Fragment; - - export type Status = SourceStatusFields.Fragment; -} - -export namespace UpdateSourceMutation { - export type Variables = { - sourceId?: string | null; - sourceProperties: UpdateSourceInput; - }; - - export type Mutation = { - __typename?: 'Mutation'; - - updateSource: UpdateSource; - }; - - export type UpdateSource = { - __typename?: 'UpdateSourceResult'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - configuration: Configuration; - - status: Status; - } & InfraSourceFields.Fragment; - - export type Configuration = SourceConfigurationFields.Fragment; - - export type Status = SourceStatusFields.Fragment; -} - -export namespace WaffleNodesQuery { - export type Variables = { - sourceId: string; - timerange: InfraTimerangeInput; - filterQuery?: string | null; - metric: InfraSnapshotMetricInput; - groupBy: InfraSnapshotGroupbyInput[]; - type: InfraNodeType; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'InfraSource'; - - id: string; - - snapshot?: Snapshot | null; - }; - - export type Snapshot = { - __typename?: 'InfraSnapshotResponse'; - - nodes: Nodes[]; - }; - - export type Nodes = { - __typename?: 'InfraSnapshotNode'; - - path: Path[]; - - metric: Metric; - }; - - export type Path = { - __typename?: 'InfraSnapshotNodePath'; - - value: string; - - label: string; - - ip?: string | null; - }; - - export type Metric = { - __typename?: 'InfraSnapshotNodeMetric'; - - name: InfraSnapshotMetricType; - - value?: number | null; - - avg?: number | null; - - max?: number | null; - }; -} - -export namespace SourceConfigurationFields { - export type Fragment = { - __typename?: 'InfraSourceConfiguration'; - - name: string; - - description: string; - - logAlias: string; - - metricAlias: string; - - fields: Fields; - - inventoryDefaultView: string; - - metricsExplorerDefaultView: string; - - logColumns: LogColumns[]; - }; - - export type Fields = { - __typename?: 'InfraSourceFields'; - - container: string; - - host: string; - - message: string[]; - - pod: string; - - tiebreaker: string; - - timestamp: string; - }; - - export type LogColumns = - | InfraSourceTimestampLogColumnInlineFragment - | InfraSourceMessageLogColumnInlineFragment - | InfraSourceFieldLogColumnInlineFragment; - - export type InfraSourceTimestampLogColumnInlineFragment = { - __typename?: 'InfraSourceTimestampLogColumn'; - - timestampColumn: TimestampColumn; - }; - - export type TimestampColumn = { - __typename?: 'InfraSourceTimestampLogColumnAttributes'; - - id: string; - }; - - export type InfraSourceMessageLogColumnInlineFragment = { - __typename?: 'InfraSourceMessageLogColumn'; - - messageColumn: MessageColumn; - }; - - export type MessageColumn = { - __typename?: 'InfraSourceMessageLogColumnAttributes'; - - id: string; - }; - - export type InfraSourceFieldLogColumnInlineFragment = { - __typename?: 'InfraSourceFieldLogColumn'; - - fieldColumn: FieldColumn; - }; - - export type FieldColumn = { - __typename?: 'InfraSourceFieldLogColumnAttributes'; - - id: string; - - field: string; - }; -} - -export namespace SourceStatusFields { - export type Fragment = { - __typename?: 'InfraSourceStatus'; - - indexFields: IndexFields[]; - - logIndicesExist: boolean; - - metricIndicesExist: boolean; - }; - - export type IndexFields = { - __typename?: 'InfraIndexField'; - - name: string; - - type: string; - - searchable: boolean; - - aggregatable: boolean; - - displayable: boolean; - }; -} - -export namespace InfraTimeKeyFields { - export type Fragment = { - __typename?: 'InfraTimeKey'; - - time: number; - - tiebreaker: number; - }; -} - -export namespace InfraSourceFields { - export type Fragment = { - __typename?: 'InfraSource'; - - id: string; - - version?: string | null; - - updatedAt?: number | null; - - origin: string; - }; -} diff --git a/x-pack/plugins/infra/public/lib/lib.ts b/x-pack/plugins/infra/public/lib/lib.ts index 782f6ce5e0eb..60e1cf0b8bc2 100644 --- a/x-pack/plugins/infra/public/lib/lib.ts +++ b/x-pack/plugins/infra/public/lib/lib.ts @@ -13,7 +13,7 @@ import { SnapshotNodeMetric, SnapshotNodePath, } from '../../common/http_api/snapshot_api'; -import { SourceQuery } from '../graphql/types'; +import { InfraSourceConfigurationFields } from '../../common/http_api/source_api'; import { WaffleSortOption } from '../pages/metrics/inventory_view/hooks/use_waffle_options'; export interface InfraWaffleMapNode { @@ -123,7 +123,7 @@ export enum InfraWaffleMapRuleOperator { } export interface InfraWaffleMapOptions { - fields?: SourceQuery.Query['source']['configuration']['fields'] | null; + fields?: InfraSourceConfigurationFields | null; formatter: InfraFormatterType; formatTemplate: string; metric: SnapshotMetricInput; diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index 24f9598484d7..1b2ea9d551a8 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -11,6 +11,7 @@ import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { EuiErrorBoundary, EuiFlexItem, EuiFlexGroup, EuiButtonEmpty } from '@elastic/eui'; import { IIndexPattern } from 'src/plugins/data/common'; +import { InfraSourceConfiguration } from '../../../common/http_api/source_api'; import { DocumentTitle } from '../../components/document_title'; import { HelpCenterContent } from '../../components/help_center_content'; import { RoutedTabs } from '../../components/navigation/routed_tabs'; @@ -36,7 +37,6 @@ import { WaffleFiltersProvider } from './inventory_view/hooks/use_waffle_filters import { InventoryAlertDropdown } from '../../alerting/inventory/components/alert_dropdown'; import { MetricsAlertDropdown } from '../../alerting/metric_threshold/components/alert_dropdown'; import { SavedView } from '../../containers/saved_view/saved_view'; -import { SourceConfigurationFields } from '../../graphql/types'; import { AlertPrefillProvider } from '../../alerting/use_alert_prefill'; import { InfraMLCapabilitiesProvider } from '../../containers/ml/infra_ml_capabilities'; import { AnomalyDetectionFlyout } from './inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout'; @@ -189,7 +189,7 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { }; const PageContent = (props: { - configuration: SourceConfigurationFields.Fragment; + configuration: InfraSourceConfiguration; createDerivedIndexPattern: (type: 'logs' | 'metrics' | 'both') => IIndexPattern; }) => { const { createDerivedIndexPattern, configuration } = props; diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts index c2cde7eb15e9..3bcf24793b6c 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts @@ -8,14 +8,16 @@ import { ReactText } from 'react'; import Color from 'color'; import { get, first, last, min, max } from 'lodash'; import { createFormatter } from '../../../../../common/formatters'; -import { InfraDataSeries } from '../../../../graphql/types'; import { InventoryVisTypeRT, InventoryFormatterType, InventoryVisType, } from '../../../../../common/inventory_models/types'; import { SeriesOverrides } from '../types'; -import { NodeDetailsMetricData } from '../../../../../common/http_api/node_details_api'; +import { + NodeDetailsDataSeries, + NodeDetailsMetricData, +} from '../../../../../common/http_api/node_details_api'; /** * Returns a formatter @@ -28,7 +30,7 @@ export const getFormatter = ( /** * Does a series have more then two points? */ -export const seriesHasLessThen2DataPoints = (series: InfraDataSeries): boolean => { +export const seriesHasLessThen2DataPoints = (series: NodeDetailsDataSeries): boolean => { return series.data.length < 2; }; diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_error.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_error.tsx index bda2a5941e02..9eb7df26565e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_error.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_error.tsx @@ -4,12 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -// import { GraphQLFormattedError } from 'graphql'; import React from 'react'; import { i18n } from '@kbn/i18n'; import { IHttpFetchError } from 'src/core/public'; import { InvalidNodeError } from './invalid_node'; -// import { InfraMetricsErrorCodes } from '../../../../common/errors'; import { DocumentTitle } from '../../../../components/document_title'; import { ErrorPageBody } from '../../../error'; diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/series_chart.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/series_chart.tsx index 0d7716ad3cc6..91b1bb9b0c1c 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/series_chart.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/series_chart.tsx @@ -13,14 +13,14 @@ import { BarSeriesStyle, AreaSeriesStyle, } from '@elastic/charts'; -import { InfraDataSeries } from '../../../../graphql/types'; +import { NodeDetailsDataSeries } from '../../../../../common/http_api/node_details_api'; import { InventoryVisType } from '../../../../../common/inventory_models/types'; interface Props { id: string; name: string; color: string | null; - series: InfraDataSeries; + series: NodeDetailsDataSeries; type: InventoryVisType; stack: boolean | undefined; } @@ -59,7 +59,7 @@ export const AreaChart = ({ id, color, series, name, type, stack }: Props) => { ); }; -export const BarChart = ({ id, color, series, name, type, stack }: Props) => { +export const BarChart = ({ id, color, series, name, stack }: Props) => { const style: RecursivePartial = { rectBorder: { stroke: color || void 0, diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart.tsx index c228f09cbb64..256fabdb792f 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart.tsx @@ -18,6 +18,7 @@ import { } from '@elastic/charts'; import { first, last } from 'lodash'; import moment from 'moment'; +import { InfraSourceConfiguration } from '../../../../../common/http_api/source_api'; import { MetricsExplorerSeries } from '../../../../../common/http_api/metrics_explorer'; import { MetricsExplorerOptions, @@ -29,7 +30,6 @@ import { euiStyled } from '../../../../../../../../src/plugins/kibana_react/comm import { createFormatterForMetric } from './helpers/create_formatter_for_metric'; import { MetricExplorerSeriesChart } from './series_chart'; import { MetricsExplorerChartContextMenu } from './chart_context_menu'; -import { SourceQuery } from '../../../../graphql/types'; import { MetricsExplorerEmptyChart } from './empty_chart'; import { MetricsExplorerNoMetrics } from './no_metrics'; import { getChartTheme } from './helpers/get_chart_theme'; @@ -46,7 +46,7 @@ interface Props { options: MetricsExplorerOptions; chartOptions: MetricsExplorerChartOptions; series: MetricsExplorerSeries; - source: SourceQuery.Query['source']['configuration'] | undefined; + source: InfraSourceConfiguration | undefined; timeRange: MetricsExplorerTimeOptions; onTimeChange: (start: string, end: string) => void; } diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx index 5d38fd436fcc..4fb13f72217b 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx @@ -14,6 +14,7 @@ import { } from '@elastic/eui'; import DateMath from '@elastic/datemath'; import { Capabilities } from 'src/core/public'; +import { InfraSourceConfiguration } from '../../../../../common/http_api/source_api'; import { AlertFlyout } from '../../../../alerting/metric_threshold/components/alert_flyout'; import { MetricsExplorerSeries } from '../../../../../common/http_api/metrics_explorer'; import { @@ -23,7 +24,6 @@ import { } from '../hooks/use_metrics_explorer_options'; import { createTSVBLink } from './helpers/create_tsvb_link'; import { getNodeDetailUrl } from '../../../link_to/redirect_to_node_detail'; -import { SourceConfiguration } from '../../../../utils/source_configuration'; import { InventoryItemType } from '../../../../../common/inventory_models/types'; import { useLinkProps } from '../../../../hooks/use_link_props'; @@ -31,14 +31,14 @@ export interface Props { options: MetricsExplorerOptions; onFilter?: (query: string) => void; series: MetricsExplorerSeries; - source?: SourceConfiguration; + source?: InfraSourceConfiguration; timeRange: MetricsExplorerTimeOptions; uiCapabilities?: Capabilities; chartOptions: MetricsExplorerChartOptions; } const fieldToNodeType = ( - source: SourceConfiguration, + source: InfraSourceConfiguration, groupBy: string | string[] ): InventoryItemType | undefined => { const fields = Array.isArray(groupBy) ? groupBy : [groupBy]; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/charts.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/charts.tsx index 270ccac00063..b9c00101d7b3 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/charts.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/charts.tsx @@ -8,6 +8,7 @@ import { EuiButton, EuiFlexGrid, EuiFlexItem, EuiText, EuiHorizontalRule } from import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; +import { InfraSourceConfiguration } from '../../../../../common/http_api/source_api'; import { MetricsExplorerResponse } from '../../../../../common/http_api/metrics_explorer'; import { MetricsExplorerOptions, @@ -17,7 +18,6 @@ import { import { InfraLoadingPanel } from '../../../../components/loading'; import { NoData } from '../../../../components/empty_states/no_data'; import { MetricsExplorerChart } from './chart'; -import { SourceQuery } from '../../../../graphql/types'; type StringOrNull = string | null; @@ -30,7 +30,7 @@ interface Props { onFilter: (filter: string) => void; onTimeChange: (start: string, end: string) => void; data: MetricsExplorerResponse | null; - source: SourceQuery.Query['source']['configuration'] | undefined; + source: InfraSourceConfiguration | undefined; timeRange: MetricsExplorerTimeOptions; } export const MetricsExplorerCharts = ({ diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.ts index 15ed28c09519..90338d714488 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.ts @@ -7,6 +7,7 @@ import { encode } from 'rison-node'; import uuid from 'uuid'; import { set } from '@elastic/safer-lodash-set'; +import { InfraSourceConfiguration } from '../../../../../../common/http_api/source_api'; import { colorTransformer, Color } from '../../../../../../common/color_palette'; import { MetricsExplorerSeries } from '../../../../../../common/http_api/metrics_explorer'; import { @@ -19,15 +20,14 @@ import { } from '../../hooks/use_metrics_explorer_options'; import { metricToFormat } from './metric_to_format'; import { InfraFormatterType } from '../../../../../lib/lib'; -import { SourceQuery } from '../../../../../graphql/types'; import { createMetricLabel } from './create_metric_label'; import { LinkDescriptor } from '../../../../../hooks/use_link_props'; /* - We've recently changed the default index pattern in Metrics UI from `metricbeat-*` to + We've recently changed the default index pattern in Metrics UI from `metricbeat-*` to `metrics-*,metricbeat-*`. There is a bug in TSVB when there is an empty index in the pattern the field dropdowns are not populated correctly. This index pattern is a temporary fix. - See: https://github.com/elastic/kibana/issues/73987 + See: https://github.com/elastic/kibana/issues/73987 */ const TSVB_WORKAROUND_INDEX_PATTERN = 'metric*'; @@ -142,7 +142,7 @@ const createTSVBIndexPattern = (alias: string) => { }; export const createTSVBLink = ( - source: SourceQuery.Query['source']['configuration'] | undefined, + source: InfraSourceConfiguration | undefined, options: MetricsExplorerOptions, series: MetricsExplorerSeries, timeRange: MetricsExplorerTimeOptions, diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts index 169bc9bcbcdb..7a235b9da64c 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts @@ -6,6 +6,7 @@ import { useState, useCallback, useContext } from 'react'; import { IIndexPattern } from 'src/plugins/data/public'; +import { InfraSourceConfiguration } from '../../../../../common/http_api/source_api'; import { MetricsExplorerMetric, MetricsExplorerAggregation, @@ -17,7 +18,6 @@ import { MetricsExplorerTimeOptions, MetricsExplorerOptions, } from './use_metrics_explorer_options'; -import { SourceQuery } from '../../../../graphql/types'; export interface MetricExplorerViewState { chartOptions: MetricsExplorerChartOptions; @@ -26,7 +26,7 @@ export interface MetricExplorerViewState { } export const useMetricsExplorerState = ( - source: SourceQuery.Query['source']['configuration'], + source: InfraSourceConfiguration, derivedIndexPattern: IIndexPattern, shouldLoadImmediately = true ) => { diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx index f566e5253c61..689a8146afa0 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx @@ -19,9 +19,9 @@ import { createSeries, } from '../../../../utils/fixtures/metrics_explorer'; import { MetricsExplorerOptions, MetricsExplorerTimeOptions } from './use_metrics_explorer_options'; -import { SourceQuery } from '../../../../../common/graphql/types'; import { IIndexPattern } from '../../../../../../../../src/plugins/data/public'; import { HttpHandler } from 'kibana/public'; +import { InfraSourceConfiguration } from '../../../../../common/http_api/source_api'; const mockedFetch = jest.fn(); @@ -37,7 +37,7 @@ const renderUseMetricsExplorerDataHook = () => { return renderHook( (props: { options: MetricsExplorerOptions; - source: SourceQuery.Query['source']['configuration'] | undefined; + source: InfraSourceConfiguration | undefined; derivedIndexPattern: IIndexPattern; timeRange: MetricsExplorerTimeOptions; afterKey: string | null | Record; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts index 924f59eb0d1d..1315b5917c97 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts @@ -8,7 +8,7 @@ import DateMath from '@elastic/datemath'; import { isEqual } from 'lodash'; import { useEffect, useState, useCallback } from 'react'; import { IIndexPattern } from 'src/plugins/data/public'; -import { SourceQuery } from '../../../../../common/graphql/types'; +import { InfraSourceConfiguration } from '../../../../../common/http_api/source_api'; import { MetricsExplorerResponse, metricsExplorerResponseRT, @@ -24,7 +24,7 @@ function isSameOptions(current: MetricsExplorerOptions, next: MetricsExplorerOpt export function useMetricsExplorerData( options: MetricsExplorerOptions, - source: SourceQuery.Query['source']['configuration'] | undefined, + source: InfraSourceConfiguration | undefined, derivedIndexPattern: IIndexPattern, timerange: MetricsExplorerTimeOptions, afterKey: string | null | Record, diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx index 20efca79650a..8ca921f4f266 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx @@ -8,8 +8,8 @@ import { EuiErrorBoundary } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useEffect } from 'react'; import { IIndexPattern } from 'src/plugins/data/public'; +import { InfraSourceConfiguration } from '../../../../common/http_api/source_api'; import { useTrackPageview } from '../../../../../observability/public'; -import { SourceQuery } from '../../../../common/graphql/types'; import { DocumentTitle } from '../../../components/document_title'; import { NoData } from '../../../components/empty_states'; import { MetricsExplorerCharts } from './components/charts'; @@ -18,7 +18,7 @@ import { useMetricsExplorerState } from './hooks/use_metric_explorer_state'; import { useSavedViewContext } from '../../../containers/saved_view/saved_view'; interface MetricsExplorerPageProps { - source: SourceQuery.Query['source']['configuration']; + source: InfraSourceConfiguration; derivedIndexPattern: IIndexPattern; } diff --git a/x-pack/plugins/infra/public/utils/apollo_client.ts b/x-pack/plugins/infra/public/utils/apollo_client.ts deleted file mode 100644 index 41831a03cabb..000000000000 --- a/x-pack/plugins/infra/public/utils/apollo_client.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; -import ApolloClient from 'apollo-client'; -import { ApolloLink } from 'apollo-link'; -import { createHttpLink } from 'apollo-link-http'; -import { withClientState } from 'apollo-link-state'; -import { HttpFetchOptions, HttpHandler } from 'src/core/public'; -import introspectionQueryResultData from '../graphql/introspection.json'; - -export const createApolloClient = (fetch: HttpHandler) => { - const cache = new InMemoryCache({ - addTypename: false, - fragmentMatcher: new IntrospectionFragmentMatcher({ - // @ts-expect-error apollo-cache-inmemory types don't match actual introspection data - introspectionQueryResultData, - }), - }); - - const wrappedFetch = (path: string, options: HttpFetchOptions) => { - return new Promise(async (resolve, reject) => { - // core.http.fetch isn't 100% compatible with the Fetch API and will - // throw Errors on 401s. This top level try / catch handles those scenarios. - try { - fetch(path, { - ...options, - // Set headers to undefined due to this bug: https://github.com/apollographql/apollo-link/issues/249, - // Apollo will try to set a "content-type" header which will conflict with the "Content-Type" header that - // core.http.fetch correctly sets. - headers: undefined, - asResponse: true, - }).then((res) => { - if (!res.response) { - return reject(); - } - // core.http.fetch will parse the Response and set a body before handing it back. As such .text() / .json() - // will have already been called on the Response instance. However, Apollo will also want to call - // .text() / .json() on the instance, as it expects the raw Response instance, rather than core's wrapper. - // .text() / .json() can only be called once, and an Error will be thrown if those methods are accessed again. - // This hacks around that by setting up a new .text() method that will restringify the JSON response we already have. - // This does result in an extra stringify / parse cycle, which isn't ideal, but as we only have a few endpoints left using - // GraphQL this shouldn't create excessive overhead. - // Ref: https://github.com/apollographql/apollo-link/blob/master/packages/apollo-link-http/src/httpLink.ts#L134 - // and - // https://github.com/apollographql/apollo-link/blob/master/packages/apollo-link-http-common/src/index.ts#L125 - return resolve({ - ...res.response, - text: () => { - return new Promise(async (resolveText, rejectText) => { - if (res.body) { - return resolveText(JSON.stringify(res.body)); - } else { - return rejectText(); - } - }); - }, - }); - }); - } catch (error) { - reject(error); - } - }); - }; - - const HttpLink = createHttpLink({ - fetch: wrappedFetch, - uri: `/api/infra/graphql`, - }); - - const graphQLOptions = { - cache, - link: ApolloLink.from([ - withClientState({ - cache, - resolvers: {}, - }), - HttpLink, - ]), - }; - - return new ApolloClient(graphQLOptions); -}; diff --git a/x-pack/plugins/infra/public/utils/apollo_context.ts b/x-pack/plugins/infra/public/utils/apollo_context.ts deleted file mode 100644 index a33a1964c4d8..000000000000 --- a/x-pack/plugins/infra/public/utils/apollo_context.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 { ApolloClient } from 'apollo-client'; -import { createContext, useContext } from 'react'; - -/** - * This is a temporary provider and hook for use with hooks until react-apollo - * has upgraded to the new-style `createContext` api. - */ - -export const ApolloClientContext = createContext | undefined>(undefined); - -export const useApolloClient = () => { - return useContext(ApolloClientContext); -}; - -export class DependencyError extends Error { - constructor(message?: string) { - super(message); - Object.setPrototypeOf(this, new.target.prototype); - } -} diff --git a/x-pack/plugins/infra/public/utils/source_configuration.ts b/x-pack/plugins/infra/public/utils/source_configuration.ts index 5104ed46000f..cbffe7826f81 100644 --- a/x-pack/plugins/infra/public/utils/source_configuration.ts +++ b/x-pack/plugins/infra/public/utils/source_configuration.ts @@ -4,14 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SourceConfigurationFields } from '../graphql/types'; +import { + InfraSavedSourceConfigurationColumn, + InfraSavedSourceConfigurationFields, + InfraSourceConfigurationMessageColumn, + InfraSourceConfigurationTimestampColumn, +} from '../../common/http_api/source_api'; -export type SourceConfiguration = SourceConfigurationFields.Fragment; - -export type LogColumnConfiguration = SourceConfigurationFields.LogColumns; -export type FieldLogColumnConfiguration = SourceConfigurationFields.InfraSourceFieldLogColumnInlineFragment; -export type MessageLogColumnConfiguration = SourceConfigurationFields.InfraSourceMessageLogColumnInlineFragment; -export type TimestampLogColumnConfiguration = SourceConfigurationFields.InfraSourceTimestampLogColumnInlineFragment; +export type LogColumnConfiguration = InfraSavedSourceConfigurationColumn; +export type FieldLogColumnConfiguration = InfraSavedSourceConfigurationFields; +export type MessageLogColumnConfiguration = InfraSourceConfigurationMessageColumn; +export type TimestampLogColumnConfiguration = InfraSourceConfigurationTimestampColumn; export const isFieldLogColumnConfiguration = ( logColumnConfiguration: LogColumnConfiguration diff --git a/x-pack/plugins/infra/scripts/combined_schema.ts b/x-pack/plugins/infra/scripts/combined_schema.ts deleted file mode 100644 index 4813a3b674b3..000000000000 --- a/x-pack/plugins/infra/scripts/combined_schema.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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 { buildSchemaFromTypeDefinitions } from 'graphql-tools'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { schemas as serverSchemas } from '../server/graphql'; - -export const schemas = [...serverSchemas]; - -// this default export is used to feed the combined types to the gql-gen tool -// which generates the corresponding typescript types -// eslint-disable-next-line import/no-default-export -export default buildSchemaFromTypeDefinitions(schemas); diff --git a/x-pack/plugins/infra/scripts/generate_types_from_graphql.js b/x-pack/plugins/infra/scripts/generate_types_from_graphql.js deleted file mode 100644 index aec5ff6da99c..000000000000 --- a/x-pack/plugins/infra/scripts/generate_types_from_graphql.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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. - */ - -require('../../../../src/setup_node_env'); - -const { join, resolve } = require('path'); -// eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved -const { generate } = require('graphql-code-generator'); - -const GRAPHQL_GLOBS = [ - join('public', 'containers', '**', '*.gql_query.ts{,x}'), - join('public', 'store', '**', '*.gql_query.ts{,x}'), - join('common', 'graphql', '**', '*.gql_query.ts{,x}'), -]; -const CLIENT_CONFIG_PATH = resolve(__dirname, 'gql_gen_client.json'); -const SERVER_CONFIG_PATH = resolve(__dirname, 'gql_gen_server.json'); -const OUTPUT_INTROSPECTION_PATH = resolve('public', 'graphql', 'introspection.json'); -const OUTPUT_CLIENT_TYPES_PATH = resolve('public', 'graphql', 'types.ts'); -const OUTPUT_COMMON_TYPES_PATH = resolve('common', 'graphql', 'types.ts'); -const OUTPUT_SERVER_TYPES_PATH = resolve('server', 'graphql', 'types.ts'); -const SCHEMA_PATH = resolve(__dirname, 'combined_schema.ts'); - -async function main() { - await generate( - { - args: GRAPHQL_GLOBS, - config: SERVER_CONFIG_PATH, - out: OUTPUT_INTROSPECTION_PATH, - overwrite: true, - schema: SCHEMA_PATH, - template: 'graphql-codegen-introspection-template', - }, - true - ); - await generate( - { - args: GRAPHQL_GLOBS, - config: CLIENT_CONFIG_PATH, - out: OUTPUT_CLIENT_TYPES_PATH, - overwrite: true, - schema: SCHEMA_PATH, - template: 'graphql-codegen-typescript-template', - }, - true - ); - await generate( - { - args: GRAPHQL_GLOBS, - config: CLIENT_CONFIG_PATH, - out: OUTPUT_COMMON_TYPES_PATH, - overwrite: true, - schema: SCHEMA_PATH, - template: 'graphql-codegen-typescript-template', - }, - true - ); - await generate( - { - args: [], - config: SERVER_CONFIG_PATH, - out: OUTPUT_SERVER_TYPES_PATH, - overwrite: true, - schema: SCHEMA_PATH, - template: 'graphql-codegen-typescript-resolvers-template', - }, - true - ); -} - -if (require.main === module) { - main(); -} diff --git a/x-pack/plugins/infra/server/graphql/index.ts b/x-pack/plugins/infra/server/graphql/index.ts deleted file mode 100644 index f5150972a3a6..000000000000 --- a/x-pack/plugins/infra/server/graphql/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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 { rootSchema } from '../../common/graphql/root/schema.gql'; -import { sharedSchema } from '../../common/graphql/shared/schema.gql'; -import { sourceStatusSchema } from './source_status/schema.gql'; -import { sourcesSchema } from './sources/schema.gql'; - -export const schemas = [rootSchema, sharedSchema, sourcesSchema, sourceStatusSchema]; diff --git a/x-pack/plugins/infra/server/graphql/source_status/index.ts b/x-pack/plugins/infra/server/graphql/source_status/index.ts deleted file mode 100644 index abc91fa3815c..000000000000 --- a/x-pack/plugins/infra/server/graphql/source_status/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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. - */ - -export { createSourceStatusResolvers } from './resolvers'; diff --git a/x-pack/plugins/infra/server/graphql/source_status/resolvers.ts b/x-pack/plugins/infra/server/graphql/source_status/resolvers.ts deleted file mode 100644 index bd92dd0f7da8..000000000000 --- a/x-pack/plugins/infra/server/graphql/source_status/resolvers.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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 { InfraIndexType, InfraSourceStatusResolvers } from '../../graphql/types'; -import { InfraFieldsDomain } from '../../lib/domains/fields_domain'; -import { InfraSourceStatus } from '../../lib/source_status'; -import { ChildResolverOf, InfraResolverOf } from '../../utils/typed_resolvers'; -import { QuerySourceResolver } from '../sources/resolvers'; - -export type InfraSourceStatusMetricAliasExistsResolver = ChildResolverOf< - InfraResolverOf, - QuerySourceResolver ->; - -export type InfraSourceStatusMetricIndicesExistResolver = ChildResolverOf< - InfraResolverOf, - QuerySourceResolver ->; - -export type InfraSourceStatusMetricIndicesResolver = ChildResolverOf< - InfraResolverOf, - QuerySourceResolver ->; - -export type InfraSourceStatusLogAliasExistsResolver = ChildResolverOf< - InfraResolverOf, - QuerySourceResolver ->; - -export type InfraSourceStatusLogIndicesExistResolver = ChildResolverOf< - InfraResolverOf, - QuerySourceResolver ->; - -export type InfraSourceStatusLogIndicesResolver = ChildResolverOf< - InfraResolverOf, - QuerySourceResolver ->; - -export type InfraSourceStatusIndexFieldsResolver = ChildResolverOf< - InfraResolverOf, - QuerySourceResolver ->; - -export const createSourceStatusResolvers = (libs: { - sourceStatus: InfraSourceStatus; - fields: InfraFieldsDomain; -}): { - InfraSourceStatus: { - metricAliasExists: InfraSourceStatusMetricAliasExistsResolver; - metricIndicesExist: InfraSourceStatusMetricIndicesExistResolver; - metricIndices: InfraSourceStatusMetricIndicesResolver; - logAliasExists: InfraSourceStatusLogAliasExistsResolver; - logIndicesExist: InfraSourceStatusLogIndicesExistResolver; - logIndices: InfraSourceStatusLogIndicesResolver; - indexFields: InfraSourceStatusIndexFieldsResolver; - }; -} => ({ - InfraSourceStatus: { - async metricAliasExists(source, args, { req }) { - return await libs.sourceStatus.hasMetricAlias(req, source.id); - }, - async metricIndicesExist(source, args, { req }) { - return await libs.sourceStatus.hasMetricIndices(req, source.id); - }, - async metricIndices(source, args, { req }) { - return await libs.sourceStatus.getMetricIndexNames(req, source.id); - }, - async logAliasExists(source, args, { req }) { - return await libs.sourceStatus.hasLogAlias(req, source.id); - }, - async logIndicesExist(source, args, { req }) { - return (await libs.sourceStatus.getLogIndexStatus(req, source.id)) !== 'missing'; - }, - async logIndices(source, args, { req }) { - return await libs.sourceStatus.getLogIndexNames(req, source.id); - }, - async indexFields(source, args, { req }) { - const fields = await libs.fields.getFields( - req, - source.id, - args.indexType || InfraIndexType.ANY - ); - return fields; - }, - }, -}); diff --git a/x-pack/plugins/infra/server/graphql/source_status/schema.gql.ts b/x-pack/plugins/infra/server/graphql/source_status/schema.gql.ts deleted file mode 100644 index e0482382c6d6..000000000000 --- a/x-pack/plugins/infra/server/graphql/source_status/schema.gql.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 gql from 'graphql-tag'; - -export const sourceStatusSchema = gql` - "A descriptor of a field in an index" - type InfraIndexField { - "The name of the field" - name: String! - "The type of the field's values as recognized by Kibana" - type: String! - "Whether the field's values can be efficiently searched for" - searchable: Boolean! - "Whether the field's values can be aggregated" - aggregatable: Boolean! - "Whether the field should be displayed based on event.module and a ECS allowed list" - displayable: Boolean! - } - - extend type InfraSourceStatus { - "Whether the configured metric alias exists" - metricAliasExists: Boolean! - "Whether the configured log alias exists" - logAliasExists: Boolean! - "Whether the configured alias or wildcard pattern resolve to any metric indices" - metricIndicesExist: Boolean! - "Whether the configured alias or wildcard pattern resolve to any log indices" - logIndicesExist: Boolean! - "The list of indices in the metric alias" - metricIndices: [String!]! - "The list of indices in the log alias" - logIndices: [String!]! - "The list of fields defined in the index mappings" - indexFields(indexType: InfraIndexType = ANY): [InfraIndexField!]! - } -`; diff --git a/x-pack/plugins/infra/server/graphql/sources/index.ts b/x-pack/plugins/infra/server/graphql/sources/index.ts deleted file mode 100644 index ee187d8c31be..000000000000 --- a/x-pack/plugins/infra/server/graphql/sources/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * 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. - */ - -export { createSourcesResolvers } from './resolvers'; -export { sourcesSchema } from './schema.gql'; diff --git a/x-pack/plugins/infra/server/graphql/sources/resolvers.ts b/x-pack/plugins/infra/server/graphql/sources/resolvers.ts deleted file mode 100644 index 15c4a6677946..000000000000 --- a/x-pack/plugins/infra/server/graphql/sources/resolvers.ts +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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 { UserInputError } from 'apollo-server-errors'; -import { failure } from 'io-ts/lib/PathReporter'; - -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { - InfraSourceLogColumn, - InfraSourceResolvers, - MutationResolvers, - QueryResolvers, - UpdateSourceLogColumnInput, -} from '../../graphql/types'; -import { InfraSourceStatus } from '../../lib/source_status'; -import { - InfraSources, - SavedSourceConfigurationFieldColumnRuntimeType, - SavedSourceConfigurationMessageColumnRuntimeType, - SavedSourceConfigurationTimestampColumnRuntimeType, - SavedSourceConfigurationColumnRuntimeType, -} from '../../lib/sources'; -import { - ChildResolverOf, - InfraResolverOf, - InfraResolverWithFields, - ResultOf, -} from '../../utils/typed_resolvers'; - -export type QuerySourceResolver = InfraResolverWithFields< - QueryResolvers.SourceResolver, - 'id' | 'version' | 'updatedAt' | 'configuration' ->; - -export type QueryAllSourcesResolver = InfraResolverWithFields< - QueryResolvers.AllSourcesResolver, - 'id' | 'version' | 'updatedAt' | 'configuration' ->; - -export type InfraSourceStatusResolver = ChildResolverOf< - InfraResolverOf>>, - QuerySourceResolver ->; - -export type MutationCreateSourceResolver = InfraResolverOf< - MutationResolvers.CreateSourceResolver<{ - source: ResultOf; - }> ->; - -export type MutationDeleteSourceResolver = InfraResolverOf; - -export type MutationUpdateSourceResolver = InfraResolverOf< - MutationResolvers.UpdateSourceResolver<{ - source: ResultOf; - }> ->; - -interface SourcesResolversDeps { - sources: InfraSources; - sourceStatus: InfraSourceStatus; -} - -export const createSourcesResolvers = ( - libs: SourcesResolversDeps -): { - Query: { - source: QuerySourceResolver; - allSources: QueryAllSourcesResolver; - }; - InfraSource: { - status: InfraSourceStatusResolver; - }; - InfraSourceLogColumn: { - __resolveType( - logColumn: InfraSourceLogColumn - ): - | 'InfraSourceTimestampLogColumn' - | 'InfraSourceMessageLogColumn' - | 'InfraSourceFieldLogColumn' - | null; - }; - Mutation: { - createSource: MutationCreateSourceResolver; - deleteSource: MutationDeleteSourceResolver; - updateSource: MutationUpdateSourceResolver; - }; -} => ({ - Query: { - async source(root, args, { req }) { - const requestedSourceConfiguration = await libs.sources.getSourceConfiguration( - req.core.savedObjects.client, - args.id - ); - - return requestedSourceConfiguration; - }, - async allSources(root, args, { req }) { - const sourceConfigurations = await libs.sources.getAllSourceConfigurations( - req.core.savedObjects.client - ); - - return sourceConfigurations; - }, - }, - InfraSource: { - async status(source) { - return source; - }, - }, - InfraSourceLogColumn: { - __resolveType(logColumn) { - if (SavedSourceConfigurationTimestampColumnRuntimeType.is(logColumn)) { - return 'InfraSourceTimestampLogColumn'; - } - - if (SavedSourceConfigurationMessageColumnRuntimeType.is(logColumn)) { - return 'InfraSourceMessageLogColumn'; - } - - if (SavedSourceConfigurationFieldColumnRuntimeType.is(logColumn)) { - return 'InfraSourceFieldLogColumn'; - } - - return null; - }, - }, - Mutation: { - async createSource(root, args, { req }) { - const sourceConfiguration = await libs.sources.createSourceConfiguration( - req.core.savedObjects.client, - args.id, - compactObject({ - ...args.sourceProperties, - fields: args.sourceProperties.fields - ? compactObject(args.sourceProperties.fields) - : undefined, - logColumns: decodeLogColumns(args.sourceProperties.logColumns), - }) - ); - - return { - source: sourceConfiguration, - }; - }, - async deleteSource(root, args, { req }) { - await libs.sources.deleteSourceConfiguration(req.core.savedObjects.client, args.id); - - return { - id: args.id, - }; - }, - async updateSource(root, args, { req }) { - const updatedSourceConfiguration = await libs.sources.updateSourceConfiguration( - req.core.savedObjects.client, - args.id, - compactObject({ - ...args.sourceProperties, - fields: args.sourceProperties.fields - ? compactObject(args.sourceProperties.fields) - : undefined, - logColumns: decodeLogColumns(args.sourceProperties.logColumns), - }) - ); - - return { - source: updatedSourceConfiguration, - }; - }, - }, -}); - -type CompactObject = { [K in keyof T]: NonNullable }; - -const compactObject = (obj: T): CompactObject => - Object.entries(obj).reduce>( - (accumulatedObj, [key, value]) => - typeof value === 'undefined' || value === null - ? accumulatedObj - : { - ...(accumulatedObj as any), - [key]: value, - }, - {} as CompactObject - ); - -const decodeLogColumns = (logColumns?: UpdateSourceLogColumnInput[] | null) => - logColumns - ? logColumns.map((logColumn) => - pipe( - SavedSourceConfigurationColumnRuntimeType.decode(logColumn), - fold((errors) => { - throw new UserInputError(failure(errors).join('\n')); - }, identity) - ) - ) - : undefined; diff --git a/x-pack/plugins/infra/server/graphql/sources/schema.gql.ts b/x-pack/plugins/infra/server/graphql/sources/schema.gql.ts deleted file mode 100644 index dbd0696fe3e0..000000000000 --- a/x-pack/plugins/infra/server/graphql/sources/schema.gql.ts +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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 gql from 'graphql-tag'; - -export const sourcesSchema = gql` - "A source of infrastructure data" - type InfraSource { - "The id of the source" - id: ID! - "The version number the source configuration was last persisted with" - version: String - "The timestamp the source configuration was last persisted at" - updatedAt: Float - "The origin of the source (one of 'fallback', 'internal', 'stored')" - origin: String! - "The raw configuration of the source" - configuration: InfraSourceConfiguration! - "The status of the source" - status: InfraSourceStatus! - } - - "The status of an infrastructure data source" - type InfraSourceStatus - - "A set of configuration options for an infrastructure data source" - type InfraSourceConfiguration { - "The name of the data source" - name: String! - "A description of the data source" - description: String! - "The alias to read metric data from" - metricAlias: String! - "The alias to read log data from" - logAlias: String! - "Default view for inventory" - inventoryDefaultView: String! - "Default view for Metrics Explorer" - metricsExplorerDefaultView: String! - "The field mapping to use for this source" - fields: InfraSourceFields! - "The columns to use for log display" - logColumns: [InfraSourceLogColumn!]! - } - - "A mapping of semantic fields to their document counterparts" - type InfraSourceFields { - "The field to identify a container by" - container: String! - "The fields to identify a host by" - host: String! - "The fields to use as the log message" - message: [String!]! - "The field to identify a pod by" - pod: String! - "The field to use as a tiebreaker for log events that have identical timestamps" - tiebreaker: String! - "The field to use as a timestamp for metrics and logs" - timestamp: String! - } - - "The built-in timestamp log column" - type InfraSourceTimestampLogColumn { - timestampColumn: InfraSourceTimestampLogColumnAttributes! - } - - type InfraSourceTimestampLogColumnAttributes { - "A unique id for the column" - id: ID! - } - - "The built-in message log column" - type InfraSourceMessageLogColumn { - messageColumn: InfraSourceMessageLogColumnAttributes! - } - - type InfraSourceMessageLogColumnAttributes { - "A unique id for the column" - id: ID! - } - - "A log column containing a field value" - type InfraSourceFieldLogColumn { - fieldColumn: InfraSourceFieldLogColumnAttributes! - } - - type InfraSourceFieldLogColumnAttributes { - "A unique id for the column" - id: ID! - "The field name this column refers to" - field: String! - } - - "All known log column types" - union InfraSourceLogColumn = - InfraSourceTimestampLogColumn - | InfraSourceMessageLogColumn - | InfraSourceFieldLogColumn - - extend type Query { - """ - Get an infrastructure data source by id. - - The resolution order for the source configuration attributes is as follows - with the first defined value winning: - - 1. The attributes of the saved object with the given 'id'. - 2. The attributes defined in the static Kibana configuration key - 'xpack.infra.sources.default'. - 3. The hard-coded default values. - - As a consequence, querying a source that doesn't exist doesn't error out, - but returns the configured or hardcoded defaults. - """ - source("The id of the source" id: ID!): InfraSource! - "Get a list of all infrastructure data sources" - allSources: [InfraSource!]! - } - - "The properties to update the source with" - input UpdateSourceInput { - "The name of the data source" - name: String - "A description of the data source" - description: String - "The alias to read metric data from" - metricAlias: String - "The alias to read log data from" - logAlias: String - "The field mapping to use for this source" - fields: UpdateSourceFieldsInput - "Name of default inventory view" - inventoryDefaultView: String - "Default view for Metrics Explorer" - metricsExplorerDefaultView: String - "The log columns to display for this source" - logColumns: [UpdateSourceLogColumnInput!] - } - - "The mapping of semantic fields of the source to be created" - input UpdateSourceFieldsInput { - "The field to identify a container by" - container: String - "The fields to identify a host by" - host: String - "The field to identify a pod by" - pod: String - "The field to use as a tiebreaker for log events that have identical timestamps" - tiebreaker: String - "The field to use as a timestamp for metrics and logs" - timestamp: String - } - - "One of the log column types to display for this source" - input UpdateSourceLogColumnInput { - "A custom field log column" - fieldColumn: UpdateSourceFieldLogColumnInput - "A built-in message log column" - messageColumn: UpdateSourceMessageLogColumnInput - "A built-in timestamp log column" - timestampColumn: UpdateSourceTimestampLogColumnInput - } - - input UpdateSourceFieldLogColumnInput { - id: ID! - field: String! - } - - input UpdateSourceMessageLogColumnInput { - id: ID! - } - - input UpdateSourceTimestampLogColumnInput { - id: ID! - } - - "The result of a successful source update" - type UpdateSourceResult { - "The source that was updated" - source: InfraSource! - } - - "The result of a source deletion operations" - type DeleteSourceResult { - "The id of the source that was deleted" - id: ID! - } - - extend type Mutation { - "Create a new source of infrastructure data" - createSource( - "The id of the source" - id: ID! - sourceProperties: UpdateSourceInput! - ): UpdateSourceResult! - "Modify an existing source" - updateSource( - "The id of the source" - id: ID! - "The properties to update the source with" - sourceProperties: UpdateSourceInput! - ): UpdateSourceResult! - "Delete a source of infrastructure data" - deleteSource("The id of the source" id: ID!): DeleteSourceResult! - } -`; diff --git a/x-pack/plugins/infra/server/graphql/types.ts b/x-pack/plugins/infra/server/graphql/types.ts deleted file mode 100644 index 712438ce2bfe..000000000000 --- a/x-pack/plugins/infra/server/graphql/types.ts +++ /dev/null @@ -1,1111 +0,0 @@ -/* tslint:disable */ -import { InfraContext } from '../lib/infra_types'; -import { GraphQLResolveInfo } from 'graphql'; - -export type Resolver = ( - parent: Parent, - args: Args, - context: Context, - info: GraphQLResolveInfo -) => Promise | Result; - -export interface ISubscriptionResolverObject { - subscribe( - parent: P, - args: Args, - context: Context, - info: GraphQLResolveInfo - ): AsyncIterator; - resolve?( - parent: P, - args: Args, - context: Context, - info: GraphQLResolveInfo - ): R | Result | Promise; -} - -export type SubscriptionResolver = - | ((...args: any[]) => ISubscriptionResolverObject) - | ISubscriptionResolverObject; - -// ==================================================== -// START: Typescript template -// ==================================================== - -// ==================================================== -// Types -// ==================================================== - -export interface Query { - /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source that doesn't exist doesn't error out,but returns the configured or hardcoded defaults. */ - source: InfraSource; - /** Get a list of all infrastructure data sources */ - allSources: InfraSource[]; -} -/** A source of infrastructure data */ -export interface InfraSource { - /** The id of the source */ - id: string; - /** The version number the source configuration was last persisted with */ - version?: string | null; - /** The timestamp the source configuration was last persisted at */ - updatedAt?: number | null; - /** The origin of the source (one of 'fallback', 'internal', 'stored') */ - origin: string; - /** The raw configuration of the source */ - configuration: InfraSourceConfiguration; - /** The status of the source */ - status: InfraSourceStatus; - - /** A snapshot of nodes */ - snapshot?: InfraSnapshotResponse | null; - - metrics: InfraMetricData[]; -} -/** A set of configuration options for an infrastructure data source */ -export interface InfraSourceConfiguration { - /** The name of the data source */ - name: string; - /** A description of the data source */ - description: string; - /** The alias to read metric data from */ - metricAlias: string; - /** The alias to read log data from */ - logAlias: string; - /** The field mapping to use for this source */ - fields: InfraSourceFields; - /** The columns to use for log display */ - logColumns: InfraSourceLogColumn[]; -} -/** A mapping of semantic fields to their document counterparts */ -export interface InfraSourceFields { - /** The field to identify a container by */ - container: string; - /** The fields to identify a host by */ - host: string; - /** The fields to use as the log message */ - message: string[]; - /** The field to identify a pod by */ - pod: string; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker: string; - /** The field to use as a timestamp for metrics and logs */ - timestamp: string; -} -/** The built-in timestamp log column */ -export interface InfraSourceTimestampLogColumn { - timestampColumn: InfraSourceTimestampLogColumnAttributes; -} - -export interface InfraSourceTimestampLogColumnAttributes { - /** A unique id for the column */ - id: string; -} -/** The built-in message log column */ -export interface InfraSourceMessageLogColumn { - messageColumn: InfraSourceMessageLogColumnAttributes; -} - -export interface InfraSourceMessageLogColumnAttributes { - /** A unique id for the column */ - id: string; -} -/** A log column containing a field value */ -export interface InfraSourceFieldLogColumn { - fieldColumn: InfraSourceFieldLogColumnAttributes; -} - -export interface InfraSourceFieldLogColumnAttributes { - /** A unique id for the column */ - id: string; - /** The field name this column refers to */ - field: string; -} -/** The status of an infrastructure data source */ -export interface InfraSourceStatus { - /** Whether the configured metric alias exists */ - metricAliasExists: boolean; - /** Whether the configured log alias exists */ - logAliasExists: boolean; - /** Whether the configured alias or wildcard pattern resolve to any metric indices */ - metricIndicesExist: boolean; - /** Whether the configured alias or wildcard pattern resolve to any log indices */ - logIndicesExist: boolean; - /** The list of indices in the metric alias */ - metricIndices: string[]; - /** The list of indices in the log alias */ - logIndices: string[]; - /** The list of fields defined in the index mappings */ - indexFields: InfraIndexField[]; -} -/** A descriptor of a field in an index */ -export interface InfraIndexField { - /** The name of the field */ - name: string; - /** The type of the field's values as recognized by Kibana */ - type: string; - /** Whether the field's values can be efficiently searched for */ - searchable: boolean; - /** Whether the field's values can be aggregated */ - aggregatable: boolean; - /** Whether the field should be displayed based on event.module and a ECS allowed list */ - displayable: boolean; -} - -export interface InfraSnapshotResponse { - /** Nodes of type host, container or pod grouped by 0, 1 or 2 terms */ - nodes: InfraSnapshotNode[]; -} - -export interface InfraSnapshotNode { - path: InfraSnapshotNodePath[]; - - metric: InfraSnapshotNodeMetric; -} - -export interface InfraSnapshotNodePath { - value: string; - - label: string; - - ip?: string | null; -} - -export interface InfraSnapshotNodeMetric { - name: InfraSnapshotMetricType; - - value?: number | null; - - avg?: number | null; - - max?: number | null; -} - -export interface InfraMetricData { - id?: InfraMetric | null; - - series: InfraDataSeries[]; -} - -export interface InfraDataSeries { - id: string; - - label: string; - - data: InfraDataPoint[]; -} - -export interface InfraDataPoint { - timestamp: number; - - value?: number | null; -} - -export interface Mutation { - /** Create a new source of infrastructure data */ - createSource: UpdateSourceResult; - /** Modify an existing source */ - updateSource: UpdateSourceResult; - /** Delete a source of infrastructure data */ - deleteSource: DeleteSourceResult; -} -/** The result of a successful source update */ -export interface UpdateSourceResult { - /** The source that was updated */ - source: InfraSource; -} -/** The result of a source deletion operations */ -export interface DeleteSourceResult { - /** The id of the source that was deleted */ - id: string; -} - -// ==================================================== -// InputTypes -// ==================================================== - -export interface InfraTimerangeInput { - /** The interval string to use for last bucket. The format is '{value}{unit}'. For example '5m' would return the metrics for the last 5 minutes of the timespan. */ - interval: string; - /** The end of the timerange */ - to: number; - /** The beginning of the timerange */ - from: number; -} - -export interface InfraSnapshotGroupbyInput { - /** The label to use in the results for the group by for the terms group by */ - label?: string | null; - /** The field to group by from a terms aggregation, this is ignored by the filter type */ - field?: string | null; -} - -export interface InfraSnapshotMetricInput { - /** The type of metric */ - type: InfraSnapshotMetricType; -} - -export interface InfraNodeIdsInput { - nodeId: string; - - cloudId?: string | null; -} -/** The properties to update the source with */ -export interface UpdateSourceInput { - /** The name of the data source */ - name?: string | null; - /** A description of the data source */ - description?: string | null; - /** The alias to read metric data from */ - metricAlias?: string | null; - /** The alias to read log data from */ - logAlias?: string | null; - /** The field mapping to use for this source */ - fields?: UpdateSourceFieldsInput | null; - /** Name of default inventory view */ - inventoryDefaultView?: string | null; - /** Default view for Metrics Explorer */ - metricsExplorerDefaultView?: string | null; - /** The log columns to display for this source */ - logColumns?: UpdateSourceLogColumnInput[] | null; -} -/** The mapping of semantic fields of the source to be created */ -export interface UpdateSourceFieldsInput { - /** The field to identify a container by */ - container?: string | null; - /** The fields to identify a host by */ - host?: string | null; - /** The field to identify a pod by */ - pod?: string | null; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker?: string | null; - /** The field to use as a timestamp for metrics and logs */ - timestamp?: string | null; -} -/** One of the log column types to display for this source */ -export interface UpdateSourceLogColumnInput { - /** A custom field log column */ - fieldColumn?: UpdateSourceFieldLogColumnInput | null; - /** A built-in message log column */ - messageColumn?: UpdateSourceMessageLogColumnInput | null; - /** A built-in timestamp log column */ - timestampColumn?: UpdateSourceTimestampLogColumnInput | null; -} - -export interface UpdateSourceFieldLogColumnInput { - id: string; - - field: string; -} - -export interface UpdateSourceMessageLogColumnInput { - id: string; -} - -export interface UpdateSourceTimestampLogColumnInput { - id: string; -} - -// ==================================================== -// Arguments -// ==================================================== - -export interface SourceQueryArgs { - /** The id of the source */ - id: string; -} -export interface SnapshotInfraSourceArgs { - timerange: InfraTimerangeInput; - - filterQuery?: string | null; -} -export interface MetricsInfraSourceArgs { - nodeIds: InfraNodeIdsInput; - - nodeType: InfraNodeType; - - timerange: InfraTimerangeInput; - - metrics: InfraMetric[]; -} -export interface IndexFieldsInfraSourceStatusArgs { - indexType?: InfraIndexType | null; -} -export interface NodesInfraSnapshotResponseArgs { - type: InfraNodeType; - - groupBy: InfraSnapshotGroupbyInput[]; - - metric: InfraSnapshotMetricInput; -} -export interface CreateSourceMutationArgs { - /** The id of the source */ - id: string; - - sourceProperties: UpdateSourceInput; -} -export interface UpdateSourceMutationArgs { - /** The id of the source */ - id: string; - /** The properties to update the source with */ - sourceProperties: UpdateSourceInput; -} -export interface DeleteSourceMutationArgs { - /** The id of the source */ - id: string; -} - -// ==================================================== -// Enums -// ==================================================== - -export enum InfraIndexType { - ANY = 'ANY', - LOGS = 'LOGS', - METRICS = 'METRICS', -} - -export enum InfraNodeType { - pod = 'pod', - container = 'container', - host = 'host', - awsEC2 = 'awsEC2', - awsS3 = 'awsS3', - awsRDS = 'awsRDS', - awsSQS = 'awsSQS', -} - -export enum InfraSnapshotMetricType { - count = 'count', - cpu = 'cpu', - load = 'load', - memory = 'memory', - tx = 'tx', - rx = 'rx', - logRate = 'logRate', - diskIOReadBytes = 'diskIOReadBytes', - diskIOWriteBytes = 'diskIOWriteBytes', - s3TotalRequests = 's3TotalRequests', - s3NumberOfObjects = 's3NumberOfObjects', - s3BucketSize = 's3BucketSize', - s3DownloadBytes = 's3DownloadBytes', - s3UploadBytes = 's3UploadBytes', - rdsConnections = 'rdsConnections', - rdsQueriesExecuted = 'rdsQueriesExecuted', - rdsActiveTransactions = 'rdsActiveTransactions', - rdsLatency = 'rdsLatency', - sqsMessagesVisible = 'sqsMessagesVisible', - sqsMessagesDelayed = 'sqsMessagesDelayed', - sqsMessagesSent = 'sqsMessagesSent', - sqsMessagesEmpty = 'sqsMessagesEmpty', - sqsOldestMessage = 'sqsOldestMessage', -} - -export enum InfraMetric { - hostSystemOverview = 'hostSystemOverview', - hostCpuUsage = 'hostCpuUsage', - hostFilesystem = 'hostFilesystem', - hostK8sOverview = 'hostK8sOverview', - hostK8sCpuCap = 'hostK8sCpuCap', - hostK8sDiskCap = 'hostK8sDiskCap', - hostK8sMemoryCap = 'hostK8sMemoryCap', - hostK8sPodCap = 'hostK8sPodCap', - hostLoad = 'hostLoad', - hostMemoryUsage = 'hostMemoryUsage', - hostNetworkTraffic = 'hostNetworkTraffic', - hostDockerOverview = 'hostDockerOverview', - hostDockerInfo = 'hostDockerInfo', - hostDockerTop5ByCpu = 'hostDockerTop5ByCpu', - hostDockerTop5ByMemory = 'hostDockerTop5ByMemory', - podOverview = 'podOverview', - podCpuUsage = 'podCpuUsage', - podMemoryUsage = 'podMemoryUsage', - podLogUsage = 'podLogUsage', - podNetworkTraffic = 'podNetworkTraffic', - containerOverview = 'containerOverview', - containerCpuKernel = 'containerCpuKernel', - containerCpuUsage = 'containerCpuUsage', - containerDiskIOOps = 'containerDiskIOOps', - containerDiskIOBytes = 'containerDiskIOBytes', - containerMemory = 'containerMemory', - containerNetworkTraffic = 'containerNetworkTraffic', - nginxHits = 'nginxHits', - nginxRequestRate = 'nginxRequestRate', - nginxActiveConnections = 'nginxActiveConnections', - nginxRequestsPerConnection = 'nginxRequestsPerConnection', - awsOverview = 'awsOverview', - awsCpuUtilization = 'awsCpuUtilization', - awsNetworkBytes = 'awsNetworkBytes', - awsNetworkPackets = 'awsNetworkPackets', - awsDiskioBytes = 'awsDiskioBytes', - awsDiskioOps = 'awsDiskioOps', - awsEC2CpuUtilization = 'awsEC2CpuUtilization', - awsEC2DiskIOBytes = 'awsEC2DiskIOBytes', - awsEC2NetworkTraffic = 'awsEC2NetworkTraffic', - awsS3TotalRequests = 'awsS3TotalRequests', - awsS3NumberOfObjects = 'awsS3NumberOfObjects', - awsS3BucketSize = 'awsS3BucketSize', - awsS3DownloadBytes = 'awsS3DownloadBytes', - awsS3UploadBytes = 'awsS3UploadBytes', - awsRDSCpuTotal = 'awsRDSCpuTotal', - awsRDSConnections = 'awsRDSConnections', - awsRDSQueriesExecuted = 'awsRDSQueriesExecuted', - awsRDSActiveTransactions = 'awsRDSActiveTransactions', - awsRDSLatency = 'awsRDSLatency', - awsSQSMessagesVisible = 'awsSQSMessagesVisible', - awsSQSMessagesDelayed = 'awsSQSMessagesDelayed', - awsSQSMessagesSent = 'awsSQSMessagesSent', - awsSQSMessagesEmpty = 'awsSQSMessagesEmpty', - awsSQSOldestMessage = 'awsSQSOldestMessage', - custom = 'custom', -} - -// ==================================================== -// Unions -// ==================================================== - -/** All known log column types */ -export type InfraSourceLogColumn = - | InfraSourceTimestampLogColumn - | InfraSourceMessageLogColumn - | InfraSourceFieldLogColumn; - -// ==================================================== -// END: Typescript template -// ==================================================== - -// ==================================================== -// Resolvers -// ==================================================== - -export namespace QueryResolvers { - export interface Resolvers { - /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source that doesn't exist doesn't error out,but returns the configured or hardcoded defaults. */ - source?: SourceResolver; - /** Get a list of all infrastructure data sources */ - allSources?: AllSourcesResolver; - } - - export type SourceResolver = Resolver< - R, - Parent, - Context, - SourceArgs - >; - export interface SourceArgs { - /** The id of the source */ - id: string; - } - - export type AllSourcesResolver< - R = InfraSource[], - Parent = never, - Context = InfraContext - > = Resolver; -} -/** A source of infrastructure data */ -export namespace InfraSourceResolvers { - export interface Resolvers { - /** The id of the source */ - id?: IdResolver; - /** The version number the source configuration was last persisted with */ - version?: VersionResolver; - /** The timestamp the source configuration was last persisted at */ - updatedAt?: UpdatedAtResolver; - /** The origin of the source (one of 'fallback', 'internal', 'stored') */ - origin?: OriginResolver; - /** The raw configuration of the source */ - configuration?: ConfigurationResolver; - /** The status of the source */ - status?: StatusResolver; - - /** A snapshot of nodes */ - snapshot?: SnapshotResolver; - - metrics?: MetricsResolver; - } - - export type IdResolver = Resolver< - R, - Parent, - Context - >; - export type VersionResolver< - R = string | null, - Parent = InfraSource, - Context = InfraContext - > = Resolver; - export type UpdatedAtResolver< - R = number | null, - Parent = InfraSource, - Context = InfraContext - > = Resolver; - export type OriginResolver = Resolver< - R, - Parent, - Context - >; - export type ConfigurationResolver< - R = InfraSourceConfiguration, - Parent = InfraSource, - Context = InfraContext - > = Resolver; - export type StatusResolver< - R = InfraSourceStatus, - Parent = InfraSource, - Context = InfraContext - > = Resolver; - - export type SnapshotResolver< - R = InfraSnapshotResponse | null, - Parent = InfraSource, - Context = InfraContext - > = Resolver; - export interface SnapshotArgs { - timerange: InfraTimerangeInput; - - filterQuery?: string | null; - } - - export type MetricsResolver< - R = InfraMetricData[], - Parent = InfraSource, - Context = InfraContext - > = Resolver; - export interface MetricsArgs { - nodeIds: InfraNodeIdsInput; - - nodeType: InfraNodeType; - - timerange: InfraTimerangeInput; - - metrics: InfraMetric[]; - } -} -/** A set of configuration options for an infrastructure data source */ -export namespace InfraSourceConfigurationResolvers { - export interface Resolvers { - /** The name of the data source */ - name?: NameResolver; - /** A description of the data source */ - description?: DescriptionResolver; - /** The alias to read metric data from */ - metricAlias?: MetricAliasResolver; - /** The alias to read log data from */ - logAlias?: LogAliasResolver; - /** The field mapping to use for this source */ - fields?: FieldsResolver; - /** The columns to use for log display */ - logColumns?: LogColumnsResolver; - } - - export type NameResolver< - R = string, - Parent = InfraSourceConfiguration, - Context = InfraContext - > = Resolver; - export type DescriptionResolver< - R = string, - Parent = InfraSourceConfiguration, - Context = InfraContext - > = Resolver; - export type MetricAliasResolver< - R = string, - Parent = InfraSourceConfiguration, - Context = InfraContext - > = Resolver; - export type LogAliasResolver< - R = string, - Parent = InfraSourceConfiguration, - Context = InfraContext - > = Resolver; - export type FieldsResolver< - R = InfraSourceFields, - Parent = InfraSourceConfiguration, - Context = InfraContext - > = Resolver; - export type LogColumnsResolver< - R = InfraSourceLogColumn[], - Parent = InfraSourceConfiguration, - Context = InfraContext - > = Resolver; -} -/** A mapping of semantic fields to their document counterparts */ -export namespace InfraSourceFieldsResolvers { - export interface Resolvers { - /** The field to identify a container by */ - container?: ContainerResolver; - /** The fields to identify a host by */ - host?: HostResolver; - /** The fields to use as the log message */ - message?: MessageResolver; - /** The field to identify a pod by */ - pod?: PodResolver; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker?: TiebreakerResolver; - /** The field to use as a timestamp for metrics and logs */ - timestamp?: TimestampResolver; - } - - export type ContainerResolver< - R = string, - Parent = InfraSourceFields, - Context = InfraContext - > = Resolver; - export type HostResolver< - R = string, - Parent = InfraSourceFields, - Context = InfraContext - > = Resolver; - export type MessageResolver< - R = string[], - Parent = InfraSourceFields, - Context = InfraContext - > = Resolver; - export type PodResolver< - R = string, - Parent = InfraSourceFields, - Context = InfraContext - > = Resolver; - export type TiebreakerResolver< - R = string, - Parent = InfraSourceFields, - Context = InfraContext - > = Resolver; - export type TimestampResolver< - R = string, - Parent = InfraSourceFields, - Context = InfraContext - > = Resolver; -} -/** The built-in timestamp log column */ -export namespace InfraSourceTimestampLogColumnResolvers { - export interface Resolvers { - timestampColumn?: TimestampColumnResolver< - InfraSourceTimestampLogColumnAttributes, - TypeParent, - Context - >; - } - - export type TimestampColumnResolver< - R = InfraSourceTimestampLogColumnAttributes, - Parent = InfraSourceTimestampLogColumn, - Context = InfraContext - > = Resolver; -} - -export namespace InfraSourceTimestampLogColumnAttributesResolvers { - export interface Resolvers< - Context = InfraContext, - TypeParent = InfraSourceTimestampLogColumnAttributes - > { - /** A unique id for the column */ - id?: IdResolver; - } - - export type IdResolver< - R = string, - Parent = InfraSourceTimestampLogColumnAttributes, - Context = InfraContext - > = Resolver; -} -/** The built-in message log column */ -export namespace InfraSourceMessageLogColumnResolvers { - export interface Resolvers { - messageColumn?: MessageColumnResolver< - InfraSourceMessageLogColumnAttributes, - TypeParent, - Context - >; - } - - export type MessageColumnResolver< - R = InfraSourceMessageLogColumnAttributes, - Parent = InfraSourceMessageLogColumn, - Context = InfraContext - > = Resolver; -} - -export namespace InfraSourceMessageLogColumnAttributesResolvers { - export interface Resolvers< - Context = InfraContext, - TypeParent = InfraSourceMessageLogColumnAttributes - > { - /** A unique id for the column */ - id?: IdResolver; - } - - export type IdResolver< - R = string, - Parent = InfraSourceMessageLogColumnAttributes, - Context = InfraContext - > = Resolver; -} -/** A log column containing a field value */ -export namespace InfraSourceFieldLogColumnResolvers { - export interface Resolvers { - fieldColumn?: FieldColumnResolver; - } - - export type FieldColumnResolver< - R = InfraSourceFieldLogColumnAttributes, - Parent = InfraSourceFieldLogColumn, - Context = InfraContext - > = Resolver; -} - -export namespace InfraSourceFieldLogColumnAttributesResolvers { - export interface Resolvers< - Context = InfraContext, - TypeParent = InfraSourceFieldLogColumnAttributes - > { - /** A unique id for the column */ - id?: IdResolver; - /** The field name this column refers to */ - field?: FieldResolver; - } - - export type IdResolver< - R = string, - Parent = InfraSourceFieldLogColumnAttributes, - Context = InfraContext - > = Resolver; - export type FieldResolver< - R = string, - Parent = InfraSourceFieldLogColumnAttributes, - Context = InfraContext - > = Resolver; -} -/** The status of an infrastructure data source */ -export namespace InfraSourceStatusResolvers { - export interface Resolvers { - /** Whether the configured metric alias exists */ - metricAliasExists?: MetricAliasExistsResolver; - /** Whether the configured log alias exists */ - logAliasExists?: LogAliasExistsResolver; - /** Whether the configured alias or wildcard pattern resolve to any metric indices */ - metricIndicesExist?: MetricIndicesExistResolver; - /** Whether the configured alias or wildcard pattern resolve to any log indices */ - logIndicesExist?: LogIndicesExistResolver; - /** The list of indices in the metric alias */ - metricIndices?: MetricIndicesResolver; - /** The list of indices in the log alias */ - logIndices?: LogIndicesResolver; - /** The list of fields defined in the index mappings */ - indexFields?: IndexFieldsResolver; - } - - export type MetricAliasExistsResolver< - R = boolean, - Parent = InfraSourceStatus, - Context = InfraContext - > = Resolver; - export type LogAliasExistsResolver< - R = boolean, - Parent = InfraSourceStatus, - Context = InfraContext - > = Resolver; - export type MetricIndicesExistResolver< - R = boolean, - Parent = InfraSourceStatus, - Context = InfraContext - > = Resolver; - export type LogIndicesExistResolver< - R = boolean, - Parent = InfraSourceStatus, - Context = InfraContext - > = Resolver; - export type MetricIndicesResolver< - R = string[], - Parent = InfraSourceStatus, - Context = InfraContext - > = Resolver; - export type LogIndicesResolver< - R = string[], - Parent = InfraSourceStatus, - Context = InfraContext - > = Resolver; - export type IndexFieldsResolver< - R = InfraIndexField[], - Parent = InfraSourceStatus, - Context = InfraContext - > = Resolver; - export interface IndexFieldsArgs { - indexType?: InfraIndexType | null; - } -} -/** A descriptor of a field in an index */ -export namespace InfraIndexFieldResolvers { - export interface Resolvers { - /** The name of the field */ - name?: NameResolver; - /** The type of the field's values as recognized by Kibana */ - type?: TypeResolver; - /** Whether the field's values can be efficiently searched for */ - searchable?: SearchableResolver; - /** Whether the field's values can be aggregated */ - aggregatable?: AggregatableResolver; - /** Whether the field should be displayed based on event.module and a ECS allowed list */ - displayable?: DisplayableResolver; - } - - export type NameResolver = Resolver< - R, - Parent, - Context - >; - export type TypeResolver = Resolver< - R, - Parent, - Context - >; - export type SearchableResolver< - R = boolean, - Parent = InfraIndexField, - Context = InfraContext - > = Resolver; - export type AggregatableResolver< - R = boolean, - Parent = InfraIndexField, - Context = InfraContext - > = Resolver; - export type DisplayableResolver< - R = boolean, - Parent = InfraIndexField, - Context = InfraContext - > = Resolver; -} - -export namespace InfraSnapshotResponseResolvers { - export interface Resolvers { - /** Nodes of type host, container or pod grouped by 0, 1 or 2 terms */ - nodes?: NodesResolver; - } - - export type NodesResolver< - R = InfraSnapshotNode[], - Parent = InfraSnapshotResponse, - Context = InfraContext - > = Resolver; - export interface NodesArgs { - type: InfraNodeType; - - groupBy: InfraSnapshotGroupbyInput[]; - - metric: InfraSnapshotMetricInput; - } -} - -export namespace InfraSnapshotNodeResolvers { - export interface Resolvers { - path?: PathResolver; - - metric?: MetricResolver; - } - - export type PathResolver< - R = InfraSnapshotNodePath[], - Parent = InfraSnapshotNode, - Context = InfraContext - > = Resolver; - export type MetricResolver< - R = InfraSnapshotNodeMetric, - Parent = InfraSnapshotNode, - Context = InfraContext - > = Resolver; -} - -export namespace InfraSnapshotNodePathResolvers { - export interface Resolvers { - value?: ValueResolver; - - label?: LabelResolver; - - ip?: IpResolver; - } - - export type ValueResolver< - R = string, - Parent = InfraSnapshotNodePath, - Context = InfraContext - > = Resolver; - export type LabelResolver< - R = string, - Parent = InfraSnapshotNodePath, - Context = InfraContext - > = Resolver; - export type IpResolver< - R = string | null, - Parent = InfraSnapshotNodePath, - Context = InfraContext - > = Resolver; -} - -export namespace InfraSnapshotNodeMetricResolvers { - export interface Resolvers { - name?: NameResolver; - - value?: ValueResolver; - - avg?: AvgResolver; - - max?: MaxResolver; - } - - export type NameResolver< - R = InfraSnapshotMetricType, - Parent = InfraSnapshotNodeMetric, - Context = InfraContext - > = Resolver; - export type ValueResolver< - R = number | null, - Parent = InfraSnapshotNodeMetric, - Context = InfraContext - > = Resolver; - export type AvgResolver< - R = number | null, - Parent = InfraSnapshotNodeMetric, - Context = InfraContext - > = Resolver; - export type MaxResolver< - R = number | null, - Parent = InfraSnapshotNodeMetric, - Context = InfraContext - > = Resolver; -} - -export namespace InfraMetricDataResolvers { - export interface Resolvers { - id?: IdResolver; - - series?: SeriesResolver; - } - - export type IdResolver< - R = InfraMetric | null, - Parent = InfraMetricData, - Context = InfraContext - > = Resolver; - export type SeriesResolver< - R = InfraDataSeries[], - Parent = InfraMetricData, - Context = InfraContext - > = Resolver; -} - -export namespace InfraDataSeriesResolvers { - export interface Resolvers { - id?: IdResolver; - - label?: LabelResolver; - - data?: DataResolver; - } - - export type IdResolver = Resolver< - R, - Parent, - Context - >; - export type LabelResolver< - R = string, - Parent = InfraDataSeries, - Context = InfraContext - > = Resolver; - export type DataResolver< - R = InfraDataPoint[], - Parent = InfraDataSeries, - Context = InfraContext - > = Resolver; -} - -export namespace InfraDataPointResolvers { - export interface Resolvers { - timestamp?: TimestampResolver; - - value?: ValueResolver; - } - - export type TimestampResolver< - R = number, - Parent = InfraDataPoint, - Context = InfraContext - > = Resolver; - export type ValueResolver< - R = number | null, - Parent = InfraDataPoint, - Context = InfraContext - > = Resolver; -} - -export namespace MutationResolvers { - export interface Resolvers { - /** Create a new source of infrastructure data */ - createSource?: CreateSourceResolver; - /** Modify an existing source */ - updateSource?: UpdateSourceResolver; - /** Delete a source of infrastructure data */ - deleteSource?: DeleteSourceResolver; - } - - export type CreateSourceResolver< - R = UpdateSourceResult, - Parent = never, - Context = InfraContext - > = Resolver; - export interface CreateSourceArgs { - /** The id of the source */ - id: string; - - sourceProperties: UpdateSourceInput; - } - - export type UpdateSourceResolver< - R = UpdateSourceResult, - Parent = never, - Context = InfraContext - > = Resolver; - export interface UpdateSourceArgs { - /** The id of the source */ - id: string; - /** The properties to update the source with */ - sourceProperties: UpdateSourceInput; - } - - export type DeleteSourceResolver< - R = DeleteSourceResult, - Parent = never, - Context = InfraContext - > = Resolver; - export interface DeleteSourceArgs { - /** The id of the source */ - id: string; - } -} -/** The result of a successful source update */ -export namespace UpdateSourceResultResolvers { - export interface Resolvers { - /** The source that was updated */ - source?: SourceResolver; - } - - export type SourceResolver< - R = InfraSource, - Parent = UpdateSourceResult, - Context = InfraContext - > = Resolver; -} -/** The result of a source deletion operations */ -export namespace DeleteSourceResultResolvers { - export interface Resolvers { - /** The id of the source that was deleted */ - id?: IdResolver; - } - - export type IdResolver< - R = string, - Parent = DeleteSourceResult, - Context = InfraContext - > = Resolver; -} diff --git a/x-pack/plugins/infra/server/infra_server.ts b/x-pack/plugins/infra/server/infra_server.ts index b510519a4fd0..6ce5d5b8c53e 100644 --- a/x-pack/plugins/infra/server/infra_server.ts +++ b/x-pack/plugins/infra/server/infra_server.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IResolvers, makeExecutableSchema } from 'graphql-tools'; import { initIpToHostName } from './routes/ip_to_hostname'; -import { schemas } from './graphql'; -import { createSourceStatusResolvers } from './graphql/source_status'; -import { createSourcesResolvers } from './graphql/sources'; import { InfraBackendLibs } from './lib/infra_types'; import { initGetLogEntryCategoriesRoute, @@ -44,16 +40,6 @@ import { initGetLogAlertsChartPreviewDataRoute } from './routes/log_alerts'; import { initProcessListRoute } from './routes/process_list'; export const initInfraServer = (libs: InfraBackendLibs) => { - const schema = makeExecutableSchema({ - resolvers: [ - createSourcesResolvers(libs) as IResolvers, - createSourceStatusResolvers(libs) as IResolvers, - ], - typeDefs: schemas, - }); - - libs.framework.registerGraphQLEndpoint('/graphql', schema); - initIpToHostName(libs); initGetLogEntryCategoriesRoute(libs); initGetLogEntryCategoryDatasetsRoute(libs); diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts index b96b0e5bb0b4..6c83dae32912 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -4,9 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { GraphQLSchema } from 'graphql'; -import { runHttpQuery } from 'apollo-server-core'; -import { schema, TypeOf } from '@kbn/config-schema'; import { InfraRouteConfig, InfraTSVBResponse, @@ -23,7 +20,6 @@ import { CoreSetup, IRouter, KibanaRequest, - KibanaResponseFactory, RouteMethod, } from '../../../../../../../src/core/server'; import { RequestHandler } from '../../../../../../../src/core/server'; @@ -73,79 +69,6 @@ export class KibanaFramework { } } - public registerGraphQLEndpoint(routePath: string, gqlSchema: GraphQLSchema) { - // These endpoints are validated by GraphQL at runtime and with GraphQL generated types - const body = schema.object({}, { unknowns: 'allow' }); - type Body = TypeOf; - - const routeOptions = { - path: `/api/infra${routePath}`, - validate: { - body, - }, - options: { - tags: ['access:infra'], - }, - }; - async function handler( - context: InfraPluginRequestHandlerContext, - request: KibanaRequest, - response: KibanaResponseFactory - ) { - try { - const query = - request.route.method === 'post' - ? (request.body as Record) - : (request.query as Record); - - const gqlResponse = await runHttpQuery([context, request], { - method: request.route.method.toUpperCase(), - options: (req: InfraPluginRequestHandlerContext, rawReq: KibanaRequest) => ({ - context: { req, rawReq }, - schema: gqlSchema, - }), - query, - }); - - return response.ok({ - body: gqlResponse, - headers: { - 'content-type': 'application/json', - }, - }); - } catch (error) { - const errorBody = { - message: error.message, - }; - - if ('HttpQueryError' !== error.name) { - return response.internalError({ - body: errorBody, - }); - } - - if (error.isGraphQLError === true) { - return response.customError({ - statusCode: error.statusCode, - body: errorBody, - headers: { - 'Content-Type': 'application/json', - }, - }); - } - - const { headers = [], statusCode = 500 } = error; - return response.customError({ - statusCode, - headers, - body: errorBody, - }); - } - } - this.router.post(routeOptions, handler); - this.router.get(routeOptions, handler); - } - callWithRequest( requestContext: InfraPluginRequestHandlerContext, endpoint: 'search', @@ -187,7 +110,7 @@ export class KibanaFramework { options?: CallWithRequestParams ): Promise; - public async callWithRequest( + public async callWithRequest( requestContext: InfraPluginRequestHandlerContext, endpoint: string, params: CallWithRequestParams diff --git a/x-pack/plugins/infra/server/lib/adapters/metrics/lib/errors.ts b/x-pack/plugins/infra/server/lib/adapters/metrics/lib/errors.ts deleted file mode 100644 index 750858f3ce1f..000000000000 --- a/x-pack/plugins/infra/server/lib/adapters/metrics/lib/errors.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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 { ApolloError } from 'apollo-server-errors'; -import { InfraMetricsErrorCodes } from '../../../../../common/errors'; - -export class InvalidNodeError extends ApolloError { - constructor(message: string) { - super(message, InfraMetricsErrorCodes.invalid_node); - Object.defineProperty(this, 'name', { value: 'InvalidNodeError' }); - } -} diff --git a/x-pack/plugins/infra/server/lib/domains/fields_domain.ts b/x-pack/plugins/infra/server/lib/domains/fields_domain.ts index a8bd09c28f94..3b0a1c61f6af 100644 --- a/x-pack/plugins/infra/server/lib/domains/fields_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/fields_domain.ts @@ -5,9 +5,8 @@ */ import type { InfraPluginRequestHandlerContext } from '../../types'; -import { InfraIndexField, InfraIndexType } from '../../graphql/types'; import { FieldsAdapter } from '../adapters/fields'; -import { InfraSources } from '../sources'; +import { InfraSourceIndexField, InfraSources } from '../sources'; export class InfraFieldsDomain { constructor( @@ -18,14 +17,14 @@ export class InfraFieldsDomain { public async getFields( requestContext: InfraPluginRequestHandlerContext, sourceId: string, - indexType: InfraIndexType - ): Promise { + indexType: 'LOGS' | 'METRICS' | 'ANY' + ): Promise { const { configuration } = await this.libs.sources.getSourceConfiguration( requestContext.core.savedObjects.client, sourceId ); - const includeMetricIndices = [InfraIndexType.ANY, InfraIndexType.METRICS].includes(indexType); - const includeLogIndices = [InfraIndexType.ANY, InfraIndexType.LOGS].includes(indexType); + const includeMetricIndices = ['ANY', 'METRICS'].includes(indexType); + const includeLogIndices = ['ANY', 'LOGS'].includes(indexType); const fields = await this.adapter.getIndexFields( requestContext, diff --git a/x-pack/plugins/infra/server/lib/infra_types.ts b/x-pack/plugins/infra/server/lib/infra_types.ts index 084ece52302b..eb24efb84645 100644 --- a/x-pack/plugins/infra/server/lib/infra_types.ts +++ b/x-pack/plugins/infra/server/lib/infra_types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InfraSourceConfiguration } from '../../common/graphql/types'; +import { InfraSourceConfiguration } from '../../common/http_api/source_api'; import { InfraFieldsDomain } from './domains/fields_domain'; import { InfraLogEntriesDomain } from './domains/log_entries_domain'; import { InfraMetricsDomain } from './domains/metrics_domain'; @@ -13,13 +13,6 @@ import { InfraSourceStatus } from './source_status'; import { InfraConfig } from '../plugin'; import { KibanaFramework } from './adapters/framework/kibana_framework_adapter'; -// NP_TODO: We shouldn't need this context anymore but I am -// not sure how the graphql stuff uses it, so we can't remove it yet -export interface InfraContext { - req: any; - rawReq?: any; -} - export interface InfraDomainLibs { fields: InfraFieldsDomain; logEntries: InfraLogEntriesDomain; diff --git a/x-pack/plugins/infra/server/routes/log_sources/status.ts b/x-pack/plugins/infra/server/routes/log_sources/status.ts index e9466f7fa887..71a91e44669d 100644 --- a/x-pack/plugins/infra/server/routes/log_sources/status.ts +++ b/x-pack/plugins/infra/server/routes/log_sources/status.ts @@ -11,7 +11,6 @@ import { LOG_SOURCE_STATUS_PATH, } from '../../../common/http_api/log_sources'; import { createValidationFunction } from '../../../common/runtime_types'; -import { InfraIndexType } from '../../graphql/types'; import { InfraBackendLibs } from '../../lib/infra_types'; export const initLogSourceStatusRoutes = ({ @@ -34,7 +33,7 @@ export const initLogSourceStatusRoutes = ({ const logIndexStatus = await sourceStatus.getLogIndexStatus(requestContext, sourceId); const logIndexFields = logIndexStatus !== 'missing' - ? await fields.getFields(requestContext, sourceId, InfraIndexType.LOGS) + ? await fields.getFields(requestContext, sourceId, 'LOGS') : []; return response.ok({ diff --git a/x-pack/plugins/infra/server/routes/source/index.ts b/x-pack/plugins/infra/server/routes/source/index.ts index 9ff3902f1eae..31d309c6295f 100644 --- a/x-pack/plugins/infra/server/routes/source/index.ts +++ b/x-pack/plugins/infra/server/routes/source/index.ts @@ -4,20 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ import { schema } from '@kbn/config-schema'; -import { SourceResponseRuntimeType } from '../../../common/http_api/source_api'; +import Boom from '@hapi/boom'; +import { createValidationFunction } from '../../../common/runtime_types'; +import { + InfraSourceStatus, + SavedSourceConfigurationRuntimeType, + SourceResponseRuntimeType, +} from '../../../common/http_api/source_api'; import { InfraBackendLibs } from '../../lib/infra_types'; -import { InfraIndexType } from '../../graphql/types'; import { hasData } from '../../lib/sources/has_data'; import { createSearchClient } from '../../lib/create_search_client'; const typeToInfraIndexType = (value: string | undefined) => { switch (value) { case 'metrics': - return InfraIndexType.METRICS; + return 'METRICS'; case 'logs': - return InfraIndexType.LOGS; + return 'LOGS'; default: - return InfraIndexType.ANY; + return 'ANY'; } }; @@ -50,14 +55,14 @@ export const initSourceRoute = (libs: InfraBackendLibs) => { return response.notFound(); } - const status = { + const status: InfraSourceStatus = { logIndicesExist: logIndexStatus !== 'missing', metricIndicesExist, indexFields, }; return response.ok({ - body: SourceResponseRuntimeType.encode({ source, status }), + body: SourceResponseRuntimeType.encode({ source: { ...source, status } }), }); } catch (error) { return response.internalError({ @@ -67,6 +72,79 @@ export const initSourceRoute = (libs: InfraBackendLibs) => { } ); + framework.registerRoute( + { + method: 'patch', + path: '/api/metrics/source/{sourceId}', + validate: { + params: schema.object({ + sourceId: schema.string(), + }), + body: createValidationFunction(SavedSourceConfigurationRuntimeType), + }, + }, + framework.router.handleLegacyErrors(async (requestContext, request, response) => { + const { sources } = libs; + const { sourceId } = request.params; + const patchedSourceConfigurationProperties = request.body; + + try { + const sourceConfiguration = await sources.getSourceConfiguration( + requestContext.core.savedObjects.client, + sourceId + ); + + if (sourceConfiguration.origin === 'internal') { + response.conflict({ + body: 'A conflicting read-only source configuration already exists.', + }); + } + + const sourceConfigurationExists = sourceConfiguration.origin === 'stored'; + const patchedSourceConfiguration = await (sourceConfigurationExists + ? sources.updateSourceConfiguration( + requestContext.core.savedObjects.client, + sourceId, + patchedSourceConfigurationProperties + ) + : sources.createSourceConfiguration( + requestContext.core.savedObjects.client, + sourceId, + patchedSourceConfigurationProperties + )); + + const [logIndexStatus, metricIndicesExist, indexFields] = await Promise.all([ + libs.sourceStatus.getLogIndexStatus(requestContext, sourceId), + libs.sourceStatus.hasMetricIndices(requestContext, sourceId), + libs.fields.getFields(requestContext, sourceId, typeToInfraIndexType('metrics')), + ]); + + const status: InfraSourceStatus = { + logIndicesExist: logIndexStatus !== 'missing', + metricIndicesExist, + indexFields, + }; + + return response.ok({ + body: SourceResponseRuntimeType.encode({ + source: { ...patchedSourceConfiguration, status }, + }), + }); + } catch (error) { + if (Boom.isBoom(error)) { + throw error; + } + + return response.customError({ + statusCode: error.statusCode ?? 500, + body: { + message: error.message ?? 'An unexpected error occurred', + }, + }); + } + }) + ); + framework.registerRoute( { method: 'get', diff --git a/x-pack/plugins/infra/server/utils/serialized_query.ts b/x-pack/plugins/infra/server/utils/serialized_query.ts index 8dfe00fcd380..3a38a0de959d 100644 --- a/x-pack/plugins/infra/server/utils/serialized_query.ts +++ b/x-pack/plugins/infra/server/utils/serialized_query.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { UserInputError } from 'apollo-server-errors'; - import { JsonObject } from '../../../../../src/plugins/kibana_utils/common'; export const parseFilterQuery = ( @@ -26,9 +24,6 @@ export const parseFilterQuery = ( return undefined; } } catch (err) { - throw new UserInputError(`Failed to parse query: ${err}`, { - query: filterQuery, - originalError: err, - }); + throw new Error(`Failed to parse query: ${err}`); } }; diff --git a/x-pack/plugins/infra/server/utils/typed_resolvers.ts b/x-pack/plugins/infra/server/utils/typed_resolvers.ts deleted file mode 100644 index d5f2d00abd50..000000000000 --- a/x-pack/plugins/infra/server/utils/typed_resolvers.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 { Resolver } from '../graphql/types'; - -type ResolverResult = R | Promise; - -type InfraResolverResult = - | Promise - | Promise<{ [P in keyof R]: () => Promise }> - | { [P in keyof R]: () => Promise } - | { [P in keyof R]: () => R[P] } - | R; - -export type ResultOf = Resolver_ extends Resolver> - ? Result - : never; - -export type SubsetResolverWithFields = R extends Resolver< - Array, - infer ParentInArray, - infer ContextInArray, - infer ArgsInArray -> - ? Resolver< - Array>>, - ParentInArray, - ContextInArray, - ArgsInArray - > - : R extends Resolver - ? Resolver>, Parent, Context, Args> - : never; - -export type SubsetResolverWithoutFields = R extends Resolver< - Array, - infer ParentInArray, - infer ContextInArray, - infer ArgsInArray -> - ? Resolver< - Array>>, - ParentInArray, - ContextInArray, - ArgsInArray - > - : R extends Resolver - ? Resolver>, Parent, Context, Args> - : never; - -export type ResolverWithParent = Resolver_ extends Resolver< - infer Result, - any, - infer Context, - infer Args -> - ? Resolver - : never; - -export type InfraResolver = Resolver< - InfraResolverResult, - Parent, - Context, - Args ->; - -export type InfraResolverOf = Resolver_ extends Resolver< - ResolverResult, - never, - infer ContextWithNeverParent, - infer ArgsWithNeverParent -> - ? InfraResolver - : Resolver_ extends Resolver< - ResolverResult, - infer Parent, - infer Context, - infer Args - > - ? InfraResolver - : never; - -export type InfraResolverWithFields = InfraResolverOf< - SubsetResolverWithFields ->; - -export type InfraResolverWithoutFields = InfraResolverOf< - SubsetResolverWithoutFields ->; - -export type ChildResolverOf = ResolverWithParent< - Resolver_, - ResultOf ->; diff --git a/x-pack/plugins/infra/types/graphql_fields.d.ts b/x-pack/plugins/infra/types/graphql_fields.d.ts deleted file mode 100644 index 5e5320a31b3b..000000000000 --- a/x-pack/plugins/infra/types/graphql_fields.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * 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. - */ - -declare module 'graphql-fields' { - function graphqlFields(info: any, obj?: any): any; - // eslint-disable-next-line import/no-default-export - export default graphqlFields; -} diff --git a/x-pack/test/api_integration/apis/metrics_ui/feature_controls.ts b/x-pack/test/api_integration/apis/metrics_ui/feature_controls.ts deleted file mode 100644 index d2b155984378..000000000000 --- a/x-pack/test/api_integration/apis/metrics_ui/feature_controls.ts +++ /dev/null @@ -1,252 +0,0 @@ -/* - * 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 expect from '@kbn/expect'; -import gql from 'graphql-tag'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -const introspectionQuery = gql` - query Schema { - __schema { - queryType { - name - } - } - } -`; - -export default function ({ getService }: FtrProviderContext) { - const security = getService('security'); - const spaces = getService('spaces'); - const clientFactory = getService('infraOpsGraphQLClientFactory'); - - const expectGraphQL403 = (result: any) => { - expect(result.response).to.be(undefined); - expect(result.error).not.to.be(undefined); - expect(result.error).to.have.property('networkError'); - expect(result.error.networkError).to.have.property('statusCode', 403); - }; - - const expectGraphQLResponse = (result: any) => { - expect(result.error).to.be(undefined); - expect(result.response).to.have.property('data'); - expect(result.response.data).to.be.an('object'); - }; - - const executeGraphQLQuery = async (username: string, password: string, spaceId?: string) => { - const queryOptions = { - query: introspectionQuery, - }; - - const basePath = spaceId ? `/s/${spaceId}` : ''; - - const client = clientFactory({ username, password, basePath }); - let error; - let response; - try { - response = await client.query(queryOptions); - } catch (err) { - error = err; - } - return { - error, - response, - }; - }; - - describe('feature controls', () => { - it(`APIs can't be accessed by user with logstash-* "read" privileges`, async () => { - const username = 'logstash_read'; - const roleName = 'logstash_read'; - const password = `${username}-password`; - try { - await security.role.create(roleName, { - elasticsearch: { - indices: [ - { - names: ['logstash-*'], - privileges: ['read', 'view_index_metadata'], - }, - ], - }, - }); - - await security.user.create(username, { - password, - roles: [roleName], - full_name: 'a kibana user', - }); - - const graphQLResult = await executeGraphQLQuery(username, password); - expectGraphQL403(graphQLResult); - } finally { - await security.role.delete(roleName); - await security.user.delete(username); - } - }); - - it('APIs can be accessed user with global "all" and logstash-* "read" privileges', async () => { - const username = 'global_all'; - const roleName = 'global_all'; - const password = `${username}-password`; - try { - await security.role.create(roleName, { - elasticsearch: { - indices: [ - { - names: ['logstash-*'], - privileges: ['read', 'view_index_metadata'], - }, - ], - }, - kibana: [ - { - base: ['all'], - spaces: ['*'], - }, - ], - }); - - await security.user.create(username, { - password, - roles: [roleName], - full_name: 'a kibana user', - }); - - const graphQLResult = await executeGraphQLQuery(username, password); - expectGraphQLResponse(graphQLResult); - } finally { - await security.role.delete(roleName); - await security.user.delete(username); - } - }); - - // this could be any role which doesn't have access to the infra feature - it(`APIs can't be accessed by user with dashboard "all" and logstash-* "read" privileges`, async () => { - const username = 'dashboard_all'; - const roleName = 'dashboard_all'; - const password = `${username}-password`; - try { - await security.role.create(roleName, { - elasticsearch: { - indices: [ - { - names: ['logstash-*'], - privileges: ['read', 'view_index_metadata'], - }, - ], - }, - kibana: [ - { - feature: { - dashboard: ['all'], - }, - spaces: ['*'], - }, - ], - }); - - await security.user.create(username, { - password, - roles: [roleName], - full_name: 'a kibana user', - }); - - const graphQLResult = await executeGraphQLQuery(username, password); - expectGraphQL403(graphQLResult); - } finally { - await security.role.delete(roleName); - await security.user.delete(username); - } - }); - - describe('spaces', () => { - // the following tests create a user_1 which has infrastructure read access to space_1, logs read access to space_2 and dashboard all access to space_3 - const space1Id = 'space_1'; - const space2Id = 'space_2'; - const space3Id = 'space_3'; - - const roleName = 'user_1'; - const username = 'user_1'; - const password = 'user_1-password'; - - before(async () => { - await spaces.create({ - id: space1Id, - name: space1Id, - disabledFeatures: [], - }); - await spaces.create({ - id: space2Id, - name: space2Id, - disabledFeatures: [], - }); - await spaces.create({ - id: space3Id, - name: space3Id, - disabledFeatures: [], - }); - await security.role.create(roleName, { - elasticsearch: { - indices: [ - { - names: ['logstash-*'], - privileges: ['read', 'view_index_metadata'], - }, - ], - }, - kibana: [ - { - feature: { - infrastructure: ['read'], - }, - spaces: [space1Id], - }, - { - feature: { - logs: ['read'], - }, - spaces: [space2Id], - }, - { - feature: { - dashboard: ['all'], - }, - spaces: [space3Id], - }, - ], - }); - await security.user.create(username, { - password, - roles: [roleName], - }); - }); - - after(async () => { - await spaces.delete(space1Id); - await spaces.delete(space2Id); - await spaces.delete(space3Id); - await security.role.delete(roleName); - await security.user.delete(username); - }); - - it('user_1 can access APIs in space_1', async () => { - const graphQLResult = await executeGraphQLQuery(username, password, space1Id); - expectGraphQLResponse(graphQLResult); - }); - - it(`user_1 can access APIs in space_2`, async () => { - const graphQLResult = await executeGraphQLQuery(username, password, space2Id); - expectGraphQLResponse(graphQLResult); - }); - - it(`user_1 can't access APIs in space_3`, async () => { - const graphQLResult = await executeGraphQLQuery(username, password, space3Id); - expectGraphQL403(graphQLResult); - }); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/metrics_ui/http_source.ts b/x-pack/test/api_integration/apis/metrics_ui/http_source.ts index 7e92caf0e37d..16816f2ce90a 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/http_source.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/http_source.ts @@ -34,7 +34,7 @@ export default function ({ getService }: FtrProviderContext) { before(() => esArchiver.load('infra/8.0.0/logs_and_metrics')); after(() => esArchiver.unload('infra/8.0.0/logs_and_metrics')); describe('/api/metrics/source/default/metrics', () => { - it('should just work', () => { + it('should just work', async () => { const resp = fetchSource(); return resp.then((data) => { expect(data).to.have.property('source'); @@ -50,14 +50,14 @@ export default function ({ getService }: FtrProviderContext) { tiebreaker: '_doc', timestamp: '@timestamp', }); - expect(data).to.have.property('status'); - expect(data?.status.metricIndicesExist).to.equal(true); - expect(data?.status.logIndicesExist).to.equal(true); + expect(data?.source).to.have.property('status'); + expect(data?.source.status?.metricIndicesExist).to.equal(true); + expect(data?.source.status?.logIndicesExist).to.equal(true); }); }); }); describe('/api/metrics/source/default/metrics/hasData', () => { - it('should just work', () => { + it('should just work', async () => { const resp = fetchHasData('metrics'); return resp.then((data) => { expect(data).to.have.property('hasData'); @@ -66,7 +66,7 @@ export default function ({ getService }: FtrProviderContext) { }); }); describe('/api/metrics/source/default/logs/hasData', () => { - it('should just work', () => { + it('should just work', async () => { const resp = fetchHasData('logs'); return resp.then((data) => { expect(data).to.have.property('hasData'); diff --git a/x-pack/test/api_integration/apis/metrics_ui/index.js b/x-pack/test/api_integration/apis/metrics_ui/index.js index 819a2d35b92a..47e688f09c78 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/index.js +++ b/x-pack/test/api_integration/apis/metrics_ui/index.js @@ -18,7 +18,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./snapshot')); loadTestFile(require.resolve('./metrics_alerting')); loadTestFile(require.resolve('./metrics_explorer')); - loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./ip_to_hostname')); loadTestFile(require.resolve('./http_source')); }); diff --git a/x-pack/test/api_integration/apis/metrics_ui/metadata.ts b/x-pack/test/api_integration/apis/metrics_ui/metadata.ts index e319e59045d2..e8bd547b3143 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/metadata.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/metadata.ts @@ -5,7 +5,6 @@ */ import expect from '@kbn/expect'; -import { InfraNodeType } from '../../../../plugins/infra/server/graphql/types'; import { InfraMetadata, InfraMetadataRequest, @@ -50,7 +49,7 @@ export default function ({ getService }: FtrProviderContext) { const metadata = await fetchMetadata({ sourceId: 'default', nodeId: 'demo-stack-mysql-01', - nodeType: InfraNodeType.host, + nodeType: 'host', timeRange: timeRange700, }); if (metadata) { @@ -70,7 +69,7 @@ export default function ({ getService }: FtrProviderContext) { const metadata = await fetchMetadata({ sourceId: 'default', nodeId: '631f36a845514442b93c3fdd2dc91bcd8feb680b8ac5832c7fb8fdc167bb938e', - nodeType: InfraNodeType.container, + nodeType: 'container', timeRange: timeRange660, }); if (metadata) { @@ -92,7 +91,7 @@ export default function ({ getService }: FtrProviderContext) { const metadata = await fetchMetadata({ sourceId: 'default', nodeId: 'gke-observability-8--observability-8--bc1afd95-f0zc', - nodeType: InfraNodeType.host, + nodeType: 'host', timeRange: timeRange800withAws, }); if (metadata) { @@ -140,7 +139,7 @@ export default function ({ getService }: FtrProviderContext) { const metadata = await fetchMetadata({ sourceId: 'default', nodeId: 'ip-172-31-47-9.us-east-2.compute.internal', - nodeType: InfraNodeType.host, + nodeType: 'host', timeRange: timeRange800withAws, }); if (metadata) { @@ -189,7 +188,7 @@ export default function ({ getService }: FtrProviderContext) { const metadata = await fetchMetadata({ sourceId: 'default', nodeId: '14887487-99f8-11e9-9a96-42010a84004d', - nodeType: InfraNodeType.pod, + nodeType: 'pod', timeRange: timeRange800withAws, }); if (metadata) { @@ -242,7 +241,7 @@ export default function ({ getService }: FtrProviderContext) { const metadata = await fetchMetadata({ sourceId: 'default', nodeId: 'c74b04834c6d7cc1800c3afbe31d0c8c0c267f06e9eb45c2b0c2df3e6cee40c5', - nodeType: InfraNodeType.container, + nodeType: 'container', timeRange: timeRange800withAws, }); if (metadata) { diff --git a/x-pack/test/api_integration/apis/metrics_ui/metrics.ts b/x-pack/test/api_integration/apis/metrics_ui/metrics.ts index b9cbc58bbd6f..e7cf2962cb31 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/metrics.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/metrics.ts @@ -7,8 +7,8 @@ import expect from '@kbn/expect'; import { first, last } from 'lodash'; +import { InfraTimerangeInput } from '../../../../plugins/infra/common/http_api/snapshot_api'; import { InventoryMetric } from '../../../../plugins/infra/common/inventory_models/types'; -import { InfraNodeType, InfraTimerangeInput } from '../../../../plugins/infra/public/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; import { DATES } from './constants'; @@ -19,7 +19,7 @@ const { min, max } = DATES['7.0.0'].hosts; interface NodeDetailsRequest { metrics: InventoryMetric[]; nodeId: string; - nodeType: InfraNodeType; + nodeType: string; sourceId: string; timerange: InfraTimerangeInput; cloudId?: string; @@ -44,7 +44,7 @@ export default function ({ getService }: FtrProviderContext) { return response.body; }; - it('should basically work', () => { + it('should basically work', async () => { const data = fetchNodeDetails({ sourceId: 'default', metrics: ['hostCpuUsage'], @@ -54,7 +54,7 @@ export default function ({ getService }: FtrProviderContext) { interval: '>=1m', }, nodeId: 'demo-stack-mysql-01', - nodeType: 'host' as InfraNodeType, + nodeType: 'host', }); return data.then((resp) => { if (!resp) { @@ -73,7 +73,7 @@ export default function ({ getService }: FtrProviderContext) { }); }); - it('should support multiple metrics', () => { + it('should support multiple metrics', async () => { const data = fetchNodeDetails({ sourceId: 'default', metrics: ['hostCpuUsage', 'hostLoad'], @@ -83,7 +83,7 @@ export default function ({ getService }: FtrProviderContext) { interval: '>=1m', }, nodeId: 'demo-stack-mysql-01', - nodeType: 'host' as InfraNodeType, + nodeType: 'host', }); return data.then((resp) => { if (!resp) { @@ -104,7 +104,7 @@ export default function ({ getService }: FtrProviderContext) { interval: '>=1m', }, nodeId: 'demo-stack-mysql-01', - nodeType: 'host' as InfraNodeType, + nodeType: 'host', }); return data.then((resp) => { if (!resp) { diff --git a/x-pack/test/api_integration/apis/metrics_ui/snapshot.ts b/x-pack/test/api_integration/apis/metrics_ui/snapshot.ts index 7339c142fb02..26048f25d55f 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/snapshot.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/snapshot.ts @@ -7,10 +7,6 @@ import expect from '@kbn/expect'; import { first, last } from 'lodash'; -import { - InfraSnapshotMetricInput, - InfraNodeType, -} from '../../../../plugins/infra/server/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; import { SnapshotNodeResponse, @@ -39,7 +35,7 @@ export default function ({ getService }: FtrProviderContext) { before(() => esArchiver.load('infra/6.6.0/docker')); after(() => esArchiver.unload('infra/6.6.0/docker')); - it('should basically work', () => { + it('should basically work', async () => { const resp = fetchSnapshot({ sourceId: 'default', timerange: { @@ -47,8 +43,8 @@ export default function ({ getService }: FtrProviderContext) { from: min, interval: '1m', }, - metrics: [{ type: 'cpu' }] as InfraSnapshotMetricInput[], - nodeType: 'container' as InfraNodeType, + metrics: [{ type: 'cpu' }], + nodeType: 'container', groupBy: [], }); return resp.then((data) => { @@ -86,7 +82,7 @@ export default function ({ getService }: FtrProviderContext) { before(() => esArchiver.load('infra/8.0.0/logs_and_metrics')); after(() => esArchiver.unload('infra/8.0.0/logs_and_metrics')); - it("should use the id for the label when the name doesn't exist", () => { + it("should use the id for the label when the name doesn't exist", async () => { const resp = fetchSnapshot({ sourceId: 'default', timerange: { @@ -94,8 +90,8 @@ export default function ({ getService }: FtrProviderContext) { from: min, interval: '1m', }, - metrics: [{ type: 'cpu' }] as InfraSnapshotMetricInput[], - nodeType: 'pod' as InfraNodeType, + metrics: [{ type: 'cpu' }], + nodeType: 'pod', groupBy: [], }); return resp.then((data) => { @@ -118,7 +114,7 @@ export default function ({ getService }: FtrProviderContext) { } }); }); - it('should have an id and label', () => { + it('should have an id and label', async () => { const resp = fetchSnapshot({ sourceId: 'default', timerange: { @@ -126,8 +122,8 @@ export default function ({ getService }: FtrProviderContext) { from: min, interval: '1m', }, - metrics: [{ type: 'cpu' }] as InfraSnapshotMetricInput[], - nodeType: 'container' as InfraNodeType, + metrics: [{ type: 'cpu' }], + nodeType: 'container', groupBy: [], }); return resp.then((data) => { @@ -157,7 +153,7 @@ export default function ({ getService }: FtrProviderContext) { before(() => esArchiver.load('infra/7.0.0/hosts')); after(() => esArchiver.unload('infra/7.0.0/hosts')); - it('should basically work', () => { + it('should basically work', async () => { const resp = fetchSnapshot({ sourceId: 'default', timerange: { @@ -165,8 +161,8 @@ export default function ({ getService }: FtrProviderContext) { from: min, interval: '1m', }, - metrics: [{ type: 'cpu' }] as InfraSnapshotMetricInput[], - nodeType: 'host' as InfraNodeType, + metrics: [{ type: 'cpu' }], + nodeType: 'host', groupBy: [], }); return resp.then((data) => { @@ -193,7 +189,7 @@ export default function ({ getService }: FtrProviderContext) { }); }); - it('should allow for overrides for interval and ignoring lookback', () => { + it('should allow for overrides for interval and ignoring lookback', async () => { const resp = fetchSnapshot({ sourceId: 'default', timerange: { @@ -203,8 +199,8 @@ export default function ({ getService }: FtrProviderContext) { forceInterval: true, ignoreLookback: true, }, - metrics: [{ type: 'cpu' }] as InfraSnapshotMetricInput[], - nodeType: 'host' as InfraNodeType, + metrics: [{ type: 'cpu' }], + nodeType: 'host', groupBy: [], includeTimeseries: true, }); @@ -229,7 +225,7 @@ export default function ({ getService }: FtrProviderContext) { }); }); - it('should allow for overrides for lookback', () => { + it('should allow for overrides for lookback', async () => { const resp = fetchSnapshot({ sourceId: 'default', timerange: { @@ -238,8 +234,8 @@ export default function ({ getService }: FtrProviderContext) { interval: '1m', lookbackSize: 6, }, - metrics: [{ type: 'cpu' }] as InfraSnapshotMetricInput[], - nodeType: 'host' as InfraNodeType, + metrics: [{ type: 'cpu' }], + nodeType: 'host', groupBy: [], includeTimeseries: true, }); @@ -277,7 +273,7 @@ export default function ({ getService }: FtrProviderContext) { id: '1', }, ] as SnapshotMetricInput[], - nodeType: 'host' as InfraNodeType, + nodeType: 'host', groupBy: [], }); @@ -303,7 +299,7 @@ export default function ({ getService }: FtrProviderContext) { } }); - it('should basically work with 1 grouping', () => { + it('should basically work with 1 grouping', async () => { const resp = fetchSnapshot({ sourceId: 'default', timerange: { @@ -311,8 +307,8 @@ export default function ({ getService }: FtrProviderContext) { from: min, interval: '1m', }, - metrics: [{ type: 'cpu' }] as InfraSnapshotMetricInput[], - nodeType: 'host' as InfraNodeType, + metrics: [{ type: 'cpu' }], + nodeType: 'host', groupBy: [{ field: 'cloud.availability_zone' }], }); return resp.then((data) => { @@ -330,7 +326,7 @@ export default function ({ getService }: FtrProviderContext) { }); }); - it('should basically work with 2 groupings', () => { + it('should basically work with 2 groupings', async () => { const resp = fetchSnapshot({ sourceId: 'default', timerange: { @@ -338,8 +334,8 @@ export default function ({ getService }: FtrProviderContext) { from: min, interval: '1m', }, - metrics: [{ type: 'cpu' }] as InfraSnapshotMetricInput[], - nodeType: 'host' as InfraNodeType, + metrics: [{ type: 'cpu' }], + nodeType: 'host', groupBy: [{ field: 'cloud.provider' }, { field: 'cloud.availability_zone' }], }); @@ -359,7 +355,7 @@ export default function ({ getService }: FtrProviderContext) { }); }); - it('should show metrics for all nodes when grouping by service type', () => { + it('should show metrics for all nodes when grouping by service type', async () => { const resp = fetchSnapshot({ sourceId: 'default', timerange: { @@ -367,8 +363,8 @@ export default function ({ getService }: FtrProviderContext) { from: min, interval: '1m', }, - metrics: [{ type: 'cpu' }] as InfraSnapshotMetricInput[], - nodeType: 'host' as InfraNodeType, + metrics: [{ type: 'cpu' }], + nodeType: 'host', groupBy: [{ field: 'service.type' }], }); return resp.then((data) => { diff --git a/x-pack/test/api_integration/apis/metrics_ui/sources.ts b/x-pack/test/api_integration/apis/metrics_ui/sources.ts index 5908523af249..d18ce882cab7 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/sources.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/sources.ts @@ -5,20 +5,27 @@ */ import expect from '@kbn/expect'; -import gql from 'graphql-tag'; -import { sourceQuery } from '../../../../plugins/infra/public/containers/source/query_source.gql_query'; import { - sourceConfigurationFieldsFragment, - sourceStatusFieldsFragment, -} from '../../../../plugins/infra/public/containers/source/source_fields_fragment.gql_query'; -import { SourceQuery } from '../../../../plugins/infra/public/graphql/types'; + SourceResponse, + InfraSavedSourceConfiguration, + SourceResponseRuntimeType, +} from '../../../../plugins/infra/common/http_api/source_api'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { sharedFragments } from '../../../../plugins/infra/common/graphql/shared'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('infraOpsGraphQLClient'); + const supertest = getService('supertest'); + const patchRequest = async ( + body: InfraSavedSourceConfiguration + ): Promise => { + const response = await supertest + .patch('/api/metrics/source/default') + .set('kbn-xsrf', 'xxx') + .send(body) + .expect(200); + return response.body; + }; describe('sources', () => { before(() => esArchiver.load('infra/metrics_and_logs')); @@ -26,409 +33,145 @@ export default function ({ getService }: FtrProviderContext) { beforeEach(() => esArchiver.load('empty_kibana')); afterEach(() => esArchiver.unload('empty_kibana')); - describe('query from container', () => { - it('returns the default source configuration when none has been saved', async () => { - const response = await client.query({ - query: sourceQuery, - variables: { - sourceId: 'default', - }, - }); - - const sourceConfiguration = response.data.source.configuration; - const sourceStatus = response.data.source.status; - - // shipped default values - expect(sourceConfiguration.name).to.be('Default'); - expect(sourceConfiguration.metricAlias).to.be('metrics-*,metricbeat-*'); - expect(sourceConfiguration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); - expect(sourceConfiguration.fields.container).to.be('container.id'); - expect(sourceConfiguration.fields.host).to.be('host.name'); - expect(sourceConfiguration.fields.pod).to.be('kubernetes.pod.uid'); - expect(sourceConfiguration.logColumns).to.have.length(3); - expect(sourceConfiguration.logColumns[0]).to.have.key('timestampColumn'); - expect(sourceConfiguration.logColumns[1]).to.have.key('fieldColumn'); - expect(sourceConfiguration.logColumns[2]).to.have.key('messageColumn'); - - // test data in x-pack/test/functional/es_archives/infra/data.json.gz - expect(sourceStatus.indexFields.length).to.be(1765); - expect(sourceStatus.logIndicesExist).to.be(true); - expect(sourceStatus.metricIndicesExist).to.be(true); - }); - }); - - describe('createSource mutation', () => { - it('saves and returns source configurations', async () => { - const response = await client.mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties: { - name: 'NAME', - description: 'DESCRIPTION', - logAlias: 'filebeat-**', - metricAlias: 'metricbeat-**', - fields: { - container: 'CONTAINER', - host: 'HOST', - pod: 'POD', - tiebreaker: 'TIEBREAKER', - timestamp: 'TIMESTAMP', - }, - logColumns: [ - { - messageColumn: { - id: 'MESSAGE_COLUMN', - }, - }, - ], - }, - sourceId: 'default', - }, - }); - - const { version, updatedAt, configuration, status } = - response.data && response.data.createSource.source; - - expect(version).to.be.a('string'); - expect(updatedAt).to.be.greaterThan(0); - expect(configuration.name).to.be('NAME'); - expect(configuration.description).to.be('DESCRIPTION'); - expect(configuration.metricAlias).to.be('metricbeat-**'); - expect(configuration.logAlias).to.be('filebeat-**'); - expect(configuration.fields.container).to.be('CONTAINER'); - expect(configuration.fields.host).to.be('HOST'); - expect(configuration.fields.pod).to.be('POD'); - expect(configuration.fields.tiebreaker).to.be('TIEBREAKER'); - expect(configuration.fields.timestamp).to.be('TIMESTAMP'); - expect(configuration.logColumns).to.have.length(1); - expect(configuration.logColumns[0]).to.have.key('messageColumn'); - - expect(status.logIndicesExist).to.be(true); - expect(status.metricIndicesExist).to.be(true); - }); - - it('saves partial source configuration and returns it amended with defaults', async () => { - const response = await client.mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties: { - name: 'NAME', - }, - sourceId: 'default', - }, - }); - - const { version, updatedAt, configuration, status } = - response.data && response.data.createSource.source; - - expect(version).to.be.a('string'); - expect(updatedAt).to.be.greaterThan(0); - expect(configuration.name).to.be('NAME'); - expect(configuration.description).to.be(''); - expect(configuration.metricAlias).to.be('metrics-*,metricbeat-*'); - expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); - expect(configuration.fields.container).to.be('container.id'); - expect(configuration.fields.host).to.be('host.name'); - expect(configuration.fields.pod).to.be('kubernetes.pod.uid'); - expect(configuration.fields.tiebreaker).to.be('_doc'); - expect(configuration.fields.timestamp).to.be('@timestamp'); - expect(configuration.logColumns).to.have.length(3); - expect(status.logIndicesExist).to.be(true); - expect(status.metricIndicesExist).to.be(true); - }); - - it('refuses to overwrite an existing source', async () => { - await client.mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties: { - name: 'NAME', - }, - sourceId: 'default', - }, - }); - - await client - .mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties: { - name: 'NAME', - }, - sourceId: 'default', - }, - }) - .then( - () => { - expect().fail('should have failed with a conflict'); - }, - (err) => { - expect(err.message).to.contain('conflict'); - } - ); - }); - }); - - describe('deleteSource mutation', () => { - it('deletes an existing source', async () => { - const creationResponse = await client.mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties: { - name: 'NAME', - }, - sourceId: 'default', - }, - }); - - const { version } = creationResponse.data && creationResponse.data.createSource.source; - - expect(version).to.be.a('string'); - - const deletionResponse = await client.mutate({ - mutation: deleteSourceMutation, - variables: { - sourceId: 'default', - }, - }); - - const { id } = deletionResponse.data && deletionResponse.data.deleteSource; - - expect(id).to.be('default'); - }); - }); - - describe('updateSource mutation', () => { + describe('patch request', () => { it('applies all top-level field updates to an existing source', async () => { - const creationResponse = await client.mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties: { - name: 'NAME', - }, - sourceId: 'default', - }, + const creationResponse = await patchRequest({ + name: 'NAME', }); - const { version: initialVersion, updatedAt: createdAt } = - creationResponse.data && creationResponse.data.createSource.source; + const initialVersion = creationResponse?.source.version; + const createdAt = creationResponse?.source.updatedAt; expect(initialVersion).to.be.a('string'); expect(createdAt).to.be.greaterThan(0); - const updateResponse = await client.mutate({ - mutation: updateSourceMutation, - variables: { - sourceId: 'default', - sourceProperties: { - name: 'UPDATED_NAME', - description: 'UPDATED_DESCRIPTION', - metricAlias: 'metricbeat-**', - logAlias: 'filebeat-**', - }, - }, + const updateResponse = await patchRequest({ + name: 'UPDATED_NAME', + description: 'UPDATED_DESCRIPTION', + metricAlias: 'metricbeat-**', + logAlias: 'filebeat-**', }); - const { version, updatedAt, configuration, status } = - updateResponse.data && updateResponse.data.updateSource.source; + expect(SourceResponseRuntimeType.is(updateResponse)).to.be(true); + + const version = updateResponse?.source.version; + const updatedAt = updateResponse?.source.updatedAt; + const configuration = updateResponse?.source.configuration; + const status = updateResponse?.source.status; expect(version).to.be.a('string'); expect(version).to.not.be(initialVersion); - expect(updatedAt).to.be.greaterThan(createdAt); - expect(configuration.name).to.be('UPDATED_NAME'); - expect(configuration.description).to.be('UPDATED_DESCRIPTION'); - expect(configuration.metricAlias).to.be('metricbeat-**'); - expect(configuration.logAlias).to.be('filebeat-**'); - expect(configuration.fields.host).to.be('host.name'); - expect(configuration.fields.pod).to.be('kubernetes.pod.uid'); - expect(configuration.fields.tiebreaker).to.be('_doc'); - expect(configuration.fields.timestamp).to.be('@timestamp'); - expect(configuration.fields.container).to.be('container.id'); - expect(configuration.logColumns).to.have.length(3); - expect(status.logIndicesExist).to.be(true); - expect(status.metricIndicesExist).to.be(true); + expect(updatedAt).to.be.greaterThan(createdAt || 0); + expect(configuration?.name).to.be('UPDATED_NAME'); + expect(configuration?.description).to.be('UPDATED_DESCRIPTION'); + expect(configuration?.metricAlias).to.be('metricbeat-**'); + expect(configuration?.logAlias).to.be('filebeat-**'); + expect(configuration?.fields.host).to.be('host.name'); + expect(configuration?.fields.pod).to.be('kubernetes.pod.uid'); + expect(configuration?.fields.tiebreaker).to.be('_doc'); + expect(configuration?.fields.timestamp).to.be('@timestamp'); + expect(configuration?.fields.container).to.be('container.id'); + expect(configuration?.logColumns).to.have.length(3); + expect(status?.logIndicesExist).to.be(true); + expect(status?.metricIndicesExist).to.be(true); }); it('applies a single top-level update to an existing source', async () => { - const creationResponse = await client.mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties: { - name: 'NAME', - }, - sourceId: 'default', - }, + const creationResponse = await patchRequest({ + name: 'NAME', }); - const { version: initialVersion, updatedAt: createdAt } = - creationResponse.data && creationResponse.data.createSource.source; + const initialVersion = creationResponse?.source.version; + const createdAt = creationResponse?.source.updatedAt; expect(initialVersion).to.be.a('string'); expect(createdAt).to.be.greaterThan(0); - const updateResponse = await client.mutate({ - mutation: updateSourceMutation, - variables: { - sourceId: 'default', - sourceProperties: { - metricAlias: 'metricbeat-**', - }, - }, + const updateResponse = await patchRequest({ + name: 'UPDATED_NAME', + description: 'UPDATED_DESCRIPTION', + metricAlias: 'metricbeat-**', }); - const { version, updatedAt, configuration, status } = - updateResponse.data && updateResponse.data.updateSource.source; + const version = updateResponse?.source.version; + const updatedAt = updateResponse?.source.updatedAt; + const configuration = updateResponse?.source.configuration; + const status = updateResponse?.source.status; expect(version).to.be.a('string'); expect(version).to.not.be(initialVersion); - expect(updatedAt).to.be.greaterThan(createdAt); - expect(configuration.metricAlias).to.be('metricbeat-**'); - expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); - expect(status.logIndicesExist).to.be(true); - expect(status.metricIndicesExist).to.be(true); + expect(updatedAt).to.be.greaterThan(createdAt || 0); + expect(configuration?.metricAlias).to.be('metricbeat-**'); + expect(configuration?.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*'); + expect(status?.logIndicesExist).to.be(true); + expect(status?.metricIndicesExist).to.be(true); }); it('applies a single nested field update to an existing source', async () => { - const creationResponse = await client.mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties: { - name: 'NAME', - fields: { - host: 'HOST', - }, - }, - sourceId: 'default', + const creationResponse = await patchRequest({ + name: 'NAME', + fields: { + host: 'HOST', }, }); - const { version: initialVersion, updatedAt: createdAt } = - creationResponse.data && creationResponse.data.createSource.source; + const initialVersion = creationResponse?.source.version; + const createdAt = creationResponse?.source.updatedAt; expect(initialVersion).to.be.a('string'); expect(createdAt).to.be.greaterThan(0); - const updateResponse = await client.mutate({ - mutation: updateSourceMutation, - variables: { - sourceId: 'default', - sourceProperties: { - fields: { - container: 'UPDATED_CONTAINER', - }, - }, + const updateResponse = await patchRequest({ + fields: { + container: 'UPDATED_CONTAINER', }, }); - const { version, updatedAt, configuration } = - updateResponse.data && updateResponse.data.updateSource.source; + const version = updateResponse?.source.version; + const updatedAt = updateResponse?.source.updatedAt; + const configuration = updateResponse?.source.configuration; expect(version).to.be.a('string'); expect(version).to.not.be(initialVersion); - expect(updatedAt).to.be.greaterThan(createdAt); - expect(configuration.fields.container).to.be('UPDATED_CONTAINER'); - expect(configuration.fields.host).to.be('HOST'); - expect(configuration.fields.pod).to.be('kubernetes.pod.uid'); - expect(configuration.fields.tiebreaker).to.be('_doc'); - expect(configuration.fields.timestamp).to.be('@timestamp'); + expect(updatedAt).to.be.greaterThan(createdAt || 0); + expect(configuration?.fields.container).to.be('UPDATED_CONTAINER'); + expect(configuration?.fields.host).to.be('HOST'); + expect(configuration?.fields.pod).to.be('kubernetes.pod.uid'); + expect(configuration?.fields.tiebreaker).to.be('_doc'); + expect(configuration?.fields.timestamp).to.be('@timestamp'); }); it('applies a log column update to an existing source', async () => { - const creationResponse = await client.mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties: { - name: 'NAME', - }, - sourceId: 'default', - }, + const creationResponse = await patchRequest({ + name: 'NAME', }); - const { version: initialVersion, updatedAt: createdAt } = - creationResponse.data && creationResponse.data.createSource.source; + const initialVersion = creationResponse?.source.version; + const createdAt = creationResponse?.source.updatedAt; - expect(initialVersion).to.be.a('string'); - expect(createdAt).to.be.greaterThan(0); - - const updateResponse = await client.mutate({ - mutation: updateSourceMutation, - variables: { - sourceId: 'default', - sourceProperties: { - logColumns: [ - { - fieldColumn: { - id: 'ADDED_COLUMN_ID', - field: 'ADDED_COLUMN_FIELD', - }, - }, - ], + const updateResponse = await patchRequest({ + logColumns: [ + { + fieldColumn: { + id: 'ADDED_COLUMN_ID', + field: 'ADDED_COLUMN_FIELD', + }, }, - }, + ], }); - const { version, updatedAt, configuration } = - updateResponse.data && updateResponse.data.updateSource.source; - + const version = updateResponse?.source.version; + const updatedAt = updateResponse?.source.updatedAt; + const configuration = updateResponse?.source.configuration; expect(version).to.be.a('string'); expect(version).to.not.be(initialVersion); - expect(updatedAt).to.be.greaterThan(createdAt); - expect(configuration.logColumns).to.have.length(1); - expect(configuration.logColumns[0]).to.have.key('fieldColumn'); - expect(configuration.logColumns[0].fieldColumn).to.have.property('id', 'ADDED_COLUMN_ID'); - expect(configuration.logColumns[0].fieldColumn).to.have.property( - 'field', - 'ADDED_COLUMN_FIELD' - ); + expect(updatedAt).to.be.greaterThan(createdAt || 0); + expect(configuration?.logColumns).to.have.length(1); + expect(configuration?.logColumns[0]).to.have.key('fieldColumn'); + const fieldColumn = (configuration?.logColumns[0] as any).fieldColumn; + expect(fieldColumn).to.have.property('id', 'ADDED_COLUMN_ID'); + expect(fieldColumn).to.have.property('field', 'ADDED_COLUMN_FIELD'); }); }); }); } - -const createSourceMutation = gql` - mutation createSource($sourceId: ID!, $sourceProperties: UpdateSourceInput!) { - createSource(id: $sourceId, sourceProperties: $sourceProperties) { - source { - ...InfraSourceFields - configuration { - ...SourceConfigurationFields - } - status { - ...SourceStatusFields - } - } - } - } - - ${sharedFragments.InfraSourceFields} - ${sourceConfigurationFieldsFragment} - ${sourceStatusFieldsFragment} -`; - -const deleteSourceMutation = gql` - mutation deleteSource($sourceId: ID!) { - deleteSource(id: $sourceId) { - id - } - } -`; - -const updateSourceMutation = gql` - mutation updateSource($sourceId: ID!, $sourceProperties: UpdateSourceInput!) { - updateSource(id: $sourceId, sourceProperties: $sourceProperties) { - source { - ...InfraSourceFields - configuration { - ...SourceConfigurationFields - } - status { - ...SourceStatusFields - } - } - } - } - - ${sharedFragments.InfraSourceFields} - ${sourceConfigurationFieldsFragment} - ${sourceStatusFieldsFragment} -`; diff --git a/x-pack/test/api_integration/services/index.ts b/x-pack/test/api_integration/services/index.ts index 7113e117582d..2ac6f30b1e18 100644 --- a/x-pack/test/api_integration/services/index.ts +++ b/x-pack/test/api_integration/services/index.ts @@ -15,10 +15,6 @@ import { EsSupertestWithoutAuthProvider } from './es_supertest_without_auth'; import { SupertestWithoutAuthProvider } from './supertest_without_auth'; import { UsageAPIProvider } from './usage_api'; -import { - InfraOpsGraphQLClientProvider, - InfraOpsGraphQLClientFactoryProvider, -} from './infraops_graphql_client'; import { SecuritySolutionGraphQLClientProvider, SecuritySolutionGraphQLClientFactoryProvider, @@ -37,8 +33,6 @@ export const services = { legacyEs: LegacyEsProvider, esSupertestWithoutAuth: EsSupertestWithoutAuthProvider, - infraOpsGraphQLClient: InfraOpsGraphQLClientProvider, - infraOpsGraphQLClientFactory: InfraOpsGraphQLClientFactoryProvider, infraOpsSourceConfiguration: InfraOpsSourceConfigurationProvider, infraLogSourceConfiguration: InfraLogSourceConfigurationProvider, securitySolutionGraphQLClient: SecuritySolutionGraphQLClientProvider, diff --git a/x-pack/test/api_integration/services/infraops_graphql_client.ts b/x-pack/test/api_integration/services/infraops_graphql_client.ts deleted file mode 100644 index 81f0ac8fad91..000000000000 --- a/x-pack/test/api_integration/services/infraops_graphql_client.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 { format as formatUrl } from 'url'; -import fetch from 'node-fetch'; -import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; -import { ApolloClient } from 'apollo-client'; -import { HttpLink } from 'apollo-link-http'; - -import { FtrProviderContext } from '../ftr_provider_context'; - -import introspectionQueryResultData from '../../../plugins/infra/public/graphql/introspection.json'; - -export function InfraOpsGraphQLClientProvider(context: FtrProviderContext) { - return InfraOpsGraphQLClientFactoryProvider(context)(); -} - -interface InfraOpsGraphQLClientFactoryOptions { - username?: string; - password?: string; - basePath?: string; -} - -export function InfraOpsGraphQLClientFactoryProvider({ getService }: FtrProviderContext) { - const config = getService('config'); - const superAuth: string = config.get('servers.elasticsearch.auth'); - const [superUsername, superPassword] = superAuth.split(':'); - - return function (options?: InfraOpsGraphQLClientFactoryOptions) { - const { username = superUsername, password = superPassword, basePath = null } = options || {}; - - const kbnURLWithoutAuth = formatUrl({ ...config.get('servers.kibana'), auth: false }); - - const httpLink = new HttpLink({ - credentials: 'same-origin', - fetch: fetch as any, - headers: { - 'kbn-xsrf': 'xxx', - authorization: `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`, - }, - uri: `${kbnURLWithoutAuth}${basePath || ''}/api/infra/graphql`, - }); - - return new ApolloClient({ - cache: new InMemoryCache({ - fragmentMatcher: new IntrospectionFragmentMatcher({ - // @ts-expect-error apollo-cache-inmemory types don't match actual introspection data - introspectionQueryResultData, - }), - }), - defaultOptions: { - query: { - fetchPolicy: 'no-cache', - }, - watchQuery: { - fetchPolicy: 'no-cache', - }, - mutate: { - fetchPolicy: 'no-cache', - } as any, - }, - link: httpLink, - }); - }; -} diff --git a/x-pack/test/api_integration/services/infraops_source_configuration.ts b/x-pack/test/api_integration/services/infraops_source_configuration.ts index 728a58829d1c..7c6f2c5aa731 100644 --- a/x-pack/test/api_integration/services/infraops_source_configuration.ts +++ b/x-pack/test/api_integration/services/infraops_source_configuration.ts @@ -4,65 +4,36 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; - +import { + InfraSavedSourceConfiguration, + SourceResponse, +} from '../../../plugins/infra/common/http_api/source_api'; import { FtrProviderContext } from '../ftr_provider_context'; -import { UpdateSourceInput, UpdateSourceResult } from '../../../plugins/infra/public/graphql/types'; - -const createSourceMutation = gql` - mutation createSource($sourceId: ID!, $sourceProperties: UpdateSourceInput!) { - createSource(id: $sourceId, sourceProperties: $sourceProperties) { - source { - id - version - configuration { - name - logColumns { - ... on InfraSourceTimestampLogColumn { - timestampColumn { - id - } - } - ... on InfraSourceMessageLogColumn { - messageColumn { - id - } - } - ... on InfraSourceFieldLogColumn { - fieldColumn { - id - field - } - } - } - } - } - } - } -`; export function InfraOpsSourceConfigurationProvider({ getService }: FtrProviderContext) { - const client = getService('infraOpsGraphQLClient'); const log = getService('log'); + const supertest = getService('supertest'); + const patchRequest = async ( + body: InfraSavedSourceConfiguration + ): Promise => { + const response = await supertest + .patch('/api/metrics/source/default') + .set('kbn-xsrf', 'xxx') + .send(body) + .expect(200); + return response.body; + }; return { - async createConfiguration(sourceId: string, sourceProperties: UpdateSourceInput) { + async createConfiguration(sourceId: string, sourceProperties: InfraSavedSourceConfiguration) { log.debug( `Creating Infra UI source configuration "${sourceId}" with properties ${JSON.stringify( sourceProperties )}` ); - const response = await client.mutate({ - mutation: createSourceMutation, - variables: { - sourceProperties, - sourceId, - }, - }); - - const result: UpdateSourceResult = response.data!.createSource; - return result.source.version; + const response = await patchRequest(sourceProperties); + return response?.source.version; }, }; } From 75d9e0a071790155fa471f7837471066657af9d7 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Tue, 2 Feb 2021 15:57:56 -0800 Subject: [PATCH 05/14] skip flaky suite (#89073) --- .../saved_object_tagging/functional/tests/maps_integration.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/saved_object_tagging/functional/tests/maps_integration.ts b/x-pack/test/saved_object_tagging/functional/tests/maps_integration.ts index 32b9cc378db4..8b7a6affb02e 100644 --- a/x-pack/test/saved_object_tagging/functional/tests/maps_integration.ts +++ b/x-pack/test/saved_object_tagging/functional/tests/maps_integration.ts @@ -33,7 +33,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await searchFilter.click(); }; - describe('maps integration', () => { + // Failing: See https://github.com/elastic/kibana/issues/89073 + describe.skip('maps integration', () => { before(async () => { await esArchiver.load('maps'); }); From 20654388a40c82dd9ae9cccf82c24ff4dffc4749 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 2 Feb 2021 20:23:56 -0500 Subject: [PATCH 06/14] [Fleet] Fix performance issue in agent status endpoint (#90066) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../fleet/server/services/agents/crud_so.ts | 42 +++++++++++++------ .../fleet/server/services/agents/status.ts | 24 ++++++++--- .../fleet/server/types/rest_spec/common.ts | 7 +++- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/agents/crud_so.ts b/x-pack/plugins/fleet/server/services/agents/crud_so.ts index eb8f389741a6..7111a2413914 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud_so.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud_so.ts @@ -12,18 +12,35 @@ import { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; import { escapeSearchQueryPhrase, normalizeKuery, findAllSOs } from '../saved_object'; import { savedObjectToAgent } from './saved_objects'; import { appContextService } from '../../services'; +import { esKuery, KueryNode } from '../../../../../../src/plugins/data/server'; const ACTIVE_AGENT_CONDITION = `${AGENT_SAVED_OBJECT_TYPE}.attributes.active:true`; const INACTIVE_AGENT_CONDITION = `NOT (${ACTIVE_AGENT_CONDITION})`; -function _joinFilters(filters: string[], operator = 'AND') { - return filters.reduce((acc: string | undefined, filter) => { - if (acc) { - return `${acc} ${operator} (${filter})`; - } - - return `(${filter})`; - }, undefined); +function _joinFilters(filters: Array) { + return filters + .filter((filter) => filter !== undefined) + .reduce((acc: KueryNode | undefined, kuery: string | KueryNode | undefined): + | KueryNode + | undefined => { + if (kuery === undefined) { + return acc; + } + const kueryNode: KueryNode = + typeof kuery === 'string' + ? esKuery.fromKueryExpression(normalizeKuery(AGENT_SAVED_OBJECT_TYPE, kuery)) + : kuery; + + if (!acc) { + return kueryNode; + } + + return { + type: 'function', + function: 'and', + arguments: [acc, kueryNode], + }; + }, undefined as KueryNode | undefined); } export async function listAgents( @@ -46,19 +63,18 @@ export async function listAgents( showInactive = false, showUpgradeable, } = options; - const filters = []; + const filters: Array = []; if (kuery && kuery !== '') { - filters.push(normalizeKuery(AGENT_SAVED_OBJECT_TYPE, kuery)); + filters.push(kuery); } if (showInactive === false) { filters.push(ACTIVE_AGENT_CONDITION); } - let { saved_objects: agentSOs, total } = await soClient.find({ type: AGENT_SAVED_OBJECT_TYPE, - filter: _joinFilters(filters), + filter: _joinFilters(filters) || '', sortField, sortOrder, page, @@ -94,7 +110,7 @@ export async function listAllAgents( const filters = []; if (kuery && kuery !== '') { - filters.push(normalizeKuery(AGENT_SAVED_OBJECT_TYPE, kuery)); + filters.push(kuery); } if (showInactive === false) { diff --git a/x-pack/plugins/fleet/server/services/agents/status.ts b/x-pack/plugins/fleet/server/services/agents/status.ts index ba8f8fc36385..726d188f723d 100644 --- a/x-pack/plugins/fleet/server/services/agents/status.ts +++ b/x-pack/plugins/fleet/server/services/agents/status.ts @@ -11,6 +11,8 @@ import { AGENT_EVENT_SAVED_OBJECT_TYPE, AGENT_SAVED_OBJECT_TYPE } from '../../co import { AgentStatus } from '../../types'; import { AgentStatusKueryHelper } from '../../../common/services'; +import { esKuery, KueryNode } from '../../../../../../src/plugins/data/server'; +import { normalizeKuery } from '../saved_object'; export async function getAgentStatusById( soClient: SavedObjectsClientContract, @@ -26,13 +28,24 @@ export const getAgentStatus = AgentStatusKueryHelper.getAgentStatus; function joinKuerys(...kuerys: Array) { return kuerys .filter((kuery) => kuery !== undefined) - .reduce((acc, kuery) => { - if (acc === '') { - return `(${kuery})`; + .reduce((acc: KueryNode | undefined, kuery: string | undefined): KueryNode | undefined => { + if (kuery === undefined) { + return acc; } + const normalizedKuery: KueryNode = esKuery.fromKueryExpression( + normalizeKuery(AGENT_SAVED_OBJECT_TYPE, kuery || '') + ); - return `${acc} and (${kuery})`; - }, ''); + if (!acc) { + return normalizedKuery; + } + + return { + type: 'function', + function: 'and', + arguments: [acc, normalizedKuery], + }; + }, undefined as KueryNode | undefined); } export async function getAgentStatusForAgentPolicy( @@ -58,6 +71,7 @@ export async function getAgentStatusForAgentPolicy( ...[ kuery, filterKuery, + `${AGENT_SAVED_OBJECT_TYPE}.attributes.active:true`, agentPolicyId ? `${AGENT_SAVED_OBJECT_TYPE}.policy_id:"${agentPolicyId}"` : undefined, ] ), diff --git a/x-pack/plugins/fleet/server/types/rest_spec/common.ts b/x-pack/plugins/fleet/server/types/rest_spec/common.ts index cdb23da5b6b1..88d60116672d 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/common.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/common.ts @@ -11,7 +11,12 @@ export const ListWithKuerySchema = schema.object({ sortField: schema.maybe(schema.string()), sortOrder: schema.maybe(schema.oneOf([schema.literal('desc'), schema.literal('asc')])), showUpgradeable: schema.maybe(schema.boolean()), - kuery: schema.maybe(schema.string()), + kuery: schema.maybe( + schema.oneOf([ + schema.string(), + schema.any(), // KueryNode + ]) + ), }); export type ListWithKuery = TypeOf; From 06bc99d825ab8b813bb5484469b83fb5c647c2f2 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Wed, 3 Feb 2021 06:56:09 +0100 Subject: [PATCH 07/14] [Discover] Fix 'auto' collapsing of documents (#89712) --- .../doc_table/create_doc_table_react.tsx | 149 ++++++++---------- .../angular/doc_table/doc_table.ts | 4 + test/functional/apps/discover/_doc_table.ts | 19 +++ 3 files changed, 93 insertions(+), 79 deletions(-) diff --git a/src/plugins/discover/public/application/angular/doc_table/create_doc_table_react.tsx b/src/plugins/discover/public/application/angular/doc_table/create_doc_table_react.tsx index cbd93feb835a..d8f826adbbb1 100644 --- a/src/plugins/discover/public/application/angular/doc_table/create_doc_table_react.tsx +++ b/src/plugins/discover/public/application/angular/doc_table/create_doc_table_react.tsx @@ -14,11 +14,27 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { getServices, IIndexPattern } from '../../../kibana_services'; import { IndexPatternField } from '../../../../../data/common/index_patterns'; -export type AngularScope = IScope; - +export interface DocTableLegacyProps { + columns: string[]; + searchDescription?: string; + searchTitle?: string; + onFilter: (field: IndexPatternField | string, value: string, type: '+' | '-') => void; + rows: Array>; + indexPattern: IIndexPattern; + minimumVisibleRows: number; + onAddColumn?: (column: string) => void; + onBackToTop: () => void; + onSort?: (sort: string[][]) => void; + onMoveColumn?: (columns: string, newIdx: number) => void; + onRemoveColumn?: (column: string) => void; + sampleSize: number; + sort?: string[][]; + useNewFieldsApi?: boolean; +} export interface AngularDirective { template: string; } +export type AngularScope = IScope & { renderProps?: DocTableLegacyProps }; /** * Compiles and injects the give angular template into the given dom node @@ -27,13 +43,12 @@ export interface AngularDirective { export async function injectAngularElement( domNode: Element, template: string, - scopeProps: any, - getInjector: () => Promise -): Promise<() => void> { - const $injector = await getInjector(); - const rootScope: AngularScope = $injector.get('$rootScope'); - const $compile: ICompileService = $injector.get('$compile'); - const newScope = Object.assign(rootScope.$new(), scopeProps); + renderProps: any, + injector: auto.IInjectorService +) { + const rootScope: IScope = injector.get('$rootScope'); + const $compile: ICompileService = injector.get('$compile'); + const newScope = Object.assign(rootScope.$new(), { renderProps }); const $target = angular.element(domNode); const $element = angular.element(template); @@ -44,87 +59,63 @@ export async function injectAngularElement( linkFn(newScope); }); - return () => { - newScope.$destroy(); - }; + return newScope; } -/** - * Converts a given legacy angular directive to a render function - * for usage in a react component. Note that the rendering is async - */ -export function convertDirectiveToRenderFn( - directive: AngularDirective, - getInjector: () => Promise -) { - return (domNode: Element, props: any) => { - let rejected = false; - - const cleanupFnPromise = injectAngularElement(domNode, directive.template, props, getInjector); +function getRenderFn(domNode: Element, props: any) { + const directive = { + template: ``, + }; - cleanupFnPromise.catch(() => { - rejected = true; + return async () => { + try { + const injector = await getServices().getEmbeddableInjector(); + return await injectAngularElement(domNode, directive.template, props, injector); + } catch (e) { render(
error
, domNode); - }); - - return () => { - if (!rejected) { - // for cleanup - // http://roubenmeschian.com/rubo/?p=51 - cleanupFnPromise.then((cleanup) => cleanup()); - } - }; + } }; } -export interface DocTableLegacyProps { - columns: string[]; - searchDescription?: string; - searchTitle?: string; - onFilter: (field: IndexPatternField | string, value: string, type: '+' | '-') => void; - rows: Array>; - indexPattern: IIndexPattern; - minimumVisibleRows: number; - onAddColumn?: (column: string) => void; - onBackToTop: () => void; - onSort?: (sort: string[][]) => void; - onMoveColumn?: (columns: string, newIdx: number) => void; - onRemoveColumn?: (column: string) => void; - sampleSize: number; - sort?: string[][]; - useNewFieldsApi?: boolean; -} - export function DocTableLegacy(renderProps: DocTableLegacyProps) { - const renderFn = convertDirectiveToRenderFn( - { - template: ``, - }, - () => getServices().getEmbeddableInjector() - ); const ref = useRef(null); + const scope = useRef(); + useEffect(() => { - if (ref && ref.current) { - return renderFn(ref.current, renderProps); + if (ref && ref.current && !scope.current) { + const fn = getRenderFn(ref.current, renderProps); + fn().then((newScope) => { + scope.current = newScope; + }); + } else if (scope && scope.current) { + scope.current.renderProps = renderProps; + scope.current.$apply(); } - }, [renderFn, renderProps]); + }, [renderProps]); + useEffect(() => { + return () => { + if (scope.current) { + scope.current.$destroy(); + } + }; + }, []); return (
diff --git a/src/plugins/discover/public/application/angular/doc_table/doc_table.ts b/src/plugins/discover/public/application/angular/doc_table/doc_table.ts index 29ea9d5db9a3..6c2a3cbfc951 100644 --- a/src/plugins/discover/public/application/angular/doc_table/doc_table.ts +++ b/src/plugins/discover/public/application/angular/doc_table/doc_table.ts @@ -59,6 +59,10 @@ export function createDocTableDirective(pagerFactory: any, $filter: any) { $scope.limit += 50; }; + $scope.$watch('minimumVisibleRows', (minimumVisibleRows: number) => { + $scope.limit = Math.max(minimumVisibleRows || 50, $scope.limit || 50); + }); + $scope.$watch('hits', (hits: any) => { if (!hits) return; diff --git a/test/functional/apps/discover/_doc_table.ts b/test/functional/apps/discover/_doc_table.ts index f8f45d2bc710..d4818d99565e 100644 --- a/test/functional/apps/discover/_doc_table.ts +++ b/test/functional/apps/discover/_doc_table.ts @@ -15,6 +15,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); const docTable = getService('docTable'); + const queryBar = getService('queryBar'); const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker']); const defaultSettings = { defaultIndex: 'logstash-*', @@ -107,6 +108,24 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // TODO: test something more meaninful here? }); }); + + it('should not close the detail panel actions when data is re-requested', async function () { + await retry.try(async function () { + const nrOfFetches = await PageObjects.discover.getNrOfFetches(); + await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); + const detailsEl = await docTable.getDetailsRows(); + const defaultMessageEl = await detailsEl[0].findByTestSubject('docTableRowDetailsTitle'); + expect(defaultMessageEl).to.be.ok(); + await queryBar.submitQuery(); + const nrOfFetchesResubmit = await PageObjects.discover.getNrOfFetches(); + expect(nrOfFetchesResubmit).to.be.above(nrOfFetches); + const defaultMessageElResubmit = await detailsEl[0].findByTestSubject( + 'docTableRowDetailsTitle' + ); + + expect(defaultMessageElResubmit).to.be.ok(); + }); + }); }); describe('add and remove columns', function () { From 14cf1875b5d5bdcda8836608d90f4eb5ede7d656 Mon Sep 17 00:00:00 2001 From: John Dorlus Date: Wed, 3 Feb 2021 02:26:30 -0500 Subject: [PATCH 08/14] [Upgrade Assistant] Fixes to Upgrade Assistant Tests and Page Objects To Stop CI Failures (#89942) * Updated test to use no hard coded waits which could be contributing to CI failures. Expect functions should be in the test file itself so I changed the page objects for page actions and extracted out the expect calls to the test files. * Added retry within the test file to retry the assertion if it doesn't pass on the first attempt. Simplified the toggle function to just click the toggle. * Fixed type check issue. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../upgrade_assistant/upgrade_assistant.ts | 43 +++++++----- .../page_objects/upgrade_assistant_page.ts | 65 +++++++++---------- 2 files changed, 58 insertions(+), 50 deletions(-) diff --git a/x-pack/test/functional/apps/upgrade_assistant/upgrade_assistant.ts b/x-pack/test/functional/apps/upgrade_assistant/upgrade_assistant.ts index 57b8fb23613b..9e742ca5463a 100644 --- a/x-pack/test/functional/apps/upgrade_assistant/upgrade_assistant.ts +++ b/x-pack/test/functional/apps/upgrade_assistant/upgrade_assistant.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function upgradeAssistantFunctionalTests({ @@ -14,6 +15,7 @@ export default function upgradeAssistantFunctionalTests({ const PageObjects = getPageObjects(['upgradeAssistant', 'common']); const security = getService('security'); const log = getService('log'); + const retry = getService('retry'); describe('Upgrade Checkup', function () { this.tags('includeFirefox'); @@ -24,41 +26,52 @@ export default function upgradeAssistantFunctionalTests({ }); after(async () => { - await PageObjects.upgradeAssistant.expectTelemetryHasFinish(); + await PageObjects.upgradeAssistant.waitForTelemetryHidden(); await esArchiver.unload('empty_kibana'); await security.testUser.restoreDefaults(); }); it('allows user to navigate to upgrade checkup', async () => { await PageObjects.upgradeAssistant.navigateToPage(); - await PageObjects.upgradeAssistant.expectUpgradeAssistant(); }); it('allows user to toggle deprecation logging', async () => { - await PageObjects.upgradeAssistant.navigateToPage(); log.debug('expect initial state to be ON'); - await PageObjects.upgradeAssistant.expectDeprecationLoggingLabel('On'); - log.debug('Now toggle to off'); - await PageObjects.upgradeAssistant.toggleDeprecationLogging(); - await PageObjects.common.sleep(2000); - log.debug('expect state to be OFF after toggle'); - await PageObjects.upgradeAssistant.expectDeprecationLoggingLabel('Off'); - await PageObjects.upgradeAssistant.toggleDeprecationLogging(); - await PageObjects.common.sleep(2000); - log.debug('expect state to be ON after toggle'); - await PageObjects.upgradeAssistant.expectDeprecationLoggingLabel('On'); + expect(await PageObjects.upgradeAssistant.deprecationLoggingEnabledLabel()).to.be('On'); + expect(await PageObjects.upgradeAssistant.isDeprecationLoggingEnabled()).to.be(true); + + await retry.try(async () => { + log.debug('Now toggle to off'); + await PageObjects.upgradeAssistant.toggleDeprecationLogging(); + + log.debug('expect state to be OFF after toggle'); + expect(await PageObjects.upgradeAssistant.isDeprecationLoggingEnabled()).to.be(false); + expect(await PageObjects.upgradeAssistant.deprecationLoggingEnabledLabel()).to.be('Off'); + }); + + log.debug('Now toggle back on.'); + await retry.try(async () => { + await PageObjects.upgradeAssistant.toggleDeprecationLogging(); + log.debug('expect state to be ON after toggle'); + expect(await PageObjects.upgradeAssistant.isDeprecationLoggingEnabled()).to.be(true); + expect(await PageObjects.upgradeAssistant.deprecationLoggingEnabledLabel()).to.be('On'); + }); }); it('allows user to open cluster tab', async () => { await PageObjects.upgradeAssistant.navigateToPage(); await PageObjects.upgradeAssistant.clickTab('cluster'); - await PageObjects.upgradeAssistant.expectIssueSummary('You have no cluster issues.'); + expect(await PageObjects.upgradeAssistant.issueSummaryText()).to.be( + 'You have no cluster issues.' + ); }); it('allows user to open indices tab', async () => { await PageObjects.upgradeAssistant.navigateToPage(); await PageObjects.upgradeAssistant.clickTab('indices'); - await PageObjects.upgradeAssistant.expectIssueSummary('You have no index issues.'); + expect(await PageObjects.upgradeAssistant.issueSummaryText()).to.be( + 'You have no index issues.' + ); }); }); } diff --git a/x-pack/test/functional/page_objects/upgrade_assistant_page.ts b/x-pack/test/functional/page_objects/upgrade_assistant_page.ts index 3fe60747505a..739b796c5a62 100644 --- a/x-pack/test/functional/page_objects/upgrade_assistant_page.ts +++ b/x-pack/test/functional/page_objects/upgrade_assistant_page.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import expect from '@kbn/expect'; import { FtrProviderContext } from '../ftr_provider_context'; export function UpgradeAssistantPageProvider({ getPageObjects, getService }: FtrProviderContext) { @@ -24,34 +23,32 @@ export function UpgradeAssistantPageProvider({ getPageObjects, getService }: Ftr return await retry.try(async () => { await common.navigateToApp('settings'); await testSubjects.click('upgrade_assistant'); + retry.waitFor('url to contain /upgrade_assistant', async () => { + const url = await browser.getCurrentUrl(); + return url.includes('/upgrade_assistant'); + }); }); } - async expectUpgradeAssistant() { - return await retry.try(async () => { - log.debug(`expectUpgradeAssistant()`); - expect(await testSubjects.exists('upgradeAssistantRoot')).to.equal(true); - const url = await browser.getCurrentUrl(); - expect(url).to.contain(`/upgrade_assistant`); - }); + async toggleDeprecationLogging() { + log.debug('toggleDeprecationLogging()'); + await testSubjects.click('upgradeAssistantDeprecationToggle'); } - async toggleDeprecationLogging() { - return await retry.try(async () => { - log.debug('toggleDeprecationLogging()'); - await testSubjects.click('upgradeAssistantDeprecationToggle'); - }); + async isDeprecationLoggingEnabled() { + const isDeprecationEnabled = await testSubjects.getAttribute( + 'upgradeAssistantDeprecationToggle', + 'aria-checked' + ); + log.debug(`Deprecation enabled == ${isDeprecationEnabled}`); + return isDeprecationEnabled === 'true'; } - async expectDeprecationLoggingLabel(labelText: string) { - return await retry.try(async () => { - log.debug('expectDeprecationLoggingLabel()'); - const label = await find.byCssSelector( - '[data-test-subj="upgradeAssistantDeprecationToggle"] ~ span' - ); - const value = await label.getVisibleText(); - expect(value).to.equal(labelText); - }); + async deprecationLoggingEnabledLabel() { + const loggingEnabledLabel = await find.byCssSelector( + '[data-test-subj="upgradeAssistantDeprecationToggle"] ~ span' + ); + return await loggingEnabledLabel.getVisibleText(); } async clickTab(tabId: string) { @@ -61,22 +58,20 @@ export function UpgradeAssistantPageProvider({ getPageObjects, getService }: Ftr }); } - async expectIssueSummary(summary: string) { - return await retry.try(async () => { - log.debug('expectIssueSummary()'); - const summaryElText = await testSubjects.getVisibleText('upgradeAssistantIssueSummary'); - expect(summaryElText).to.eql(summary); + async waitForTelemetryHidden() { + const self = this; + retry.waitFor('Telemetry to disappear.', async () => { + return (await self.isTelemetryExists()) === false; }); } - async expectTelemetryHasFinish() { - return await retry.try(async () => { - log.debug('expectTelemetryHasFinish'); - const isTelemetryFinished = !(await testSubjects.exists( - 'upgradeAssistantTelemetryRunning' - )); - expect(isTelemetryFinished).to.equal(true); - }); + async issueSummaryText() { + log.debug('expectIssueSummary()'); + return await testSubjects.getVisibleText('upgradeAssistantIssueSummary'); + } + + async isTelemetryExists() { + return await testSubjects.exists('upgradeAssistantTelemetryRunning'); } } From af454d61bf74ae12dca94ca1df2c7f2baad50615 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Wed, 3 Feb 2021 10:29:50 +0300 Subject: [PATCH 09/14] Timelion reads raw field list from saved object, should grab from index pattern api (#89988) * Timelion reads raw field list from saved object, should grab from index pattern api Closes: #84387 * fix PR comment --- .../timelion_expression_input_helpers.test.ts | 4 +- .../public/helpers/arg_value_suggestions.ts | 39 +++++-------------- .../public/helpers/plugin_services.ts | 6 --- .../vis_type_timelion/public/plugin.ts | 3 +- .../vis_type_timelion/server/plugin.ts | 4 +- .../vis_type_timelion/server/routes/run.ts | 10 ++++- .../server/series_functions/es/es.test.js | 12 ++---- .../server/series_functions/es/index.js | 21 +++------- 8 files changed, 31 insertions(+), 68 deletions(-) diff --git a/src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts b/src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts index 25ec32652797..a1c47292ba81 100644 --- a/src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts +++ b/src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts @@ -8,14 +8,12 @@ import { SUGGESTION_TYPE, suggest } from './timelion_expression_input_helpers'; import { getArgValueSuggestions } from '../helpers/arg_value_suggestions'; -import { setIndexPatterns, setSavedObjectsClient } from '../helpers/plugin_services'; +import { setIndexPatterns } from '../helpers/plugin_services'; import { IndexPatternsContract } from 'src/plugins/data/public'; -import { SavedObjectsClient } from 'kibana/public'; import { ITimelionFunction } from '../../common/types'; describe('Timelion expression suggestions', () => { setIndexPatterns({} as IndexPatternsContract); - setSavedObjectsClient({} as SavedObjectsClient); const argValueSuggestions = getArgValueSuggestions(); diff --git a/src/plugins/vis_type_timelion/public/helpers/arg_value_suggestions.ts b/src/plugins/vis_type_timelion/public/helpers/arg_value_suggestions.ts index 444559a0b458..919429ca049e 100644 --- a/src/plugins/vis_type_timelion/public/helpers/arg_value_suggestions.ts +++ b/src/plugins/vis_type_timelion/public/helpers/arg_value_suggestions.ts @@ -7,9 +7,9 @@ */ import { get } from 'lodash'; -import { getIndexPatterns, getSavedObjectsClient } from './plugin_services'; +import { getIndexPatterns } from './plugin_services'; import { TimelionFunctionArgs } from '../../common/types'; -import { indexPatterns as indexPatternsUtils, IndexPatternAttributes } from '../../../data/public'; +import { indexPatterns as indexPatternsUtils } from '../../../data/public'; export interface Location { min: number; @@ -32,7 +32,6 @@ export interface FunctionArg { export function getArgValueSuggestions() { const indexPatterns = getIndexPatterns(); - const savedObjectsClient = getSavedObjectsClient(); async function getIndexPattern(functionArgs: FunctionArg[]) { const indexPatternArg = functionArgs.find(({ name }) => name === 'index'); @@ -42,22 +41,9 @@ export function getArgValueSuggestions() { } const indexPatternTitle = get(indexPatternArg, 'value.text'); - const { savedObjects } = await savedObjectsClient.find({ - type: 'index-pattern', - fields: ['title'], - search: `"${indexPatternTitle}"`, - searchFields: ['title'], - perPage: 10, - }); - const indexPatternSavedObject = savedObjects.find( - ({ attributes }) => attributes.title === indexPatternTitle + return (await indexPatterns.find(indexPatternTitle)).find( + (index) => index.title === indexPatternTitle ); - if (!indexPatternSavedObject) { - // index argument does not match an index pattern - return; - } - - return await indexPatterns.get(indexPatternSavedObject.id); } function containsFieldName(partial: string, field: { name: string }) { @@ -73,18 +59,11 @@ export function getArgValueSuggestions() { es: { async index(partial: string) { const search = partial ? `${partial}*` : '*'; - const resp = await savedObjectsClient.find({ - type: 'index-pattern', - fields: ['title', 'type'], - search: `${search}`, - searchFields: ['title'], - perPage: 25, - }); - return resp.savedObjects - .filter((savedObject) => !savedObject.get('type')) - .map((savedObject) => { - return { name: savedObject.attributes.title }; - }); + const size = 25; + + return (await indexPatterns.find(search, size)).map(({ title }) => ({ + name: title, + })); }, async metric(partial: string, functionArgs: FunctionArg[]) { if (!partial || !partial.includes(':')) { diff --git a/src/plugins/vis_type_timelion/public/helpers/plugin_services.ts b/src/plugins/vis_type_timelion/public/helpers/plugin_services.ts index 0a85b1c1e5fe..5c23652c3207 100644 --- a/src/plugins/vis_type_timelion/public/helpers/plugin_services.ts +++ b/src/plugins/vis_type_timelion/public/helpers/plugin_services.ts @@ -7,7 +7,6 @@ */ import type { IndexPatternsContract, ISearchStart } from 'src/plugins/data/public'; -import type { SavedObjectsClientContract } from 'kibana/public'; import { createGetterSetter } from '../../../kibana_utils/public'; export const [getIndexPatterns, setIndexPatterns] = createGetterSetter( @@ -15,8 +14,3 @@ export const [getIndexPatterns, setIndexPatterns] = createGetterSetter('Search'); - -export const [ - getSavedObjectsClient, - setSavedObjectsClient, -] = createGetterSetter('SavedObjectsClient'); diff --git a/src/plugins/vis_type_timelion/public/plugin.ts b/src/plugins/vis_type_timelion/public/plugin.ts index e69b42d6c526..1d200be0d276 100644 --- a/src/plugins/vis_type_timelion/public/plugin.ts +++ b/src/plugins/vis_type_timelion/public/plugin.ts @@ -25,7 +25,7 @@ import { VisualizationsSetup } from '../../visualizations/public'; import { getTimelionVisualizationConfig } from './timelion_vis_fn'; import { getTimelionVisDefinition } from './timelion_vis_type'; -import { setIndexPatterns, setSavedObjectsClient, setDataSearch } from './helpers/plugin_services'; +import { setIndexPatterns, setDataSearch } from './helpers/plugin_services'; import { ConfigSchema } from '../config'; import { getArgValueSuggestions } from './helpers/arg_value_suggestions'; @@ -92,7 +92,6 @@ export class TimelionVisPlugin public start(core: CoreStart, plugins: TimelionVisStartDependencies) { setIndexPatterns(plugins.data.indexPatterns); - setSavedObjectsClient(core.savedObjects.client); setDataSearch(plugins.data.search); return { diff --git a/src/plugins/vis_type_timelion/server/plugin.ts b/src/plugins/vis_type_timelion/server/plugin.ts index fca557efc01e..6a108fc76589 100644 --- a/src/plugins/vis_type_timelion/server/plugin.ts +++ b/src/plugins/vis_type_timelion/server/plugin.ts @@ -46,7 +46,9 @@ export interface TimelionPluginStartDeps { export class Plugin { constructor(private readonly initializerContext: PluginInitializerContext) {} - public async setup(core: CoreSetup): Promise> { + public async setup( + core: CoreSetup + ): Promise> { const config = await this.initializerContext.config .create>() .pipe(first()) diff --git a/src/plugins/vis_type_timelion/server/routes/run.ts b/src/plugins/vis_type_timelion/server/routes/run.ts index ae26013cc39f..2f6c0d709fdc 100644 --- a/src/plugins/vis_type_timelion/server/routes/run.ts +++ b/src/plugins/vis_type_timelion/server/routes/run.ts @@ -18,6 +18,7 @@ import getNamespacesSettings from '../lib/get_namespaced_settings'; import getTlConfig from '../handlers/lib/tl_config'; import { TimelionFunctionInterface } from '../types'; import { ConfigManager } from '../lib/config_manager'; +import { TimelionPluginStartDeps } from '../plugin'; const timelionDefaults = getNamespacesSettings(); @@ -32,7 +33,7 @@ export function runRoute( logger: Logger; getFunction: (name: string) => TimelionFunctionInterface; configManager: ConfigManager; - core: CoreSetup; + core: CoreSetup; } ) { router.post( @@ -77,17 +78,22 @@ export function runRoute( }, router.handleLegacyErrors(async (context, request, response) => { try { + const [, { data }] = await core.getStartServices(); const uiSettings = await context.core.uiSettings.client.getAll(); + const indexPatternsService = await data.indexPatterns.indexPatternsServiceFactory( + context.core.savedObjects.client, + context.core.elasticsearch.client.asCurrentUser + ); const tlConfig = getTlConfig({ context, request, settings: _.defaults(uiSettings, timelionDefaults), // Just in case they delete some setting. getFunction, + getIndexPatternsService: () => indexPatternsService, getStartServices: core.getStartServices, allowedGraphiteUrls: configManager.getGraphiteUrls(), esShardTimeout: configManager.getEsShardTimeout(), - savedObjectsClient: context.core.savedObjects.client, }); const chainRunner = chainRunnerFn(tlConfig); const sheet = await Bluebird.all(chainRunner.processRequest(request.body)); diff --git a/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js b/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js index 671042ae6f24..8828fd6917fe 100644 --- a/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js +++ b/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js @@ -22,16 +22,12 @@ import { UI_SETTINGS } from '../../../../data/server'; describe('es', () => { let tlConfig; - function stubRequestAndServer(response, indexPatternSavedObjects = []) { + function stubRequestAndServer(response) { return { context: { search: { search: jest.fn().mockReturnValue(of(response)) } }, - savedObjectsClient: { - find: function () { - return Promise.resolve({ - saved_objects: indexPatternSavedObjects, - }); - }, - }, + getIndexPatternsService: () => ({ + find: async () => [], + }), }; } diff --git a/src/plugins/vis_type_timelion/server/series_functions/es/index.js b/src/plugins/vis_type_timelion/server/series_functions/es/index.js index bce048503956..7aacc1c1632f 100644 --- a/src/plugins/vis_type_timelion/server/series_functions/es/index.js +++ b/src/plugins/vis_type_timelion/server/series_functions/es/index.js @@ -96,23 +96,12 @@ export default new Datasource('es', { kibana: true, fit: 'nearest', }); + const indexPatternsService = tlConfig.getIndexPatternsService(); + const indexPatternSpec = (await indexPatternsService.find(config.index)).find( + (index) => index.title === config.index + ); - const findResp = await tlConfig.savedObjectsClient.find({ - type: 'index-pattern', - fields: ['title', 'fields'], - search: `"${config.index}"`, - search_fields: ['title'], - }); - const indexPatternSavedObject = findResp.saved_objects.find((savedObject) => { - return savedObject.attributes.title === config.index; - }); - let scriptedFields = []; - if (indexPatternSavedObject) { - const fields = JSON.parse(indexPatternSavedObject.attributes.fields); - scriptedFields = fields.filter((field) => { - return field.scripted; - }); - } + const scriptedFields = indexPatternSpec?.getScriptedFields() ?? []; const esShardTimeout = tlConfig.esShardTimeout; From ebf93e20276b370838b4ab6ab7510d6b2e38a712 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Wed, 3 Feb 2021 08:42:41 +0100 Subject: [PATCH 10/14] [Discover] Unskip brushing histogram functional test (#89400) --- test/functional/apps/discover/_discover.ts | 20 ++++++++++++++++--- test/functional/page_objects/discover_page.ts | 2 ++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/test/functional/apps/discover/_discover.ts b/test/functional/apps/discover/_discover.ts index bf0a02755383..552022241a72 100644 --- a/test/functional/apps/discover/_discover.ts +++ b/test/functional/apps/discover/_discover.ts @@ -18,6 +18,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const queryBar = getService('queryBar'); const inspector = getService('inspector'); + const elasticChart = getService('elasticChart'); const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker']); const defaultSettings = { defaultIndex: 'logstash-*', @@ -31,7 +32,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // and load a set of makelogs data await esArchiver.loadIfNeeded('logstash_functional'); await kibanaServer.uiSettings.replace(defaultSettings); - log.debug('discover'); await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setDefaultAbsoluteRange(); }); @@ -99,11 +99,25 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it.skip('should modify the time range when the histogram is brushed', async function () { + it('should modify the time range when the histogram is brushed', async function () { + // this is the number of renderings of the histogram needed when new data is fetched + // this needs to be improved + const renderingCountInc = 3; + const prevRenderingCount = await elasticChart.getVisualizationRenderingCount(); await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await retry.waitFor('chart rendering complete', async () => { + const actualRenderingCount = await elasticChart.getVisualizationRenderingCount(); + log.debug(`Number of renderings before brushing: ${actualRenderingCount}`); + return actualRenderingCount === prevRenderingCount + renderingCountInc; + }); await PageObjects.discover.brushHistogram(); await PageObjects.discover.waitUntilSearchingHasFinished(); - + await retry.waitFor('chart rendering complete after being brushed', async () => { + const actualRenderingCount = await elasticChart.getVisualizationRenderingCount(); + log.debug(`Number of renderings after brushing: ${actualRenderingCount}`); + return actualRenderingCount === prevRenderingCount + 6; + }); const newDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); expect(Math.round(newDurationHours)).to.be(26); diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 88a138ee09bf..33cee4f40d08 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -136,12 +136,14 @@ export function DiscoverPageProvider({ getService, getPageObjects }: FtrProvider } public async clickHistogramBar() { + await elasticChart.waitForRenderComplete(); const el = await elasticChart.getCanvas(); await browser.getActions().move({ x: 0, y: 20, origin: el._webElement }).click().perform(); } public async brushHistogram() { + await elasticChart.waitForRenderComplete(); const el = await elasticChart.getCanvas(); await browser.dragAndDrop( From d560b1ccc8343b7b5d8fe108be9f2190517cdf1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Wed, 3 Feb 2021 08:53:57 +0100 Subject: [PATCH 11/14] [DOCS] Uses doc link service in discover (#88835) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: lcawl --- .../kibana-plugin-core-public.doclinksstart.links.md | 1 + src/core/public/doc_links/doc_links_service.ts | 2 ++ src/core/public/public.api.md | 1 + .../public/application/components/doc/doc.test.tsx | 7 +++++++ .../discover/public/application/components/doc/doc.tsx | 9 ++------- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md index 79c603165cae..51e8d1a0b6be 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md @@ -122,6 +122,7 @@ readonly links: { createPipeline: string; createTransformRequest: string; executeWatchActionModes: string; + indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index c732fc7823b6..885e3e238243 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -226,6 +226,7 @@ export class DocLinksService { createPipeline: `${ELASTICSEARCH_DOCS}put-pipeline-api.html`, createTransformRequest: `${ELASTICSEARCH_DOCS}put-transform.html#put-transform-request-body`, executeWatchActionModes: `${ELASTICSEARCH_DOCS}watcher-api-execute-watch.html#watcher-api-execute-watch-action-mode`, + indexExists: `${ELASTICSEARCH_DOCS}indices-exists.html`, openIndex: `${ELASTICSEARCH_DOCS}indices-open-close.html`, putComponentTemplate: `${ELASTICSEARCH_DOCS}indices-component-template.html`, painlessExecute: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/painless/${DOC_LINK_VERSION}/painless-execute-api.html`, @@ -357,6 +358,7 @@ export interface DocLinksStart { createPipeline: string; createTransformRequest: string; executeWatchActionModes: string; + indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 0097127924a5..37ebbcaa752a 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -575,6 +575,7 @@ export interface DocLinksStart { createPipeline: string; createTransformRequest: string; executeWatchActionModes: string; + indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; diff --git a/src/plugins/discover/public/application/components/doc/doc.test.tsx b/src/plugins/discover/public/application/components/doc/doc.test.tsx index 25f5c1669b92..f96ca6ad9aff 100644 --- a/src/plugins/discover/public/application/components/doc/doc.test.tsx +++ b/src/plugins/discover/public/application/components/doc/doc.test.tsx @@ -29,6 +29,13 @@ jest.mock('../../../kibana_services', () => { search: mockSearchApi, }, }, + docLinks: { + links: { + apis: { + indexExists: 'mockUrl', + }, + }, + }, }), getDocViewsRegistry: () => ({ addDocView(view: any) { diff --git a/src/plugins/discover/public/application/components/doc/doc.tsx b/src/plugins/discover/public/application/components/doc/doc.tsx index aad5b5e95ba3..9f78ae0e29ce 100644 --- a/src/plugins/discover/public/application/components/doc/doc.tsx +++ b/src/plugins/discover/public/application/components/doc/doc.tsx @@ -36,7 +36,7 @@ export interface DocProps { export function Doc(props: DocProps) { const [reqState, hit, indexPattern] = useEsDocSearch(props); - + const indexExistsLink = getServices().docLinks.links.apis.indexExists; return ( @@ -91,12 +91,7 @@ export function Doc(props: DocProps) { defaultMessage="{indexName} is missing." values={{ indexName: props.index }} />{' '} - + Date: Wed, 3 Feb 2021 10:15:53 +0200 Subject: [PATCH 12/14] Remove navigation from Discover to Visualize (#89132) * Remove navigation from Discover to Visualize * Remove unused translation * Remove oss check from functional test * Fix functional test * Skip test for OSS * Fix * Should not remove the uiSettings getter and setter * Move the isOss flag inside the test * Cleanup Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- src/plugins/visualize/kibana.json | 1 - .../public/actions/visualize_field_action.ts | 88 ---------- src/plugins/visualize/public/plugin.ts | 34 +--- src/plugins/visualize/public/services.ts | 17 +- .../visualize/public/url_generator.test.ts | 89 ---------- src/plugins/visualize/public/url_generator.ts | 124 -------------- .../apps/discover/_field_visualize.ts | 159 ------------------ test/functional/apps/discover/index.ts | 1 - .../apps/management/_scripted_fields.js | 103 ++---------- test/functional/apps/management/index.ts | 2 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 12 files changed, 23 insertions(+), 597 deletions(-) delete mode 100644 src/plugins/visualize/public/actions/visualize_field_action.ts delete mode 100644 src/plugins/visualize/public/url_generator.test.ts delete mode 100644 src/plugins/visualize/public/url_generator.ts delete mode 100644 test/functional/apps/discover/_field_visualize.ts diff --git a/src/plugins/visualize/kibana.json b/src/plugins/visualize/kibana.json index 2256a7a7f550..144d33debe3c 100644 --- a/src/plugins/visualize/kibana.json +++ b/src/plugins/visualize/kibana.json @@ -11,7 +11,6 @@ "visualizations", "embeddable", "dashboard", - "uiActions", "presentationUtil" ], "optionalPlugins": [ diff --git a/src/plugins/visualize/public/actions/visualize_field_action.ts b/src/plugins/visualize/public/actions/visualize_field_action.ts deleted file mode 100644 index f83e1f193032..000000000000 --- a/src/plugins/visualize/public/actions/visualize_field_action.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * and the Server Side Public License, v 1; you may not use this file except in - * compliance with, at your election, the Elastic License or the Server Side - * Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; -import { - createAction, - ACTION_VISUALIZE_FIELD, - VisualizeFieldContext, -} from '../../../ui_actions/public'; -import { - getApplication, - getUISettings, - getIndexPatterns, - getQueryService, - getShareService, -} from '../services'; -import { VISUALIZE_APP_URL_GENERATOR, VisualizeUrlGeneratorState } from '../url_generator'; -import { AGGS_TERMS_SIZE_SETTING } from '../../common/constants'; - -export const visualizeFieldAction = createAction({ - type: ACTION_VISUALIZE_FIELD, - id: ACTION_VISUALIZE_FIELD, - getDisplayName: () => - i18n.translate('visualize.discover.visualizeFieldLabel', { - defaultMessage: 'Visualize field', - }), - isCompatible: async () => !!getApplication().capabilities.visualize.show, - getHref: async (context) => { - const url = await getVisualizeUrl(context); - return url; - }, - execute: async (context) => { - const url = await getVisualizeUrl(context); - const hash = url.split('#')[1]; - - getApplication().navigateToApp('visualize', { - path: `/#${hash}`, - }); - }, -}); - -const getVisualizeUrl = async (context: VisualizeFieldContext) => { - const indexPattern = await getIndexPatterns().get(context.indexPatternId); - const field = indexPattern.fields.find((fld) => fld.name === context.fieldName); - const aggsTermSize = getUISettings().get(AGGS_TERMS_SIZE_SETTING); - let agg; - - // If we're visualizing a date field, and our index is time based (and thus has a time filter), - // then run a date histogram - if (field?.type === 'date' && indexPattern.timeFieldName === context.fieldName) { - agg = { - type: 'date_histogram', - schema: 'segment', - params: { - field: context.fieldName, - interval: 'auto', - }, - }; - } else { - agg = { - type: 'terms', - schema: 'segment', - params: { - field: context.fieldName, - size: parseInt(aggsTermSize, 10), - orderBy: '1', - }, - }; - } - const generator = getShareService().urlGenerators.getUrlGenerator(VISUALIZE_APP_URL_GENERATOR); - const urlState: VisualizeUrlGeneratorState = { - filters: getQueryService().filterManager.getFilters(), - query: getQueryService().queryString.getQuery(), - timeRange: getQueryService().timefilter.timefilter.getTime(), - indexPatternId: context.indexPatternId, - type: 'histogram', - vis: { - type: 'histogram', - aggs: [{ schema: 'metric', type: 'count', id: '1' }, agg], - }, - }; - return generator.createUrl(urlState); -}; diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index 8d02e0854966..e240e391d605 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -39,18 +39,8 @@ import { DEFAULT_APP_CATEGORIES } from '../../../core/public'; import { SavedObjectsStart } from '../../saved_objects/public'; import { EmbeddableStart } from '../../embeddable/public'; import { DashboardStart } from '../../dashboard/public'; -import { UiActionsSetup, VISUALIZE_FIELD_TRIGGER } from '../../ui_actions/public'; import type { SavedObjectTaggingOssPluginStart } from '../../saved_objects_tagging_oss/public'; -import { - setUISettings, - setApplication, - setIndexPatterns, - setQueryService, - setShareService, - setVisEditorsRegistry, -} from './services'; -import { visualizeFieldAction } from './actions/visualize_field_action'; -import { createVisualizeUrlGenerator } from './url_generator'; +import { setVisEditorsRegistry, setUISettings } from './services'; import { createVisEditorsRegistry, VisEditorsRegistry } from './vis_editors_registry'; export interface VisualizePluginStartDependencies { @@ -71,7 +61,6 @@ export interface VisualizePluginSetupDependencies { urlForwarding: UrlForwardingSetup; data: DataPublicPluginSetup; share?: SharePluginSetup; - uiActions: UiActionsSetup; } export interface VisualizePluginSetup { @@ -96,7 +85,7 @@ export class VisualizePlugin public async setup( core: CoreSetup, - { home, urlForwarding, data, share, uiActions }: VisualizePluginSetupDependencies + { home, urlForwarding, data }: VisualizePluginSetupDependencies ) { const { appMounted, @@ -129,19 +118,8 @@ export class VisualizePlugin this.stopUrlTracking = () => { stopUrlTracker(); }; - if (share) { - share.urlGenerators.registerUrlGenerator( - createVisualizeUrlGenerator(async () => { - const [coreStart] = await core.getStartServices(); - return { - appBasePath: coreStart.application.getUrlForApp('visualize'), - useHashedUrl: coreStart.uiSettings.get('state:storeInSessionStorage'), - }; - }) - ); - } + setUISettings(core.uiSettings); - uiActions.addTriggerAction(VISUALIZE_FIELD_TRIGGER, visualizeFieldAction); core.application.register({ id: 'visualize', @@ -245,12 +223,6 @@ export class VisualizePlugin public start(core: CoreStart, plugins: VisualizePluginStartDependencies) { setVisEditorsRegistry(this.visEditorsRegistry); - setApplication(core.application); - setIndexPatterns(plugins.data.indexPatterns); - setQueryService(plugins.data.query); - if (plugins.share) { - setShareService(plugins.share); - } } stop() { diff --git a/src/plugins/visualize/public/services.ts b/src/plugins/visualize/public/services.ts index 48c9965b4210..ced651047814 100644 --- a/src/plugins/visualize/public/services.ts +++ b/src/plugins/visualize/public/services.ts @@ -5,28 +5,13 @@ * compliance with, at your election, the Elastic License or the Server Side * Public License, v 1. */ - -import { ApplicationStart, IUiSettingsClient } from '../../../core/public'; +import { IUiSettingsClient } from '../../../core/public'; import { createGetterSetter } from '../../../plugins/kibana_utils/public'; -import { IndexPatternsContract, DataPublicPluginStart } from '../../../plugins/data/public'; -import { SharePluginStart } from '../../../plugins/share/public'; import { VisEditorsRegistry } from './vis_editors_registry'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); -export const [getApplication, setApplication] = createGetterSetter('Application'); - -export const [getShareService, setShareService] = createGetterSetter('Share'); - -export const [getIndexPatterns, setIndexPatterns] = createGetterSetter( - 'IndexPatterns' -); - export const [ getVisEditorsRegistry, setVisEditorsRegistry, ] = createGetterSetter('VisEditorsRegistry'); - -export const [getQueryService, setQueryService] = createGetterSetter< - DataPublicPluginStart['query'] ->('Query'); diff --git a/src/plugins/visualize/public/url_generator.test.ts b/src/plugins/visualize/public/url_generator.test.ts deleted file mode 100644 index 25db806109aa..000000000000 --- a/src/plugins/visualize/public/url_generator.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * and the Server Side Public License, v 1; you may not use this file except in - * compliance with, at your election, the Elastic License or the Server Side - * Public License, v 1. - */ - -import { createVisualizeUrlGenerator } from './url_generator'; -import { esFilters } from '../../data/public'; - -const APP_BASE_PATH: string = 'test/app/visualize'; -const VISUALIZE_ID: string = '13823000-99b9-11ea-9eb6-d9e8adceb647'; -const INDEXPATTERN_ID: string = '13823000-99b9-11ea-9eb6-d9e8adceb647'; - -describe('visualize url generator', () => { - test('creates a link to a new visualization', async () => { - const generator = createVisualizeUrlGenerator(() => - Promise.resolve({ - appBasePath: APP_BASE_PATH, - useHashedUrl: false, - }) - ); - const url = await generator.createUrl!({ indexPatternId: INDEXPATTERN_ID, type: 'table' }); - expect(url).toMatchInlineSnapshot( - `"test/app/visualize#/create?_g=()&_a=()&indexPattern=${INDEXPATTERN_ID}&type=table"` - ); - }); - - test('creates a link with global time range set up', async () => { - const generator = createVisualizeUrlGenerator(() => - Promise.resolve({ - appBasePath: APP_BASE_PATH, - useHashedUrl: false, - }) - ); - const url = await generator.createUrl!({ - timeRange: { to: 'now', from: 'now-15m', mode: 'relative' }, - indexPatternId: INDEXPATTERN_ID, - type: 'table', - }); - expect(url).toMatchInlineSnapshot( - `"test/app/visualize#/create?_g=(time:(from:now-15m,mode:relative,to:now))&_a=()&indexPattern=${INDEXPATTERN_ID}&type=table"` - ); - }); - - test('creates a link with filters, time range, refresh interval and query to a saved visualization', async () => { - const generator = createVisualizeUrlGenerator(() => - Promise.resolve({ - appBasePath: APP_BASE_PATH, - useHashedUrl: false, - indexPatternId: INDEXPATTERN_ID, - type: 'table', - }) - ); - const url = await generator.createUrl!({ - timeRange: { to: 'now', from: 'now-15m', mode: 'relative' }, - refreshInterval: { pause: false, value: 300 }, - visualizationId: VISUALIZE_ID, - filters: [ - { - meta: { - alias: null, - disabled: false, - negate: false, - }, - query: { query: 'q1' }, - }, - { - meta: { - alias: null, - disabled: false, - negate: false, - }, - query: { query: 'q1' }, - $state: { - store: esFilters.FilterStateStore.GLOBAL_STATE, - }, - }, - ], - query: { query: 'q2', language: 'kuery' }, - indexPatternId: INDEXPATTERN_ID, - type: 'table', - }); - expect(url).toMatchInlineSnapshot( - `"test/app/visualize#/edit/${VISUALIZE_ID}?_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,negate:!f),query:(query:q1))),refreshInterval:(pause:!f,value:300),time:(from:now-15m,mode:relative,to:now))&_a=(filters:!((meta:(alias:!n,disabled:!f,negate:!f),query:(query:q1))),query:(language:kuery,query:q2))&indexPattern=${INDEXPATTERN_ID}&type=table"` - ); - }); -}); diff --git a/src/plugins/visualize/public/url_generator.ts b/src/plugins/visualize/public/url_generator.ts deleted file mode 100644 index 57fa9b2ae480..000000000000 --- a/src/plugins/visualize/public/url_generator.ts +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * and the Server Side Public License, v 1; you may not use this file except in - * compliance with, at your election, the Elastic License or the Server Side - * Public License, v 1. - */ - -import { - TimeRange, - Filter, - Query, - esFilters, - QueryState, - RefreshInterval, -} from '../../data/public'; -import { setStateToKbnUrl } from '../../kibana_utils/public'; -import { UrlGeneratorsDefinition } from '../../share/public'; -import { STATE_STORAGE_KEY, GLOBAL_STATE_STORAGE_KEY } from '../common/constants'; - -export const VISUALIZE_APP_URL_GENERATOR = 'VISUALIZE_APP_URL_GENERATOR'; - -export interface VisualizeUrlGeneratorState { - /** - * If given, it will load the given visualization else will load the create a new visualization page. - */ - visualizationId?: string; - /** - * Optionally set the time range in the time picker. - */ - timeRange?: TimeRange; - - /** - * Optional set indexPatternId. - */ - indexPatternId?: string; - - /** - * Optional set visualization type. - */ - type?: string; - - /** - * Optionally set the visualization. - */ - vis?: unknown; - - /** - * Optionally set the refresh interval. - */ - refreshInterval?: RefreshInterval; - - /** - * Optionally apply filers. NOTE: if given and used in conjunction with `dashboardId`, and the - * saved dashboard has filters saved with it, this will _replace_ those filters. - */ - filters?: Filter[]; - /** - * Optionally set a query. NOTE: if given and used in conjunction with `dashboardId`, and the - * saved dashboard has a query saved with it, this will _replace_ that query. - */ - query?: Query; - /** - * If not given, will use the uiSettings configuration for `storeInSessionStorage`. useHash determines - * whether to hash the data in the url to avoid url length issues. - */ - hash?: boolean; -} - -export const createVisualizeUrlGenerator = ( - getStartServices: () => Promise<{ - appBasePath: string; - useHashedUrl: boolean; - }> -): UrlGeneratorsDefinition => ({ - id: VISUALIZE_APP_URL_GENERATOR, - createUrl: async ({ - visualizationId, - filters, - indexPatternId, - query, - refreshInterval, - vis, - type, - timeRange, - hash, - }: VisualizeUrlGeneratorState): Promise => { - const startServices = await getStartServices(); - const useHash = hash ?? startServices.useHashedUrl; - const appBasePath = startServices.appBasePath; - const mode = visualizationId ? `edit/${visualizationId}` : `create`; - - const appState: { - query?: Query; - filters?: Filter[]; - vis?: unknown; - } = {}; - const queryState: QueryState = {}; - - if (query) appState.query = query; - if (filters && filters.length) - appState.filters = filters?.filter((f) => !esFilters.isFilterPinned(f)); - if (vis) appState.vis = vis; - - if (timeRange) queryState.time = timeRange; - if (filters && filters.length) - queryState.filters = filters?.filter((f) => esFilters.isFilterPinned(f)); - if (refreshInterval) queryState.refreshInterval = refreshInterval; - - let url = `${appBasePath}#/${mode}`; - url = setStateToKbnUrl(GLOBAL_STATE_STORAGE_KEY, queryState, { useHash }, url); - url = setStateToKbnUrl(STATE_STORAGE_KEY, appState, { useHash }, url); - - if (indexPatternId) { - url = `${url}&indexPattern=${indexPatternId}`; - } - - if (type) { - url = `${url}&type=${type}`; - } - - return url; - }, -}); diff --git a/test/functional/apps/discover/_field_visualize.ts b/test/functional/apps/discover/_field_visualize.ts deleted file mode 100644 index e11ef249d8c7..000000000000 --- a/test/functional/apps/discover/_field_visualize.ts +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * and the Server Side Public License, v 1; you may not use this file except in - * compliance with, at your election, the Elastic License or the Server Side - * Public License, v 1. - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const filterBar = getService('filterBar'); - const inspector = getService('inspector'); - const kibanaServer = getService('kibanaServer'); - const log = getService('log'); - const queryBar = getService('queryBar'); - const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker', 'visualize']); - const defaultSettings = { - defaultIndex: 'logstash-*', - }; - - describe('discover field visualize button', function () { - // unskipped on cloud as these tests test the navigation - // from Discover to Visualize which happens only on OSS - this.tags(['skipCloud']); - before(async function () { - log.debug('load kibana index with default index pattern'); - await esArchiver.load('discover'); - - // and load a set of makelogs data - await esArchiver.loadIfNeeded('logstash_functional'); - await kibanaServer.uiSettings.replace(defaultSettings); - }); - - beforeEach(async () => { - log.debug('go to discover'); - await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setDefaultAbsoluteRange(); - }); - - it('should be able to visualize a field and save the visualization', async () => { - await PageObjects.discover.findFieldByName('type'); - log.debug('visualize a type field'); - await PageObjects.discover.clickFieldListItemVisualize('type'); - await PageObjects.visualize.saveVisualizationExpectSuccess('Top 5 server types'); - }); - - it('should visualize a field in area chart', async () => { - await PageObjects.discover.findFieldByName('phpmemory'); - log.debug('visualize a phpmemory field'); - await PageObjects.discover.clickFieldListItemVisualize('phpmemory'); - await PageObjects.header.waitUntilLoadingHasFinished(); - const expectedTableData = [ - ['0', '10'], - ['58,320', '2'], - ['171,080', '2'], - ['3,240', '1'], - ['3,520', '1'], - ['3,880', '1'], - ['4,120', '1'], - ['4,640', '1'], - ['4,760', '1'], - ['5,680', '1'], - ['7,160', '1'], - ['7,400', '1'], - ['8,400', '1'], - ['8,800', '1'], - ['8,960', '1'], - ['9,400', '1'], - ['10,280', '1'], - ['10,840', '1'], - ['13,080', '1'], - ['13,360', '1'], - ]; - await inspector.open(); - await inspector.expectTableData(expectedTableData); - await inspector.close(); - }); - - it('should not show the "Visualize" button for geo field', async () => { - await PageObjects.discover.findFieldByName('geo.coordinates'); - log.debug('visualize a geo field'); - await PageObjects.discover.expectMissingFieldListItemVisualize('geo.coordinates'); - }); - - it('should preserve app filters in visualize', async () => { - await filterBar.addFilter('bytes', 'is between', '3500', '4000'); - await PageObjects.discover.findFieldByName('geo.src'); - log.debug('visualize a geo.src field with filter applied'); - await PageObjects.discover.clickFieldListItemVisualize('geo.src'); - await PageObjects.header.waitUntilLoadingHasFinished(); - - expect(await filterBar.hasFilter('bytes', '3,500 to 4,000')).to.be(true); - const expectedTableData = [ - ['CN', '133'], - ['IN', '120'], - ['US', '58'], - ['ID', '28'], - ['BD', '25'], - ['BR', '22'], - ['EG', '14'], - ['NG', '14'], - ['PK', '13'], - ['IR', '12'], - ['PH', '12'], - ['JP', '11'], - ['RU', '11'], - ['DE', '8'], - ['FR', '8'], - ['MX', '8'], - ['TH', '8'], - ['TR', '8'], - ['CA', '6'], - ['SA', '6'], - ]; - await inspector.open(); - await inspector.expectTableData(expectedTableData); - await inspector.close(); - }); - - it('should preserve query in visualize', async () => { - await queryBar.setQuery('machine.os : ios'); - await queryBar.submitQuery(); - await PageObjects.discover.findFieldByName('geo.dest'); - log.debug('visualize a geo.dest field with query applied'); - await PageObjects.discover.clickFieldListItemVisualize('geo.dest'); - await PageObjects.header.waitUntilLoadingHasFinished(); - - expect(await queryBar.getQueryString()).to.equal('machine.os : ios'); - const expectedTableData = [ - ['CN', '519'], - ['IN', '495'], - ['US', '275'], - ['ID', '82'], - ['PK', '75'], - ['BR', '71'], - ['NG', '54'], - ['BD', '51'], - ['JP', '47'], - ['MX', '47'], - ['IR', '44'], - ['PH', '44'], - ['RU', '42'], - ['ET', '33'], - ['TH', '33'], - ['EG', '32'], - ['VN', '32'], - ['DE', '31'], - ['FR', '30'], - ['GB', '30'], - ]; - await inspector.open(); - await inspector.expectTableData(expectedTableData); - await inspector.close(); - }); - }); -} diff --git a/test/functional/apps/discover/index.ts b/test/functional/apps/discover/index.ts index 4f42b41a1e02..b4fc4ead2d52 100644 --- a/test/functional/apps/discover/index.ts +++ b/test/functional/apps/discover/index.ts @@ -27,7 +27,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_discover')); loadTestFile(require.resolve('./_discover_histogram')); loadTestFile(require.resolve('./_doc_table')); - loadTestFile(require.resolve('./_field_visualize')); loadTestFile(require.resolve('./_filter_editor')); loadTestFile(require.resolve('./_errors')); loadTestFile(require.resolve('./_field_data')); diff --git a/test/functional/apps/management/_scripted_fields.js b/test/functional/apps/management/_scripted_fields.js index 62edbc50879a..d1a4c93cec04 100644 --- a/test/functional/apps/management/_scripted_fields.js +++ b/test/functional/apps/management/_scripted_fields.js @@ -27,13 +27,12 @@ import expect from '@kbn/expect'; export default function ({ getService, getPageObjects }) { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const deployment = getService('deployment'); const log = getService('log'); const browser = getService('browser'); const retry = getService('retry'); - const inspector = getService('inspector'); const testSubjects = getService('testSubjects'); const filterBar = getService('filterBar'); - const deployment = getService('deployment'); const PageObjects = getPageObjects([ 'common', 'header', @@ -188,39 +187,11 @@ export default function ({ getService, getPageObjects }) { }); it('should visualize scripted field in vertical bar chart', async function () { - await filterBar.removeAllFilters(); - await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName); - await PageObjects.header.waitUntilLoadingHasFinished(); - - if (await deployment.isOss()) { - // OSS renders a vertical bar chart and we check the data in the Inspect panel - const expectedChartValues = [ - ['14', '31'], - ['10', '29'], - ['7', '24'], - ['11', '24'], - ['12', '23'], - ['20', '23'], - ['19', '21'], - ['6', '20'], - ['17', '20'], - ['30', '20'], - ['13', '19'], - ['18', '18'], - ['16', '17'], - ['5', '16'], - ['8', '16'], - ['15', '14'], - ['3', '13'], - ['2', '12'], - ['9', '10'], - ['4', '9'], - ]; - - await inspector.open(); - await inspector.setTablePageSize(50); - await inspector.expectTableData(expectedChartValues); - } else { + const isOss = await deployment.isOss(); + if (!isOss) { + await filterBar.removeAllFilters(); + await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName); + await PageObjects.header.waitUntilLoadingHasFinished(); // verify Lens opens a visualization expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( 'Average of ram_Pain1' @@ -306,16 +277,10 @@ export default function ({ getService, getPageObjects }) { }); it('should visualize scripted field in vertical bar chart', async function () { - await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - if (await deployment.isOss()) { - // OSS renders a vertical bar chart and we check the data in the Inspect panel - await inspector.open(); - await inspector.expectTableData([ - ['good', '359'], - ['bad', '27'], - ]); - } else { + const isOss = await deployment.isOss(); + if (!isOss) { + await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); + await PageObjects.header.waitUntilLoadingHasFinished(); // verify Lens opens a visualization expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( 'Top values of painString' @@ -402,16 +367,10 @@ export default function ({ getService, getPageObjects }) { }); it('should visualize scripted field in vertical bar chart', async function () { - await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - if (await deployment.isOss()) { - // OSS renders a vertical bar chart and we check the data in the Inspect panel - await inspector.open(); - await inspector.expectTableData([ - ['true', '359'], - ['false', '27'], - ]); - } else { + const isOss = await deployment.isOss(); + if (!isOss) { + await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); + await PageObjects.header.waitUntilLoadingHasFinished(); // verify Lens opens a visualization expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( 'Top values of painBool' @@ -501,36 +460,10 @@ export default function ({ getService, getPageObjects }) { }); it('should visualize scripted field in vertical bar chart', async function () { - await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - - if (await deployment.isOss()) { - // OSS renders a vertical bar chart and we check the data in the Inspect panel - await inspector.open(); - await inspector.setTablePageSize(50); - await inspector.expectTableData([ - ['2015-09-17 20:00', '1'], - ['2015-09-17 21:00', '1'], - ['2015-09-17 23:00', '1'], - ['2015-09-18 00:00', '1'], - ['2015-09-18 03:00', '1'], - ['2015-09-18 04:00', '1'], - ['2015-09-18 04:00', '1'], - ['2015-09-18 04:00', '1'], - ['2015-09-18 04:00', '1'], - ['2015-09-18 05:00', '1'], - ['2015-09-18 05:00', '1'], - ['2015-09-18 05:00', '1'], - ['2015-09-18 05:00', '1'], - ['2015-09-18 06:00', '1'], - ['2015-09-18 06:00', '1'], - ['2015-09-18 06:00', '1'], - ['2015-09-18 06:00', '1'], - ['2015-09-18 07:00', '1'], - ['2015-09-18 07:00', '1'], - ['2015-09-18 07:00', '1'], - ]); - } else { + const isOss = await deployment.isOss(); + if (!isOss) { + await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); + await PageObjects.header.waitUntilLoadingHasFinished(); // verify Lens opens a visualization expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( 'painDate' diff --git a/test/functional/apps/management/index.ts b/test/functional/apps/management/index.ts index ca8985387502..3de11fbf4c99 100644 --- a/test/functional/apps/management/index.ts +++ b/test/functional/apps/management/index.ts @@ -31,10 +31,10 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_index_pattern_results_sort')); loadTestFile(require.resolve('./_index_pattern_popularity')); loadTestFile(require.resolve('./_kibana_settings')); - loadTestFile(require.resolve('./_scripted_fields')); loadTestFile(require.resolve('./_scripted_fields_preview')); loadTestFile(require.resolve('./_mgmt_import_saved_objects')); loadTestFile(require.resolve('./_index_patterns_empty')); + loadTestFile(require.resolve('./_scripted_fields')); }); describe('', function () { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index fdf1c74f2051..cab6973072f2 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4713,7 +4713,6 @@ "visualize.createVisualization.failedToLoadErrorMessage": "ビジュアライゼーションを読み込めませんでした", "visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "indexPatternまたはsavedSearchIdが必要です", "visualize.createVisualization.noVisTypeErrorMessage": "有効なビジュアライゼーションタイプを指定してください", - "visualize.discover.visualizeFieldLabel": "Visualizeフィールド", "visualize.editor.createBreadcrumb": "作成", "visualize.editor.defaultEditBreadcrumbText": "編集", "visualize.experimentalVisInfoText": "このビジュアライゼーションはまだ実験段階であり、オフィシャルGA機能のサポートSLAが適用されません。フィードバックがある場合は、{githubLink}で問題を報告してください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b3fefd55ce55..dbd4c426c345 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4718,7 +4718,6 @@ "visualize.createVisualization.failedToLoadErrorMessage": "无法加载可视化", "visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "必须提供 indexPattern 或 savedSearchId", "visualize.createVisualization.noVisTypeErrorMessage": "必须提供有效的可视化类型", - "visualize.discover.visualizeFieldLabel": "可视化字段", "visualize.editor.createBreadcrumb": "创建", "visualize.editor.defaultEditBreadcrumbText": "编辑", "visualize.experimentalVisInfoText": "此可视化为试验性功能,不受正式发行版功能支持 SLA 的约束。如欲提供反馈,请在 {githubLink} 中创建问题。", From 22a903a9e3ccf45d9fbaa3576375052e61c1f43c Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Wed, 3 Feb 2021 08:47:11 +0000 Subject: [PATCH 13/14] [Security Solution] Saving is not working if hitting "favorites button" beforehand (#88642) * fix favorites for templates * fix integration test * fix integration test * fix event details request * handle data when searchstrategy is still running Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/graphql/introspection.json | 42 +++++++ .../security_solution/public/graphql/types.ts | 21 ++++ .../open_timeline/note_previews/index.tsx | 13 +- .../containers/favorite/persist.gql_query.ts | 17 ++- .../timelines/store/timeline/epic_favorite.ts | 10 ++ .../server/graphql/timeline/resolvers.ts | 9 +- .../server/graphql/timeline/schema.gql.ts | 5 +- .../security_solution/server/graphql/types.ts | 39 ++++++ .../server/lib/timeline/saved_object.ts | 20 ++- .../timeline/factory/events/details/index.ts | 10 +- .../saved_objects/timeline.ts | 115 ++++++++++++++++++ 11 files changed, 290 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/security_solution/public/graphql/introspection.json b/x-pack/plugins/security_solution/public/graphql/introspection.json index 9e0cf10a54aa..a2f1f222173d 100644 --- a/x-pack/plugins/security_solution/public/graphql/introspection.json +++ b/x-pack/plugins/security_solution/public/graphql/introspection.json @@ -3365,6 +3365,24 @@ "description": "", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null + }, + { + "name": "templateTimelineId", + "description": "", + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "defaultValue": null + }, + { + "name": "templateTimelineVersion", + "description": "", + "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, + "defaultValue": null + }, + { + "name": "timelineType", + "description": "", + "type": { "kind": "ENUM", "name": "TimelineType", "ofType": null }, + "defaultValue": null } ], "type": { @@ -4149,6 +4167,30 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "templateTimelineId", + "description": "", + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "templateTimelineVersion", + "description": "", + "args": [], + "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "timelineType", + "description": "", + "args": [], + "type": { "kind": "ENUM", "name": "TimelineType", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "version", "description": "", diff --git a/x-pack/plugins/security_solution/public/graphql/types.ts b/x-pack/plugins/security_solution/public/graphql/types.ts index 435576a02b30..a5e027c69546 100644 --- a/x-pack/plugins/security_solution/public/graphql/types.ts +++ b/x-pack/plugins/security_solution/public/graphql/types.ts @@ -835,6 +835,12 @@ export interface ResponseFavoriteTimeline { savedObjectId: string; + templateTimelineId?: Maybe; + + templateTimelineVersion?: Maybe; + + timelineType?: Maybe; + version: string; favorite?: Maybe; @@ -1691,6 +1697,12 @@ export interface PersistTimelineMutationArgs { } export interface PersistFavoriteMutationArgs { timelineId?: Maybe; + + templateTimelineId?: Maybe; + + templateTimelineVersion?: Maybe; + + timelineType?: Maybe; } export interface DeleteTimelineMutationArgs { id: string[]; @@ -2096,6 +2108,9 @@ export namespace DeleteTimelineMutation { export namespace PersistTimelineFavoriteMutation { export type Variables = { timelineId?: Maybe; + templateTimelineId?: Maybe; + templateTimelineVersion?: Maybe; + timelineType: TimelineType; }; export type Mutation = { @@ -2112,6 +2127,12 @@ export namespace PersistTimelineFavoriteMutation { version: string; favorite: Maybe; + + templateTimelineId: Maybe; + + templateTimelineVersion: Maybe; + + timelineType: Maybe; }; export type Favorite = { diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx index d6ea611660ed..2c7b917d373c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx @@ -18,6 +18,8 @@ import { timelineActions } from '../../../store/timeline'; import { NOTE_CONTENT_CLASS_NAME } from '../../timeline/body/helpers'; import * as i18n from './translations'; import { TimelineTabs } from '../../../../../common/types/timeline'; +import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; +import { sourcererSelectors } from '../../../../common/store'; export const NotePreviewsContainer = styled.section` padding-top: ${({ theme }) => `${theme.eui.euiSizeS}`}; @@ -35,6 +37,12 @@ const ToggleEventDetailsButtonComponent: React.FC timelineId, }) => { const dispatch = useDispatch(); + const existingIndexNamesSelector = useMemo( + () => sourcererSelectors.getAllExistingIndexNamesSelector(), + [] + ); + const existingIndexNames = useDeepEqualSelector(existingIndexNamesSelector); + const handleClick = useCallback(() => { dispatch( timelineActions.toggleExpandedEvent({ @@ -42,12 +50,11 @@ const ToggleEventDetailsButtonComponent: React.FC timelineId, event: { eventId, - // we don't store yet info about event index name in note - indexName: '', + indexName: existingIndexNames.join(','), }, }) ); - }, [dispatch, eventId, timelineId]); + }, [dispatch, eventId, existingIndexNames, timelineId]); return ( ; @@ -63,7 +64,13 @@ export const createTimelineResolvers = ( return true; }, async persistFavorite(root, args, { req }) { - return libs.timeline.persistFavorite(req, args.timelineId || null); + return libs.timeline.persistFavorite( + req, + args.timelineId || null, + args.templateTimelineId || null, + args.templateTimelineVersion || null, + args.timelineType || TimelineType.default + ); }, async persistTimeline(root, args, { req }) { return libs.timeline.persistTimeline( diff --git a/x-pack/plugins/security_solution/server/graphql/timeline/schema.gql.ts b/x-pack/plugins/security_solution/server/graphql/timeline/schema.gql.ts index ca6c57f025fa..933c3e912389 100644 --- a/x-pack/plugins/security_solution/server/graphql/timeline/schema.gql.ts +++ b/x-pack/plugins/security_solution/server/graphql/timeline/schema.gql.ts @@ -294,6 +294,9 @@ export const timelineSchema = gql` code: Float message: String savedObjectId: String! + templateTimelineId: String + templateTimelineVersion: Int + timelineType: TimelineType version: String! favorite: [FavoriteTimelineResult!] } @@ -320,7 +323,7 @@ export const timelineSchema = gql` extend type Mutation { "Persists a timeline" persistTimeline(id: ID, version: String, timeline: TimelineInput!): ResponseTimeline! - persistFavorite(timelineId: ID): ResponseFavoriteTimeline! + persistFavorite(timelineId: ID, templateTimelineId: String, templateTimelineVersion: Int, timelineType: TimelineType): ResponseFavoriteTimeline! deleteTimeline(id: [ID!]!): Boolean! } `; diff --git a/x-pack/plugins/security_solution/server/graphql/types.ts b/x-pack/plugins/security_solution/server/graphql/types.ts index 3ea964c0ee01..783e61106387 100644 --- a/x-pack/plugins/security_solution/server/graphql/types.ts +++ b/x-pack/plugins/security_solution/server/graphql/types.ts @@ -837,6 +837,12 @@ export interface ResponseFavoriteTimeline { savedObjectId: string; + templateTimelineId?: Maybe; + + templateTimelineVersion?: Maybe; + + timelineType?: Maybe; + version: string; favorite?: Maybe; @@ -1693,6 +1699,12 @@ export interface PersistTimelineMutationArgs { } export interface PersistFavoriteMutationArgs { timelineId?: Maybe; + + templateTimelineId?: Maybe; + + templateTimelineVersion?: Maybe; + + timelineType?: Maybe; } export interface DeleteTimelineMutationArgs { id: string[]; @@ -3419,6 +3431,12 @@ export namespace MutationResolvers { > = Resolver; export interface PersistFavoriteArgs { timelineId?: Maybe; + + templateTimelineId?: Maybe; + + templateTimelineVersion?: Maybe; + + timelineType?: Maybe; } export type DeleteTimelineResolver = Resolver< @@ -3492,6 +3510,12 @@ export namespace ResponseFavoriteTimelineResolvers { savedObjectId?: SavedObjectIdResolver; + templateTimelineId?: TemplateTimelineIdResolver, TypeParent, TContext>; + + templateTimelineVersion?: TemplateTimelineVersionResolver, TypeParent, TContext>; + + timelineType?: TimelineTypeResolver, TypeParent, TContext>; + version?: VersionResolver; favorite?: FavoriteResolver, TypeParent, TContext>; @@ -3512,6 +3536,21 @@ export namespace ResponseFavoriteTimelineResolvers { Parent = ResponseFavoriteTimeline, TContext = SiemContext > = Resolver; + export type TemplateTimelineIdResolver< + R = Maybe, + Parent = ResponseFavoriteTimeline, + TContext = SiemContext + > = Resolver; + export type TemplateTimelineVersionResolver< + R = Maybe, + Parent = ResponseFavoriteTimeline, + TContext = SiemContext + > = Resolver; + export type TimelineTypeResolver< + R = Maybe, + Parent = ResponseFavoriteTimeline, + TContext = SiemContext + > = Resolver; export type VersionResolver< R = string, Parent = ResponseFavoriteTimeline, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts index 83566a619061..c2698749f9d8 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts @@ -76,7 +76,10 @@ export interface Timeline { persistFavorite: ( request: FrameworkRequest, - timelineId: string | null + timelineId: string | null, + templateTimelineId: string | null, + templateTimelineVersion: number | null, + timelineType: TimelineType ) => Promise; persistTimeline: ( @@ -281,7 +284,10 @@ export const getDraftTimeline = async ( export const persistFavorite = async ( request: FrameworkRequest, - timelineId: string | null + timelineId: string | null, + templateTimelineId: string | null, + templateTimelineVersion: number | null, + timelineType: TimelineType ): Promise => { const userName = request.user?.username ?? UNAUTHENTICATED_USER; const fullName = request.user?.full_name ?? ''; @@ -324,7 +330,12 @@ export const persistFavorite = async ( timeline.favorite = [userFavoriteTimeline]; } - const persistResponse = await persistTimeline(request, timelineId, null, timeline); + const persistResponse = await persistTimeline(request, timelineId, null, { + ...timeline, + templateTimelineId, + templateTimelineVersion, + timelineType, + }); return { savedObjectId: persistResponse.timeline.savedObjectId, version: persistResponse.timeline.version, @@ -332,6 +343,9 @@ export const persistFavorite = async ( persistResponse.timeline.favorite != null ? persistResponse.timeline.favorite.filter((fav) => fav.userName === userName) : [], + templateTimelineId, + templateTimelineVersion, + timelineType, }; } catch (err) { if (getOr(null, 'output.statusCode', err) === 403) { diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts index d9fa4fdda9be..7e657757d247 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts @@ -32,11 +32,19 @@ export const timelineEventsDetails: SecuritySolutionTimelineFactory { + const titleToSaved = 'hello title'; + const templateTimelineIdFromStore = 'f4a90a2d-365c-407b-9fef-c1dcb33a6ab3'; + const templateTimelineVersionFromStore = 1; + const response = await createBasicTimeline(client, titleToSaved); + const { savedObjectId, version } = response.data && response.data.persistTimeline.timeline; + + const responseToTest = await client.mutate({ + mutation: persistTimelineFavoriteMutation, + variables: { + timelineId: savedObjectId, + templateTimelineId: templateTimelineIdFromStore, + templateTimelineVersion: templateTimelineVersionFromStore, + timelineType: TimelineType.template, + }, + }); + + expect(responseToTest.data!.persistFavorite.savedObjectId).to.be(savedObjectId); + expect(responseToTest.data!.persistFavorite.favorite.length).to.be(1); + expect(responseToTest.data!.persistFavorite.version).to.not.be.eql(version); + expect(responseToTest.data!.persistFavorite.templateTimelineId).to.be.eql( + templateTimelineIdFromStore + ); + expect(responseToTest.data!.persistFavorite.templateTimelineVersion).to.be.eql( + templateTimelineVersionFromStore + ); + expect(responseToTest.data!.persistFavorite.timelineType).to.be.eql(TimelineType.template); }); it('to Unfavorite an existing timeline', async () => { @@ -226,6 +262,9 @@ export default function ({ getService }: FtrProviderContext) { mutation: persistTimelineFavoriteMutation, variables: { timelineId: savedObjectId, + templateTimelineId: null, + templateTimelineVersion: null, + timelineType: TimelineType.default, }, }); @@ -233,12 +272,57 @@ export default function ({ getService }: FtrProviderContext) { mutation: persistTimelineFavoriteMutation, variables: { timelineId: savedObjectId, + templateTimelineId: null, + templateTimelineVersion: null, + timelineType: TimelineType.default, }, }); expect(responseToTest.data!.persistFavorite.savedObjectId).to.be(savedObjectId); expect(responseToTest.data!.persistFavorite.favorite).to.be.empty(); expect(responseToTest.data!.persistFavorite.version).to.not.be.eql(version); + expect(responseToTest.data!.persistFavorite.templateTimelineId).to.be.eql(null); + expect(responseToTest.data!.persistFavorite.templateTimelineVersion).to.be.eql(null); + expect(responseToTest.data!.persistFavorite.timelineType).to.be.eql(TimelineType.default); + }); + + it('to Unfavorite an existing timeline template', async () => { + const titleToSaved = 'hello title'; + const templateTimelineIdFromStore = 'f4a90a2d-365c-407b-9fef-c1dcb33a6ab3'; + const templateTimelineVersionFromStore = 1; + const response = await createBasicTimeline(client, titleToSaved); + const { savedObjectId, version } = response.data && response.data.persistTimeline.timeline; + + await client.mutate({ + mutation: persistTimelineFavoriteMutation, + variables: { + timelineId: savedObjectId, + templateTimelineId: templateTimelineIdFromStore, + templateTimelineVersion: templateTimelineVersionFromStore, + timelineType: TimelineType.template, + }, + }); + + const responseToTest = await client.mutate({ + mutation: persistTimelineFavoriteMutation, + variables: { + timelineId: savedObjectId, + templateTimelineId: templateTimelineIdFromStore, + templateTimelineVersion: templateTimelineVersionFromStore, + timelineType: TimelineType.template, + }, + }); + + expect(responseToTest.data!.persistFavorite.savedObjectId).to.be(savedObjectId); + expect(responseToTest.data!.persistFavorite.favorite).to.be.empty(); + expect(responseToTest.data!.persistFavorite.version).to.not.be.eql(version); + expect(responseToTest.data!.persistFavorite.templateTimelineId).to.be.eql( + templateTimelineIdFromStore + ); + expect(responseToTest.data!.persistFavorite.templateTimelineVersion).to.be.eql( + templateTimelineVersionFromStore + ); + expect(responseToTest.data!.persistFavorite.timelineType).to.be.eql(TimelineType.template); }); it('to a timeline without a timelineId', async () => { @@ -246,12 +330,43 @@ export default function ({ getService }: FtrProviderContext) { mutation: persistTimelineFavoriteMutation, variables: { timelineId: null, + templateTimelineId: null, + templateTimelineVersion: null, + timelineType: TimelineType.default, }, }); expect(response.data!.persistFavorite.savedObjectId).to.not.be.empty(); expect(response.data!.persistFavorite.favorite.length).to.be(1); expect(response.data!.persistFavorite.version).to.not.be.empty(); + expect(response.data!.persistFavorite.templateTimelineId).to.be.eql(null); + expect(response.data!.persistFavorite.templateTimelineVersion).to.be.eql(null); + expect(response.data!.persistFavorite.timelineType).to.be.eql(TimelineType.default); + }); + + it('to a timeline template without a timelineId', async () => { + const templateTimelineIdFromStore = 'f4a90a2d-365c-407b-9fef-c1dcb33a6ab3'; + const templateTimelineVersionFromStore = 1; + const response = await client.mutate({ + mutation: persistTimelineFavoriteMutation, + variables: { + timelineId: null, + templateTimelineId: templateTimelineIdFromStore, + templateTimelineVersion: templateTimelineVersionFromStore, + timelineType: TimelineType.template, + }, + }); + + expect(response.data!.persistFavorite.savedObjectId).to.not.be.empty(); + expect(response.data!.persistFavorite.favorite.length).to.be(1); + expect(response.data!.persistFavorite.version).to.not.be.empty(); + expect(response.data!.persistFavorite.templateTimelineId).to.be.eql( + templateTimelineIdFromStore + ); + expect(response.data!.persistFavorite.templateTimelineVersion).to.be.eql( + templateTimelineVersionFromStore + ); + expect(response.data!.persistFavorite.timelineType).to.be.eql(TimelineType.template); }); }); From 8f70c52180befcef8fc38baabfeb2a91603fd4be Mon Sep 17 00:00:00 2001 From: Peter Pisljar Date: Wed, 3 Feb 2021 11:47:24 +0100 Subject: [PATCH 14/14] cleaning up tabify to return Datatable (#89857) --- .../kibana-plugin-plugins-data-public.md | 3 - ...s-data-public.tabbedaggcolumn.aggconfig.md | 11 --- ...-plugins-data-public.tabbedaggcolumn.id.md | 11 --- ...gin-plugins-data-public.tabbedaggcolumn.md | 22 ----- ...lugins-data-public.tabbedaggcolumn.name.md | 11 --- ...plugin-plugins-data-public.tabbedaggrow.md | 13 --- ...plugins-data-public.tabbedtable.columns.md | 11 --- ...-plugin-plugins-data-public.tabbedtable.md | 21 ---- ...in-plugins-data-public.tabbedtable.rows.md | 11 --- .../kibana-plugin-plugins-data-server.md | 3 - ...s-data-server.tabbedaggcolumn.aggconfig.md | 11 --- ...-plugins-data-server.tabbedaggcolumn.id.md | 11 --- ...gin-plugins-data-server.tabbedaggcolumn.md | 22 ----- ...lugins-data-server.tabbedaggcolumn.name.md | 11 --- ...plugin-plugins-data-server.tabbedaggrow.md | 13 --- ...plugins-data-server.tabbedtable.columns.md | 11 --- ...-plugin-plugins-data-server.tabbedtable.md | 21 ---- ...in-plugins-data-server.tabbedtable.rows.md | 11 --- .../expressions/esaggs/create_filter.test.ts | 7 +- .../expressions/esaggs/create_filter.ts | 6 +- .../search/expressions/esaggs/esaggs_fn.ts | 57 +---------- .../esaggs/request_handler.test.ts | 1 - .../expressions/esaggs/request_handler.ts | 3 - .../data/common/search/tabify/index.ts | 2 - .../search/tabify/response_writer.test.ts | 96 ++++++++++++++++++- .../common/search/tabify/response_writer.ts | 46 +++++++-- .../data/common/search/tabify/tabify.test.ts | 7 +- .../data/common/search/tabify/types.ts | 6 -- src/plugins/data/public/index.ts | 4 - .../index_patterns/index_pattern.stub.ts | 3 +- src/plugins/data/public/public.api.md | 51 +++------- .../public/search/expressions/esaggs.test.ts | 6 +- .../data/public/search/expressions/esaggs.ts | 14 +-- src/plugins/data/server/index.ts | 4 - .../server/search/expressions/esaggs.test.ts | 6 +- .../data/server/search/expressions/esaggs.ts | 17 +--- src/plugins/data/server/server.api.md | 49 +++------- 37 files changed, 183 insertions(+), 430 deletions(-) delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggrow.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.columns.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.rows.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggrow.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.columns.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.rows.md diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index 4bbc76b78ba0..f576d795b93a 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -92,8 +92,6 @@ | [SearchInterceptorDeps](./kibana-plugin-plugins-data-public.searchinterceptordeps.md) | | | [SearchSessionInfoProvider](./kibana-plugin-plugins-data-public.searchsessioninfoprovider.md) | Provide info about current search session to be stored in the Search Session saved object | | [SearchSourceFields](./kibana-plugin-plugins-data-public.searchsourcefields.md) | search source fields | -| [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) | \* | -| [TabbedTable](./kibana-plugin-plugins-data-public.tabbedtable.md) | \* | ## Variables @@ -187,7 +185,6 @@ | [SavedQueryTimeFilter](./kibana-plugin-plugins-data-public.savedquerytimefilter.md) | | | [SearchBarProps](./kibana-plugin-plugins-data-public.searchbarprops.md) | | | [StatefulSearchBarProps](./kibana-plugin-plugins-data-public.statefulsearchbarprops.md) | | -| [TabbedAggRow](./kibana-plugin-plugins-data-public.tabbedaggrow.md) | \* | | [TimefilterContract](./kibana-plugin-plugins-data-public.timefiltercontract.md) | | | [TimeHistoryContract](./kibana-plugin-plugins-data-public.timehistorycontract.md) | | | [TimeRange](./kibana-plugin-plugins-data-public.timerange.md) | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md deleted file mode 100644 index b010667af79e..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) > [aggConfig](./kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md) - -## TabbedAggColumn.aggConfig property - -Signature: - -```typescript -aggConfig: IAggConfig; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md deleted file mode 100644 index 86f8b0131204..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) > [id](./kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md) - -## TabbedAggColumn.id property - -Signature: - -```typescript -id: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.md deleted file mode 100644 index 578a2b159f9e..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) - -## TabbedAggColumn interface - -\* - -Signature: - -```typescript -export interface TabbedAggColumn -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [aggConfig](./kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md) | IAggConfig | | -| [id](./kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md) | string | | -| [name](./kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md) | string | | - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md deleted file mode 100644 index ce20c1c50b98..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) > [name](./kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md) - -## TabbedAggColumn.name property - -Signature: - -```typescript -name: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggrow.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggrow.md deleted file mode 100644 index 28519d95c437..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggrow.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggRow](./kibana-plugin-plugins-data-public.tabbedaggrow.md) - -## TabbedAggRow type - -\* - -Signature: - -```typescript -export declare type TabbedAggRow = Record; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.columns.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.columns.md deleted file mode 100644 index 8256291d368c..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.columns.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedTable](./kibana-plugin-plugins-data-public.tabbedtable.md) > [columns](./kibana-plugin-plugins-data-public.tabbedtable.columns.md) - -## TabbedTable.columns property - -Signature: - -```typescript -columns: TabbedAggColumn[]; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.md deleted file mode 100644 index 51b1bfa9b436..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.md +++ /dev/null @@ -1,21 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedTable](./kibana-plugin-plugins-data-public.tabbedtable.md) - -## TabbedTable interface - -\* - -Signature: - -```typescript -export interface TabbedTable -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [columns](./kibana-plugin-plugins-data-public.tabbedtable.columns.md) | TabbedAggColumn[] | | -| [rows](./kibana-plugin-plugins-data-public.tabbedtable.rows.md) | TabbedAggRow[] | | - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.rows.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.rows.md deleted file mode 100644 index 19a973b18d75..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.rows.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedTable](./kibana-plugin-plugins-data-public.tabbedtable.md) > [rows](./kibana-plugin-plugins-data-public.tabbedtable.rows.md) - -## TabbedTable.rows property - -Signature: - -```typescript -rows: TabbedAggRow[]; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 27a386a714fc..6847808d51bd 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -66,8 +66,6 @@ | [RefreshInterval](./kibana-plugin-plugins-data-server.refreshinterval.md) | | | [SearchStrategyDependencies](./kibana-plugin-plugins-data-server.searchstrategydependencies.md) | | | [SearchUsage](./kibana-plugin-plugins-data-server.searchusage.md) | | -| [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) | \* | -| [TabbedTable](./kibana-plugin-plugins-data-server.tabbedtable.md) | \* | ## Variables @@ -112,6 +110,5 @@ | [KibanaContext](./kibana-plugin-plugins-data-server.kibanacontext.md) | | | [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | | | [Query](./kibana-plugin-plugins-data-server.query.md) | | -| [TabbedAggRow](./kibana-plugin-plugins-data-server.tabbedaggrow.md) | \* | | [TimeRange](./kibana-plugin-plugins-data-server.timerange.md) | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md deleted file mode 100644 index 9870f7380e16..000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) > [aggConfig](./kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md) - -## TabbedAggColumn.aggConfig property - -Signature: - -```typescript -aggConfig: IAggConfig; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md deleted file mode 100644 index 4f5a964a07a0..000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) > [id](./kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md) - -## TabbedAggColumn.id property - -Signature: - -```typescript -id: string; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.md deleted file mode 100644 index 5e47f745fa17..000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) - -## TabbedAggColumn interface - -\* - -Signature: - -```typescript -export interface TabbedAggColumn -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [aggConfig](./kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md) | IAggConfig | | -| [id](./kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md) | string | | -| [name](./kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md) | string | | - diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md deleted file mode 100644 index 8a07e2708066..000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) > [name](./kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md) - -## TabbedAggColumn.name property - -Signature: - -```typescript -name: string; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggrow.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggrow.md deleted file mode 100644 index d592aeff8963..000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggrow.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggRow](./kibana-plugin-plugins-data-server.tabbedaggrow.md) - -## TabbedAggRow type - -\* - -Signature: - -```typescript -export declare type TabbedAggRow = Record; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.columns.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.columns.md deleted file mode 100644 index 55f079c581c8..000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.columns.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedTable](./kibana-plugin-plugins-data-server.tabbedtable.md) > [columns](./kibana-plugin-plugins-data-server.tabbedtable.columns.md) - -## TabbedTable.columns property - -Signature: - -```typescript -columns: TabbedAggColumn[]; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.md deleted file mode 100644 index 1bb055a2a3ce..000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.md +++ /dev/null @@ -1,21 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedTable](./kibana-plugin-plugins-data-server.tabbedtable.md) - -## TabbedTable interface - -\* - -Signature: - -```typescript -export interface TabbedTable -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [columns](./kibana-plugin-plugins-data-server.tabbedtable.columns.md) | TabbedAggColumn[] | | -| [rows](./kibana-plugin-plugins-data-server.tabbedtable.rows.md) | TabbedAggRow[] | | - diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.rows.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.rows.md deleted file mode 100644 index b783919a2657..000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.rows.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedTable](./kibana-plugin-plugins-data-server.tabbedtable.md) > [rows](./kibana-plugin-plugins-data-server.tabbedtable.rows.md) - -## TabbedTable.rows property - -Signature: - -```typescript -rows: TabbedAggRow[]; -``` diff --git a/src/plugins/data/common/search/expressions/esaggs/create_filter.test.ts b/src/plugins/data/common/search/expressions/esaggs/create_filter.test.ts index 076eeaba32c5..e4d4d0e5e7a1 100644 --- a/src/plugins/data/common/search/expressions/esaggs/create_filter.test.ts +++ b/src/plugins/data/common/search/expressions/esaggs/create_filter.test.ts @@ -10,12 +10,12 @@ import { isRangeFilter } from '../../../es_query/filters'; import { BytesFormat, FieldFormatsGetConfigFn } from '../../../field_formats'; import { AggConfigs, IAggConfig } from '../../aggs'; import { mockAggTypesRegistry } from '../../aggs/test_helpers'; -import { TabbedTable } from '../../tabify'; import { createFilter } from './create_filter'; +import { Datatable } from '../../../../../expressions/common'; describe('createFilter', () => { - let table: TabbedTable; + let table: Datatable; let aggConfig: IAggConfig; const typesRegistry = mockAggTypesRegistry(); @@ -62,11 +62,12 @@ describe('createFilter', () => { beforeEach(() => { table = { + type: 'datatable', columns: [ { id: '1-1', name: 'test', - aggConfig, + meta: { type: 'number' }, }, ], rows: [ diff --git a/src/plugins/data/common/search/expressions/esaggs/create_filter.ts b/src/plugins/data/common/search/expressions/esaggs/create_filter.ts index e02d50485ad9..f6a372cacd50 100644 --- a/src/plugins/data/common/search/expressions/esaggs/create_filter.ts +++ b/src/plugins/data/common/search/expressions/esaggs/create_filter.ts @@ -8,9 +8,9 @@ import { Filter } from '../../../es_query'; import { IAggConfig } from '../../aggs'; -import { TabbedTable } from '../../tabify'; +import { Datatable } from '../../../../../expressions/common'; -const getOtherBucketFilterTerms = (table: TabbedTable, columnIndex: number, rowIndex: number) => { +const getOtherBucketFilterTerms = (table: Datatable, columnIndex: number, rowIndex: number) => { if (rowIndex === -1) { return []; } @@ -36,7 +36,7 @@ const getOtherBucketFilterTerms = (table: TabbedTable, columnIndex: number, rowI export const createFilter = ( aggConfigs: IAggConfig[], - table: TabbedTable, + table: Datatable, columnIndex: number, rowIndex: number, cellValue: any diff --git a/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts b/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts index 1e48c5b78612..f12ab6ba068f 100644 --- a/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts +++ b/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts @@ -8,22 +8,16 @@ import { i18n } from '@kbn/i18n'; -import { - Datatable, - DatatableColumn, - ExpressionFunctionDefinition, -} from 'src/plugins/expressions/common'; +import { Datatable, ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; -import { FormatFactory } from '../../../field_formats/utils'; import { IndexPatternExpressionType } from '../../../index_patterns/expressions'; import { IndexPatternsContract } from '../../../index_patterns/index_patterns'; -import { calculateBounds } from '../../../query'; import { AggsStart, AggExpressionType } from '../../aggs'; import { ISearchStartSearchSource } from '../../search_source'; import { KibanaContext } from '../kibana_context_type'; -import { handleRequest, RequestHandlerParams } from './request_handler'; +import { handleRequest } from './request_handler'; const name = 'esaggs'; @@ -48,7 +42,6 @@ export type EsaggsExpressionFunctionDefinition = ExpressionFunctionDefinition< /** @internal */ export interface EsaggsStartDependencies { aggs: AggsStart; - deserializeFieldFormat: FormatFactory; indexPatterns: IndexPatternsContract; searchSource: ISearchStartSearchSource; getNow?: () => Date; @@ -103,48 +96,4 @@ export const getEsaggsMeta: () => Omit }); /** @internal */ -export async function handleEsaggsRequest( - input: Input, - args: Arguments, - params: RequestHandlerParams -): Promise { - const resolvedTimeRange = - input?.timeRange && calculateBounds(input.timeRange, { forceNow: params.getNow?.() }); - - const response = await handleRequest(params); - - const table: Datatable = { - type: 'datatable', - rows: response.rows, - columns: response.columns.map((column) => { - const cleanedColumn: DatatableColumn = { - id: column.id, - name: column.name, - meta: { - type: column.aggConfig.params.field?.type || 'number', - field: column.aggConfig.params.field?.name, - index: params.indexPattern?.title, - params: column.aggConfig.toSerializedFieldFormat(), - source: name, - sourceParams: { - indexPatternId: params.indexPattern?.id, - appliedTimeRange: - column.aggConfig.params.field?.name && - input?.timeRange && - args.timeFields && - args.timeFields.includes(column.aggConfig.params.field?.name) - ? { - from: resolvedTimeRange?.min?.toISOString(), - to: resolvedTimeRange?.max?.toISOString(), - } - : undefined, - ...column.aggConfig.serialize(), - }, - }, - }; - return cleanedColumn; - }), - }; - - return table; -} +export { handleRequest as handleEsaggsRequest }; diff --git a/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts b/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts index 3932348928ac..72ac022e4fd3 100644 --- a/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts +++ b/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts @@ -34,7 +34,6 @@ describe('esaggs expression function - public', () => { toDsl: jest.fn().mockReturnValue({ aggs: {} }), onSearchRequestStart: jest.fn(), } as unknown) as jest.Mocked, - deserializeFieldFormat: jest.fn(), filters: undefined, indexPattern: ({ id: 'logstash-*' } as unknown) as jest.Mocked, inspectorAdapters: {}, diff --git a/src/plugins/data/common/search/expressions/esaggs/request_handler.ts b/src/plugins/data/common/search/expressions/esaggs/request_handler.ts index 70b1221a7473..fc9d47a5a2f7 100644 --- a/src/plugins/data/common/search/expressions/esaggs/request_handler.ts +++ b/src/plugins/data/common/search/expressions/esaggs/request_handler.ts @@ -18,7 +18,6 @@ import { Query, TimeRange, } from '../../../../common'; -import { FormatFactory } from '../../../../common/field_formats/utils'; import { IAggConfigs } from '../../aggs'; import { ISearchStartSearchSource } from '../../search_source'; @@ -29,7 +28,6 @@ import { getRequestInspectorStats, getResponseInspectorStats } from '../utils'; export interface RequestHandlerParams { abortSignal?: AbortSignal; aggs: IAggConfigs; - deserializeFieldFormat: FormatFactory; filters?: Filter[]; indexPattern?: IndexPattern; inspectorAdapters: Adapters; @@ -46,7 +44,6 @@ export interface RequestHandlerParams { export const handleRequest = async ({ abortSignal, aggs, - deserializeFieldFormat, filters, indexPattern, inspectorAdapters, diff --git a/src/plugins/data/common/search/tabify/index.ts b/src/plugins/data/common/search/tabify/index.ts index 9c650061fb01..f93b3fcde345 100644 --- a/src/plugins/data/common/search/tabify/index.ts +++ b/src/plugins/data/common/search/tabify/index.ts @@ -30,5 +30,3 @@ export { tabifyDocs }; export { tabifyAggResponse } from './tabify'; export { tabifyGetColumns } from './get_columns'; - -export { TabbedTable, TabbedAggRow, TabbedAggColumn } from './types'; diff --git a/src/plugins/data/common/search/tabify/response_writer.test.ts b/src/plugins/data/common/search/tabify/response_writer.test.ts index 9a37a2de9b5b..9d9060f75126 100644 --- a/src/plugins/data/common/search/tabify/response_writer.test.ts +++ b/src/plugins/data/common/search/tabify/response_writer.test.ts @@ -59,6 +59,7 @@ describe('TabbedAggResponseWriter class', () => { getByName: (name: string) => fields.find((f) => f.name === name), filter: () => fields, }, + getFormatterForField: () => ({ toJSON: () => '' }), } as any; return new TabbedAggResponseWriter(new AggConfigs(indexPattern, aggs, { typesRegistry }), { @@ -136,31 +137,116 @@ describe('TabbedAggResponseWriter class', () => { const response = responseWriter.response(); + expect(response).toHaveProperty('type', 'datatable'); expect(response).toHaveProperty('rows'); expect(response.rows).toEqual([{ 'col-0-1': 'US', 'col-1-2': 5 }]); expect(response).toHaveProperty('columns'); expect(response.columns.length).toEqual(2); expect(response.columns[0]).toHaveProperty('id', 'col-0-1'); expect(response.columns[0]).toHaveProperty('name', 'geo.src: Descending'); - expect(response.columns[0]).toHaveProperty('aggConfig'); + expect(response.columns[0]).toHaveProperty('meta', { + index: 'logstash-*', + params: { + id: 'terms', + params: { + missingBucketLabel: 'Missing', + otherBucketLabel: 'Other', + }, + }, + field: 'geo.src', + source: 'esaggs', + sourceParams: { + enabled: true, + id: '1', + indexPatternId: '1234', + params: { + field: 'geo.src', + missingBucket: false, + missingBucketLabel: 'Missing', + order: 'desc', + otherBucket: false, + otherBucketLabel: 'Other', + size: 5, + }, + type: 'terms', + }, + type: 'number', + }); + expect(response.columns[1]).toHaveProperty('id', 'col-1-2'); expect(response.columns[1]).toHaveProperty('name', 'Count'); - expect(response.columns[1]).toHaveProperty('aggConfig'); + expect(response.columns[1]).toHaveProperty('meta', { + index: 'logstash-*', + params: { + id: 'number', + }, + source: 'esaggs', + sourceParams: { + enabled: true, + id: '2', + indexPatternId: '1234', + params: {}, + type: 'count', + }, + type: 'number', + }); }); test('produces correct response for no data', () => { const response = responseWriter.response(); - + expect(response).toHaveProperty('type', 'datatable'); expect(response).toHaveProperty('rows'); expect(response.rows.length).toBe(0); expect(response).toHaveProperty('columns'); expect(response.columns.length).toEqual(2); expect(response.columns[0]).toHaveProperty('id', 'col-0-1'); expect(response.columns[0]).toHaveProperty('name', 'geo.src: Descending'); - expect(response.columns[0]).toHaveProperty('aggConfig'); + expect(response.columns[0]).toHaveProperty('meta', { + index: 'logstash-*', + params: { + id: 'terms', + params: { + missingBucketLabel: 'Missing', + otherBucketLabel: 'Other', + }, + }, + field: 'geo.src', + source: 'esaggs', + sourceParams: { + enabled: true, + id: '1', + indexPatternId: '1234', + params: { + field: 'geo.src', + missingBucket: false, + missingBucketLabel: 'Missing', + order: 'desc', + otherBucket: false, + otherBucketLabel: 'Other', + size: 5, + }, + type: 'terms', + }, + type: 'number', + }); + expect(response.columns[1]).toHaveProperty('id', 'col-1-2'); expect(response.columns[1]).toHaveProperty('name', 'Count'); - expect(response.columns[1]).toHaveProperty('aggConfig'); + expect(response.columns[1]).toHaveProperty('meta', { + index: 'logstash-*', + params: { + id: 'number', + }, + source: 'esaggs', + sourceParams: { + enabled: true, + id: '2', + indexPatternId: '1234', + params: {}, + type: 'count', + }, + type: 'number', + }); }); }); }); diff --git a/src/plugins/data/common/search/tabify/response_writer.ts b/src/plugins/data/common/search/tabify/response_writer.ts index c03b477ca1cd..2026b51b8efb 100644 --- a/src/plugins/data/common/search/tabify/response_writer.ts +++ b/src/plugins/data/common/search/tabify/response_writer.ts @@ -10,7 +10,8 @@ import { isEmpty } from 'lodash'; import { IAggConfigs } from '../aggs'; import { tabifyGetColumns } from './get_columns'; -import { TabbedResponseWriterOptions, TabbedAggColumn, TabbedAggRow, TabbedTable } from './types'; +import { TabbedResponseWriterOptions, TabbedAggColumn, TabbedAggRow } from './types'; +import { Datatable, DatatableColumn } from '../../../../expressions/common/expression_types/specs'; interface BufferColumn { id: string; @@ -28,19 +29,18 @@ export class TabbedAggResponseWriter { metricBuffer: BufferColumn[] = []; private readonly partialRows: boolean; + private readonly params: Partial; /** * @param {AggConfigs} aggs - the agg configs object to which the aggregation response correlates * @param {boolean} metricsAtAllLevels - setting to true will produce metrics for every bucket * @param {boolean} partialRows - setting to true will not remove rows with missing values */ - constructor( - aggs: IAggConfigs, - { metricsAtAllLevels = false, partialRows = false }: Partial - ) { - this.partialRows = partialRows; + constructor(aggs: IAggConfigs, params: Partial) { + this.partialRows = params.partialRows || false; + this.params = params; - this.columns = tabifyGetColumns(aggs.getResponseAggs(), !metricsAtAllLevels); + this.columns = tabifyGetColumns(aggs.getResponseAggs(), !params.metricsAtAllLevels); this.rows = []; } @@ -65,9 +65,37 @@ export class TabbedAggResponseWriter { } } - response(): TabbedTable { + response(): Datatable { return { - columns: this.columns, + type: 'datatable', + columns: this.columns.map((column) => { + const cleanedColumn: DatatableColumn = { + id: column.id, + name: column.name, + meta: { + type: column.aggConfig.params.field?.type || 'number', + field: column.aggConfig.params.field?.name, + index: column.aggConfig.getIndexPattern()?.title, + params: column.aggConfig.toSerializedFieldFormat(), + source: 'esaggs', + sourceParams: { + indexPatternId: column.aggConfig.getIndexPattern()?.id, + appliedTimeRange: + column.aggConfig.params.field?.name && + this.params.timeRange && + this.params.timeRange.timeFields && + this.params.timeRange.timeFields.includes(column.aggConfig.params.field?.name) + ? { + from: this.params.timeRange?.from?.toISOString(), + to: this.params.timeRange?.to?.toISOString(), + } + : undefined, + ...column.aggConfig.serialize(), + }, + }, + }; + return cleanedColumn; + }), rows: this.rows, }; } diff --git a/src/plugins/data/common/search/tabify/tabify.test.ts b/src/plugins/data/common/search/tabify/tabify.test.ts index 02d734129d8e..f2c980196ab2 100644 --- a/src/plugins/data/common/search/tabify/tabify.test.ts +++ b/src/plugins/data/common/search/tabify/tabify.test.ts @@ -27,6 +27,9 @@ describe('tabifyAggResponse Integration', () => { getByName: () => field, filter: () => [field], }, + getFormatterForField: () => ({ + toJSON: () => '{}', + }), } as unknown) as IndexPattern; return new AggConfigs(indexPattern, aggs, { typesRegistry }); @@ -48,7 +51,7 @@ describe('tabifyAggResponse Integration', () => { expect(resp.columns).toHaveLength(1); expect(resp.rows[0]).toEqual({ 'col-0-1': 1000 }); - expect(resp.columns[0]).toHaveProperty('aggConfig', aggConfigs.aggs[0]); + expect(resp.columns[0]).toHaveProperty('name', aggConfigs.aggs[0].makeLabel()); }); describe('transforms a complex response', () => { @@ -78,7 +81,7 @@ describe('tabifyAggResponse Integration', () => { expect(table.columns).toHaveLength(aggs.length); aggs.forEach((agg, i) => { - expect(table.columns[i]).toHaveProperty('aggConfig', agg); + expect(table.columns[i]).toHaveProperty('name', agg.makeLabel()); }); } diff --git a/src/plugins/data/common/search/tabify/types.ts b/src/plugins/data/common/search/tabify/types.ts index 2dace451059b..779eec1b71ba 100644 --- a/src/plugins/data/common/search/tabify/types.ts +++ b/src/plugins/data/common/search/tabify/types.ts @@ -45,9 +45,3 @@ export interface TabbedAggColumn { /** @public **/ export type TabbedAggRow = Record; - -/** @public **/ -export interface TabbedTable { - columns: TabbedAggColumn[]; - rows: TabbedAggRow[]; -} diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index fc8c44e8d187..15288d24726f 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -344,10 +344,6 @@ export { ExpressionFunctionKibanaContext, ExpressionValueSearchContext, KibanaContext, - // tabify - TabbedAggColumn, - TabbedAggRow, - TabbedTable, } from '../common'; export type { AggConfigs, AggConfig } from '../common'; diff --git a/src/plugins/data/public/index_patterns/index_pattern.stub.ts b/src/plugins/data/public/index_patterns/index_pattern.stub.ts index d0b711284df8..a9dbd1973ef9 100644 --- a/src/plugins/data/public/index_patterns/index_pattern.stub.ts +++ b/src/plugins/data/public/index_patterns/index_pattern.stub.ts @@ -47,7 +47,7 @@ export class StubIndexPattern { formatHit: Record; fieldsFetcher: Record; formatField: Function; - getFormatterForField: () => { convert: Function }; + getFormatterForField: () => { convert: Function; toJSON: Function }; _reindexFields: Function; stubSetFieldFormat: Function; fields?: FieldSpec[]; @@ -87,6 +87,7 @@ export class StubIndexPattern { this.formatField = this.formatHit.formatField; this.getFormatterForField = () => ({ convert: () => '', + toJSON: () => '{}', }); this._reindexFields = function () { diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 78947feb88c2..408573e12eba 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -2476,27 +2476,6 @@ export const syncQueryStateWithUrl: (query: Pick; - -// @public (undocumented) -export interface TabbedTable { - // (undocumented) - columns: TabbedAggColumn[]; - // (undocumented) - rows: TabbedAggRow[]; -} - // Warning: (ae-forgotten-export) The symbol "Timefilter" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "TimefilterContract" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -2622,21 +2601,21 @@ export const UI_SETTINGS: { // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:403:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:415:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:419:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:420:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:423:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:424:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:427:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:396:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:396:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:396:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:396:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:398:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:415:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:416:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:419:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:420:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:423:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:34:5 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/search/session/session_service.ts:41:5 - (ae-forgotten-export) The symbol "UrlGeneratorStateMapping" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/public/search/expressions/esaggs.test.ts b/src/plugins/data/public/search/expressions/esaggs.test.ts index 18752b82bc18..01ba19a9d8df 100644 --- a/src/plugins/data/public/search/expressions/esaggs.test.ts +++ b/src/plugins/data/public/search/expressions/esaggs.test.ts @@ -64,7 +64,6 @@ describe('esaggs expression function - public', () => { aggs: ({ createAggConfigs: jest.fn().mockReturnValue({ foo: 'bar' }), } as unknown) as jest.Mocked, - deserializeFieldFormat: jest.fn().mockImplementation((f: any) => f), indexPatterns: ({ create: jest.fn().mockResolvedValue({}), } as unknown) as jest.Mocked, @@ -99,10 +98,9 @@ describe('esaggs expression function - public', () => { test('calls handleEsaggsRequest with all of the right dependencies', async () => { await definition().fn(null, args, mockHandlers); - expect(handleEsaggsRequest).toHaveBeenCalledWith(null, args, { + expect(handleEsaggsRequest).toHaveBeenCalledWith({ abortSignal: mockHandlers.abortSignal, aggs: { foo: 'bar' }, - deserializeFieldFormat: startDependencies.deserializeFieldFormat, filters: undefined, indexPattern: {}, inspectorAdapters: mockHandlers.inspectorAdapters, @@ -130,8 +128,6 @@ describe('esaggs expression function - public', () => { await definition().fn(input, args, mockHandlers); expect(handleEsaggsRequest).toHaveBeenCalledWith( - input, - args, expect.objectContaining({ filters: input.filters, query: input.query, diff --git a/src/plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts index 0753e0e15a0a..6f7411cf0747 100644 --- a/src/plugins/data/public/search/expressions/esaggs.ts +++ b/src/plugins/data/public/search/expressions/esaggs.ts @@ -37,13 +37,7 @@ export function getFunctionDefinition({ return (): EsaggsExpressionFunctionDefinition => ({ ...getEsaggsMeta(), async fn(input, args, { inspectorAdapters, abortSignal, getSearchSessionId }) { - const { - aggs, - deserializeFieldFormat, - indexPatterns, - searchSource, - getNow, - } = await getStartDependencies(); + const { aggs, indexPatterns, searchSource, getNow } = await getStartDependencies(); const indexPattern = await indexPatterns.create(args.index.value, true); const aggConfigs = aggs.createAggConfigs( @@ -51,10 +45,9 @@ export function getFunctionDefinition({ args.aggs!.map((agg) => agg.value) ); - return await handleEsaggsRequest(input, args, { + return await handleEsaggsRequest({ abortSignal: (abortSignal as unknown) as AbortSignal, aggs: aggConfigs, - deserializeFieldFormat, filters: get(input, 'filters', undefined), indexPattern, inspectorAdapters: inspectorAdapters as Adapters, @@ -93,10 +86,9 @@ export function getEsaggs({ return getFunctionDefinition({ getStartDependencies: async () => { const [, , self] = await getStartServices(); - const { fieldFormats, indexPatterns, search, nowProvider } = self; + const { indexPatterns, search, nowProvider } = self; return { aggs: search.aggs, - deserializeFieldFormat: fieldFormats.deserialize.bind(fieldFormats), indexPatterns, searchSource: search.searchSource, getNow: () => nowProvider.get(), diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 370ff180fa56..8853f1fc34f9 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -213,10 +213,6 @@ export { IEsSearchRequest, IEsSearchResponse, ES_SEARCH_STRATEGY, - // tabify - TabbedAggColumn, - TabbedAggRow, - TabbedTable, } from '../common'; export { diff --git a/src/plugins/data/server/search/expressions/esaggs.test.ts b/src/plugins/data/server/search/expressions/esaggs.test.ts index d71abbcd460c..229665d33887 100644 --- a/src/plugins/data/server/search/expressions/esaggs.test.ts +++ b/src/plugins/data/server/search/expressions/esaggs.test.ts @@ -66,7 +66,6 @@ describe('esaggs expression function - server', () => { aggs: ({ createAggConfigs: jest.fn().mockReturnValue({ foo: 'bar' }), } as unknown) as jest.Mocked, - deserializeFieldFormat: jest.fn().mockImplementation((f: any) => f), indexPatterns: ({ create: jest.fn().mockResolvedValue({}), } as unknown) as jest.Mocked, @@ -107,10 +106,9 @@ describe('esaggs expression function - server', () => { test('calls handleEsaggsRequest with all of the right dependencies', async () => { await definition().fn(null, args, mockHandlers); - expect(handleEsaggsRequest).toHaveBeenCalledWith(null, args, { + expect(handleEsaggsRequest).toHaveBeenCalledWith({ abortSignal: mockHandlers.abortSignal, aggs: { foo: 'bar' }, - deserializeFieldFormat: startDependencies.deserializeFieldFormat, filters: undefined, indexPattern: {}, inspectorAdapters: mockHandlers.inspectorAdapters, @@ -138,8 +136,6 @@ describe('esaggs expression function - server', () => { await definition().fn(input, args, mockHandlers); expect(handleEsaggsRequest).toHaveBeenCalledWith( - input, - args, expect.objectContaining({ filters: input.filters, query: input.query, diff --git a/src/plugins/data/server/search/expressions/esaggs.ts b/src/plugins/data/server/search/expressions/esaggs.ts index 8f73f970c7ef..13168879b8ba 100644 --- a/src/plugins/data/server/search/expressions/esaggs.ts +++ b/src/plugins/data/server/search/expressions/esaggs.ts @@ -53,12 +53,7 @@ export function getFunctionDefinition({ ); } - const { - aggs, - deserializeFieldFormat, - indexPatterns, - searchSource, - } = await getStartDependencies(kibanaRequest); + const { aggs, indexPatterns, searchSource } = await getStartDependencies(kibanaRequest); const indexPattern = await indexPatterns.create(args.index.value, true); const aggConfigs = aggs.createAggConfigs( @@ -66,10 +61,9 @@ export function getFunctionDefinition({ args.aggs!.map((agg) => agg.value) ); - return await handleEsaggsRequest(input, args, { + return await handleEsaggsRequest({ abortSignal: (abortSignal as unknown) as AbortSignal, aggs: aggConfigs, - deserializeFieldFormat, filters: get(input, 'filters', undefined), indexPattern, inspectorAdapters: inspectorAdapters as Adapters, @@ -106,16 +100,13 @@ export function getEsaggs({ }): () => EsaggsExpressionFunctionDefinition { return getFunctionDefinition({ getStartDependencies: async (request: KibanaRequest) => { - const [{ elasticsearch, savedObjects, uiSettings }, , self] = await getStartServices(); - const { fieldFormats, indexPatterns, search } = self; + const [{ elasticsearch, savedObjects }, , self] = await getStartServices(); + const { indexPatterns, search } = self; const esClient = elasticsearch.client.asScoped(request); const savedObjectsClient = savedObjects.getScopedClient(request); - const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient); - const scopedFieldFormats = await fieldFormats.fieldFormatServiceFactory(uiSettingsClient); return { aggs: await search.aggs.asScopedToClient(savedObjectsClient, esClient.asCurrentUser), - deserializeFieldFormat: scopedFieldFormats.deserialize.bind(scopedFieldFormats), indexPatterns: await indexPatterns.indexPatternsServiceFactory( savedObjectsClient, esClient.asCurrentUser diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 635428f298ab..8f8761534d03 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -1324,27 +1324,6 @@ export function shimHitsTotal(response: SearchResponse, { legacyHitsTot // @public (undocumented) export function shouldReadFieldFromDocValues(aggregatable: boolean, esType: string): boolean; -// @public (undocumented) -export interface TabbedAggColumn { - // (undocumented) - aggConfig: IAggConfig; - // (undocumented) - id: string; - // (undocumented) - name: string; -} - -// @public (undocumented) -export type TabbedAggRow = Record; - -// @public (undocumented) -export interface TabbedTable { - // (undocumented) - columns: TabbedAggColumn[]; - // (undocumented) - rows: TabbedAggRow[]; -} - // Warning: (ae-missing-release-tag) "TimeRange" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1435,20 +1414,20 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/server/index.ts:100:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:126:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:126:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:246:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:247:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:256:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:257:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:258:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:262:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:263:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:267:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:270:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:271:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:240:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:240:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:240:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:240:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:242:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:252:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:253:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:254:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:258:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:259:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:263:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:266:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:267:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index_patterns/index_patterns_service.ts:59:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts // src/plugins/data/server/plugin.ts:79:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts // src/plugins/data/server/search/types.ts:103:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts