From 653073f8c6d199b069830c3acc13fb0c6664e9d8 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Tue, 8 Oct 2024 18:57:23 +0200 Subject: [PATCH 001/110] [Lens] Fix partition theme after ech upgrade (#195269) ## Summary When I've updated elastic-charts with the last new version, the `point.fill` parameter of lineSeriesStyle has changed in value. This created an unwanted change also in the partition chart that was using that style to color the partition sector borders. I've removed the useless color override of `sectorLineStroke` in the overwrite partition theme, leaving the control to use the chart theme. I've also removed the possibility of unwanted changes for other properties like `fontFamily` and in the `linkedText.textColor`. In the same PR I've removed duplicated tests that where testing exactly the same code/arguments/data, the only difference was the test name. I've also refactored a bit the code, cleaning up the typings and consolidating a bit the theme override logic --- .../partition_vis_component.test.tsx.snap | 24 -- .../components/partition_vis_component.tsx | 10 +- .../public/utils/get_partition_theme.test.ts | 297 +++++------------- .../public/utils/get_partition_theme.ts | 159 ++++------ 4 files changed, 153 insertions(+), 337 deletions(-) diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/components/__snapshots__/partition_vis_component.test.tsx.snap b/src/plugins/chart_expressions/expression_partition_vis/public/components/__snapshots__/partition_vis_component.test.tsx.snap index 35c1fc0e63213..e1293b9986f04 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/components/__snapshots__/partition_vis_component.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_partition_vis/public/components/__snapshots__/partition_vis_component.test.tsx.snap @@ -810,17 +810,13 @@ exports[`PartitionVisComponent should render correct structure for donut 1`] = ` "partition": Object { "circlePadding": 4, "emptySizeRatio": 0.3, - "fontFamily": "Inter, BlinkMacSystemFont, Helvetica, Arial, sans-serif", "linkLabel": Object { - "fontSize": 11, "maxCount": 5, "maxTextLength": 100, - "textColor": "#343741", }, "maxFontSize": 16, "minFontSize": 10, "outerSizeRatio": undefined, - "sectorLineStroke": "__use__series__color__", "sectorLineWidth": 1.5, }, }, @@ -1742,17 +1738,13 @@ exports[`PartitionVisComponent should render correct structure for mosaic 1`] = "partition": Object { "circlePadding": 4, "emptySizeRatio": 0, - "fontFamily": "Inter, BlinkMacSystemFont, Helvetica, Arial, sans-serif", "linkLabel": Object { - "fontSize": 11, "maxCount": 5, "maxTextLength": undefined, - "textColor": "#343741", }, "maxFontSize": 16, "minFontSize": 10, "outerSizeRatio": 1, - "sectorLineStroke": "__use__series__color__", "sectorLineWidth": 1.5, }, }, @@ -2738,17 +2730,13 @@ exports[`PartitionVisComponent should render correct structure for multi-metric "partition": Object { "circlePadding": 4, "emptySizeRatio": 0, - "fontFamily": "Inter, BlinkMacSystemFont, Helvetica, Arial, sans-serif", "linkLabel": Object { - "fontSize": 11, "maxCount": 5, "maxTextLength": 100, - "textColor": "#343741", }, "maxFontSize": 16, "minFontSize": 10, "outerSizeRatio": undefined, - "sectorLineStroke": "__use__series__color__", "sectorLineWidth": 1.5, }, }, @@ -3734,17 +3722,13 @@ exports[`PartitionVisComponent should render correct structure for pie 1`] = ` "partition": Object { "circlePadding": 4, "emptySizeRatio": 0, - "fontFamily": "Inter, BlinkMacSystemFont, Helvetica, Arial, sans-serif", "linkLabel": Object { - "fontSize": 11, "maxCount": 5, "maxTextLength": 100, - "textColor": "#343741", }, "maxFontSize": 16, "minFontSize": 10, "outerSizeRatio": undefined, - "sectorLineStroke": "__use__series__color__", "sectorLineWidth": 1.5, }, }, @@ -4666,17 +4650,13 @@ exports[`PartitionVisComponent should render correct structure for treemap 1`] = "partition": Object { "circlePadding": 4, "emptySizeRatio": 0, - "fontFamily": "Inter, BlinkMacSystemFont, Helvetica, Arial, sans-serif", "linkLabel": Object { - "fontSize": 11, "maxCount": 5, "maxTextLength": undefined, - "textColor": "#343741", }, "maxFontSize": 16, "minFontSize": 10, "outerSizeRatio": 1, - "sectorLineStroke": "__use__series__color__", "sectorLineWidth": 1.5, }, }, @@ -5562,17 +5542,13 @@ exports[`PartitionVisComponent should render correct structure for waffle 1`] = "partition": Object { "circlePadding": 4, "emptySizeRatio": 0, - "fontFamily": "Inter, BlinkMacSystemFont, Helvetica, Arial, sans-serif", "linkLabel": Object { - "fontSize": 11, "maxCount": 5, "maxTextLength": undefined, - "textColor": "#343741", }, "maxFontSize": 16, "minFontSize": 10, "outerSizeRatio": undefined, - "sectorLineStroke": "__use__series__color__", "sectorLineWidth": 1.5, }, }, diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx index 826e868cab540..5baf582877a68 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx +++ b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx @@ -378,19 +378,11 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => { getPartitionTheme( visType, visParams, - chartBaseTheme, containerDimensions, rescaleFactor, hasOpenedOnAggBasedEditor ), - [ - visType, - visParams, - chartBaseTheme, - containerDimensions, - rescaleFactor, - hasOpenedOnAggBasedEditor, - ] + [visType, visParams, containerDimensions, rescaleFactor, hasOpenedOnAggBasedEditor] ); const fixedViewPort = document.getElementById('app-fixed-viewport'); diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_partition_theme.test.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_partition_theme.test.ts index 26508151e9c59..e6cfeabb5e70c 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_partition_theme.test.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_partition_theme.test.ts @@ -11,8 +11,6 @@ import { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common'; import { getPartitionTheme } from './get_partition_theme'; import { createMockPieParams, createMockDonutParams, createMockPartitionVisParams } from '../mocks'; import { ChartTypes, LabelPositions, PartitionVisParams } from '../../common/types'; -import { RecursivePartial } from '@elastic/eui'; -import { Theme } from '@elastic/charts'; const column: ExpressionValueVisDimension = { type: 'vis_dimension', @@ -29,11 +27,6 @@ const column: ExpressionValueVisDimension = { const splitRows = [column]; const splitColumns = [column]; -const chartTheme: RecursivePartial = { - barSeriesStyle: { displayValue: { fontFamily: 'Arial' } }, - lineSeriesStyle: { point: { fill: '#fff' } }, - axes: { axisTitle: { fill: '#000' } }, -}; const linkLabelWithEnoughSpace = (visParams: PartitionVisParams) => ({ maxCount: Number.POSITIVE_INFINITY, @@ -41,36 +34,33 @@ const linkLabelWithEnoughSpace = (visParams: PartitionVisParams) => ({ maxTextLength: visParams.labels.truncate ?? undefined, }); -const linkLabelsWithoutSpaceForOuterLabels = { maxCount: 0 }; +const linkLabelsWithoutSpaceForOuterLabels = (visParams: PartitionVisParams) => ({ + maxCount: 0, + maxTextLength: visParams.labels.truncate ?? undefined, +}); -const linkLabelsWithoutSpaceForLabels = { +const linkLabelsWithoutSpaceForLabels = (visParams: PartitionVisParams) => ({ maxCount: 0, maximumSection: Number.POSITIVE_INFINITY, -}; + maxTextLength: visParams.labels.truncate ?? undefined, +}); -const getStaticThemePartition = ( - theme: RecursivePartial, - visParams: PartitionVisParams -) => ({ - fontFamily: theme.barSeriesStyle?.displayValue?.fontFamily, +const getStaticThemePartition = (visParams: PartitionVisParams) => ({ outerSizeRatio: 1, minFontSize: 10, maxFontSize: 16, emptySizeRatio: visParams.emptySizeRatio ?? 0, - sectorLineStroke: theme.lineSeriesStyle?.point?.fill, sectorLineWidth: 1.5, circlePadding: 4, }); -const getStaticThemeOptions = (theme: RecursivePartial, visParams: PartitionVisParams) => ({ - partition: getStaticThemePartition(theme, visParams), +const getStaticThemeOptions = (visParams: PartitionVisParams) => ({ + partition: getStaticThemePartition(visParams), chartMargins: { top: 0, left: 0, bottom: 0, right: 0 }, }); -const getDefaultLinkLabel = (visParams: PartitionVisParams, theme: RecursivePartial) => ({ +const getDefaultLinkLabel = (visParams: PartitionVisParams) => ({ maxCount: 5, - fontSize: 11, - textColor: theme.axes?.axisTitle?.fill, maxTextLength: visParams.labels.truncate ?? undefined, }); @@ -86,165 +76,99 @@ const runPieDonutWaffleTestSuites = (chartType: ChartTypes, visParams: Partition dimensions: { ...visParams.dimensions, splitColumn: splitColumns }, }; - it('should return correct default theme options', () => { - const theme = getPartitionTheme(chartType, visParams, chartTheme, dimensions); - expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), - partition: { - ...getStaticThemePartition(chartTheme, visParams), - outerSizeRatio: undefined, - linkLabel: getDefaultLinkLabel(visParams, chartTheme), - }, - }); - }); - - it('should not return padding settings if dimensions are not specified', () => { - const theme = getPartitionTheme(chartType, visParams, chartTheme, dimensions); - - expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), - partition: { - ...getStaticThemePartition(chartTheme, visParams), - outerSizeRatio: undefined, - linkLabel: getDefaultLinkLabel(visParams, chartTheme), - }, - }); - }); - it('should not return padding settings if split column or row are specified', () => { - const themeForSplitColumns = getPartitionTheme( - chartType, - vParamsSplitColumns, - chartTheme, - dimensions - ); + const themeForSplitColumns = getPartitionTheme(chartType, vParamsSplitColumns, dimensions); expect(themeForSplitColumns).toEqual({ - ...getStaticThemeOptions(chartTheme, vParamsSplitColumns), + ...getStaticThemeOptions(vParamsSplitColumns), partition: { - ...getStaticThemePartition(chartTheme, vParamsSplitColumns), + ...getStaticThemePartition(vParamsSplitColumns), outerSizeRatio: undefined, - linkLabel: linkLabelsWithoutSpaceForOuterLabels, + linkLabel: linkLabelsWithoutSpaceForOuterLabels(vParamsSplitColumns), }, }); - const themeForSplitRows = getPartitionTheme( - chartType, - vParamsSplitRows, - chartTheme, - dimensions - ); + const themeForSplitRows = getPartitionTheme(chartType, vParamsSplitRows, dimensions); expect(themeForSplitRows).toEqual({ - ...getStaticThemeOptions(chartTheme, vParamsSplitRows), + ...getStaticThemeOptions(vParamsSplitRows), partition: { - ...getStaticThemePartition(chartTheme, vParamsSplitRows), + ...getStaticThemePartition(vParamsSplitRows), outerSizeRatio: undefined, - linkLabel: linkLabelsWithoutSpaceForOuterLabels, + linkLabel: linkLabelsWithoutSpaceForOuterLabels(vParamsSplitRows), }, }); }); it('should return adjusted padding settings if dimensions are specified and is on aggBased editor', () => { const specifiedDimensions = { width: 2000, height: 2000 }; - const theme = getPartitionTheme( - chartType, - visParams, - chartTheme, - specifiedDimensions, - undefined, - true - ); + const theme = getPartitionTheme(chartType, visParams, specifiedDimensions, undefined, true); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), + ...getStaticThemeOptions(visParams), chartPaddings: { top: 500, bottom: 500, left: 500, right: 500 }, partition: { - ...getStaticThemePartition(chartTheme, visParams), - linkLabel: getDefaultLinkLabel(visParams, chartTheme), + ...getStaticThemePartition(visParams), + linkLabel: getDefaultLinkLabel(visParams), }, }); }); it('should return right settings for the theme related fields', () => { - const theme = getPartitionTheme(chartType, visParams, chartTheme, dimensions); + const theme = getPartitionTheme(chartType, visParams, dimensions); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), + ...getStaticThemeOptions(visParams), partition: { - ...getStaticThemePartition(chartTheme, visParams), + ...getStaticThemePartition(visParams), outerSizeRatio: undefined, - linkLabel: getDefaultLinkLabel(visParams, chartTheme), + linkLabel: getDefaultLinkLabel(visParams), }, }); }); it('should return undefined outerSizeRatio for split chart and show labels', () => { const specifiedDimensions = { width: 2000, height: 2000 }; - const theme = getPartitionTheme(chartType, vParamsSplitRows, chartTheme, specifiedDimensions); + const theme = getPartitionTheme(chartType, vParamsSplitRows, specifiedDimensions); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, vParamsSplitRows), + ...getStaticThemeOptions(vParamsSplitRows), partition: { - ...getStaticThemePartition(chartTheme, vParamsSplitRows), + ...getStaticThemePartition(vParamsSplitRows), outerSizeRatio: undefined, - linkLabel: linkLabelsWithoutSpaceForOuterLabels, + linkLabel: linkLabelsWithoutSpaceForOuterLabels(vParamsSplitRows), }, }); const themeForSplitColumns = getPartitionTheme( chartType, vParamsSplitColumns, - chartTheme, specifiedDimensions ); expect(themeForSplitColumns).toEqual({ - ...getStaticThemeOptions(chartTheme, vParamsSplitColumns), + ...getStaticThemeOptions(vParamsSplitColumns), partition: { - ...getStaticThemePartition(chartTheme, vParamsSplitColumns), + ...getStaticThemePartition(vParamsSplitColumns), outerSizeRatio: undefined, - linkLabel: linkLabelsWithoutSpaceForOuterLabels, + linkLabel: linkLabelsWithoutSpaceForOuterLabels(vParamsSplitColumns), }, }); }); - it( - 'should return undefined outerSizeRatio for not specified dimensions, visible labels,' + - 'and default labels position and not split chart', - () => { - const theme = getPartitionTheme(chartType, visParams, chartTheme, dimensions); - - expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), - partition: { - ...getStaticThemePartition(chartTheme, visParams), - outerSizeRatio: undefined, - linkLabel: getDefaultLinkLabel(visParams, chartTheme), - }, - }); - } - ); - it( 'should return rescaleFactor value for outerSizeRatio if dimensions are specified,' + ' is not split chart, labels are shown and labels position is not `inside`', () => { const specifiedDimensions = { width: 2000, height: 2000 }; const rescaleFactor = 2; - const theme = getPartitionTheme( - chartType, - visParams, - chartTheme, - specifiedDimensions, - rescaleFactor - ); + const theme = getPartitionTheme(chartType, visParams, specifiedDimensions, rescaleFactor); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), + ...getStaticThemeOptions(visParams), partition: { - ...getStaticThemePartition(chartTheme, visParams), + ...getStaticThemePartition(visParams), outerSizeRatio: rescaleFactor, - linkLabel: getDefaultLinkLabel(visParams, chartTheme), + linkLabel: getDefaultLinkLabel(visParams), }, }); } @@ -260,20 +184,14 @@ const runPieDonutWaffleTestSuites = (chartType: ChartTypes, visParams: Partition labels: { ...visParams.labels, position: LabelPositions.INSIDE }, }; - const theme = getPartitionTheme( - chartType, - vParams, - chartTheme, - specifiedDimensions, - rescaleFactor - ); + const theme = getPartitionTheme(chartType, vParams, specifiedDimensions, rescaleFactor); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, vParams), + ...getStaticThemeOptions(vParams), partition: { - ...getStaticThemePartition(chartTheme, vParams), + ...getStaticThemePartition(vParams), outerSizeRatio: 0.5, - linkLabel: linkLabelsWithoutSpaceForOuterLabels, + linkLabel: linkLabelsWithoutSpaceForOuterLabels(vParams), }, }); } @@ -287,12 +205,12 @@ const runPieDonutWaffleTestSuites = (chartType: ChartTypes, visParams: Partition ...visParams, labels: { ...visParams.labels, last_level: true }, }; - const theme = getPartitionTheme(chartType, vParams, chartTheme, specifiedDimensions); + const theme = getPartitionTheme(chartType, vParams, specifiedDimensions); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, vParams), + ...getStaticThemeOptions(vParams), partition: { - ...getStaticThemePartition(chartTheme, vParams), + ...getStaticThemePartition(vParams), linkLabel: linkLabelWithEnoughSpace(vParams), }, }); @@ -304,55 +222,50 @@ const runPieDonutWaffleTestSuites = (chartType: ChartTypes, visParams: Partition ...visParams, labels: { ...visParams.labels, position: LabelPositions.INSIDE }, }; - const theme = getPartitionTheme(chartType, vParams, chartTheme, dimensions); + const theme = getPartitionTheme(chartType, vParams, dimensions); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, vParams), + ...getStaticThemeOptions(vParams), partition: { - ...getStaticThemePartition(chartTheme, vParams), + ...getStaticThemePartition(vParams), outerSizeRatio: undefined, - linkLabel: linkLabelsWithoutSpaceForOuterLabels, + linkLabel: linkLabelsWithoutSpaceForOuterLabels(vParams), }, }); - const themeSplitColumns = getPartitionTheme( - chartType, - vParamsSplitColumns, - chartTheme, - dimensions - ); + const themeSplitColumns = getPartitionTheme(chartType, vParamsSplitColumns, dimensions); expect(themeSplitColumns).toEqual({ - ...getStaticThemeOptions(chartTheme, vParamsSplitColumns), + ...getStaticThemeOptions(vParamsSplitColumns), partition: { - ...getStaticThemePartition(chartTheme, vParamsSplitColumns), + ...getStaticThemePartition(vParamsSplitColumns), outerSizeRatio: undefined, - linkLabel: linkLabelsWithoutSpaceForOuterLabels, + linkLabel: linkLabelsWithoutSpaceForOuterLabels(vParamsSplitColumns), }, }); - const themeSplitRows = getPartitionTheme(chartType, vParamsSplitRows, chartTheme, dimensions); + const themeSplitRows = getPartitionTheme(chartType, vParamsSplitRows, dimensions); expect(themeSplitRows).toEqual({ - ...getStaticThemeOptions(chartTheme, vParamsSplitRows), + ...getStaticThemeOptions(vParamsSplitRows), partition: { - ...getStaticThemePartition(chartTheme, vParamsSplitRows), + ...getStaticThemePartition(vParamsSplitRows), outerSizeRatio: undefined, - linkLabel: linkLabelsWithoutSpaceForOuterLabels, + linkLabel: linkLabelsWithoutSpaceForOuterLabels(vParamsSplitRows), }, }); }); it('should hide links if labels are not shown', () => { const vParams = { ...visParams, labels: { ...visParams.labels, show: false } }; - const theme = getPartitionTheme(chartType, vParams, chartTheme, dimensions); + const theme = getPartitionTheme(chartType, vParams, dimensions); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, vParams), + ...getStaticThemeOptions(vParams), partition: { - ...getStaticThemePartition(chartTheme, vParams), + ...getStaticThemePartition(vParams), outerSizeRatio: undefined, - linkLabel: linkLabelsWithoutSpaceForLabels, + linkLabel: linkLabelsWithoutSpaceForLabels(vParams), }, }); }); @@ -369,101 +282,61 @@ const runTreemapMosaicTestSuites = (chartType: ChartTypes, visParams: PartitionV }; it('should return correct theme options', () => { - const theme = getPartitionTheme(chartType, visParams, chartTheme, dimensions); - expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), - partition: { - ...getStaticThemePartition(chartTheme, visParams), - linkLabel: getDefaultLinkLabel(visParams, chartTheme), - }, - }); - }); - - it('should return empty padding settings if dimensions are not specified', () => { - const theme = getPartitionTheme(chartType, visParams, chartTheme, dimensions); - + const theme = getPartitionTheme(chartType, visParams, dimensions); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), + ...getStaticThemeOptions(visParams), partition: { - ...getStaticThemePartition(chartTheme, visParams), - linkLabel: getDefaultLinkLabel(visParams, chartTheme), + ...getStaticThemePartition(visParams), + linkLabel: getDefaultLinkLabel(visParams), }, }); }); it('should return padding settings if split column or row are specified', () => { - const themeForSplitColumns = getPartitionTheme( - chartType, - vParamsSplitColumns, - chartTheme, - dimensions - ); + const themeForSplitColumns = getPartitionTheme(chartType, vParamsSplitColumns, dimensions); expect(themeForSplitColumns).toEqual({ - ...getStaticThemeOptions(chartTheme, vParamsSplitColumns), + ...getStaticThemeOptions(vParamsSplitColumns), partition: { - ...getStaticThemePartition(chartTheme, vParamsSplitColumns), - linkLabel: getDefaultLinkLabel(vParamsSplitColumns, chartTheme), + ...getStaticThemePartition(vParamsSplitColumns), + linkLabel: getDefaultLinkLabel(vParamsSplitColumns), }, }); - const themeForSplitRows = getPartitionTheme( - chartType, - vParamsSplitRows, - chartTheme, - dimensions - ); + const themeForSplitRows = getPartitionTheme(chartType, vParamsSplitRows, dimensions); expect(themeForSplitRows).toEqual({ - ...getStaticThemeOptions(chartTheme, vParamsSplitRows), + ...getStaticThemeOptions(vParamsSplitRows), partition: { - ...getStaticThemePartition(chartTheme, vParamsSplitRows), - linkLabel: getDefaultLinkLabel(vParamsSplitRows, chartTheme), + ...getStaticThemePartition(vParamsSplitRows), + linkLabel: getDefaultLinkLabel(vParamsSplitRows), }, }); }); it('should return fullfilled padding settings if dimensions are specified', () => { const specifiedDimensions = { width: 2000, height: 2000 }; - const theme = getPartitionTheme( - chartType, - visParams, - chartTheme, - specifiedDimensions, - undefined, - true - ); + const theme = getPartitionTheme(chartType, visParams, specifiedDimensions, undefined, true); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), + ...getStaticThemeOptions(visParams), chartPaddings: { top: 500, bottom: 500, left: 500, right: 500 }, partition: { - ...getStaticThemePartition(chartTheme, visParams), - linkLabel: getDefaultLinkLabel(visParams, chartTheme), - }, - }); - }); - - it('should return settings for the theme related fields', () => { - const theme = getPartitionTheme(chartType, visParams, chartTheme, dimensions); - expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), - partition: { - ...getStaticThemePartition(chartTheme, visParams), - linkLabel: getDefaultLinkLabel(visParams, chartTheme), + ...getStaticThemePartition(visParams), + linkLabel: getDefaultLinkLabel(visParams), }, }); }); it('should make color transparent if labels are hidden', () => { const vParams = { ...visParams, labels: { ...visParams.labels, show: false } }; - const theme = getPartitionTheme(chartType, vParams, chartTheme, dimensions); + const theme = getPartitionTheme(chartType, vParams, dimensions); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, vParams), + ...getStaticThemeOptions(vParams), partition: { - ...getStaticThemePartition(chartTheme, vParams), - linkLabel: getDefaultLinkLabel(visParams, chartTheme), + ...getStaticThemePartition(vParams), + linkLabel: getDefaultLinkLabel(visParams), fillLabel: { textColor: 'rgba(0,0,0,0)' }, }, }); @@ -481,14 +354,14 @@ describe('Donut getPartitionTheme', () => { runPieDonutWaffleTestSuites(chartType, visParams); it('should return correct empty size ratio and partitionLayout', () => { - const theme = getPartitionTheme(ChartTypes.DONUT, visParams, chartTheme, dimensions); + const theme = getPartitionTheme(ChartTypes.DONUT, visParams, dimensions); expect(theme).toEqual({ - ...getStaticThemeOptions(chartTheme, visParams), + ...getStaticThemeOptions(visParams), outerSizeRatio: undefined, partition: { - ...getStaticThemePartition(chartTheme, visParams), - linkLabel: getDefaultLinkLabel(visParams, chartTheme), + ...getStaticThemePartition(visParams), + linkLabel: getDefaultLinkLabel(visParams), outerSizeRatio: undefined, }, }); diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_partition_theme.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_partition_theme.ts index e1e47dc27fc5b..8ee92d31544b5 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_partition_theme.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_partition_theme.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { RecursivePartial, Theme, PartialTheme } from '@elastic/charts'; +import { PartialTheme } from '@elastic/charts'; import { ChartTypes, LabelPositions, @@ -15,37 +15,13 @@ import { PieContainerDimensions, } from '../../common/types'; -type GetThemeByTypeFn = ( - chartType: ChartTypes, - visParams: PartitionVisParams, - dimensions?: PieContainerDimensions, - rescaleFactor?: number -) => PartialTheme; - -type GetThemeFn = ( - chartType: ChartTypes, - visParams: PartitionVisParams, - chartTheme: RecursivePartial, - dimensions?: PieContainerDimensions, - rescaleFactor?: number, - hasOpenedOnAggBasedEditor?: boolean -) => PartialTheme; +const MAX_SIZE = 1000; -type GetPieDonutWaffleThemeFn = ( +function getPieDonutWaffleCommonTheme( visParams: PartitionVisParams, dimensions?: PieContainerDimensions, - rescaleFactor?: number -) => PartialTheme; - -type GetTreemapMosaicThemeFn = (visParams: PartitionVisParams) => PartialTheme; - -const MAX_SIZE = 1000; - -const getPieDonutWaffleCommonTheme: GetPieDonutWaffleThemeFn = ( - visParams, - dimensions, rescaleFactor = 1 -) => { +): PartialTheme['partition'] { const isSplitChart = Boolean(visParams.dimensions.splitColumn || visParams.dimensions.splitRow); const preventLinksFromShowing = (visParams.labels.position === LabelPositions.INSIDE || isSplitChart) && visParams.labels.show; @@ -59,15 +35,14 @@ const getPieDonutWaffleCommonTheme: GetPieDonutWaffleThemeFn = ( } : { outerSizeRatio: undefined }; - const theme: PartialTheme = {}; - theme.partition = { ...(usingOuterSizeRatio ?? {}) }; + const partitionTheme: PartialTheme['partition'] = { ...(usingOuterSizeRatio ?? {}) }; if ( visParams.labels.show && visParams.labels.position === LabelPositions.DEFAULT && visParams.labels.last_level ) { - theme.partition.linkLabel = { + partitionTheme.linkLabel = { maxCount: Number.POSITIVE_INFINITY, maximumSection: Number.POSITIVE_INFINITY, maxTextLength: visParams.labels.truncate ?? undefined, @@ -76,7 +51,7 @@ const getPieDonutWaffleCommonTheme: GetPieDonutWaffleThemeFn = ( if (preventLinksFromShowing || !visParams.labels.show) { // Prevent links from showing - theme.partition.linkLabel = { + partitionTheme.linkLabel = { maxCount: 0, ...(!visParams.labels.show ? { maximumSection: Number.POSITIVE_INFINITY } : {}), }; @@ -84,48 +59,55 @@ const getPieDonutWaffleCommonTheme: GetPieDonutWaffleThemeFn = ( if (!preventLinksFromShowing && dimensions && !isSplitChart) { // shrink up to 20% to give some room for the linked values - theme.partition.outerSizeRatio = rescaleFactor; + partitionTheme.outerSizeRatio = rescaleFactor; } - return theme; -}; + return partitionTheme; +} + +function getDonutSpecificTheme( + visParams: PartitionVisParams, + dimensions?: PieContainerDimensions, + rescaleFactor?: number +): PartialTheme['partition'] { + const partition = getPieDonutWaffleCommonTheme(visParams, dimensions, rescaleFactor); + return { ...partition, emptySizeRatio: visParams.emptySizeRatio }; +} -const getDonutSpecificTheme: GetPieDonutWaffleThemeFn = (visParams, ...args) => { - const { partition, ...restTheme } = getPieDonutWaffleCommonTheme(visParams, ...args); - return { ...restTheme, partition: { ...partition, emptySizeRatio: visParams.emptySizeRatio } }; -}; +function getTreemapMosaicCommonTheme(visParams: PartitionVisParams): PartialTheme['partition'] { + return !visParams.labels.show ? { fillLabel: { textColor: 'rgba(0,0,0,0)' } } : {}; +} -const getTreemapMosaicCommonTheme: GetTreemapMosaicThemeFn = (visParams) => { - if (!visParams.labels.show) { - return { - partition: { - fillLabel: { textColor: 'rgba(0,0,0,0)' }, - }, - }; +function getSpecificTheme( + chartType: ChartTypes, + visParams: PartitionVisParams, + dimensions?: PieContainerDimensions, + rescaleFactor?: number +): PartialTheme['partition'] { + switch (chartType) { + case ChartTypes.PIE: + return getPieDonutWaffleCommonTheme(visParams, dimensions, rescaleFactor); + case ChartTypes.DONUT: + return getDonutSpecificTheme(visParams, dimensions, rescaleFactor); + case ChartTypes.TREEMAP: + return getTreemapMosaicCommonTheme(visParams); + case ChartTypes.MOSAIC: + return getTreemapMosaicCommonTheme(visParams); + case ChartTypes.WAFFLE: + return getPieDonutWaffleCommonTheme(visParams, dimensions, rescaleFactor); } - return {}; -}; +} -const getSpecificTheme: GetThemeByTypeFn = (chartType, visParams, dimensions, rescaleFactor) => - ({ - [ChartTypes.PIE]: () => getPieDonutWaffleCommonTheme(visParams, dimensions, rescaleFactor), - [ChartTypes.DONUT]: () => getDonutSpecificTheme(visParams, dimensions, rescaleFactor), - [ChartTypes.TREEMAP]: () => getTreemapMosaicCommonTheme(visParams), - [ChartTypes.MOSAIC]: () => getTreemapMosaicCommonTheme(visParams), - [ChartTypes.WAFFLE]: () => getPieDonutWaffleCommonTheme(visParams, dimensions, rescaleFactor), - }[chartType]()); - -export const getPartitionTheme: GetThemeFn = ( - chartType, - visParams, - chartTheme, - dimensions, +export function getPartitionTheme( + chartType: ChartTypes, + visParams: PartitionVisParams, + dimensions?: PieContainerDimensions, rescaleFactor = 1, - hasOpenedOnAggBasedEditor -) => { + hasOpenedOnAggBasedEditor?: boolean +): PartialTheme { // On small multiples we want the labels to only appear inside const isSplitChart = Boolean(visParams.dimensions.splitColumn || visParams.dimensions.splitRow); - const paddingProps: PartialTheme | null = + const paddingProps: PartialTheme = dimensions && !isSplitChart && hasOpenedOnAggBasedEditor ? { chartPaddings: { @@ -135,34 +117,27 @@ export const getPartitionTheme: GetThemeFn = ( right: ((1 - Math.min(1, MAX_SIZE / dimensions?.width)) / 2) * dimensions?.height, }, } - : null; - const partition = { - fontFamily: chartTheme.barSeriesStyle?.displayValue?.fontFamily, - outerSizeRatio: 1, - minFontSize: 10, - maxFontSize: 16, - emptySizeRatio: 0, - sectorLineStroke: chartTheme.lineSeriesStyle?.point?.fill, - sectorLineWidth: 1.5, - circlePadding: 4, - linkLabel: { - maxCount: 5, - fontSize: 11, - textColor: chartTheme.axes?.axisTitle?.fill, - maxTextLength: visParams.labels.truncate ?? undefined, - }, - }; - const { partition: specificPartition = {}, ...restSpecificTheme } = getSpecificTheme( - chartType, - visParams, - dimensions, - rescaleFactor - ); + : {}; + + const specificPartition = getSpecificTheme(chartType, visParams, dimensions, rescaleFactor); return { - partition: { ...partition, ...specificPartition }, + partition: { + outerSizeRatio: 1, + minFontSize: 10, + maxFontSize: 16, + emptySizeRatio: 0, + sectorLineWidth: 1.5, + circlePadding: 4, + ...specificPartition, + linkLabel: { + // fontSize: 11, + maxTextLength: visParams.labels.truncate ?? undefined, + maxCount: 5, + ...specificPartition?.linkLabel, + }, + }, chartMargins: { top: 0, bottom: 0, left: 0, right: 0 }, - ...(paddingProps ?? {}), - ...restSpecificTheme, + ...paddingProps, }; -}; +} From a78a31d1873a7dca3d175870aee05801b056f5a4 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Tue, 8 Oct 2024 20:04:40 +0300 Subject: [PATCH 002/110] fix: [Obs Applications > Services | Traces | Dependencies][SCREEN READER]: H1 tag should not include secondary information (#193880) Closes: https://github.com/elastic/kibana/issues/194988 Closes: https://github.com/elastic/kibana/issues/194987 Closes: https://github.com/elastic/kibana/issues/194986 ## Description Observability has a few pages that wrap related information like alert counts in the H1 tag. This presents a challenge to screen readers because all of that information now becomes the heading level one. It clogs up the Headings menu and makes it harder to reason about the page and what's primary information vs. secondary. ## What was changed?: 1. extra content has been removed from `pageTitle` and moved to `rightSideItems`. ## Screen: image > [!NOTE] > On smaller screens (at certain resolutions) sometimes we have an issue described in https://github.com/elastic/eui/issues/8039 . But It's not a blocker for that PR and will be fixed on EUI side --- .../templates/apm_main_template/index.tsx | 47 +++++++------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_main_template/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_main_template/index.tsx index e536ed9456801..f4ef2044a38c7 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_main_template/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_main_template/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiPageHeaderProps } from '@elastic/eui'; +import { EuiFlexGroup, EuiPageHeaderProps } from '@elastic/eui'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { entityCentricExperience } from '@kbn/observability-plugin/common'; import { ObservabilityPageTemplateProps } from '@kbn/observability-shared-plugin/public'; @@ -132,35 +132,24 @@ export function ApmMainTemplate({ noDataConfig, }); - const rightSideItems = [...(showServiceGroupSaveButton ? [] : [])]; - const sanitizedPath = getPathForFeedback(window.location.pathname); - const pageHeaderTitle = ( - - {pageHeader?.pageTitle ?? pageTitle} - - - - - - - {environmentFilter && } - - - - ); + const rightSideItems = [ + ...(showServiceGroupSaveButton ? [] : []), + ...(environmentFilter ? [] : []), + , + ]; const [dismissedEntitiesInventoryCallout, setdismissedEntitiesInventoryCallout] = useLocalStorage( `apm.dismissedEntitiesInventoryCallout`, @@ -180,7 +169,7 @@ export function ApmMainTemplate({ pageHeader={{ rightSideItems, ...pageHeader, - pageTitle: pageHeaderTitle, + pageTitle: pageHeader?.pageTitle ?? pageTitle, children: ( {showEntitiesInventoryCallout ? ( From d583ddf41ac41f09fd97fbd6b91c2d7076333d97 Mon Sep 17 00:00:00 2001 From: Linghao Su Date: Wed, 9 Oct 2024 01:28:57 +0800 Subject: [PATCH 003/110] [Vega] Fix tooltip position on faceted charts (#194620) Fixes #163815 where the tooltip was incorrectly positioned on faceted Vega charts --- .../vega/public/vega_view/vega_tooltip.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.js b/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.js index e12316c242d77..306d00a145c15 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.js +++ b/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.js @@ -79,12 +79,19 @@ export class TooltipHandler { anchorBounds = createRect(event.clientX, event.clientY, 0, 0); } else { const containerBox = this.container.getBoundingClientRect(); - anchorBounds = createRect( - containerBox.left + view._origin[0] + item.bounds.x1, - containerBox.top + view._origin[1] + item.bounds.y1, - item.bounds.width(), - item.bounds.height() - ); + let left = containerBox.left + view._origin[0] + item.bounds.x1; + let top = containerBox.top + view._origin[1] + item.bounds.y1; + + // loop item mark group + let ancestorItem = item; + + while (ancestorItem.mark.group) { + ancestorItem = ancestorItem.mark.group; + left += ancestorItem.x; + top += ancestorItem.y; + } + + anchorBounds = createRect(left, top, item.bounds.width(), item.bounds.height()); } const pos = calculatePopoverPosition( From bf621693f20b012593ec5fcb84c7386da952aeb3 Mon Sep 17 00:00:00 2001 From: Jedr Blaszyk Date: Tue, 8 Oct 2024 19:30:46 +0200 Subject: [PATCH 004/110] [Search] Fix issue with crawler not getting deleted (#195440) ## Summary The bug is that connector doc can be of `elastic-crawler` service type, we forgot about this in the logic that handles detaching the index from connector upon index delation. This change checks if a connector doc, matching the `index_name` to be deleted, is of crawler type: - If yes, delete the connector (crawler) doc, as crawler is always tied 1:1 to an index - If no, detach the index, leave the connector doc in the connector index This bug was likely introduced as a part of: https://github.com/elastic/kibana/pull/183833 (some lazy engineer forgot to test for this edge case ...) ## Validation ### Delete Crawler case 1: Delete Crawler deletes crawler doc + related index https://github.com/user-attachments/assets/68ad14f7-4a7f-408c-8731-6ed0465f9ef1 ### Delete Crawler case 2: Delete crawler-related index deletes crawler doc https://github.com/user-attachments/assets/e2995697-32c4-4f8f-90ce-9c06c7e6d208 --- .../routes/enterprise_search/indices.ts | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts index 78d7d2076438e..70b46205c5e88 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts @@ -14,7 +14,12 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; -import { deleteConnectorSecret, updateConnectorIndexName } from '@kbn/search-connectors'; +import { + CRAWLER_SERVICE_TYPE, + deleteConnectorSecret, + deleteConnectorById, + updateConnectorIndexName, +} from '@kbn/search-connectors'; import { fetchConnectorByIndexName, fetchConnectors, @@ -207,13 +212,17 @@ export function registerIndexRoutes({ } if (connector) { - // detach the deleted index without removing the connector - await updateConnectorIndexName(client.asCurrentUser, connector.id, null); - if (connector.api_key_id) { - await client.asCurrentUser.security.invalidateApiKey({ ids: [connector.api_key_id] }); - } - if (connector.api_key_secret_id) { - await deleteConnectorSecret(client.asCurrentUser, connector.api_key_secret_id); + if (connector.service_type === CRAWLER_SERVICE_TYPE) { + await deleteConnectorById(client.asCurrentUser, connector.id); + } else { + // detach the deleted index without removing the connector + await updateConnectorIndexName(client.asCurrentUser, connector.id, null); + if (connector.api_key_id) { + await client.asCurrentUser.security.invalidateApiKey({ ids: [connector.api_key_id] }); + } + if (connector.api_key_secret_id) { + await deleteConnectorSecret(client.asCurrentUser, connector.api_key_secret_id); + } } } From f892d31285f7879e3374b5dfa55be103271af2de Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 9 Oct 2024 04:36:20 +1100 Subject: [PATCH 005/110] skip failing test suite (#195453) --- x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts index b6c210ece2ddc..d74bd2483f746 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts @@ -43,6 +43,7 @@ import { import { ServerlessRoleName } from '../../support/roles'; import { getAdvancedButton } from '../../screens/integrations'; +// Failing: See https://github.com/elastic/kibana/issues/195453 // Failing: See https://github.com/elastic/kibana/issues/195453 describe.skip('ALL - Saved queries', { tags: ['@ess', '@serverless'] }, () => { let caseId: string; From 8c7d22c0af40ca5772bc9c97610817600a5596f2 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 9 Oct 2024 04:36:32 +1100 Subject: [PATCH 006/110] skip failing test suite (#195476) --- .../management/cypress/e2e/endpoint_list/endpoints.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts index 12cdfcfa6e09c..03b9797abb56e 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts @@ -28,7 +28,8 @@ import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; -describe('Endpoints page', { tags: ['@ess', '@serverless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/195476 +describe.skip('Endpoints page', { tags: ['@ess', '@serverless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; From 93c82265fbeaf8e0b19c818dd295251781a686ce Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 9 Oct 2024 04:36:49 +1100 Subject: [PATCH 007/110] skip failing test suite (#171435) --- x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts index 6f551ad39b196..cafc97cb646ea 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts @@ -19,7 +19,8 @@ import { LIVE_QUERY_EDITOR } from '../../screens/live_query'; import { getAdvancedButton } from '../../screens/integrations'; import { ServerlessRoleName } from '../../support/roles'; -describe('ALL - Live Query', { tags: ['@ess', '@serverless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/171435 +describe.skip('ALL - Live Query', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { cy.login(ServerlessRoleName.SOC_MANAGER); navigateTo('/app/osquery'); From 2bb8c6326645603aedd721d85463a4b32f2cdc6d Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 8 Oct 2024 18:37:32 +0100 Subject: [PATCH 008/110] skip flaky suite (#195458) --- x-pack/plugins/osquery/cypress/e2e/all/live_query_run.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/osquery/cypress/e2e/all/live_query_run.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/live_query_run.cy.ts index c74b253ae9d41..f0a19907d57d8 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/live_query_run.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/live_query_run.cy.ts @@ -23,7 +23,8 @@ import { getAdvancedButton } from '../../screens/integrations'; import { loadSavedQuery, cleanupSavedQuery } from '../../tasks/api_fixtures'; import { ServerlessRoleName } from '../../support/roles'; -describe('ALL - Live Query run custom and saved', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/195458 +describe.skip('ALL - Live Query run custom and saved', { tags: ['@ess', '@serverless'] }, () => { let savedQueryId: string; let savedQueryName: string; From 16cd4bb1fed3bb4d4959b3162e873891dfab4b92 Mon Sep 17 00:00:00 2001 From: Jatin Kathuria Date: Tue, 8 Oct 2024 19:46:43 +0200 Subject: [PATCH 009/110] [Security Solution] skips Flaky test (#195435) ## Summary Skips Flaky test : https://github.com/elastic/kibana/issues/189794 --- .../timeline/tabs/query/query_tab_unified_components.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx index 7a6c23279f435..9d450f46f4b01 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx @@ -901,7 +901,8 @@ describe('query tab with unified timeline', () => { ); }); - it( + // Flaky: https://github.com/elastic/kibana/issues/189794 + it.skip( 'should have the notification dot & correct tooltip', async () => { renderTestComponents(); From 9c8f689aca23ed8b1f560c57a9a660d318375412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Tue, 8 Oct 2024 13:48:07 -0400 Subject: [PATCH 010/110] Put the auto calculation of capacity behind a feature flag, for now (#195390) In this PR, I'm preparing for the 8.16 release where we'd like to start rolling out the `mget` task claiming strategy separately from the added concurrency. To accomplish this, we need to put the capacity calculation behind a feature flag that is default to false for now, until we do a second rollout with an increased concurrency. The increased concurrency can be calculated and adjusted based on experiments of clusters setting `xpack.task_manager.capacity` to a higher value and observe the resource usage. PR to deploy to Cloud and verify that we always default to 10 normal tasks: https://github.com/elastic/kibana/pull/195392 --- .../resources/base/bin/kibana-docker | 1 + .../task_manager/server/config.test.ts | 3 + x-pack/plugins/task_manager/server/config.ts | 1 + .../server/ephemeral_task_lifecycle.test.ts | 1 + .../managed_configuration.test.ts | 3 + .../lib/calculate_health_status.test.ts | 1 + .../server/lib/get_default_capacity.test.ts | 62 +++++++++++++++++++ .../server/lib/get_default_capacity.ts | 9 ++- .../server/metrics/create_aggregator.test.ts | 1 + .../configuration_statistics.test.ts | 1 + .../task_manager/server/plugin.test.ts | 1 + x-pack/plugins/task_manager/server/plugin.ts | 5 +- .../server/polling_lifecycle.test.ts | 1 + 13 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index 110ca72895e86..3c1e7ebe857fa 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -416,6 +416,7 @@ kibana_vars=( xpack.spaces.maxSpaces xpack.task_manager.capacity xpack.task_manager.claim_strategy + xpack.task_manager.auto_calculate_default_ech_capacity xpack.task_manager.discovery.active_nodes_lookback xpack.task_manager.discovery.interval xpack.task_manager.kibanas_per_partition diff --git a/x-pack/plugins/task_manager/server/config.test.ts b/x-pack/plugins/task_manager/server/config.test.ts index fa8c18207a692..34dd5f1c6fbff 100644 --- a/x-pack/plugins/task_manager/server/config.test.ts +++ b/x-pack/plugins/task_manager/server/config.test.ts @@ -13,6 +13,7 @@ describe('config validation', () => { expect(configSchema.validate(config)).toMatchInlineSnapshot(` Object { "allow_reading_invalid_state": true, + "auto_calculate_default_ech_capacity": false, "claim_strategy": "update_by_query", "discovery": Object { "active_nodes_lookback": "30s", @@ -75,6 +76,7 @@ describe('config validation', () => { expect(configSchema.validate(config)).toMatchInlineSnapshot(` Object { "allow_reading_invalid_state": true, + "auto_calculate_default_ech_capacity": false, "claim_strategy": "update_by_query", "discovery": Object { "active_nodes_lookback": "30s", @@ -135,6 +137,7 @@ describe('config validation', () => { expect(configSchema.validate(config)).toMatchInlineSnapshot(` Object { "allow_reading_invalid_state": true, + "auto_calculate_default_ech_capacity": false, "claim_strategy": "update_by_query", "discovery": Object { "active_nodes_lookback": "30s", diff --git a/x-pack/plugins/task_manager/server/config.ts b/x-pack/plugins/task_manager/server/config.ts index db07494ef4f06..f640ed2165f22 100644 --- a/x-pack/plugins/task_manager/server/config.ts +++ b/x-pack/plugins/task_manager/server/config.ts @@ -204,6 +204,7 @@ export const configSchema = schema.object( }), claim_strategy: schema.string({ defaultValue: CLAIM_STRATEGY_UPDATE_BY_QUERY }), request_timeouts: requestTimeoutsConfig, + auto_calculate_default_ech_capacity: schema.boolean({ defaultValue: false }), }, { validate: (config) => { diff --git a/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts b/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts index 31c873554ee77..ec45959157770 100644 --- a/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts +++ b/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts @@ -88,6 +88,7 @@ describe('EphemeralTaskLifecycle', () => { request_timeouts: { update_by_query: 1000, }, + auto_calculate_default_ech_capacity: false, ...config, }, elasticsearchAndSOAvailability$, diff --git a/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts b/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts index 92d97eea7c6b2..ab1d1bc0498fd 100644 --- a/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts +++ b/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts @@ -87,6 +87,7 @@ describe('managed configuration', () => { request_timeouts: { update_by_query: 1000, }, + auto_calculate_default_ech_capacity: false, }); logger = context.logger.get('taskManager'); @@ -209,6 +210,7 @@ describe('managed configuration', () => { request_timeouts: { update_by_query: 1000, }, + auto_calculate_default_ech_capacity: false, }); logger = context.logger.get('taskManager'); @@ -334,6 +336,7 @@ describe('managed configuration', () => { request_timeouts: { update_by_query: 1000, }, + auto_calculate_default_ech_capacity: false, }); logger = context.logger.get('taskManager'); diff --git a/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts b/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts index 24e2f510f949c..b973a5c1cd5e6 100644 --- a/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts +++ b/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts @@ -60,6 +60,7 @@ const config = { request_timeouts: { update_by_query: 1000, }, + auto_calculate_default_ech_capacity: false, }; const getStatsWithTimestamp = ({ diff --git a/x-pack/plugins/task_manager/server/lib/get_default_capacity.test.ts b/x-pack/plugins/task_manager/server/lib/get_default_capacity.test.ts index 09a4719508230..76271e6cebeaf 100644 --- a/x-pack/plugins/task_manager/server/lib/get_default_capacity.test.ts +++ b/x-pack/plugins/task_manager/server/lib/get_default_capacity.test.ts @@ -9,9 +9,56 @@ import { CLAIM_STRATEGY_UPDATE_BY_QUERY, CLAIM_STRATEGY_MGET, DEFAULT_CAPACITY } import { getDefaultCapacity } from './get_default_capacity'; describe('getDefaultCapacity', () => { + it('returns default capacity when autoCalculateDefaultEchCapacity=false', () => { + expect( + getDefaultCapacity({ + autoCalculateDefaultEchCapacity: false, + heapSizeLimit: 851443712, + isCloud: false, + isServerless: false, + isBackgroundTaskNodeOnly: false, + claimStrategy: CLAIM_STRATEGY_MGET, + }) + ).toBe(DEFAULT_CAPACITY); + + expect( + getDefaultCapacity({ + autoCalculateDefaultEchCapacity: false, + heapSizeLimit: 851443712, + isCloud: false, + isServerless: true, + isBackgroundTaskNodeOnly: false, + claimStrategy: CLAIM_STRATEGY_MGET, + }) + ).toBe(DEFAULT_CAPACITY); + + expect( + getDefaultCapacity({ + autoCalculateDefaultEchCapacity: false, + heapSizeLimit: 851443712, + isCloud: false, + isServerless: false, + isBackgroundTaskNodeOnly: true, + claimStrategy: CLAIM_STRATEGY_MGET, + }) + ).toBe(DEFAULT_CAPACITY); + + expect( + getDefaultCapacity({ + autoCalculateDefaultEchCapacity: false, + heapSizeLimit: 851443712, + isCloud: false, + isServerless: true, + isBackgroundTaskNodeOnly: true, + claimStrategy: CLAIM_STRATEGY_MGET, + }) + ).toBe(DEFAULT_CAPACITY); + }); + it('returns default capacity when not in cloud', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: false, isServerless: false, @@ -22,6 +69,7 @@ describe('getDefaultCapacity', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: false, isServerless: true, @@ -32,6 +80,7 @@ describe('getDefaultCapacity', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: false, isServerless: false, @@ -42,6 +91,7 @@ describe('getDefaultCapacity', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: false, isServerless: true, @@ -54,6 +104,7 @@ describe('getDefaultCapacity', () => { it('returns default capacity when default claim strategy', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: true, isServerless: false, @@ -64,6 +115,7 @@ describe('getDefaultCapacity', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: true, isServerless: false, @@ -76,6 +128,7 @@ describe('getDefaultCapacity', () => { it('returns default capacity when serverless', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: false, isServerless: true, @@ -86,6 +139,7 @@ describe('getDefaultCapacity', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: false, isServerless: true, @@ -96,6 +150,7 @@ describe('getDefaultCapacity', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: true, isServerless: true, @@ -106,6 +161,7 @@ describe('getDefaultCapacity', () => { expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: true, isServerless: true, @@ -119,6 +175,7 @@ describe('getDefaultCapacity', () => { // 1GB expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: true, isServerless: false, @@ -130,6 +187,7 @@ describe('getDefaultCapacity', () => { // 1GB but somehow background task node only is true expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 851443712, isCloud: true, isServerless: false, @@ -141,6 +199,7 @@ describe('getDefaultCapacity', () => { // 2GB expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 1702887424, isCloud: true, isServerless: false, @@ -152,6 +211,7 @@ describe('getDefaultCapacity', () => { // 2GB but somehow background task node only is true expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 1702887424, isCloud: true, isServerless: false, @@ -163,6 +223,7 @@ describe('getDefaultCapacity', () => { // 4GB expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 3405774848, isCloud: true, isServerless: false, @@ -174,6 +235,7 @@ describe('getDefaultCapacity', () => { // 4GB background task only expect( getDefaultCapacity({ + autoCalculateDefaultEchCapacity: true, heapSizeLimit: 3405774848, isCloud: true, isServerless: false, diff --git a/x-pack/plugins/task_manager/server/lib/get_default_capacity.ts b/x-pack/plugins/task_manager/server/lib/get_default_capacity.ts index dff31ae3afd50..113747f2196a8 100644 --- a/x-pack/plugins/task_manager/server/lib/get_default_capacity.ts +++ b/x-pack/plugins/task_manager/server/lib/get_default_capacity.ts @@ -8,6 +8,7 @@ import { CLAIM_STRATEGY_MGET, DEFAULT_CAPACITY } from '../config'; interface GetDefaultCapacityOpts { + autoCalculateDefaultEchCapacity: boolean; claimStrategy?: string; heapSizeLimit: number; isCloud: boolean; @@ -24,6 +25,7 @@ const HEAP_TO_CAPACITY_MAP = [ ]; export function getDefaultCapacity({ + autoCalculateDefaultEchCapacity, claimStrategy, heapSizeLimit: heapSizeLimitInBytes, isCloud, @@ -31,7 +33,12 @@ export function getDefaultCapacity({ isBackgroundTaskNodeOnly, }: GetDefaultCapacityOpts) { // perform heap size based calculations only in cloud - if (isCloud && !isServerless && claimStrategy === CLAIM_STRATEGY_MGET) { + if ( + autoCalculateDefaultEchCapacity && + isCloud && + !isServerless && + claimStrategy === CLAIM_STRATEGY_MGET + ) { // convert bytes to GB const heapSizeLimitInGB = heapSizeLimitInBytes / 1e9; diff --git a/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts b/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts index 6b768a9f4d4e9..e56d57e170558 100644 --- a/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts +++ b/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts @@ -78,6 +78,7 @@ const config: TaskManagerConfig = { request_timeouts: { update_by_query: 1000, }, + auto_calculate_default_ech_capacity: false, }; describe('createAggregator', () => { diff --git a/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts b/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts index 2be1930786fa8..1bcd3e286d4a3 100644 --- a/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts +++ b/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts @@ -56,6 +56,7 @@ describe('Configuration Statistics Aggregator', () => { request_timeouts: { update_by_query: 1000, }, + auto_calculate_default_ech_capacity: false, }; const managedConfig = { diff --git a/x-pack/plugins/task_manager/server/plugin.test.ts b/x-pack/plugins/task_manager/server/plugin.test.ts index a7d452f76d6e2..890c7daf7a111 100644 --- a/x-pack/plugins/task_manager/server/plugin.test.ts +++ b/x-pack/plugins/task_manager/server/plugin.test.ts @@ -87,6 +87,7 @@ const pluginInitializerContextParams = { request_timeouts: { update_by_query: 1000, }, + auto_calculate_default_ech_capacity: false, }; describe('TaskManagerPlugin', () => { diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index 87acf096d007c..56f73ed1cc6c3 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -286,6 +286,7 @@ export class TaskManagerPlugin const isServerless = this.initContext.env.packageInfo.buildFlavor === 'serverless'; const defaultCapacity = getDefaultCapacity({ + autoCalculateDefaultEchCapacity: this.config.auto_calculate_default_ech_capacity, claimStrategy: this.config?.claim_strategy, heapSizeLimit: this.heapSizeLimit, isCloud: cloud?.isCloudEnabled ?? false, @@ -300,7 +301,9 @@ export class TaskManagerPlugin this.config!.claim_strategy } isBackgroundTaskNodeOnly=${this.isNodeBackgroundTasksOnly()} heapSizeLimit=${ this.heapSizeLimit - } defaultCapacity=${defaultCapacity}` + } defaultCapacity=${defaultCapacity} autoCalculateDefaultEchCapacity=${ + this.config.auto_calculate_default_ech_capacity + }` ); const managedConfiguration = createManagedConfiguration({ diff --git a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts index 0b6d4ce983d5b..ce874833b5c38 100644 --- a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts +++ b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts @@ -91,6 +91,7 @@ describe('TaskPollingLifecycle', () => { request_timeouts: { update_by_query: 1000, }, + auto_calculate_default_ech_capacity: false, }, taskStore: mockTaskStore, logger: taskManagerLogger, From aec74fc6e700416d2944ea336290289959e55d83 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 8 Oct 2024 18:49:21 +0100 Subject: [PATCH 011/110] skip flaky suite (#172549) --- .../e2e/response_actions/response_actions_history.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts index dfd67d6854b63..93c6f0698a81a 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts @@ -10,7 +10,8 @@ import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts'; import { login } from '../../tasks/login'; import { loadPage } from '../../tasks/common'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/172549 +describe.skip( 'Response actions history page', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { From 74470ecd62d98401fcdfead3a4113f0729caa9c0 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 8 Oct 2024 18:50:12 +0100 Subject: [PATCH 012/110] skip flaky suite (#195477) --- .../e2e/rbac/endpoint_role_rbac_with_space_awareness.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac_with_space_awareness.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac_with_space_awareness.cy.ts index 424b3fc954c57..2a3d2876ea488 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac_with_space_awareness.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac_with_space_awareness.cy.ts @@ -23,7 +23,8 @@ import { setSecuritySolutionEndpointGroupPrivilege, } from '../../screens/stack_management/role_page'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/195477 +describe.skip( 'When defining a kibana role for Endpoint security access with space awareness enabled', { // TODO:PR Remove `'@skipInServerlessMKI` once PR merges to `main` From 550015b0410963173cbfed4dd994288978ec9e30 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 8 Oct 2024 18:51:30 +0100 Subject: [PATCH 013/110] skip flaky suite (#192222) --- .../knowledge_base/knowledge_base_user_instructions.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/observability_ai_assistant_api_integration/tests/knowledge_base/knowledge_base_user_instructions.spec.ts b/x-pack/test/observability_ai_assistant_api_integration/tests/knowledge_base/knowledge_base_user_instructions.spec.ts index bf2eef14db553..04e05fc9ad31b 100644 --- a/x-pack/test/observability_ai_assistant_api_integration/tests/knowledge_base/knowledge_base_user_instructions.spec.ts +++ b/x-pack/test/observability_ai_assistant_api_integration/tests/knowledge_base/knowledge_base_user_instructions.spec.ts @@ -51,7 +51,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { await clearConversations(es); }); - describe('when creating private and public user instructions', () => { + // FLAKY: https://github.com/elastic/kibana/issues/192222 + describe.skip('when creating private and public user instructions', () => { before(async () => { await clearKnowledgeBase(es); From bb6e78ebbf8304c7be34345ed215674dc509632a Mon Sep 17 00:00:00 2001 From: Thom Heymann <190132+thomheymann@users.noreply.github.com> Date: Tue, 8 Oct 2024 19:13:04 +0100 Subject: [PATCH 014/110] [Observability] Unified Kubernetes Observability with OpenTelemetry (#194169) --- .../observability_onboarding_flow.tsx | 4 + .../public/application/pages/index.ts | 1 + .../application/pages/otel_kubernetes.tsx | 36 ++ .../kubernetes/use_kubernetes_flow.ts | 18 +- .../otel_kubernetes/index.tsx | 8 + .../otel_kubernetes/otel_kubernetes_panel.tsx | 331 ++++++++++++++++++ .../quickstart_flows/shared/empty_prompt.tsx | 2 +- .../shared/get_started_panel.tsx | 55 +-- .../server/routes/kubernetes/route.ts | 12 +- 9 files changed, 434 insertions(+), 33 deletions(-) create mode 100644 x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/otel_kubernetes.tsx create mode 100644 x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_kubernetes/index.tsx create mode 100644 x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_kubernetes/otel_kubernetes_panel.tsx diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/observability_onboarding_flow.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/observability_onboarding_flow.tsx index 95b31aab24966..348b3c65f9371 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/observability_onboarding_flow.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/observability_onboarding_flow.tsx @@ -16,6 +16,7 @@ import { KubernetesPage, LandingPage, OtelLogsPage, + OtelKubernetesPage, SystemLogsPage, FirehosePage, } from './pages'; @@ -50,6 +51,9 @@ export function ObservabilityOnboardingFlow() { + + + diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/index.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/index.ts index cd4b821f3cc0d..7e5606205b607 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/index.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/index.ts @@ -8,6 +8,7 @@ export { AutoDetectPage } from './auto_detect'; export { CustomLogsPage } from './custom_logs'; export { KubernetesPage } from './kubernetes'; +export { OtelKubernetesPage } from './otel_kubernetes'; export { LandingPage } from './landing'; export { OtelLogsPage } from './otel_logs'; export { SystemLogsPage } from './system_logs'; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/otel_kubernetes.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/otel_kubernetes.tsx new file mode 100644 index 0000000000000..c4fba1fd8ff0e --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/pages/otel_kubernetes.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { OtelKubernetesPanel } from '../quickstart_flows/otel_kubernetes/otel_kubernetes_panel'; +import { PageTemplate } from './template'; +import { CustomHeader } from '../header'; + +export const OtelKubernetesPage = () => ( + + } + > + + +); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/use_kubernetes_flow.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/use_kubernetes_flow.ts index e0a8c7722290f..4e8a54ccd77e7 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/use_kubernetes_flow.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/use_kubernetes_flow.ts @@ -11,7 +11,9 @@ import { OBSERVABILITY_ONBOARDING_FLOW_PROGRESS_TELEMETRY_EVENT } from '../../.. import { ObservabilityOnboardingAppServices } from '../../..'; import { useFetcher } from '../../../hooks/use_fetcher'; -export function useKubernetesFlow() { +export function useKubernetesFlow( + onboardingFlowType: 'kubernetes_otel' | 'kubernetes' = 'kubernetes' +) { const { services: { analytics, @@ -20,21 +22,27 @@ export function useKubernetesFlow() { } = useKibana(); const { data, status, error, refetch } = useFetcher( (callApi) => { - return callApi('POST /internal/observability_onboarding/kubernetes/flow'); + return callApi('POST /internal/observability_onboarding/kubernetes/flow', { + params: { + body: { + pkgName: onboardingFlowType, + }, + }, + }); }, - [], + [onboardingFlowType], { showToastOnError: false } ); useEffect(() => { if (data?.onboardingId !== undefined) { analytics?.reportEvent(OBSERVABILITY_ONBOARDING_FLOW_PROGRESS_TELEMETRY_EVENT.eventType, { - onboardingFlowType: 'kubernetes', + onboardingFlowType, onboardingId: data?.onboardingId, step: 'in_progress', }); } - }, [analytics, cloudServiceProvider, data?.onboardingId]); + }, [onboardingFlowType, analytics, cloudServiceProvider, data?.onboardingId]); return { data, status, error, refetch } as const; } diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_kubernetes/index.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_kubernetes/index.tsx new file mode 100644 index 0000000000000..596a035d4b4d1 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_kubernetes/index.tsx @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { OtelKubernetesPanel } from './otel_kubernetes_panel'; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_kubernetes/otel_kubernetes_panel.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_kubernetes/otel_kubernetes_panel.tsx new file mode 100644 index 0000000000000..c745793c47b3a --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_kubernetes/otel_kubernetes_panel.tsx @@ -0,0 +1,331 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { + EuiPanel, + EuiSkeletonText, + EuiSpacer, + EuiSteps, + EuiButtonGroup, + EuiIconTip, + EuiCodeBlock, + EuiLink, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; +import { EmptyPrompt } from '../shared/empty_prompt'; +import { GetStartedPanel } from '../shared/get_started_panel'; +import { FeedbackButtons } from '../shared/feedback_buttons'; +import { CopyToClipboardButton } from '../shared/copy_to_clipboard_button'; +import { ObservabilityOnboardingContextValue } from '../../../plugin'; +import { useKubernetesFlow } from '../kubernetes/use_kubernetes_flow'; + +const CLUSTER_OVERVIEW_DASHBOARD_ID = 'kubernetes_otel-cluster-overview'; + +export const OtelKubernetesPanel: React.FC = () => { + const { data, error, refetch } = useKubernetesFlow('kubernetes_otel'); + const [idSelected, setIdSelected] = useState('nodejs'); + const { + services: { share }, + } = useKibana(); + const apmLocator = share.url.locators.get('APM_LOCATOR'); + const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR); + + if (error) { + return ( + + ); + } + + const namespace = 'opentelemetry-operator-system'; + const valuesFile = + 'https://raw.githubusercontent.com/elastic/opentelemetry/refs/heads/main/resources/kubernetes/operator/helm/values.yaml'; + + const addRepoCommand = `helm repo add open-telemetry 'https://open-telemetry.github.io/opentelemetry-helm-charts' --force-update`; + const installStackCommand = data + ? `kubectl create namespace ${namespace} +kubectl create secret generic elastic-secret-otel \\ + --namespace ${namespace} \\ + --from-literal=elastic_endpoint='${data.elasticsearchUrl}' \\ + --from-literal=elastic_api_key='${data.apiKeyEncoded}' +helm install opentelemetry-kube-stack open-telemetry/opentelemetry-kube-stack \\ + --namespace ${namespace} \\ + --create-namespace \\ + --values '${valuesFile}'` + : undefined; + + return ( + + + + {addRepoCommand} + + + + + ), + }, + { + title: i18n.translate( + 'xpack.observability_onboarding.otelKubernetesPanel.installStackStepTitle', + { + defaultMessage: 'Install the OpenTelemetry Operator', + } + ), + children: installStackCommand ? ( + <> +

+ + {i18n.translate( + 'xpack.observability_onboarding.otelKubernetesPanel.certmanagerLinkLabel', + { defaultMessage: 'cert-manager' } + )} + + ), + }} + />{' '} + +

+ + + {installStackCommand} + + + + + + + + + {i18n.translate( + 'xpack.observability_onboarding.otelKubernetesPanel.downloadValuesFileButtonEmptyLabel', + { defaultMessage: 'Download values file' } + )} + + + + + ) : ( + + ), + }, + { + title: i18n.translate( + 'xpack.observability_onboarding.otelKubernetesPanel.instrumentApplicationStepTitle', + { + defaultMessage: 'Instrument your application (optional)', + } + ), + children: ( + <> +

+ {i18n.translate( + 'xpack.observability_onboarding.otelKubernetesPanel.theOperatorAutomatesTheLabel', + { + defaultMessage: + 'The Operator automates the injection of auto-instrumentation libraries into the annotated pods for some languages.', + } + )} +

+ + setIdSelected(optionId)} + options={[ + { + id: 'nodejs', + label: 'Node.js', + }, + { + id: 'java', + label: 'Java', + }, + { + id: 'python', + label: 'Python', + }, + { + id: 'dotnet', + label: '.NET', + }, + { + id: 'go', + label: 'Go', + }, + ]} + /> + + + {`apiVersion: v1 +kind: Pod +metadata: + name: my-app + annotations: + instrumentation.opentelemetry.io/inject-${idSelected}: "true" +spec: + containers: + - name: my-app + image: my-app:latest`} + + + + +

+ + {i18n.translate( + 'xpack.observability_onboarding.otelKubernetesPanel.referToTheDocumentationLinkLabel', + { defaultMessage: 'refer to the documentation' } + )} + + ), + }} + /> +

+ + ), + }, + { + title: i18n.translate( + 'xpack.observability_onboarding.otelKubernetesPanel.monitorStepTitle', + { + defaultMessage: 'Visualize your data', + } + ), + children: data ? ( + <> +

+ {i18n.translate( + 'xpack.observability_onboarding.otelKubernetesPanel.onceYourKubernetesInfrastructureLabel', + { + defaultMessage: + 'Analyse your Kubernetes cluster’s health and monitor your container workloads.', + } + )} +

+ + + + ) : ( + + ), + }, + ]} + /> + +
+ ); +}; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/empty_prompt.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/empty_prompt.tsx index b5b427a718d67..771948f062fcf 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/empty_prompt.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/empty_prompt.tsx @@ -35,7 +35,7 @@ export const EmptyPrompt: FunctionComponent = ({ useEffect(() => { analytics?.reportEvent(OBSERVABILITY_ONBOARDING_FLOW_ERROR_TELEMETRY_EVENT.eventType, { onboardingFlowType, - error, + error: error.body?.message ?? error.message, context: telemetryEventContext, }); }, [analytics, error, onboardingFlowType, telemetryEventContext]); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx index 98fb6c74a37de..e529a0782e395 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx @@ -37,7 +37,7 @@ export function GetStartedPanel({ }: { onboardingFlowType: string; dataset: string; - integration: string; + integration?: string; newTab: boolean; actionLinks: Array<{ id: string; @@ -88,7 +88,7 @@ export function GetStartedPanel({ - + {actionLinks.map(({ id, title, label, href }) => ( @@ -110,30 +110,33 @@ export function GetStartedPanel({ - - - - - {i18n.translate( - 'xpack.observability_onboarding.dataIngestStatus.viewAllAssetsLinkText', - { - defaultMessage: 'View all assets', - } - )} - - ), - }} - /> - + {integration && ( + <> + + + + {i18n.translate( + 'xpack.observability_onboarding.dataIngestStatus.viewAllAssetsLinkText', + { + defaultMessage: 'View all assets', + } + )} + + ), + }} + /> + + + )} ); } diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/kubernetes/route.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/kubernetes/route.ts index 7f63ec61249f5..33a501bd184b9 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/kubernetes/route.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/kubernetes/route.ts @@ -29,10 +29,14 @@ export interface HasKubernetesDataRouteResponse { const createKubernetesOnboardingFlowRoute = createObservabilityOnboardingServerRoute({ endpoint: 'POST /internal/observability_onboarding/kubernetes/flow', + params: t.type({ + body: t.type({ pkgName: t.union([t.literal('kubernetes'), t.literal('kubernetes_otel')]) }), + }), options: { tags: [] }, async handler({ context, request, + params, plugins, services, kibanaVersion, @@ -55,8 +59,14 @@ const createKubernetesOnboardingFlowRoute = createObservabilityOnboardingServerR const [{ encoded: apiKeyEncoded }, elasticAgentVersion] = await Promise.all([ createShipperApiKey(client.asCurrentUser, 'kubernetes_onboarding'), getAgentVersion(fleetPluginStart, kibanaVersion), - packageClient.ensureInstalledPackage({ pkgName: 'kubernetes' }), + // System package is always required packageClient.ensureInstalledPackage({ pkgName: 'system' }), + // Kubernetes package is required for both classic kubernetes and otel + packageClient.ensureInstalledPackage({ pkgName: 'kubernetes' }), + // Kubernetes otel package is required only for otel + params.body.pkgName === 'kubernetes_otel' + ? packageClient.ensureInstalledPackage({ pkgName: 'kubernetes_otel' }) + : undefined, ]); const elasticsearchUrlList = plugins.cloud?.setup?.elasticsearchUrl From 2d6874981ec036dd992c2481a13228aed5bd68a2 Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Tue, 8 Oct 2024 14:25:23 -0400 Subject: [PATCH 015/110] Fixing flaky backfill tests (#194328) Resolves https://github.com/elastic/kibana/issues/192144 and https://github.com/elastic/kibana/issues/181862 ## Summary Unskipped the test that was skipped in https://github.com/elastic/kibana/issues/181862 but it did not fail at all during the 2400 times total I ran the flaky test runner so I'm going to unskip and see if it comes back ever While running the flaky test runner, I saw this test from https://github.com/elastic/kibana/issues/192144 be flaky so I addressed in this PR. This was caused by the query for the alert documents sometimes not returning the alert docs in timestamp order, which is important because I'm trying to compare the actual alert timestamp to the expected alert timestamp (in order). Added a sort order to the alert query. --------- Co-authored-by: Elastic Machine --- .../group1/tests/alerting/backfill/find.ts | 3 +- .../tests/alerting/backfill/task_runner.ts | 31 ++++++++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/find.ts index 829c6770b67ae..91f10338ac007 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/find.ts @@ -135,8 +135,7 @@ export default function findBackfillTests({ getService }: FtrProviderContext) { for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; - // FLAKY: https://github.com/elastic/kibana/issues/181862 - describe.skip(scenario.id, () => { + describe(scenario.id, () => { const apiOptions = { spaceId: space.id, username: user.username, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/task_runner.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/task_runner.ts index e66121a4c33db..e9fa1724f4bca 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/task_runner.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/task_runner.ts @@ -53,6 +53,7 @@ import { export default function createBackfillTaskRunnerTests({ getService }: FtrProviderContext) { const es = getService('es'); const retry = getService('retry'); + const log = getService('log'); const esTestIndexTool = new ESTestIndexTool(es, retry); const supertestWithoutAuth = getService('supertestWithoutAuth'); const supertest = getService('supertest'); @@ -65,25 +66,25 @@ export default function createBackfillTaskRunnerTests({ getService }: FtrProvide moment().utc().subtract(14, 'days').toISOString(), // backfill execution set 1 - moment().utc().startOf('day').subtract(13, 'days').add(64, 'seconds').toISOString(), - moment().utc().startOf('day').subtract(13, 'days').add(65, 'seconds').toISOString(), - moment().utc().startOf('day').subtract(13, 'days').add(66, 'seconds').toISOString(), + moment().utc().startOf('day').subtract(13, 'days').add(10, 'minutes').toISOString(), + moment().utc().startOf('day').subtract(13, 'days').add(11, 'minutes').toISOString(), + moment().utc().startOf('day').subtract(13, 'days').add(12, 'minutes').toISOString(), // backfill execution set 2 - moment().utc().startOf('day').subtract(12, 'days').add(89, 'seconds').toISOString(), + moment().utc().startOf('day').subtract(12, 'days').add(20, 'minutes').toISOString(), // backfill execution set 3 - moment().utc().startOf('day').subtract(11, 'days').add(785, 'seconds').toISOString(), - moment().utc().startOf('day').subtract(11, 'days').add(888, 'seconds').toISOString(), - moment().utc().startOf('day').subtract(11, 'days').add(954, 'seconds').toISOString(), - moment().utc().startOf('day').subtract(11, 'days').add(1045, 'seconds').toISOString(), - moment().utc().startOf('day').subtract(11, 'days').add(1145, 'seconds').toISOString(), + moment().utc().startOf('day').subtract(11, 'days').add(30, 'minutes').toISOString(), + moment().utc().startOf('day').subtract(11, 'days').add(31, 'minutes').toISOString(), + moment().utc().startOf('day').subtract(11, 'days').add(32, 'minutes').toISOString(), + moment().utc().startOf('day').subtract(11, 'days').add(33, 'minutes').toISOString(), + moment().utc().startOf('day').subtract(11, 'days').add(34, 'minutes').toISOString(), // backfill execution set 4 purposely left empty // after last backfill - moment().utc().startOf('day').subtract(9, 'days').add(666, 'seconds').toISOString(), - moment().utc().startOf('day').subtract(9, 'days').add(667, 'seconds').toISOString(), + moment().utc().startOf('day').subtract(9, 'days').add(40, 'minutes').toISOString(), + moment().utc().startOf('day').subtract(9, 'days').add(41, 'minutes').toISOString(), ]; describe('ad hoc backfill task', () => { @@ -175,6 +176,9 @@ export default function createBackfillTaskRunnerTests({ getService }: FtrProvide .send([{ rule_id: ruleId, start, end }]) .expect(200); + log.info(`originalDocTimestamps ${JSON.stringify(originalDocTimestamps)}`); + log.info(`scheduledBackfill ${JSON.stringify(response2.body)}`); + const scheduleResult = response2.body; expect(scheduleResult.length).to.eql(1); @@ -668,7 +672,10 @@ export default function createBackfillTaskRunnerTests({ getService }: FtrProvide async function queryForAlertDocs(): Promise>> { const searchResult = await es.search({ index: alertsAsDataIndex, - body: { query: { match_all: {} } }, + body: { + sort: [{ [ALERT_ORIGINAL_TIME]: { order: 'asc' } }], + query: { match_all: {} }, + }, }); return searchResult.hits.hits as Array>; } From 407137a6befb38f34cb11f6a3b6a741a27977031 Mon Sep 17 00:00:00 2001 From: Paulo Silva Date: Tue, 8 Oct 2024 11:56:08 -0700 Subject: [PATCH 016/110] [Fleet] add escapeMultilineString Handlebar helper (#195159) ## Summary Adding a handlebar helper to escape multiline strings. It has the same function as `escapeStringHelper`, but does not wrap strings in single quotes, allowing concatenation of escaped variables in the `hbs` template such as this example: ```hbs audit_rules: "{{escape_multiline_string audit_rules}} {{escape_multiline_string " # Session data audit rules -a always,exit -F arch=b64 -S execve,execveat -k exec -a always,exit -F arch=b64 -S exit_group -a always,exit -F arch=b64 -S setsid"}}" {{else}} {{#if audit_rules}} audit_rules: {{escape_string audit_rules}} {{/if}} {{/if}} ``` The above would not be possible using only `escape_string` as `audit_rules` would be wrapped in single quotes. ## Screenshots The example above illustrates how this option allows the Auditd manager integration to append Session data audit rules to the `audit_rules` field when Session data is enabled in the integration ([PR](https://github.com/elastic/integrations/pull/11336)). image image --- .../server/services/epm/agent/agent.test.ts | 74 +++++++++++++++++++ .../fleet/server/services/epm/agent/agent.ts | 12 +++ 2 files changed, 86 insertions(+) diff --git a/x-pack/plugins/fleet/server/services/epm/agent/agent.test.ts b/x-pack/plugins/fleet/server/services/epm/agent/agent.test.ts index a3e5749384c0b..7a2a175c4697f 100644 --- a/x-pack/plugins/fleet/server/services/epm/agent/agent.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/agent/agent.test.ts @@ -261,6 +261,80 @@ New lines and \\n escaped values.`, }); }); + describe('escape_multiline_string helper', () => { + it('should escape new lines', () => { + const streamTemplate = ` + input: log + multiline_text: "{{escape_multiline_string multiline_text}}" + `; + + const vars = { + multiline_text: { + type: 'textarea', + value: `This is a text with +New lines and \n escaped values.`, + }, + }; + + const output = compileTemplate(vars, streamTemplate); + expect(output).toEqual({ + input: 'log', + multiline_text: `This is a text with +New lines and +escaped values.`, + }); + }); + + it('should escape single quotes', () => { + const streamTemplate = ` + input: log + multiline_text: "{{escape_multiline_string multiline_text}}" + `; + + const vars = { + multiline_text: { + type: 'textarea', + value: `This is a multiline text with +'escaped values.'`, + }, + }; + + const output = compileTemplate(vars, streamTemplate); + expect(output).toEqual({ + input: 'log', + multiline_text: `This is a multiline text with +''escaped values.''`, + }); + }); + + it('should allow concatenation of multiline strings', () => { + const streamTemplate = ` +input: log +multiline_text: "{{escape_multiline_string multiline_text}}{{escape_multiline_string " +This is a concatenated text +with new lines"}}" + `; + + const vars = { + multiline_text: { + type: 'textarea', + value: `This is a text with +New lines and\nescaped values.`, + }, + }; + + const output = compileTemplate(vars, streamTemplate); + expect(output).toEqual({ + input: 'log', + multiline_text: `This is a text with +New lines and +escaped values. +This is a concatenated text +with new lines`, + }); + }); + }); + describe('to_json helper', () => { const streamTemplate = ` input: log diff --git a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts index 29d6c3c18fc56..8cfa5305413a5 100644 --- a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts +++ b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts @@ -131,6 +131,18 @@ function escapeStringHelper(str: string) { } handlebars.registerHelper('escape_string', escapeStringHelper); +/** + * escapeMultilineStringHelper will escape a multiline string by doubling the newlines + * and escaping single quotes. + * This is useful when the string is multiline and needs to be escaped in a yaml file + * without wrapping it in single quotes. + */ +function escapeMultilineStringHelper(str: string) { + if (!str) return undefined; + return str.replace(/\'/g, "''").replace(/\n/g, '\n\n'); +} +handlebars.registerHelper('escape_multiline_string', escapeMultilineStringHelper); + // toJsonHelper will convert any object to a Json string. function toJsonHelper(value: any) { if (typeof value === 'string') { From 0c5c7124766af7e719bf57fe54497d0084541938 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Tue, 8 Oct 2024 21:17:38 +0200 Subject: [PATCH 017/110] [ftr] print response body for API key creation failure (#195379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary We are currently investigating test failures against ESS deployment: Failed to create API key for user `admin` role ``` [00:00:00] └-> "before all" hook in "Burn rate rule" [00:00:00] │ debg new cloud SAML authentication with 'admin' role [00:00:00] │ debg Requesting url (redacted): [https://bk-stateful-ftr-16-2c9ee40b2d03.kb.eu-west-1.aws.qa.cld.elstc.co/api/status] [00:00:00] │ info Reading cloud user credentials from /root/.qaf/data/git/kibana/.ftr/role_users.json [00:00:04] └- ✖ fail: apis Slo - Burn rate rule Burn rate rule "before all" hook in "Burn rate rule" [00:00:04] │ Error: expected 400 to equal 200 [00:00:04] │ at Assertion.assert (expect.js:100:11) [00:00:04] │ at Assertion.apply (expect.js:227:8) [00:00:04] │ at Assertion.be (expect.js:69:22) [00:00:04] │ at Object.createM2mApiKeyWithRoleScope (saml_auth_provider.ts:113:25) [00:00:04] │ at processTicksAndRejections (node:internal/process/task_queues:95:5) [00:00:04] │ at Context. (burn_rate_rule.ts:40:24) [00:00:04] │ at Object.apply (wrap_function.js:74:16) ``` Currently we get only status code and it doesn't tell much about the issue. This PR will print response body + status code --- .../services/saml_auth/saml_auth_provider.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/kbn-ftr-common-functional-services/services/saml_auth/saml_auth_provider.ts b/packages/kbn-ftr-common-functional-services/services/saml_auth/saml_auth_provider.ts index 67d77583af713..1ee239ac5448e 100644 --- a/packages/kbn-ftr-common-functional-services/services/saml_auth/saml_auth_provider.ts +++ b/packages/kbn-ftr-common-functional-services/services/saml_auth/saml_auth_provider.ts @@ -101,7 +101,7 @@ export function SamlAuthProvider({ getService }: FtrProviderContext) { }; } - const { body, status } = await supertestWithoutAuth + const response = await supertestWithoutAuth .post('/internal/security/api_key') .set(INTERNAL_REQUEST_HEADERS) .set(adminCookieHeader) @@ -110,9 +110,14 @@ export function SamlAuthProvider({ getService }: FtrProviderContext) { metadata: {}, role_descriptors: roleDescriptors, }); - expect(status).to.be(200); - const apiKey = body; + if (response.status !== 200) { + throw new Error( + `Failed to create API key for '${role}' role with response text: ${response.text}` + ); + } + + const apiKey = response.body; const apiKeyHeader = { Authorization: 'ApiKey ' + apiKey.encoded }; log.debug(`Created api key for role: [${role}]`); From 187afe78ce7b047026b3d9dd6e98a67fe92a3047 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 8 Oct 2024 20:21:09 +0100 Subject: [PATCH 018/110] skip flaky suite (#170370) --- .../response_actions/response_console/process_operations.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts index e09aa8dc9fc85..9484122c013d7 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts @@ -26,7 +26,8 @@ import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_ const AGENT_BEAT_FILE_PATH_SUFFIX = '/components/agentbeat'; -describe('Response console', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/170370 +describe.skip('Response console', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { beforeEach(() => { login(); }); From 31f4f2c9842f3f6713e004be22087379e9ccf3e7 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Tue, 8 Oct 2024 21:23:12 +0200 Subject: [PATCH 019/110] [deps] Replace compare-versions with semver (#195287) ## Summary We are reducing the number of dependencies by replacing the `compare-versions` library with the already used `semver` library that offer the same functionality. --- package.json | 1 - packages/kbn-sort-predicates/src/sorting.ts | 7 +++++-- .../vis_types/vega/public/data_model/vega_parser.ts | 8 ++++++-- .../public/pages/rules/rules_container.tsx | 7 +++++-- yarn.lock | 5 ----- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 1b4a27b012a60..cd72443e90172 100644 --- a/package.json +++ b/package.json @@ -1075,7 +1075,6 @@ "classnames": "2.2.6", "color": "^4.2.3", "commander": "^4.1.1", - "compare-versions": "3.5.1", "constate": "^3.3.2", "copy-to-clipboard": "^3.0.8", "core-js": "^3.37.1", diff --git a/packages/kbn-sort-predicates/src/sorting.ts b/packages/kbn-sort-predicates/src/sorting.ts index d56ca8f550c80..8adfc237bc7f5 100644 --- a/packages/kbn-sort-predicates/src/sorting.ts +++ b/packages/kbn-sort-predicates/src/sorting.ts @@ -7,8 +7,9 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import versionCompare from 'compare-versions'; import valid from 'semver/functions/valid'; +import semVerCompare from 'semver/functions/compare'; +import semVerCoerce from 'semver/functions/coerce'; import ipaddr, { type IPv4, type IPv6 } from 'ipaddr.js'; import { FieldFormat } from '@kbn/field-formats-plugin/common'; import moment from 'moment'; @@ -154,7 +155,9 @@ const versionComparison: CompareFn = (v1, v2, direction) => { if (bInvalid) { return direction * -1; } - return versionCompare(valueA, valueB); + const semVerValueA = semVerCoerce(valueA) ?? ''; + const semVerValueB = semVerCoerce(valueB) ?? ''; + return semVerCompare(semVerValueA, semVerValueB); }; const openRange = { gte: -Infinity, lt: Infinity }; diff --git a/src/plugins/vis_types/vega/public/data_model/vega_parser.ts b/src/plugins/vis_types/vega/public/data_model/vega_parser.ts index d41ec9759373c..0a0d0ec4151ae 100644 --- a/src/plugins/vis_types/vega/public/data_model/vega_parser.ts +++ b/src/plugins/vis_types/vega/public/data_model/vega_parser.ts @@ -9,7 +9,8 @@ import _ from 'lodash'; import schemaParser from 'vega-schema-url-parser'; -import versionCompare from 'compare-versions'; +import semVerCompare from 'semver/functions/compare'; +import semVerCoerce from 'semver/functions/coerce'; import hjson from 'hjson'; import { euiPaletteColorBlind } from '@elastic/eui'; import { euiThemeVars } from '@kbn/ui-theme'; @@ -17,6 +18,7 @@ import { i18n } from '@kbn/i18n'; import { logger, Warn, None, version as vegaVersion } from 'vega'; import { compile, TopLevelSpec, version as vegaLiteVersion } from 'vega-lite'; + import { EsQueryParser } from './es_query_parser'; import { Utils } from './utils'; import { EmsFileParser } from './ems_file_parser'; @@ -558,8 +560,10 @@ The URL is an identifier only. Kibana and your browser will never access this UR const schema = schemaParser(spec.$schema); const isVegaLite = schema.library === 'vega-lite'; const libVersion = isVegaLite ? vegaLiteVersion : vegaVersion; + const schemaSemVer = semVerCoerce(schema.version) ?? ''; + const libSemVersion = semVerCoerce(libVersion) ?? ''; - if (versionCompare(schema.version, libVersion) > 0) { + if (semVerCompare(schemaSemVer, libSemVersion) > 0) { this._onWarning( i18n.translate( 'visTypeVega.vegaParser.notValidLibraryVersionForInputSpecWarningMessage', diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx index 1b1af9aab4292..8eaec34adf1cf 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx @@ -5,7 +5,6 @@ * 2.0. */ import React, { useState, useMemo, useEffect } from 'react'; -import compareVersions from 'compare-versions'; import { EuiSpacer } from '@elastic/eui'; import { useParams, useHistory, generatePath } from 'react-router-dom'; import type { @@ -14,6 +13,8 @@ import type { RuleStateAttributes, } from '@kbn/cloud-security-posture-common/schema/rules/latest'; import { extractErrorMessage } from '@kbn/cloud-security-posture-common'; +import semVerCompare from 'semver/functions/compare'; +import semVerCoerce from 'semver/functions/coerce'; import { benchmarksNavigation } from '../../common/navigation/constants'; import { buildRuleKey } from '../../../common/utils/rules_states'; import { RulesTable } from './rules_table'; @@ -197,7 +198,9 @@ export const RulesContainer = () => { return a.localeCompare(b, 'en', { sensitivity: 'base' }); }); - const cleanedRuleNumberList = [...new Set(ruleNumberList)].sort(compareVersions); + const cleanedRuleNumberList = [...new Set(ruleNumberList)].sort((a, b) => + semVerCompare(semVerCoerce(a) ?? '', semVerCoerce(b) ?? '') + ); const rulesPageData = useMemo( () => getRulesPageData(filteredRulesWithStates, status, error, rulesQuery), diff --git a/yarn.lock b/yarn.lock index 465601b23df34..1c831df8f53e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14706,11 +14706,6 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -compare-versions@3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.5.1.tgz#26e1f5cf0d48a77eced5046b9f67b6b61075a393" - integrity sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg== - compare-versions@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" From 4ad15861489904aae1b8a0bb3d35bf3fca6eb729 Mon Sep 17 00:00:00 2001 From: Tre Date: Tue, 8 Oct 2024 20:23:33 +0100 Subject: [PATCH 020/110] [Ownership] Fixup wrong assignment (#195462) ## Summary Fixup line broken by this [merge](https://github.com/elastic/kibana/pull/195272). Contributes to: https://github.com/elastic/kibana/issues/194815 --- .github/CODEOWNERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d4c8f52704e96..a20e12d88c352 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1013,6 +1013,8 @@ packages/kbn-zod-helpers @elastic/security-detection-rule-management # The #CC# prefix delineates Code Coverage, # used for the 'team' designator within Kibana Stats +x-pack/test_serverless/api_integration/test_suites/common/platform_security @elastic/kibana-security + # Data Discovery /x-pack/test_serverless/functional/es_archives/pre_calculated_histogram @elastic/kibana-data-discovery /x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern @elastic/kibana-data-discovery @@ -1511,7 +1513,6 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints /x-pack/test/functional/es_archives/auditbeat/default @elastic/security-solution /x-pack/test/functional/es_archives/auditbeat/hosts @elastic/security-solution /x-pack/test_serverless/functional/page_objects/svl_management_page.ts @elastic/security-solution -/x-pack/test_serverless/api_integration/test_suites/common/platform_security/ @elastic/security-solution /x-pack/test_serverless/api_integration/test_suites/security @elastic/security-solution /x-pack/test_serverless/functional/page_objects/svl_sec_landing_page.ts @elastic/security-solution From e98fa183aaa050999b524425b7dd1479d64c9426 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 8 Oct 2024 20:27:10 +0100 Subject: [PATCH 021/110] skip flaky suite (#193294) --- .../test_suites/observability/onboarding/firehose.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test_serverless/functional/test_suites/observability/onboarding/firehose.ts b/x-pack/test_serverless/functional/test_suites/observability/onboarding/firehose.ts index 22c700d16be2d..c2d2161c7491a 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/onboarding/firehose.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/onboarding/firehose.ts @@ -20,7 +20,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const synthtrace = getService('svlLogsSynthtraceClient'); - describe('Onboarding Firehose Quickstart Flow', () => { + // FLAKY: https://github.com/elastic/kibana/issues/193294 + describe.skip('Onboarding Firehose Quickstart Flow', () => { before(async () => { await PageObjects.svlCommonPage.loginAsAdmin(); // Onboarding requires admin role await PageObjects.common.navigateToUrlWithBrowserHistory( From 13c949462931960a4ca5eb82f9dbe955893d426b Mon Sep 17 00:00:00 2001 From: "elastic-renovate-prod[bot]" <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:44:39 +0200 Subject: [PATCH 022/110] Update dependency re2js to v0.4.2 (main) (#193897) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cd72443e90172..02b7f61924abb 100644 --- a/package.json +++ b/package.json @@ -1199,7 +1199,7 @@ "query-string": "^6.13.2", "rbush": "^3.0.1", "re-resizable": "^6.9.9", - "re2js": "0.4.1", + "re2js": "0.4.2", "react": "^17.0.2", "react-ace": "^7.0.5", "react-diff-view": "^3.2.1", diff --git a/yarn.lock b/yarn.lock index 1c831df8f53e8..c3ec4698df7d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26595,10 +26595,10 @@ re-resizable@^6.9.9: resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216" integrity sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA== -re2js@0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/re2js/-/re2js-0.4.1.tgz#74a87a90b79ab5dc1effed818151354c8faccb3d" - integrity sha512-Kxb+OKXrEPowP4bXAF07NDXtgYX07S8HeVGgadx5/D/R41LzWg1kgTD2szIv2iHJM3vrAPnDKaBzfUE/7QWX9w== +re2js@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/re2js/-/re2js-0.4.2.tgz#e344697e64d128ea65c121d6581e67ee5bfa5feb" + integrity sha512-wuv0p0BGbrVIkobV8zh82WjDurXko0QNCgaif6DdRAljgVm2iio4PVYCwjAxGaWen1/QZXWDM67dIslmz7AIbA== react-ace@^7.0.5: version "7.0.5" From 942a1f1e693c5ff86cbcbd93d65bde0915fed274 Mon Sep 17 00:00:00 2001 From: Mario Duarte Date: Tue, 8 Oct 2024 21:57:54 +0200 Subject: [PATCH 023/110] CP-7782 - Replace E2E pipeline execution with serverless-quality-gates CHECK_SYNTHETICS (#195214) --- .../emergency/pipeline.tests-production.yaml | 12 +++++++----- .../quality-gates/emergency/pipeline.tests-qa.yaml | 12 +++++++----- .../emergency/pipeline.tests-staging.yaml | 12 +++++++----- .../quality-gates/pipeline.tests-production.yaml | 12 +++++++----- .../pipelines/quality-gates/pipeline.tests-qa.yaml | 12 +++++++----- .../quality-gates/pipeline.tests-staging.yaml | 12 +++++++----- 6 files changed, 42 insertions(+), 30 deletions(-) diff --git a/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-production.yaml b/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-production.yaml index f7689ffeab928..c81208c7cf61c 100644 --- a/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-production.yaml +++ b/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-production.yaml @@ -16,14 +16,16 @@ steps: DEPLOYMENT_SLICES: ${DEPLOYMENT_SLICES:-""} soft_fail: true - - label: ":rocket: control-plane e2e tests" + - label: ":rocket: Run serverless synthetics check" if: build.env("ENVIRONMENT") == "production-canary" - trigger: "ess-k8s-production-e2e-tests" # https://buildkite.com/elastic/ess-k8s-production-e2e-tests + trigger: "serverless-quality-gates" build: - env: - REGION_ID: aws-us-east-1 - NAME_PREFIX: ci_test_kibana-promotion_ message: "${BUILDKITE_MESSAGE} (triggered by pipeline.tests-production.yaml)" + env: + TARGET_ENV: production + SERVICE: kibana + CHECK_SYNTHETICS: true + CHECK_SYNTHETICS_TAG: serverless-platform-core-validation - label: ":cookie: 24h bake time before continuing promotion" if: build.env("ENVIRONMENT") == "production-canary" diff --git a/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-qa.yaml b/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-qa.yaml index 1c0e69ef7a7b4..3c2f123914c3d 100644 --- a/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-qa.yaml +++ b/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-qa.yaml @@ -3,10 +3,12 @@ # A failure in this pipeline build will prevent further progression to the subsequent stage. steps: - - label: ":rocket: control-plane e2e tests" - trigger: "ess-k8s-qa-e2e-tests-daily" # https://buildkite.com/elastic/ess-k8s-qa-e2e-tests-daily + - label: ":rocket: Run serverless synthetics check" + trigger: "serverless-quality-gates" build: - env: - REGION_ID: aws-eu-west-1 - NAME_PREFIX: ci_test_kibana-promotion_ message: "${BUILDKITE_MESSAGE} (triggered by pipeline.tests-qa.yaml)" + env: + TARGET_ENV: qa + SERVICE: kibana + CHECK_SYNTHETICS: true + CHECK_SYNTHETICS_TAG: serverless-platform-core-validation \ No newline at end of file diff --git a/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-staging.yaml b/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-staging.yaml index 2bd85e2ad8a74..5c2da1b4fe891 100644 --- a/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-staging.yaml +++ b/.buildkite/pipelines/quality-gates/emergency/pipeline.tests-staging.yaml @@ -3,13 +3,15 @@ # A failure in this pipeline build will prevent further progression to the subsequent stage. steps: - - label: ":rocket: control-plane e2e tests" - trigger: "ess-k8s-staging-e2e-tests" # https://buildkite.com/elastic/ess-k8s-staging-e2e-tests + - label: ":rocket: Run serverless synthetics check" + trigger: "serverless-quality-gates" build: - env: - REGION_ID: aws-us-east-1 - NAME_PREFIX: ci_test_kibana-promotion_ message: "${BUILDKITE_MESSAGE} (triggered by pipeline.tests-staging.yaml)" + env: + TARGET_ENV: staging + SERVICE: kibana + CHECK_SYNTHETICS: true + CHECK_SYNTHETICS_TAG: serverless-platform-core-validation - label: ":kibana: Kibana Serverless Tests for ${ENVIRONMENT}" trigger: appex-qa-serverless-kibana-ftr-tests # https://buildkite.com/elastic/appex-qa-serverless-kibana-ftr-tests diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml index f7689ffeab928..c81208c7cf61c 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml @@ -16,14 +16,16 @@ steps: DEPLOYMENT_SLICES: ${DEPLOYMENT_SLICES:-""} soft_fail: true - - label: ":rocket: control-plane e2e tests" + - label: ":rocket: Run serverless synthetics check" if: build.env("ENVIRONMENT") == "production-canary" - trigger: "ess-k8s-production-e2e-tests" # https://buildkite.com/elastic/ess-k8s-production-e2e-tests + trigger: "serverless-quality-gates" build: - env: - REGION_ID: aws-us-east-1 - NAME_PREFIX: ci_test_kibana-promotion_ message: "${BUILDKITE_MESSAGE} (triggered by pipeline.tests-production.yaml)" + env: + TARGET_ENV: production + SERVICE: kibana + CHECK_SYNTHETICS: true + CHECK_SYNTHETICS_TAG: serverless-platform-core-validation - label: ":cookie: 24h bake time before continuing promotion" if: build.env("ENVIRONMENT") == "production-canary" diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml index 3d9363279507f..6730ad5c5840d 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml @@ -29,13 +29,15 @@ steps: ENVIRONMENT: ${ENVIRONMENT} message: "${BUILDKITE_MESSAGE} (triggered by pipeline.tests-qa.yaml)" - - label: ":rocket: control-plane e2e tests" - trigger: "ess-k8s-qa-e2e-tests-daily" # https://buildkite.com/elastic/ess-k8s-qa-e2e-tests-daily + - label: ":rocket: Run serverless synthetics check" + trigger: "serverless-quality-gates" build: - env: - REGION_ID: aws-eu-west-1 - NAME_PREFIX: ci_test_kibana-promotion_ message: "${BUILDKITE_MESSAGE} (triggered by pipeline.tests-qa.yaml)" + env: + TARGET_ENV: qa + SERVICE: kibana + CHECK_SYNTHETICS: true + CHECK_SYNTHETICS_TAG: serverless-platform-core-validation - wait: ~ diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml index 2bd85e2ad8a74..5c2da1b4fe891 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml @@ -3,13 +3,15 @@ # A failure in this pipeline build will prevent further progression to the subsequent stage. steps: - - label: ":rocket: control-plane e2e tests" - trigger: "ess-k8s-staging-e2e-tests" # https://buildkite.com/elastic/ess-k8s-staging-e2e-tests + - label: ":rocket: Run serverless synthetics check" + trigger: "serverless-quality-gates" build: - env: - REGION_ID: aws-us-east-1 - NAME_PREFIX: ci_test_kibana-promotion_ message: "${BUILDKITE_MESSAGE} (triggered by pipeline.tests-staging.yaml)" + env: + TARGET_ENV: staging + SERVICE: kibana + CHECK_SYNTHETICS: true + CHECK_SYNTHETICS_TAG: serverless-platform-core-validation - label: ":kibana: Kibana Serverless Tests for ${ENVIRONMENT}" trigger: appex-qa-serverless-kibana-ftr-tests # https://buildkite.com/elastic/appex-qa-serverless-kibana-ftr-tests From 91c045d698b2e68afd13f5d4bef9229d8a231abe Mon Sep 17 00:00:00 2001 From: Hannah Mudge Date: Tue, 8 Oct 2024 14:34:01 -0600 Subject: [PATCH 024/110] [Canvas] Cleanup services (#194634) Closes https://github.com/elastic/kibana/issues/194050 ## Summary This PR refactors the Canvas services to no longer use the `PluginServiceProvider` from the `PresentationUtil` plugin. Note that the Canvas storybooks are broken on main (and they have been for who knows how long) and so, while I did make some changes to the storybooks to make them **compile**, I didn't bother to get them fully functional. Note that the Ecommerce workpad is broken - this is not due to this PR, it is a [bug](https://github.com/elastic/kibana/issues/195297) that is present on main. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Catherine Liu --- .../renderers/embeddable/embeddable.tsx | 5 +- x-pack/plugins/canvas/jest.config.js | 1 + .../services/nav_link.ts => jest_setup.ts} | 7 +- x-pack/plugins/canvas/public/application.tsx | 25 +-- .../canvas/public/components/app/index.tsx | 26 ++- .../components/asset_manager/asset_manager.ts | 6 +- .../datasource/datasource_component.js | 11 +- .../datasource/datasource_preview/index.js | 7 +- .../components/element_content/index.tsx | 9 +- .../embeddable_flyout/flyout.component.tsx | 35 ++- .../components/embeddable_flyout/flyout.tsx | 7 +- .../es_data_view_select.component.tsx | 8 +- .../es_data_view_select.tsx | 7 +- .../components/es_field_select/index.tsx | 7 +- .../es_fields_select/es_fields_select.tsx | 7 +- .../public/components/expression/index.tsx | 7 +- .../public/components/function_form/index.tsx | 10 +- .../components/function_form_list/index.js | 4 +- .../public/components/home/home.stories.tsx | 2 +- .../home/hooks/use_clone_workpad.ts | 7 +- .../home/hooks/use_create_from_template.ts | 7 +- .../home/hooks/use_create_workpad.ts | 7 +- .../home/hooks/use_delete_workpad.ts | 83 ++++---- .../home/hooks/use_find_templates.ts | 6 +- .../components/home/hooks/use_find_workpad.ts | 8 +- .../home/hooks/use_import_workpad.ts | 7 +- .../my_workpads/my_workpads.component.tsx | 2 +- .../home/my_workpads/my_workpads.stories.tsx | 2 +- .../home/my_workpads/my_workpads.tsx | 2 +- .../my_workpads/workpad_table.component.tsx | 2 +- .../my_workpads/workpad_table.stories.tsx | 4 +- .../home/my_workpads/workpad_table.tsx | 11 +- .../workpad_table_tools.component.tsx | 2 +- .../workpad_templates.stories.tsx | 2 +- .../public/components/home_app/home_app.tsx | 7 +- .../hooks/workpad/use_download_workpad.ts | 7 +- .../hooks/workpad/use_incoming_embeddable.ts | 8 +- .../saved_elements_modal.tsx | 7 +- .../public/components/workpad/workpad.tsx | 6 +- .../hooks/use_canvas_filters.ts | 6 +- .../editor_menu/editor_menu.tsx | 23 +- .../labs_control/labs_control.tsx | 10 +- .../flyout/hooks/use_download_runtime.ts | 18 +- .../workpad_header/share_menu/share_menu.tsx | 22 +- .../canvas/public/functions/filters.ts | 6 +- x-pack/plugins/canvas/public/lib/assets.ts | 5 +- .../canvas/public/lib/create_handlers.ts | 7 +- .../canvas/public/lib/data_view_helpers.ts | 26 +++ .../public/lib/element_handler_creators.ts | 11 +- .../plugins/canvas/public/lib/fullscreen.js | 7 +- .../canvas/public/lib/template_service.ts | 5 +- x-pack/plugins/canvas/public/plugin.tsx | 27 ++- .../use_fullscreen_presentation_helper.ts | 12 +- .../routes/workpad/hooks/use_workpad.test.tsx | 18 +- .../routes/workpad/hooks/use_workpad.ts | 22 +- .../hooks/use_workpad_persist.test.tsx | 15 +- .../workpad/hooks/use_workpad_persist.ts | 15 +- .../workpad/workpad_presentation_helper.tsx | 9 +- .../services/canvas_custom_element_service.ts | 62 ++++++ ...sions.ts => canvas_expressions_service.ts} | 61 +++--- .../filters.ts => canvas_filters_service.ts} | 30 ++- .../notify.ts => canvas_notify_service.ts} | 22 +- .../public/services/canvas_workpad_service.ts | 200 ++++++++++++++++++ .../canvas/public/services/custom_element.ts | 21 -- .../canvas/public/services/data_views.ts | 14 -- .../canvas/public/services/embeddables.ts | 22 -- .../canvas/public/services/expressions.ts | 8 - .../plugins/canvas/public/services/filters.ts | 8 - .../plugins/canvas/public/services/index.ts | 56 +---- .../public/services/kibana/custom_element.ts | 44 ---- .../public/services/kibana/data_views.ts | 50 ----- .../public/services/kibana/embeddables.ts | 22 -- .../canvas/public/services/kibana/index.ts | 66 ------ .../canvas/public/services/kibana/labs.ts | 23 -- .../canvas/public/services/kibana/nav_link.ts | 28 --- .../canvas/public/services/kibana/platform.ts | 46 ---- .../public/services/kibana/reporting.ts | 45 ---- .../public/services/kibana/ui_actions.ts | 19 -- .../public/services/kibana/visualizations.ts | 21 -- .../canvas/public/services/kibana/workpad.ts | 170 --------------- .../canvas/public/services/kibana_services.ts | 76 +++++++ x-pack/plugins/canvas/public/services/labs.ts | 14 -- .../public/services/legacy/reporting.ts | 42 ---- .../plugins/canvas/public/services/mocks.ts | 125 +++++++++++ .../plugins/canvas/public/services/notify.ts | 15 -- .../canvas/public/services/platform.ts | 37 ---- .../canvas/public/services/reporting.ts | 13 -- .../canvas/public/services/storybook/index.ts | 60 ------ .../public/services/storybook/notify.ts | 22 -- .../public/services/storybook/workpad.ts | 122 ----------- .../public/services/stubs/custom_element.ts | 21 -- .../public/services/stubs/data_views.ts | 26 --- .../public/services/stubs/embeddables.ts | 20 -- .../public/services/stubs/expressions.ts | 41 ---- .../canvas/public/services/stubs/filters.ts | 23 -- .../canvas/public/services/stubs/index.ts | 61 ------ .../canvas/public/services/stubs/labs.ts | 25 --- .../canvas/public/services/stubs/nav_link.ts | 17 -- .../canvas/public/services/stubs/notify.ts | 21 -- .../canvas/public/services/stubs/platform.ts | 39 ---- .../public/services/stubs/reporting.tsx | 17 -- .../public/services/stubs/ui_actions.ts | 17 -- .../public/services/stubs/visualizations.ts | 19 -- .../canvas/public/services/stubs/workpad.ts | 115 ---------- .../canvas/public/services/ui_actions.ts | 12 -- .../canvas/public/services/visualizations.ts | 14 -- .../plugins/canvas/public/services/workpad.ts | 43 ---- .../canvas/public/state/actions/elements.js | 32 ++- .../canvas/public/state/actions/filters.js | 13 ++ .../canvas/public/state/initial_state.js | 7 +- .../canvas/public/state/reducers/elements.js | 16 +- .../public/state/reducers/embeddable.ts | 7 +- .../public/state/reducers/resolved_args.js | 8 +- .../canvas/public/state/reducers/transient.js | 31 ++- .../canvas/public/state/reducers/workpad.js | 52 ++--- .../__snapshots__/app.test.tsx.snap | 2 +- .../shareable_runtime/components/app.test.tsx | 14 +- .../__snapshots__/settings.test.tsx.snap | 20 +- .../footer/settings/settings.test.tsx | 14 +- .../shareable_runtime/test/selectors.ts | 2 +- x-pack/plugins/canvas/storybook/constants.ts | 31 +++ .../decorators/services_decorator.tsx | 14 +- x-pack/plugins/canvas/tsconfig.json | 7 +- 123 files changed, 989 insertions(+), 2018 deletions(-) rename x-pack/plugins/canvas/{public/services/nav_link.ts => jest_setup.ts} (65%) create mode 100644 x-pack/plugins/canvas/public/lib/data_view_helpers.ts create mode 100644 x-pack/plugins/canvas/public/services/canvas_custom_element_service.ts rename x-pack/plugins/canvas/public/services/{kibana/expressions.ts => canvas_expressions_service.ts} (65%) rename x-pack/plugins/canvas/public/services/{kibana/filters.ts => canvas_filters_service.ts} (51%) rename x-pack/plugins/canvas/public/services/{kibana/notify.ts => canvas_notify_service.ts} (71%) create mode 100644 x-pack/plugins/canvas/public/services/canvas_workpad_service.ts delete mode 100644 x-pack/plugins/canvas/public/services/custom_element.ts delete mode 100644 x-pack/plugins/canvas/public/services/data_views.ts delete mode 100644 x-pack/plugins/canvas/public/services/embeddables.ts delete mode 100644 x-pack/plugins/canvas/public/services/expressions.ts delete mode 100644 x-pack/plugins/canvas/public/services/filters.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/custom_element.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/data_views.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/embeddables.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/index.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/labs.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/nav_link.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/platform.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/reporting.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/ui_actions.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/visualizations.ts delete mode 100644 x-pack/plugins/canvas/public/services/kibana/workpad.ts create mode 100644 x-pack/plugins/canvas/public/services/kibana_services.ts delete mode 100644 x-pack/plugins/canvas/public/services/labs.ts delete mode 100644 x-pack/plugins/canvas/public/services/legacy/reporting.ts create mode 100644 x-pack/plugins/canvas/public/services/mocks.ts delete mode 100644 x-pack/plugins/canvas/public/services/notify.ts delete mode 100644 x-pack/plugins/canvas/public/services/platform.ts delete mode 100644 x-pack/plugins/canvas/public/services/reporting.ts delete mode 100644 x-pack/plugins/canvas/public/services/storybook/index.ts delete mode 100644 x-pack/plugins/canvas/public/services/storybook/notify.ts delete mode 100644 x-pack/plugins/canvas/public/services/storybook/workpad.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/custom_element.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/data_views.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/embeddables.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/expressions.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/filters.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/index.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/labs.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/nav_link.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/notify.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/platform.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/reporting.tsx delete mode 100644 x-pack/plugins/canvas/public/services/stubs/ui_actions.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/visualizations.ts delete mode 100644 x-pack/plugins/canvas/public/services/stubs/workpad.ts delete mode 100644 x-pack/plugins/canvas/public/services/ui_actions.ts delete mode 100644 x-pack/plugins/canvas/public/services/visualizations.ts delete mode 100644 x-pack/plugins/canvas/public/services/workpad.ts create mode 100644 x-pack/plugins/canvas/public/state/actions/filters.js diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx index d088988c243fe..a21528fb970fb 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx @@ -19,7 +19,6 @@ import React, { FC } from 'react'; import ReactDOM from 'react-dom'; import { useSearchApi } from '@kbn/presentation-publishing'; import { omit } from 'lodash'; -import { pluginServices } from '../../../public/services'; import { CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib'; import { RendererStrings } from '../../../i18n'; import { @@ -32,6 +31,7 @@ import { EmbeddableExpression } from '../../expression_types/embeddable'; import { StartDeps } from '../../plugin'; import { embeddableInputToExpression } from './embeddable_input_to_expression'; import { useGetAppContext } from './use_get_app_context'; +import { embeddableService } from '../../../public/services/kibana_services'; const { embeddable: strings } = RendererStrings; @@ -132,13 +132,12 @@ export const embeddableRendererFactory = ( help: strings.getHelpDescription(), reuseDomNode: true, render: async (domNode, { input, embeddableType, canvasApi }, handlers) => { - const { embeddables } = pluginServices.getServices(); const uniqueId = handlers.getElementId(); const isByValueEnabled = plugins.presentationUtil.labsService.isProjectEnabled( 'labs:canvas:byValueEmbeddable' ); - if (embeddables.reactEmbeddableRegistryHasKey(embeddableType)) { + if (embeddableService.reactEmbeddableRegistryHasKey(embeddableType)) { /** * Prioritize React embeddables */ diff --git a/x-pack/plugins/canvas/jest.config.js b/x-pack/plugins/canvas/jest.config.js index 2bff284e94ad8..f7a9224795b4a 100644 --- a/x-pack/plugins/canvas/jest.config.js +++ b/x-pack/plugins/canvas/jest.config.js @@ -17,4 +17,5 @@ module.exports = { collectCoverageFrom: [ '/x-pack/plugins/canvas/{canvas_plugin_src,common,i18n,public,server,shareable_runtime}/**/*.{js,ts,tsx}', ], + setupFiles: ['/x-pack/plugins/canvas/jest_setup.ts'], }; diff --git a/x-pack/plugins/canvas/public/services/nav_link.ts b/x-pack/plugins/canvas/jest_setup.ts similarity index 65% rename from x-pack/plugins/canvas/public/services/nav_link.ts rename to x-pack/plugins/canvas/jest_setup.ts index 02c7ca50219a6..d9c0c26ea5a38 100644 --- a/x-pack/plugins/canvas/public/services/nav_link.ts +++ b/x-pack/plugins/canvas/jest_setup.ts @@ -5,6 +5,7 @@ * 2.0. */ -export interface CanvasNavLinkService { - updatePath: (path: string) => void; -} +import { setStubKibanaServices } from './public/services/mocks'; + +// Start the kibana services with stubs +setStubKibanaServices(); diff --git a/x-pack/plugins/canvas/public/application.tsx b/x-pack/plugins/canvas/public/application.tsx index 72440e3e6873c..222b64e4175e9 100644 --- a/x-pack/plugins/canvas/public/application.tsx +++ b/x-pack/plugins/canvas/public/application.tsx @@ -19,7 +19,6 @@ import { AppMountParameters, CoreStart, CoreSetup, AppUpdater } from '@kbn/core/ import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { PluginServices } from '@kbn/presentation-util-plugin/public'; import { CanvasStartDeps, CanvasSetupDeps } from './plugin'; import { App } from './components/app'; @@ -32,12 +31,7 @@ import { init as initStatsReporter } from './lib/ui_metric'; import { CapabilitiesStrings } from '../i18n'; -import { - startLegacyServices, - services, - LegacyServicesProvider, - CanvasPluginServices, -} from './services'; +import { startLegacyServices, services, LegacyServicesProvider } from './services'; import { initFunctions } from './functions'; // @ts-expect-error untyped local import { appUnload } from './state/actions/app'; @@ -56,29 +50,26 @@ export const renderApp = ({ startPlugins, params, canvasStore, - pluginServices, + appUpdater, }: { coreStart: CoreStart; startPlugins: CanvasStartDeps; params: AppMountParameters; canvasStore: Store; - pluginServices: PluginServices; + appUpdater: BehaviorSubject; }) => { const { element } = params; element.classList.add('canvas'); element.classList.add('canvasContainerWrapper'); - const ServicesContextProvider = pluginServices.getContextProvider(); ReactDOM.render( - - - - - - - + + + + + , element diff --git a/x-pack/plugins/canvas/public/components/app/index.tsx b/x-pack/plugins/canvas/public/components/app/index.tsx index e23891ccc9bca..0ae3fcf95e6be 100644 --- a/x-pack/plugins/canvas/public/components/app/index.tsx +++ b/x-pack/plugins/canvas/public/components/app/index.tsx @@ -5,14 +5,17 @@ * 2.0. */ -import React, { FC, useEffect } from 'react'; +import { AppUpdater, ScopedHistory } from '@kbn/core/public'; import PropTypes from 'prop-types'; -import { ScopedHistory } from '@kbn/core/public'; -import { useNavLinkService } from '../../services'; +import React, { FC, useEffect } from 'react'; +import { BehaviorSubject } from 'rxjs'; // @ts-expect-error import { shortcutManager } from '../../lib/shortcut_manager'; import { CanvasRouter } from '../../routes'; import { Flyouts } from '../flyouts'; +import { getSessionStorage } from '../../lib/storage'; +import { SESSIONSTORAGE_LASTPATH } from '../../../common/lib'; +import { coreServices } from '../../services/kibana_services'; class ShortcutManagerContextWrapper extends React.Component> { static childContextTypes = { @@ -28,12 +31,21 @@ class ShortcutManagerContextWrapper extends React.Component = ({ history }) => { - const { updatePath } = useNavLinkService(); - +export const App: FC<{ history: ScopedHistory; appUpdater: BehaviorSubject }> = ({ + history, + appUpdater, +}) => { useEffect(() => { return history.listen(({ pathname, search }) => { - updatePath(pathname + search); + const path = pathname + search; + appUpdater.next(() => ({ + defaultPath: path, + })); + + getSessionStorage().set( + `${SESSIONSTORAGE_LASTPATH}:${coreServices.http.basePath.get()}`, + path + ); }); }); diff --git a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.ts b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.ts index b46c9f07f7caa..582c5174b663f 100644 --- a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.ts +++ b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.ts @@ -20,7 +20,7 @@ import { State, AssetType, CanvasWorkpad } from '../../../types'; import { AssetManager as Component } from './asset_manager.component'; import { getFullWorkpadPersisted } from '../../state/selectors/workpad'; -import { pluginServices } from '../../services'; +import { getCanvasWorkpadService } from '../../services/canvas_workpad_service'; export const AssetManager = connect( (state: State) => ({ @@ -31,7 +31,7 @@ export const AssetManager = connect( onAddAsset: (workpad: CanvasWorkpad, type: AssetType['type'], content: AssetType['value']) => { // make the ID here and pass it into the action const asset = createAsset(type, content); - const { notify, workpad: workpadService } = pluginServices.getServices(); + const workpadService = getCanvasWorkpadService(); return workpadService .updateAssets(workpad.id, { ...workpad.assets, [asset.id]: asset }) @@ -40,7 +40,7 @@ export const AssetManager = connect( // then return the id, so the caller knows the id that will be created return asset.id; }) - .catch((error) => notifyError(error, notify.error)); + .catch((error) => notifyError(error)); }, }), (stateProps, dispatchProps, ownProps) => { diff --git a/x-pack/plugins/canvas/public/components/datasource/datasource_component.js b/x-pack/plugins/canvas/public/components/datasource/datasource_component.js index 4b64149d2a8f6..0d61015536294 100644 --- a/x-pack/plugins/canvas/public/components/datasource/datasource_component.js +++ b/x-pack/plugins/canvas/public/components/datasource/datasource_component.js @@ -20,7 +20,7 @@ import { import { isEqual } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { pluginServices } from '../../services'; +import { dataViewsService } from '../../services/kibana_services'; import { DatasourceSelector } from './datasource_selector'; import { DatasourcePreview } from './datasource_preview'; @@ -67,12 +67,9 @@ export class DatasourceComponent extends PureComponent { state = { defaultIndex: '' }; componentDidMount() { - pluginServices - .getServices() - .dataViews.getDefaultDataView() - .then((defaultDataView) => { - this.setState({ defaultIndex: defaultDataView.title }); - }); + dataViewsService.getDefaultDataView().then((defaultDataView) => { + this.setState({ defaultIndex: defaultDataView.title }); + }); } componentDidUpdate(prevProps) { diff --git a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/index.js b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/index.js index 1ca674bfb6f9d..f6f535058ea21 100644 --- a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/index.js +++ b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/index.js @@ -8,18 +8,17 @@ import React, { useState, useEffect } from 'react'; import { PropTypes } from 'prop-types'; import { Loading } from '../../loading'; -import { useExpressionsService } from '../../../services'; +import { getCanvasExpressionService } from '../../../services/canvas_expressions_service'; import { DatasourcePreview as Component } from './datasource_preview'; export const DatasourcePreview = (props) => { const [datatable, setDatatable] = useState(); - const expressionsService = useExpressionsService(); useEffect(() => { - expressionsService + getCanvasExpressionService() .interpretAst({ type: 'expression', chain: [props.function] }, {}) .then(setDatatable); - }, [expressionsService, props.function, setDatatable]); + }, [props.function, setDatatable]); if (!datatable) { return ; diff --git a/x-pack/plugins/canvas/public/components/element_content/index.tsx b/x-pack/plugins/canvas/public/components/element_content/index.tsx index bdbfc205d4c81..72ff04cbf2055 100644 --- a/x-pack/plugins/canvas/public/components/element_content/index.tsx +++ b/x-pack/plugins/canvas/public/components/element_content/index.tsx @@ -5,23 +5,24 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { getSelectedPage, getPageById } from '../../state/selectors/workpad'; -import { useExpressionsService } from '../../services'; import { ElementContent as Component, Props as ComponentProps } from './element_content'; import { State } from '../../../types'; +import { getCanvasExpressionService } from '../../services/canvas_expressions_service'; export type Props = Omit; export const ElementContent = (props: Props) => { - const expressionsService = useExpressionsService(); const selectedPageId = useSelector(getSelectedPage); const backgroundColor = useSelector((state: State) => getPageById(state, selectedPageId)?.style.background) || ''; const { renderable } = props; - const renderFunction = renderable ? expressionsService.getRenderer(renderable.as) : null; + const renderFunction = useMemo(() => { + return renderable ? getCanvasExpressionService().getRenderer(renderable.as) : null; + }, [renderable]); return ; }; diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx index 9adde7ab57718..fbb7b971bfcb4 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx @@ -5,14 +5,18 @@ * 2.0. */ -import React, { FC, useCallback, useMemo } from 'react'; -import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody, EuiTitle } from '@elastic/eui'; +import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import React, { FC, useCallback, useMemo } from 'react'; -import { SavedObjectFinder, SavedObjectMetaData } from '@kbn/saved-objects-finder-plugin/public'; -import { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common'; import { EmbeddableFactory, ReactEmbeddableSavedObject } from '@kbn/embeddable-plugin/public'; -import { useEmbeddablesService, usePlatformService } from '../../services'; +import { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common'; +import { SavedObjectFinder, SavedObjectMetaData } from '@kbn/saved-objects-finder-plugin/public'; +import { + contentManagementService, + coreServices, + embeddableService, +} from '../../services/kibana_services'; const strings = { getNoItemsText: () => @@ -45,13 +49,8 @@ export const AddEmbeddableFlyout: FC = ({ onClose, isByValueEnabled, }) => { - const embeddablesService = useEmbeddablesService(); - const platformService = usePlatformService(); - const { getEmbeddableFactories, getReactEmbeddableSavedObjects } = embeddablesService; - const { getContentManagement, getUISettings } = platformService; - const legacyFactoriesBySavedObjectType: LegacyFactoryMap = useMemo(() => { - return [...getEmbeddableFactories()] + return [...embeddableService.getEmbeddableFactories()] .filter( (embeddableFactory) => Boolean(embeddableFactory.savedObjectMetaData?.type) && !embeddableFactory.isContainerType @@ -60,10 +59,10 @@ export const AddEmbeddableFlyout: FC = ({ acc[factory.savedObjectMetaData!.type] = factory; return acc; }, {} as LegacyFactoryMap); - }, [getEmbeddableFactories]); + }, []); const factoriesBySavedObjectType: FactoryMap = useMemo(() => { - return [...getReactEmbeddableSavedObjects()] + return [...embeddableService.getReactEmbeddableSavedObjects()] .filter(([type, embeddableFactory]) => { return Boolean(embeddableFactory.savedObjectMetaData?.type); }) @@ -74,7 +73,7 @@ export const AddEmbeddableFlyout: FC = ({ }; return acc; }, {} as FactoryMap); - }, [getReactEmbeddableSavedObjects]); + }, []); const metaData = useMemo( () => @@ -111,7 +110,7 @@ export const AddEmbeddableFlyout: FC = ({ onSelect(id, type, isByValueEnabled); return; } - const embeddableFactories = getEmbeddableFactories(); + const embeddableFactories = embeddableService.getEmbeddableFactories(); // Find the embeddable type from the saved object type const found = Array.from(embeddableFactories).find((embeddableFactory) => { return Boolean( @@ -124,7 +123,7 @@ export const AddEmbeddableFlyout: FC = ({ onSelect(id, foundEmbeddableType, isByValueEnabled); }, - [isByValueEnabled, getEmbeddableFactories, onSelect, factoriesBySavedObjectType] + [isByValueEnabled, onSelect, factoriesBySavedObjectType] ); return ( @@ -141,8 +140,8 @@ export const AddEmbeddableFlyout: FC = ({ showFilter={true} noItemsMessage={strings.getNoItemsText()} services={{ - contentClient: getContentManagement().client, - uiSettings: getUISettings(), + contentClient: contentManagementService.client, + uiSettings: coreServices.uiSettings, }} /> diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx index d2772a04cdc2e..3ecabeb8974f1 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx @@ -15,7 +15,7 @@ import { getSelectedPage } from '../../state/selectors/workpad'; import { EmbeddableTypes } from '../../../canvas_plugin_src/expression_types/embeddable'; import { embeddableInputToExpression } from '../../../canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression'; import { State } from '../../../types'; -import { useLabsService } from '../../services'; +import { presentationUtilService } from '../../services/kibana_services'; const allowedEmbeddables = { [EmbeddableTypes.map]: (id: string) => { @@ -67,8 +67,9 @@ export const AddEmbeddablePanel: React.FunctionComponent = ({ availableEmbeddables, ...restProps }) => { - const labsService = useLabsService(); - const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable'); + const isByValueEnabled = presentationUtilService.labsService.isProjectEnabled( + 'labs:canvas:byValueEmbeddable' + ); const dispatch = useDispatch(); const pageId = useSelector((state) => getSelectedPage(state)); diff --git a/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx b/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx index 4539b1f7274fc..18a98630635cb 100644 --- a/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx +++ b/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx @@ -7,14 +7,12 @@ import React, { FocusEventHandler } from 'react'; import { EuiComboBox } from '@elastic/eui'; -import { DataView } from '@kbn/data-views-plugin/common'; - -type DataViewOption = Pick; +import { DataViewListItem } from '@kbn/data-views-plugin/common'; export interface ESDataViewSelectProps { loading: boolean; value: string; - dataViews: DataViewOption[]; + dataViews: DataViewListItem[]; onChange: (string: string) => void; onBlur: FocusEventHandler | undefined; onFocus: FocusEventHandler | undefined; @@ -31,7 +29,7 @@ export const ESDataViewSelect: React.FunctionComponent = onFocus, onBlur, }) => { - const selectedDataView = dataViews.find((view) => value === view.title) as DataViewOption; + const selectedDataView = dataViews.find((view) => value === view.title); const selectedOption = selectedDataView ? { value: selectedDataView.title, label: selectedDataView.name || selectedDataView.title } diff --git a/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx b/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx index 271662755d32a..217b7c79c8e75 100644 --- a/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx +++ b/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx @@ -5,25 +5,24 @@ * 2.0. */ -import { DataView } from '@kbn/data-views-plugin/common'; +import { DataViewListItem } from '@kbn/data-views-plugin/common'; import { sortBy } from 'lodash'; import React, { FC, useRef, useState } from 'react'; import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { useDataViewsService } from '../../services'; import { ESDataViewSelect as Component, ESDataViewSelectProps as Props, } from './es_data_view_select.component'; +import { getDataViews } from '../../lib/data_view_helpers'; type ESDataViewSelectProps = Omit; export const ESDataViewSelect: FC = (props) => { const { value, onChange } = props; - const [dataViews, setDataViews] = useState>>([]); + const [dataViews, setDataViews] = useState([]); const [loading, setLoading] = useState(true); const mounted = useRef(true); - const { getDataViews } = useDataViewsService(); useEffectOnce(() => { getDataViews().then((newDataViews) => { diff --git a/x-pack/plugins/canvas/public/components/es_field_select/index.tsx b/x-pack/plugins/canvas/public/components/es_field_select/index.tsx index 653eec22d77d9..f41f67bb6ee95 100644 --- a/x-pack/plugins/canvas/public/components/es_field_select/index.tsx +++ b/x-pack/plugins/canvas/public/components/es_field_select/index.tsx @@ -6,8 +6,8 @@ */ import React, { useState, useEffect, useRef } from 'react'; -import { useDataViewsService } from '../../services'; import { ESFieldSelect as Component, ESFieldSelectProps as Props } from './es_field_select'; +import { getDataViewFields } from '../../lib/data_view_helpers'; type ESFieldSelectProps = Omit; @@ -15,17 +15,16 @@ export const ESFieldSelect: React.FunctionComponent = (props const { index, value, onChange } = props; const [fields, setFields] = useState([]); const loadingFields = useRef(false); - const { getFields } = useDataViewsService(); useEffect(() => { loadingFields.current = true; - getFields(index) + getDataViewFields(index) .then((newFields) => setFields(newFields || [])) .finally(() => { loadingFields.current = false; }); - }, [index, getFields]); + }, [index]); useEffect(() => { if (!loadingFields.current && value && !fields.includes(value)) { diff --git a/x-pack/plugins/canvas/public/components/es_fields_select/es_fields_select.tsx b/x-pack/plugins/canvas/public/components/es_fields_select/es_fields_select.tsx index c929203f9e094..0cde66199b4b3 100644 --- a/x-pack/plugins/canvas/public/components/es_fields_select/es_fields_select.tsx +++ b/x-pack/plugins/canvas/public/components/es_fields_select/es_fields_select.tsx @@ -8,11 +8,11 @@ import React, { useState, useEffect, useRef } from 'react'; import { isEqual } from 'lodash'; import usePrevious from 'react-use/lib/usePrevious'; -import { useDataViewsService } from '../../services'; import { ESFieldsSelect as Component, ESFieldsSelectProps as Props, } from './es_fields_select.component'; +import { getDataViewFields } from '../../lib/data_view_helpers'; type ESFieldsSelectProps = Omit & { index: string }; @@ -21,11 +21,10 @@ export const ESFieldsSelect: React.FunctionComponent = (pro const [fields, setFields] = useState([]); const prevIndex = usePrevious(index); const mounted = useRef(true); - const { getFields } = useDataViewsService(); useEffect(() => { if (prevIndex !== index) { - getFields(index).then((newFields) => { + getDataViewFields(index).then((newFields) => { if (!mounted.current) { return; } @@ -37,7 +36,7 @@ export const ESFieldsSelect: React.FunctionComponent = (pro } }); } - }, [fields, index, onChange, prevIndex, selected, getFields]); + }, [fields, index, onChange, prevIndex, selected]); useEffect( () => () => { diff --git a/x-pack/plugins/canvas/public/components/expression/index.tsx b/x-pack/plugins/canvas/public/components/expression/index.tsx index 37bbbd1f5a4c1..1d0c9915bf347 100644 --- a/x-pack/plugins/canvas/public/components/expression/index.tsx +++ b/x-pack/plugins/canvas/public/components/expression/index.tsx @@ -8,7 +8,6 @@ import React, { FC, useState, useCallback, useMemo, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { fromExpression } from '@kbn/interpreter'; -import { useExpressionsService } from '../../services'; import { getSelectedPage, getSelectedElement } from '../../state/selectors/workpad'; // @ts-expect-error import { setExpression, flushContext } from '../../state/actions/elements'; @@ -16,6 +15,7 @@ import { setExpression, flushContext } from '../../state/actions/elements'; import { ElementNotSelected } from './element_not_selected'; import { Expression as Component } from './expression'; import { State, CanvasElement } from '../../../types'; +import { getCanvasExpressionService } from '../../services/canvas_expressions_service'; interface ExpressionProps { done: () => void; @@ -45,7 +45,6 @@ export const Expression: FC = ({ done }) => { }; const ExpressionContainer: FC = ({ done, element, pageId }) => { - const expressions = useExpressionsService(); const dispatch = useDispatch(); const [isCompact, setCompact] = useState(true); const toggleCompactView = useCallback(() => { @@ -111,8 +110,8 @@ const ExpressionContainer: FC = ({ done, element, page }, [element, setFormState, formState]); const functionDefinitions = useMemo( - () => Object.values(expressions.getFunctions()), - [expressions] + () => Object.values(getCanvasExpressionService().getFunctions()), + [] ); return ( diff --git a/x-pack/plugins/canvas/public/components/function_form/index.tsx b/x-pack/plugins/canvas/public/components/function_form/index.tsx index 202bb4384d696..f58eb496f7139 100644 --- a/x-pack/plugins/canvas/public/components/function_form/index.tsx +++ b/x-pack/plugins/canvas/public/components/function_form/index.tsx @@ -34,8 +34,8 @@ import { findExistingAsset } from '../../lib/find_existing_asset'; import { FunctionForm as Component } from './function_form'; import { Args, ArgType, ArgTypeDef } from '../../expression_types/types'; import { State, ExpressionContext, CanvasElement, AssetType } from '../../../types'; -import { useNotifyService, useWorkpadService } from '../../services'; import { createAsset, notifyError } from '../../lib/assets'; +import { getCanvasWorkpadService } from '../../services/canvas_workpad_service'; interface FunctionFormProps { name: string; @@ -54,8 +54,6 @@ interface FunctionFormProps { export const FunctionForm: React.FunctionComponent = (props) => { const { expressionIndex, ...restProps } = props; const { nextArgType, path, parentPath, argType } = restProps; - const service = useWorkpadService(); - const notifyService = useNotifyService(); const dispatch = useDispatch(); const context = useSelector( @@ -113,16 +111,16 @@ export const FunctionForm: React.FunctionComponent = (props) // make the ID here and pass it into the action const asset = createAsset(type, content); - return service + return getCanvasWorkpadService() .updateAssets(workpad.id, { ...workpad.assets, [asset.id]: asset }) .then((res) => { dispatch(setAsset(asset)); // then return the id, so the caller knows the id that will be created return asset.id; }) - .catch((error) => notifyError(error, notifyService.error)); + .catch((error) => notifyError(error)); }, - [dispatch, notifyService, service, workpad.assets, workpad.id] + [dispatch, workpad.assets, workpad.id] ); const onAssetAdd = useCallback( diff --git a/x-pack/plugins/canvas/public/components/function_form_list/index.js b/x-pack/plugins/canvas/public/components/function_form_list/index.js index 0ad6651e3f57e..6de7b81b12b01 100644 --- a/x-pack/plugins/canvas/public/components/function_form_list/index.js +++ b/x-pack/plugins/canvas/public/components/function_form_list/index.js @@ -8,7 +8,7 @@ import { compose, withProps } from 'react-recompose'; import { get } from 'lodash'; import { toExpression } from '@kbn/interpreter'; -import { pluginServices } from '../../services'; +import { getCanvasExpressionService } from '../../services/canvas_expressions_service'; import { getArgTypeDef } from '../../lib/args'; import { FunctionFormList as Component } from './function_form_list'; @@ -78,7 +78,7 @@ const componentFactory = ({ parentPath, removable, }) => { - const { expressions } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); return { args, nestedFunctionsArgs: argsWithExprFunctions, diff --git a/x-pack/plugins/canvas/public/components/home/home.stories.tsx b/x-pack/plugins/canvas/public/components/home/home.stories.tsx index 0130f9f3f894b..cfebd509c80ef 100644 --- a/x-pack/plugins/canvas/public/components/home/home.stories.tsx +++ b/x-pack/plugins/canvas/public/components/home/home.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { reduxDecorator } from '../../../storybook'; -import { argTypes } from '../../services/storybook'; +import { argTypes } from '../../../storybook/constants'; import { Home } from './home'; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_clone_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_clone_workpad.ts index 001a711a58a72..90a7c4c33de89 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_clone_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_clone_workpad.ts @@ -9,16 +9,17 @@ import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; import { getId } from '../../../lib/get_id'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useCloneWorkpad = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const history = useHistory(); return useCallback( async (workpadId: string) => { + const workpadService = getCanvasWorkpadService(); try { let workpad = await workpadService.get(workpadId); @@ -35,7 +36,7 @@ export const useCloneWorkpad = () => { notifyService.error(err, { title: errors.getCloneFailureErrorMessage() }); } }, - [notifyService, workpadService, history] + [notifyService, history] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_create_from_template.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_create_from_template.ts index 968f9398ba857..6b57cf61ca905 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_create_from_template.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_create_from_template.ts @@ -9,15 +9,16 @@ import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; import { CanvasTemplate } from '../../../../types'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useCreateFromTemplate = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const history = useHistory(); return useCallback( async (template: CanvasTemplate) => { + const workpadService = getCanvasWorkpadService(); try { const result = await workpadService.createFromTemplate(template.id); history.push(`/workpad/${result.id}/page/1`); @@ -27,6 +28,6 @@ export const useCreateFromTemplate = () => { }); } }, - [workpadService, notifyService, history] + [notifyService, history] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_create_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_create_workpad.ts index 3290bc8227a29..f950a4adcd037 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_create_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_create_workpad.ts @@ -11,17 +11,18 @@ import { i18n } from '@kbn/i18n'; // @ts-expect-error import { getDefaultWorkpad } from '../../../state/defaults'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; import type { CanvasWorkpad } from '../../../../types'; export const useCreateWorkpad = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const history = useHistory(); return useCallback( async (_workpad?: CanvasWorkpad | null) => { + const workpadService = getCanvasWorkpadService(); const workpad = _workpad || (getDefaultWorkpad() as CanvasWorkpad); try { @@ -34,7 +35,7 @@ export const useCreateWorkpad = () => { } return; }, - [notifyService, history, workpadService] + [notifyService, history] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_delete_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_delete_workpad.ts index 722ddae7411c9..dc52fe2e82d5c 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_delete_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_delete_workpad.ts @@ -8,51 +8,48 @@ import { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { getCanvasNotifyService } from '../../../services/canvas_notify_service'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useDeleteWorkpads = () => { - const workpadService = useWorkpadService(); - const notifyService = useNotifyService(); - - return useCallback( - async (workpadIds: string[]) => { - const removedWorkpads = workpadIds.map(async (id) => { - try { - await workpadService.remove(id); - return { id, err: null }; - } catch (err) { - return { id, err }; - } - }); - - return Promise.all(removedWorkpads).then((results) => { - const [passes, errored] = results.reduce<[string[], string[]]>( - ([passesArr, errorsArr], result) => { - if (result.err) { - errorsArr.push(result.id); - } else { - passesArr.push(result.id); - } - - return [passesArr, errorsArr]; - }, - [[], []] - ); - - const removedIds = workpadIds.filter((id) => passes.includes(id)); - - if (errored.length > 0) { - notifyService.error(errors.getDeleteFailureErrorMessage()); - } - - return { - removedIds, - errored, - }; - }); - }, - [workpadService, notifyService] - ); + return useCallback(async (workpadIds: string[]) => { + const workpadService = getCanvasWorkpadService(); + + const removedWorkpads = workpadIds.map(async (id) => { + try { + await workpadService.remove(id); + return { id, err: null }; + } catch (err) { + return { id, err }; + } + }); + + return Promise.all(removedWorkpads).then((results) => { + const [passes, errored] = results.reduce<[string[], string[]]>( + ([passesArr, errorsArr], result) => { + if (result.err) { + errorsArr.push(result.id); + } else { + passesArr.push(result.id); + } + + return [passesArr, errorsArr]; + }, + [[], []] + ); + + const removedIds = workpadIds.filter((id) => passes.includes(id)); + + if (errored.length > 0) { + getCanvasNotifyService().error(errors.getDeleteFailureErrorMessage()); + } + + return { + removedIds, + errored, + }; + }); + }, []); }; const errors = { diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_find_templates.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_find_templates.ts index 9364a79987908..426b612774762 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_find_templates.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_find_templates.ts @@ -6,10 +6,8 @@ */ import { useCallback } from 'react'; - -import { useWorkpadService } from '../../../services'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useFindTemplates = () => { - const workpadService = useWorkpadService(); - return useCallback(async () => await workpadService.findTemplates(), [workpadService]); + return useCallback(async () => await getCanvasWorkpadService().findTemplates(), []); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_find_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_find_workpad.ts index 10352d0472e8c..59ff5cd0561b5 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_find_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_find_workpad.ts @@ -8,21 +8,21 @@ import { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useFindWorkpads = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); return useCallback( async (text = '') => { try { - return await workpadService.find(text); + return await getCanvasWorkpadService().find(text); } catch (err) { notifyService.error(err, { title: errors.getFindFailureErrorMessage() }); } }, - [notifyService, workpadService] + [notifyService] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_import_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_import_workpad.ts index bd780ee01507d..bb3f447cd107b 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_import_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_import_workpad.ts @@ -9,17 +9,18 @@ import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; import type { CanvasWorkpad } from '../../../../types'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useImportWorkpad = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const history = useHistory(); return useCallback( async (workpad: CanvasWorkpad) => { + const workpadService = getCanvasWorkpadService(); try { const importedWorkpad = await workpadService.import(workpad); history.push(`/workpad/${importedWorkpad.id}/page/1`); @@ -30,7 +31,7 @@ export const useImportWorkpad = () => { } return; }, - [notifyService, history, workpadService] + [notifyService, history] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.component.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.component.tsx index d9e3f0e4e2c99..6f25bbf8720cf 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.component.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.component.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { FoundWorkpad } from '../../../services/workpad'; +import { FoundWorkpad } from '../../../services/canvas_workpad_service'; import { UploadDropzone } from './upload_dropzone'; import { HomeEmptyPrompt } from './empty_prompt'; import { WorkpadTable } from './workpad_table'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.stories.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.stories.tsx index 52afd552bbc49..967419e9b8b06 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.stories.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.stories.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { EuiPanel } from '@elastic/eui'; import { reduxDecorator } from '../../../../storybook'; -import { argTypes } from '../../../services/storybook'; +import { argTypes } from '../../../../storybook/constants'; import { MyWorkpads as Component } from './my_workpads'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.tsx index b75c8864ad495..44b3c5938af6c 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.tsx @@ -7,7 +7,7 @@ import React, { useState, useEffect, createContext, Dispatch, SetStateAction } from 'react'; import { useFindWorkpads } from '../hooks'; -import { FoundWorkpad } from '../../../services/workpad'; +import { FoundWorkpad } from '../../../services/canvas_workpad_service'; import { Loading } from '../loading'; import { MyWorkpads as Component } from './my_workpads.component'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.component.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.component.tsx index c64ab50ad8a09..f8e349351ba4c 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.component.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.component.tsx @@ -21,7 +21,7 @@ import { import moment from 'moment'; import { RoutingLink } from '../../routing'; -import { FoundWorkpad } from '../../../services/workpad'; +import { FoundWorkpad } from '../../../services/canvas_workpad_service'; import { WorkpadTableTools } from './workpad_table_tools'; import { WorkpadImport } from './workpad_import'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.stories.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.stories.tsx index 6675dea238cc4..f9418f35e6256 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.stories.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.stories.tsx @@ -9,9 +9,9 @@ import React, { useState, useEffect } from 'react'; import { EuiPanel } from '@elastic/eui'; import { reduxDecorator } from '../../../../storybook'; +import { argTypes } from '../../../../storybook/constants'; -import { argTypes } from '../../../services/storybook'; -import { getSomeWorkpads } from '../../../services/stubs/workpad'; +import { getSomeWorkpads } from '../../../services/mocks'; import { WorkpadTable as Component } from './workpad_table'; import { WorkpadsContext } from './my_workpads'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.tsx index 6d88691f2eabe..7bbb3a57ab9ce 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.tsx @@ -8,17 +8,16 @@ import React, { useContext } from 'react'; import { useSelector } from 'react-redux'; -import { canUserWrite as canUserWriteSelector } from '../../../state/selectors/app'; import type { State } from '../../../../types'; -import { usePlatformService } from '../../../services'; -import { useCloneWorkpad } from '../hooks'; +import { canUserWrite as canUserWriteSelector } from '../../../state/selectors/app'; import { useDownloadWorkpad } from '../../hooks'; +import { useCloneWorkpad } from '../hooks'; -import { WorkpadTable as Component } from './workpad_table.component'; +import { coreServices } from '../../../services/kibana_services'; import { WorkpadsContext } from './my_workpads'; +import { WorkpadTable as Component } from './workpad_table.component'; export const WorkpadTable = () => { - const platformService = usePlatformService(); const onCloneWorkpad = useCloneWorkpad(); const onExportWorkpad = useDownloadWorkpad(); const context = useContext(WorkpadsContext); @@ -33,7 +32,7 @@ export const WorkpadTable = () => { const { workpads } = context; - const dateFormat = platformService.getUISetting('dateFormat'); + const dateFormat = coreServices.uiSettings.get('dateFormat'); return ; }; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table_tools.component.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table_tools.component.tsx index 251a40ff4d45d..148e1973352bc 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table_tools.component.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table_tools.component.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { EuiButton, EuiToolTip, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; import { ConfirmModal } from '../../confirm_modal'; -import { FoundWorkpad } from '../../../services/workpad'; +import { FoundWorkpad } from '../../../services/canvas_workpad_service'; export interface Props { workpads: FoundWorkpad[]; diff --git a/x-pack/plugins/canvas/public/components/home/workpad_templates/workpad_templates.stories.tsx b/x-pack/plugins/canvas/public/components/home/workpad_templates/workpad_templates.stories.tsx index 92583ca845aa8..c6a3347f6c39a 100644 --- a/x-pack/plugins/canvas/public/components/home/workpad_templates/workpad_templates.stories.tsx +++ b/x-pack/plugins/canvas/public/components/home/workpad_templates/workpad_templates.stories.tsx @@ -9,7 +9,7 @@ import { EuiPanel } from '@elastic/eui'; import React from 'react'; import { reduxDecorator } from '../../../../storybook'; -import { argTypes } from '../../../services/storybook'; +import { argTypes } from '../../../../storybook/constants'; import { WorkpadTemplates as Component } from './workpad_templates'; diff --git a/x-pack/plugins/canvas/public/components/home_app/home_app.tsx b/x-pack/plugins/canvas/public/components/home_app/home_app.tsx index 086a737d525e9..54d9659f5a1d8 100644 --- a/x-pack/plugins/canvas/public/components/home_app/home_app.tsx +++ b/x-pack/plugins/canvas/public/components/home_app/home_app.tsx @@ -11,17 +11,16 @@ import { useDispatch } from 'react-redux'; import { getBaseBreadcrumb } from '../../lib/breadcrumbs'; import { resetWorkpad } from '../../state/actions/workpad'; import { HomeApp as Component } from './home_app.component'; -import { usePlatformService } from '../../services'; +import { coreServices } from '../../services/kibana_services'; export const HomeApp = () => { - const { setBreadcrumbs } = usePlatformService(); const dispatch = useDispatch(); const onLoad = () => dispatch(resetWorkpad()); const history = useHistory(); useEffect(() => { - setBreadcrumbs([getBaseBreadcrumb(history)]); - }, [setBreadcrumbs, history]); + coreServices.chrome.setBreadcrumbs([getBaseBreadcrumb(history)]); + }, [history]); return ; }; diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/use_download_workpad.ts b/x-pack/plugins/canvas/public/components/hooks/workpad/use_download_workpad.ts index dadf03a8fac5a..394274b1eb133 100644 --- a/x-pack/plugins/canvas/public/components/hooks/workpad/use_download_workpad.ts +++ b/x-pack/plugins/canvas/public/components/hooks/workpad/use_download_workpad.ts @@ -8,9 +8,10 @@ import { useCallback } from 'react'; import fileSaver from 'file-saver'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; import { CanvasWorkpad } from '../../../../types'; import type { CanvasRenderedWorkpad } from '../../../../shareable_runtime/types'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; const strings = { getDownloadFailureErrorMessage: () => @@ -28,12 +29,12 @@ const strings = { export const useDownloadWorkpad = () => { const notifyService = useNotifyService(); - const workpadService = useWorkpadService(); const download = useDownloadWorkpadBlob(); return useCallback( async (workpadId: string) => { try { + const workpadService = getCanvasWorkpadService(); const workpad = await workpadService.get(workpadId); download(workpad, `canvas-workpad-${workpad.name}-${workpad.id}`); @@ -41,7 +42,7 @@ export const useDownloadWorkpad = () => { notifyService.error(err, { title: strings.getDownloadFailureErrorMessage() }); } }, - [workpadService, notifyService, download] + [notifyService, download] ); }; diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts b/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts index 0a4e66917814d..50c3e527bbbae 100644 --- a/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts +++ b/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts @@ -12,7 +12,7 @@ import { ErrorStrings } from '../../../../i18n'; import { CANVAS_APP } from '../../../../common/lib'; import { decode } from '../../../../common/lib/embeddable_dataurl'; import { CanvasElement, CanvasPage } from '../../../../types'; -import { useEmbeddablesService, useLabsService, useNotifyService } from '../../../services'; +import { useNotifyService } from '../../../services'; // @ts-expect-error unconverted file import { addElement, fetchAllRenderables } from '../../../state/actions/elements'; // @ts-expect-error unconverted file @@ -24,16 +24,16 @@ import { } from '../../../state/actions/embeddable'; import { clearValue } from '../../../state/actions/resolved_args'; import { embeddableInputToExpression } from '../../../../canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression'; +import { embeddableService, presentationUtilService } from '../../../services/kibana_services'; const { actionsElements: strings } = ErrorStrings; export const useIncomingEmbeddable = (selectedPage: CanvasPage) => { - const embeddablesService = useEmbeddablesService(); - const labsService = useLabsService(); + const labsService = presentationUtilService.labsService; const dispatch = useDispatch(); const notifyService = useNotifyService(); const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable'); - const stateTransferService = embeddablesService.getStateTransfer(); + const stateTransferService = embeddableService.getStateTransfer(); // fetch incoming embeddable from state transfer service. const incomingEmbeddable = stateTransferService.getIncomingEmbeddablePackage(CANVAS_APP, true); diff --git a/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.tsx b/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.tsx index 19e786edfd5fb..5aeb8847ab887 100644 --- a/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.tsx +++ b/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { camelCase } from 'lodash'; import { cloneSubgraphs } from '../../lib/clone_subgraphs'; -import { useNotifyService, useCustomElementService } from '../../services'; +import { useNotifyService } from '../../services'; // @ts-expect-error untyped local import { selectToplevelNodes } from '../../state/actions/transient'; // @ts-expect-error untyped local @@ -21,6 +21,7 @@ import { Props as ComponentProps, } from './saved_elements_modal.component'; import { PositionedElement, CustomElement } from '../../../types'; +import { getCustomElementService } from '../../services/canvas_custom_element_service'; const customElementAdded = 'elements-custom-added'; @@ -28,7 +29,7 @@ export type Props = Pick; export const SavedElementsModal = ({ onClose }: Props) => { const notifyService = useNotifyService(); - const customElementService = useCustomElementService(); + const customElementService = useMemo(() => getCustomElementService(), []); const dispatch = useDispatch(); const pageId = useSelector(getSelectedPage); const [customElements, setCustomElements] = useState([]); diff --git a/x-pack/plugins/canvas/public/components/workpad/workpad.tsx b/x-pack/plugins/canvas/public/components/workpad/workpad.tsx index 1e604a6deb850..6052e6951a8e9 100644 --- a/x-pack/plugins/canvas/public/components/workpad/workpad.tsx +++ b/x-pack/plugins/canvas/public/components/workpad/workpad.tsx @@ -24,10 +24,10 @@ import { useZoomHandlers } from '../../lib/app_handler_creators'; import { trackCanvasUiMetric, METRIC_TYPE } from '../../lib/ui_metric'; import { LAUNCHED_FULLSCREEN, LAUNCHED_FULLSCREEN_AUTOPLAY } from '../../../common/lib/constants'; import { WorkpadRoutingContext } from '../../routes/workpad'; -import { usePlatformService } from '../../services'; import { Workpad as WorkpadComponent, Props } from './workpad.component'; import { State } from '../../../types'; import { useIncomingEmbeddable } from '../hooks'; +import { coreServices } from '../../services/kibana_services'; type ContainerProps = Pick; @@ -40,9 +40,7 @@ export const Workpad: FC = (props) => { const { isFullscreen, setFullscreen, undo, redo, autoplayInterval, nextPage, previousPage } = useContext(WorkpadRoutingContext); - const platformService = usePlatformService(); - - const hasHeaderBanner = useObservable(platformService.hasHeaderBanner$()); + const hasHeaderBanner = useObservable(coreServices.chrome.hasHeaderBanner$()); const propsFromState = useSelector((state: State) => { const { width, height, id: workpadId, css: workpadCss } = getWorkpad(state); diff --git a/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts b/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts index bdccc8040c5de..9aa9aecdfd516 100644 --- a/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts +++ b/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts @@ -5,17 +5,19 @@ * 2.0. */ +import { useMemo } from 'react'; import { AstFunction, fromExpression } from '@kbn/interpreter'; import { shallowEqual, useSelector } from 'react-redux'; + import { State } from '../../../../types'; import { getFiltersByFilterExpressions } from '../../../lib/filter'; import { adaptCanvasFilter } from '../../../lib/filter_adapters'; -import { useFiltersService } from '../../../services'; +import { getCanvasFiltersService } from '../../../services/canvas_filters_service'; const extractExpressionAST = (filters: string[]) => fromExpression(filters.join(' | ')); export function useCanvasFilters(filterExprsToGroupBy: AstFunction[] = []) { - const filtersService = useFiltersService(); + const filtersService = useMemo(() => getCanvasFiltersService(), []); const filterExpressions = useSelector( (state: State) => filtersService.getFilters(state), shallowEqual diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx index fd644903ac25d..06d20e919dcbe 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx @@ -21,11 +21,6 @@ import { import { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public/actions'; import { trackCanvasUiMetric, METRIC_TYPE } from '../../../lib/ui_metric'; -import { - useEmbeddablesService, - useUiActionsService, - useVisualizationsService, -} from '../../../services'; import { CANVAS_APP } from '../../../../common/lib'; import { ElementSpec } from '../../../../types'; import { EditorMenu as Component } from './editor_menu.component'; @@ -33,6 +28,11 @@ import { embeddableInputToExpression } from '../../../../canvas_plugin_src/rende import { EmbeddableInput as CanvasEmbeddableInput } from '../../../../canvas_plugin_src/expression_types'; import { useCanvasApi } from '../../hooks/use_canvas_api'; import { ADD_CANVAS_ELEMENT_TRIGGER } from '../../../state/triggers/add_canvas_element_trigger'; +import { + embeddableService, + uiActionsService, + visualizationsService, +} from '../../../services/kibana_services'; interface Props { /** @@ -47,18 +47,15 @@ interface UnwrappedEmbeddableFactory { } export const EditorMenu: FC = ({ addElement }) => { - const embeddablesService = useEmbeddablesService(); const { pathname, search, hash } = useLocation(); - const stateTransferService = embeddablesService.getStateTransfer(); - const visualizationsService = useVisualizationsService(); - const uiActions = useUiActionsService(); + const stateTransferService = embeddableService.getStateTransfer(); const canvasApi = useCanvasApi(); const [addPanelActions, setAddPanelActions] = useState>>([]); const embeddableFactories = useMemo( - () => (embeddablesService ? Array.from(embeddablesService.getEmbeddableFactories()) : []), - [embeddablesService] + () => (embeddableService ? Array.from(embeddableService.getEmbeddableFactories()) : []), + [] ); const [unwrappedEmbeddableFactories, setUnwrappedEmbeddableFactories] = useState< @@ -79,7 +76,7 @@ export const EditorMenu: FC = ({ addElement }) => { useEffect(() => { let mounted = true; async function loadPanelActions() { - const registeredActions = await uiActions?.getTriggerCompatibleActions?.( + const registeredActions = await uiActionsService.getTriggerCompatibleActions( ADD_CANVAS_ELEMENT_TRIGGER, { embeddable: canvasApi } ); @@ -89,7 +86,7 @@ export const EditorMenu: FC = ({ addElement }) => { return () => { mounted = false; }; - }, [uiActions, canvasApi]); + }, [canvasApi]); const createNewVisType = useCallback( (visType?: BaseVisType | VisTypeAlias) => () => { diff --git a/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx b/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx index 75d6f8064f32a..6e6ca58f0dd72 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx @@ -5,13 +5,14 @@ * 2.0. */ -import React, { useState } from 'react'; import { EuiButtonEmpty, EuiNotificationBadge } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import React, { useState } from 'react'; import { LazyLabsFlyout, withSuspense } from '@kbn/presentation-util-plugin/public'; -import { useLabsService } from '../../../services'; +import { UI_SETTINGS } from '../../../../common'; +import { coreServices, presentationUtilService } from '../../../services/kibana_services'; const strings = { getLabsButtonLabel: () => @@ -23,14 +24,13 @@ const strings = { const Flyout = withSuspense(LazyLabsFlyout, null); export const LabsControl = () => { - const { isLabsEnabled, getProjects } = useLabsService(); const [isShown, setIsShown] = useState(false); - if (!isLabsEnabled()) { + if (!coreServices.uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI)) { return null; } - const projects = getProjects(['canvas']); + const projects = presentationUtilService.labsService.getProjects(['canvas']); const overrideCount = Object.values(projects).filter( (project) => project.status.isOverride ).length; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/hooks/use_download_runtime.ts b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/hooks/use_download_runtime.ts index cd1635d65a573..49bd93c290ce8 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/hooks/use_download_runtime.ts +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/hooks/use_download_runtime.ts @@ -5,14 +5,16 @@ * 2.0. */ -import { useCallback } from 'react'; -import fileSaver from 'file-saver'; import { i18n } from '@kbn/i18n'; +import fileSaver from 'file-saver'; +import { useCallback } from 'react'; import { API_ROUTE_SHAREABLE_RUNTIME_DOWNLOAD } from '../../../../../../common/lib/constants'; import { ZIP } from '../../../../../../i18n/constants'; -import { usePlatformService, useNotifyService, useWorkpadService } from '../../../../../services'; import type { CanvasRenderedWorkpad } from '../../../../../../shareable_runtime/types'; +import { useNotifyService } from '../../../../../services'; +import { coreServices } from '../../../../../services/kibana_services'; +import { getCanvasWorkpadService } from '../../../../../services/canvas_workpad_service'; const strings = { getDownloadRuntimeFailureErrorMessage: () => @@ -35,28 +37,28 @@ const strings = { }; export const useDownloadRuntime = () => { - const platformService = usePlatformService(); const notifyService = useNotifyService(); const downloadRuntime = useCallback(() => { try { - const path = `${platformService.getBasePath()}${API_ROUTE_SHAREABLE_RUNTIME_DOWNLOAD}`; + const path = `${coreServices.http.basePath.get()}${API_ROUTE_SHAREABLE_RUNTIME_DOWNLOAD}`; window.open(path); return; } catch (err) { notifyService.error(err, { title: strings.getDownloadRuntimeFailureErrorMessage() }); } - }, [platformService, notifyService]); + }, [notifyService]); return downloadRuntime; }; export const useDownloadZippedRuntime = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const downloadZippedRuntime = useCallback( (workpad: CanvasRenderedWorkpad) => { + const workpadService = getCanvasWorkpadService(); + const downloadZip = async () => { try { let runtimeZipBlob: Blob | undefined; @@ -80,7 +82,7 @@ export const useDownloadZippedRuntime = () => { downloadZip(); }, - [notifyService, workpadService] + [notifyService] ); return downloadZippedRuntime; }; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx index c66336a9153c0..e4239864c1915 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx @@ -9,11 +9,11 @@ import React, { useCallback } from 'react'; import { useSelector } from 'react-redux'; import { i18n } from '@kbn/i18n'; import { State } from '../../../../types'; -import { useReportingService, usePlatformService } from '../../../services'; import { getPages, getWorkpad } from '../../../state/selectors/workpad'; import { useDownloadWorkpad } from '../../hooks'; import { ShareMenu as ShareMenuComponent } from './share_menu.component'; import { getPdfJobParams } from './utils'; +import { kibanaVersion, reportingService } from '../../../services/kibana_services'; const strings = { getUnknownExportErrorMessage: (type: string) => @@ -27,32 +27,30 @@ const strings = { export const ShareMenu = () => { const downloadWorkpad = useDownloadWorkpad(); - const reportingService = useReportingService(); - const platformService = usePlatformService(); const { workpad, pageCount } = useSelector((state: State) => ({ workpad: getWorkpad(state), pageCount: getPages(state).length, })); - const ReportingPanelPDFComponent = reportingService.getReportingPanelPDFComponent(); - const sharingData = { workpad, pageCount, }; - const ReportingComponent = - ReportingPanelPDFComponent !== null - ? ({ onClose }: { onClose: () => void }) => ( - getPdfJobParams(sharingData, platformService.getKibanaVersion())} + const ReportingComponent = reportingService + ? ({ onClose }: { onClose: () => void }) => { + const ReportingPanelPDFV2 = reportingService!.components.ReportingPanelPDFV2; + return ( + getPdfJobParams(sharingData, kibanaVersion)} layoutOption="canvas" onClose={onClose} objectId={workpad.id} /> - ) - : null; + ); + } + : null; const onExport = useCallback( (type: string) => { diff --git a/x-pack/plugins/canvas/public/functions/filters.ts b/x-pack/plugins/canvas/public/functions/filters.ts index a168020b6eef8..a37953657e157 100644 --- a/x-pack/plugins/canvas/public/functions/filters.ts +++ b/x-pack/plugins/canvas/public/functions/filters.ts @@ -7,10 +7,11 @@ import { fromExpression } from '@kbn/interpreter'; import { get } from 'lodash'; -import { pluginServices } from '../services'; import type { FiltersFunction } from '../../common/functions'; import { buildFiltersFunction } from '../../common/functions'; import { InitializeArguments } from '.'; +import { getCanvasFiltersService } from '../services/canvas_filters_service'; +import { getCanvasExpressionService } from '../services/canvas_expressions_service'; export interface Arguments { group: string[]; @@ -40,7 +41,8 @@ function getFiltersByGroup(allFilters: string[], groups?: string[], ungrouped = export function filtersFunctionFactory(initialize: InitializeArguments): () => FiltersFunction { const fn: FiltersFunction['fn'] = (input, { group, ungrouped }) => { - const { expressions, filters: filtersService } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); + const filtersService = getCanvasFiltersService(); const filterList = getFiltersByGroup(filtersService.getFilters(), group, ungrouped); diff --git a/x-pack/plugins/canvas/public/lib/assets.ts b/x-pack/plugins/canvas/public/lib/assets.ts index d7fd0ecbac57f..b51cda9216fbc 100644 --- a/x-pack/plugins/canvas/public/lib/assets.ts +++ b/x-pack/plugins/canvas/public/lib/assets.ts @@ -6,8 +6,8 @@ */ import { i18n } from '@kbn/i18n'; import { AssetType, CanvasAsset } from '../../types'; -import { CanvasNotifyService } from '../services/notify'; import { getId } from './get_id'; +import { getCanvasNotifyService } from '../services/canvas_notify_service'; const strings = { getSaveFailureTitle: () => @@ -32,7 +32,8 @@ export const createAsset = (type: AssetType['type'], content: AssetType['value'] '@created': new Date().toISOString(), }); -export const notifyError = (err: any, notifyErrorFn: CanvasNotifyService['error']) => { +export const notifyError = (err: any) => { + const { error: notifyErrorFn } = getCanvasNotifyService(); const statusCode = err.response && err.response.status; switch (statusCode) { case 400: diff --git a/x-pack/plugins/canvas/public/lib/create_handlers.ts b/x-pack/plugins/canvas/public/lib/create_handlers.ts index 374bdaff99721..8b78914d77071 100644 --- a/x-pack/plugins/canvas/public/lib/create_handlers.ts +++ b/x-pack/plugins/canvas/public/lib/create_handlers.ts @@ -12,8 +12,10 @@ import { } from '@kbn/expressions-plugin/public'; import { updateEmbeddableExpression, fetchEmbeddableRenderable } from '../state/actions/embeddable'; import { RendererHandlers, CanvasElement } from '../../types'; -import { pluginServices } from '../services'; +import { getCanvasFiltersService } from '../services/canvas_filters_service'; import { clearValue } from '../state/actions/resolved_args'; +// @ts-expect-error unconverted file +import { fetchAllRenderables } from '../state/actions/elements'; // This class creates stub handlers to ensure every element and renderer fulfills the contract. // TODO: consider warning if these methods are invoked but not implemented by the renderer...? @@ -80,7 +82,7 @@ export const createDispatchedHandlerFactory = ( oldElement = element; } - const { filters } = pluginServices.getServices(); + const filters = getCanvasFiltersService(); const handlers: RendererHandlers & { event: IInterpreterRenderHandlers['event']; @@ -94,6 +96,7 @@ export const createDispatchedHandlerFactory = ( break; case 'applyFilterAction': filters.updateFilter(element.id, event.data); + dispatch(fetchAllRenderables()); break; case 'onComplete': this.onComplete(event.data); diff --git a/x-pack/plugins/canvas/public/lib/data_view_helpers.ts b/x-pack/plugins/canvas/public/lib/data_view_helpers.ts new file mode 100644 index 0000000000000..0bec688f6788a --- /dev/null +++ b/x-pack/plugins/canvas/public/lib/data_view_helpers.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { dataViewsService } from '../services/kibana_services'; +import { getCanvasNotifyService } from '../services/canvas_notify_service'; +import { ErrorStrings } from '../../i18n'; + +export const getDataViews = async () => { + try { + return await dataViewsService.getIdsWithTitle(); + } catch (e) { + const { esService: strings } = ErrorStrings; + getCanvasNotifyService().error(e, { title: strings.getIndicesFetchErrorMessage() }); + } + return []; +}; + +export const getDataViewFields = async (dataViewTitle: string) => { + const dataView = await dataViewsService.create({ title: dataViewTitle }); + + return dataView.fields.filter((field) => !field.name.startsWith('_')).map((field) => field.name); +}; diff --git a/x-pack/plugins/canvas/public/lib/element_handler_creators.ts b/x-pack/plugins/canvas/public/lib/element_handler_creators.ts index 82b9827529040..72a7df3a26775 100644 --- a/x-pack/plugins/canvas/public/lib/element_handler_creators.ts +++ b/x-pack/plugins/canvas/public/lib/element_handler_creators.ts @@ -8,10 +8,11 @@ import { camelCase } from 'lodash'; import { getClipboardData, setClipboardData } from './clipboard'; import { cloneSubgraphs } from './clone_subgraphs'; -import { pluginServices } from '../services'; import { getId } from './get_id'; import { PositionedElement } from '../../types'; import { ELEMENT_NUDGE_OFFSET, ELEMENT_SHIFT_OFFSET } from '../../common/lib/constants'; +import { getCanvasNotifyService } from '../services/canvas_notify_service'; +import { getCustomElementService } from '../services/canvas_custom_element_service'; const extractId = (node: { id: string }): string => node.id; @@ -71,8 +72,8 @@ export const basicHandlerCreators = { createCustomElement: ({ selectedNodes }: Props) => (name = '', description = '', image = ''): void => { - const notifyService = pluginServices.getServices().notify; - const customElementService = pluginServices.getServices().customElement; + const notifyService = getCanvasNotifyService(); + const customElementService = getCustomElementService(); if (selectedNodes.length) { const content = JSON.stringify({ selectedNodes }); @@ -145,7 +146,7 @@ export const clipboardHandlerCreators = { cutNodes: ({ pageId, removeNodes, selectedNodes }: Props) => (): void => { - const notifyService = pluginServices.getServices().notify; + const notifyService = getCanvasNotifyService(); if (selectedNodes.length) { setClipboardData({ selectedNodes }); @@ -156,7 +157,7 @@ export const clipboardHandlerCreators = { copyNodes: ({ selectedNodes }: Props) => (): void => { - const notifyService = pluginServices.getServices().notify; + const notifyService = getCanvasNotifyService(); if (selectedNodes.length) { setClipboardData({ selectedNodes }); diff --git a/x-pack/plugins/canvas/public/lib/fullscreen.js b/x-pack/plugins/canvas/public/lib/fullscreen.js index fd4e0b65785b9..50a9578b07b78 100644 --- a/x-pack/plugins/canvas/public/lib/fullscreen.js +++ b/x-pack/plugins/canvas/public/lib/fullscreen.js @@ -5,22 +5,21 @@ * 2.0. */ -import { pluginServices } from '../services'; +import { coreServices } from '../services/kibana_services'; export const fullscreenClass = 'canvas-isFullscreen'; export function setFullscreen(fullscreen, doc = document) { - const platformService = pluginServices.getServices().platform; const enabled = Boolean(fullscreen); const body = doc.querySelector('body'); const bodyClassList = body.classList; const isFullscreen = bodyClassList.contains(fullscreenClass); if (enabled && !isFullscreen) { - platformService.setFullscreen(false); + coreServices.chrome.setIsVisible(false); bodyClassList.add(fullscreenClass); } else if (!enabled && isFullscreen) { bodyClassList.remove(fullscreenClass); - platformService.setFullscreen(true); + coreServices.chrome.setIsVisible(true); } } diff --git a/x-pack/plugins/canvas/public/lib/template_service.ts b/x-pack/plugins/canvas/public/lib/template_service.ts index d5ec467f18740..481733b781d85 100644 --- a/x-pack/plugins/canvas/public/lib/template_service.ts +++ b/x-pack/plugins/canvas/public/lib/template_service.ts @@ -9,12 +9,11 @@ import { API_ROUTE_TEMPLATES } from '../../common/lib/constants'; import { fetch } from '../../common/lib/fetch'; -import { pluginServices } from '../services'; import { CanvasTemplate } from '../../types'; +import { coreServices } from '../services/kibana_services'; const getApiPath = function () { - const platformService = pluginServices.getServices().platform; - const basePath = platformService.getBasePath(); + const basePath = coreServices.http.basePath.get(); return `${basePath}${API_ROUTE_TEMPLATES}`; }; diff --git a/x-pack/plugins/canvas/public/plugin.tsx b/x-pack/plugins/canvas/public/plugin.tsx index 5f385ce5f079b..bd4e920a56f7e 100644 --- a/x-pack/plugins/canvas/public/plugin.tsx +++ b/x-pack/plugins/canvas/public/plugin.tsx @@ -38,6 +38,7 @@ import { initLoadingIndicator } from './lib/loading_indicator'; import { getPluginApi, CanvasApi } from './plugin_api'; import { setupExpressions } from './setup_expressions'; import { addCanvasElementTrigger } from './state/triggers/add_canvas_element_trigger'; +import { setKibanaServices, untilPluginStartServicesReady } from './services/kibana_services'; export type { CoreStart, CoreSetup }; @@ -121,22 +122,13 @@ export class CanvasPlugin setupExpressions({ coreSetup, setupPlugins }); // Get start services - const [coreStart, startPlugins] = await coreSetup.getStartServices(); + const [[coreStart, startPlugins]] = await Promise.all([ + coreSetup.getStartServices(), + untilPluginStartServicesReady(), + ]); srcPlugin.start(coreStart, startPlugins); - const { pluginServices } = await import('./services'); - const { pluginServiceRegistry } = await import('./services/kibana'); - - pluginServices.setRegistry( - pluginServiceRegistry.start({ - coreStart, - startPlugins, - appUpdater: this.appUpdater, - initContext: this.initContext, - }) - ); - const { expressions, presentationUtil } = startPlugins; await presentationUtil.registerExpressionsLanguage( Object.values(expressions.getFunctions()) @@ -154,7 +146,13 @@ export class CanvasPlugin this.appUpdater ); - const unmount = renderApp({ coreStart, startPlugins, params, canvasStore, pluginServices }); + const unmount = renderApp({ + coreStart, + startPlugins, + params, + canvasStore, + appUpdater: this.appUpdater, + }); return () => { unmount(); @@ -190,6 +188,7 @@ export class CanvasPlugin } public start(coreStart: CoreStart, startPlugins: CanvasStartDeps) { + setKibanaServices(coreStart, startPlugins, this.initContext); initLoadingIndicator(coreStart.http.addLoadingCountSource); } } diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_fullscreen_presentation_helper.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_fullscreen_presentation_helper.ts index ca66fa227e4eb..e517f74030c87 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_fullscreen_presentation_helper.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_fullscreen_presentation_helper.ts @@ -6,32 +6,30 @@ */ import { useContext, useEffect } from 'react'; import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { usePlatformService } from '../../../services'; import { WorkpadRoutingContext } from '..'; +import { coreServices } from '../../../services/kibana_services'; const fullscreenClass = 'canvas-isFullscreen'; export const useFullscreenPresentationHelper = () => { const { isFullscreen } = useContext(WorkpadRoutingContext); - const { setFullscreen } = usePlatformService(); - useEffect(() => { const body = document.querySelector('body'); const bodyClassList = body!.classList; const hasFullscreenClass = bodyClassList.contains(fullscreenClass); if (isFullscreen && !hasFullscreenClass) { - setFullscreen(false); + coreServices.chrome.setIsVisible(false); bodyClassList.add(fullscreenClass); } else if (!isFullscreen && hasFullscreenClass) { bodyClassList.remove(fullscreenClass); - setFullscreen(true); + coreServices.chrome.setIsVisible(true); } - }, [isFullscreen, setFullscreen]); + }, [isFullscreen]); // Remove fullscreen when component unmounts useEffectOnce(() => () => { - setFullscreen(true); + coreServices.chrome.setIsVisible(true); document.querySelector('body')?.classList.remove(fullscreenClass); }); }; diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.test.tsx b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.test.tsx index 0d73fe49601c8..1ba0dacd8c143 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.test.tsx +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.test.tsx @@ -7,6 +7,7 @@ import { renderHook } from '@testing-library/react-hooks'; import { useWorkpad } from './use_workpad'; +import { spacesService } from '../../../services/kibana_services'; const mockDispatch = jest.fn(); const mockSelector = jest.fn(); @@ -25,21 +26,22 @@ const workpadResponse = { assets, }; -// Mock the hooks and actions used by the UseWorkpad hook +// Mock the hooks, actions, and services used by the UseWorkpad hook jest.mock('react-redux', () => ({ useDispatch: () => mockDispatch, useSelector: () => mockSelector, })); -jest.mock('../../../services', () => ({ - useWorkpadService: () => ({ - resolve: mockResolveWorkpad, - }), - usePlatformService: () => ({ - redirectLegacyUrl: mockRedirectLegacyUrl, - }), +jest.mock('../../../services/canvas_workpad_service', () => ({ + getCanvasWorkpadService: () => { + return { + resolve: mockResolveWorkpad, + }; + }, })); +spacesService!.ui.redirectLegacyUrl = mockRedirectLegacyUrl; + jest.mock('../../../state/actions/workpad', () => ({ setWorkpad: (payload: any) => ({ type: 'setWorkpad', diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts index 61908d96828fd..c02432477a840 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts @@ -8,7 +8,6 @@ import { useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { useDispatch, useSelector } from 'react-redux'; -import { useWorkpadService, usePlatformService } from '../../../services'; import { getWorkpad } from '../../../state/selectors/workpad'; import { setWorkpad } from '../../../state/actions/workpad'; // @ts-expect-error @@ -16,7 +15,11 @@ import { setAssets } from '../../../state/actions/assets'; // @ts-expect-error import { setZoomScale } from '../../../state/actions/transient'; import { CanvasWorkpad } from '../../../../types'; -import type { ResolveWorkpadResponse } from '../../../services/workpad'; +import { + ResolveWorkpadResponse, + getCanvasWorkpadService, +} from '../../../services/canvas_workpad_service'; +import { spacesService } from '../../../services/kibana_services'; const getWorkpadLabel = () => i18n.translate('xpack.canvas.workpadResolve.redirectLabel', { @@ -32,9 +35,6 @@ export const useWorkpad = ( loadPages: boolean = true, getRedirectPath: (workpadId: string) => string ): [CanvasWorkpad | undefined, string | Error | undefined] => { - const workpadService = useWorkpadService(); - const workpadResolve = workpadService.resolve; - const platformService = usePlatformService(); const dispatch = useDispatch(); const storedWorkpad = useSelector(getWorkpad); const [error, setError] = useState(undefined); @@ -47,14 +47,12 @@ export const useWorkpad = ( const { workpad: { assets, ...workpad }, ...resolveProps - } = await workpadResolve(workpadId); - + } = await getCanvasWorkpadService().resolve(workpadId); setResolveInfo({ id: workpadId, ...resolveProps }); // If it's an alias match, we know we are going to redirect so don't even dispatch that we got the workpad if (storedWorkpad.id !== workpadId && resolveProps.outcome !== 'aliasMatch') { workpad.aliasId = resolveProps.aliasId; - dispatch(setAssets(assets)); dispatch(setWorkpad(workpad, { loadPages })); dispatch(setZoomScale(1)); @@ -63,7 +61,7 @@ export const useWorkpad = ( setError(e as Error | string); } })(); - }, [workpadId, dispatch, setError, loadPages, workpadResolve, storedWorkpad.id]); + }, [workpadId, dispatch, setError, loadPages, storedWorkpad.id]); useEffect(() => { // If the resolved info is not for the current workpad id, bail out @@ -75,16 +73,16 @@ export const useWorkpad = ( if (!resolveInfo) return; const { aliasId, outcome, aliasPurpose } = resolveInfo; - if (outcome === 'aliasMatch' && platformService.redirectLegacyUrl && aliasId) { + if (outcome === 'aliasMatch' && spacesService && aliasId) { const redirectPath = getRedirectPath(aliasId); - await platformService.redirectLegacyUrl({ + await spacesService.ui.redirectLegacyUrl({ path: `#${redirectPath}`, aliasPurpose, objectNoun: getWorkpadLabel(), }); } })(); - }, [workpadId, resolveInfo, getRedirectPath, platformService]); + }, [workpadId, resolveInfo, getRedirectPath]); return [storedWorkpad.id === workpadId ? storedWorkpad : undefined, error]; }; diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.test.tsx b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.test.tsx index 395cf774760fd..3193ad3dd79e5 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.test.tsx +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.test.tsx @@ -19,12 +19,17 @@ jest.mock('react-redux', () => ({ useSelector: (selector: any) => selector(mockGetState()), })); +jest.mock('../../../services/canvas_workpad_service', () => ({ + getCanvasWorkpadService: () => { + return { + updateWorkpad: mockUpdateWorkpad, + updateAssets: mockUpdateAssets, + update: mockUpdate, + }; + }, +})); + jest.mock('../../../services', () => ({ - useWorkpadService: () => ({ - updateWorkpad: mockUpdateWorkpad, - updateAssets: mockUpdateAssets, - update: mockUpdate, - }), useNotifyService: () => ({ error: mockNotifyError, }), diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.ts index 45e21e59717ad..f0f885c94eabc 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.ts @@ -10,13 +10,10 @@ import { useSelector } from 'react-redux'; import { CanvasWorkpad, State } from '../../../../types'; import { getWorkpad } from '../../../state/selectors/workpad'; import { canUserWrite } from '../../../state/selectors/app'; -import { useWorkpadService, useNotifyService } from '../../../services'; import { notifyError } from '../../../lib/assets'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useWorkpadPersist = () => { - const service = useWorkpadService(); - const notifyService = useNotifyService(); - // Watch for workpad state and then persist those changes const [workpad, canWrite]: [CanvasWorkpad, boolean] = useSelector((state: State) => [ getWorkpad(state), @@ -30,10 +27,12 @@ export const useWorkpadPersist = () => { useEffect(() => { if (canWrite) { if (workpadChanged) { - service.updateWorkpad(workpad.id, workpad).catch((err) => { - notifyError(err, notifyService.error); - }); + getCanvasWorkpadService() + .updateWorkpad(workpad.id, workpad) + .catch((err) => { + notifyError(err); + }); } } - }, [service, workpad, workpadChanged, canWrite, notifyService.error]); + }, [workpad, workpadChanged, canWrite]); }; diff --git a/x-pack/plugins/canvas/public/routes/workpad/workpad_presentation_helper.tsx b/x-pack/plugins/canvas/public/routes/workpad/workpad_presentation_helper.tsx index 0dfb4dd8fbf78..bde100182788e 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/workpad_presentation_helper.tsx +++ b/x-pack/plugins/canvas/public/routes/workpad/workpad_presentation_helper.tsx @@ -14,7 +14,7 @@ import { getWorkpad } from '../../state/selectors/workpad'; import { useFullscreenPresentationHelper } from './hooks/use_fullscreen_presentation_helper'; import { useAutoplayHelper } from './hooks/use_autoplay_helper'; import { useRefreshHelper } from './hooks/use_refresh_helper'; -import { usePlatformService } from '../../services'; +import { coreServices, spacesService } from '../../services/kibana_services'; const getWorkpadLabel = () => i18n.translate('xpack.canvas.workpadConflict.redirectLabel', { @@ -22,7 +22,6 @@ const getWorkpadLabel = () => }); export const WorkpadPresentationHelper: FC> = ({ children }) => { - const platformService = usePlatformService(); const workpad = useSelector(getWorkpad); useFullscreenPresentationHelper(); useAutoplayHelper(); @@ -30,18 +29,18 @@ export const WorkpadPresentationHelper: FC> = ({ chil const history = useHistory(); useEffect(() => { - platformService.setBreadcrumbs([ + coreServices.chrome.setBreadcrumbs([ getBaseBreadcrumb(history), getWorkpadBreadcrumb({ name: workpad.name }), ]); - }, [workpad.name, platformService, history]); + }, [workpad.name, history]); useEffect(() => { setDocTitle(workpad.name || getUntitledWorkpadLabel()); }, [workpad.name, workpad.id]); const conflictElement = workpad.aliasId - ? platformService.getLegacyUrlConflict?.({ + ? spacesService?.ui.components.getLegacyUrlConflict({ objectNoun: getWorkpadLabel(), currentObjectId: workpad.id, otherObjectId: workpad.aliasId, diff --git a/x-pack/plugins/canvas/public/services/canvas_custom_element_service.ts b/x-pack/plugins/canvas/public/services/canvas_custom_element_service.ts new file mode 100644 index 0000000000000..1f0e13d2fbeae --- /dev/null +++ b/x-pack/plugins/canvas/public/services/canvas_custom_element_service.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { API_ROUTE_CUSTOM_ELEMENT } from '../../common/lib'; +import { CustomElement } from '../../types'; +import { coreServices } from './kibana_services'; + +export interface CustomElementFindResponse { + total: number; + customElements: CustomElement[]; +} + +class CanvasCustomElementService { + public apiPath = `${API_ROUTE_CUSTOM_ELEMENT}`; + + public async create(customElement: CustomElement) { + await coreServices.http.post(this.apiPath, { + body: JSON.stringify(customElement), + version: '1', + }); + } + + public async get(customElementId: string): Promise { + return await coreServices.http + .get<{ data: CustomElement }>(`${this.apiPath}/${customElementId}`, { version: '1' }) + .then(({ data: element }) => element); + } + + public async update(id: string, element: Partial) { + await coreServices.http.put(`${this.apiPath}/${id}`, { + body: JSON.stringify(element), + version: '1', + }); + } + + public async remove(id: string) { + await coreServices.http.delete(`${this.apiPath}/${id}`, { version: '1' }); + } + + public async find(searchTerm: string): Promise { + return await coreServices.http.get(`${this.apiPath}/find`, { + query: { + name: searchTerm, + perPage: 10000, + }, + version: '1', + }); + } +} + +let canvasCustomElementService: CanvasCustomElementService; + +export const getCustomElementService = () => { + if (!canvasCustomElementService) { + canvasCustomElementService = new CanvasCustomElementService(); + } + return canvasCustomElementService; +}; diff --git a/x-pack/plugins/canvas/public/services/kibana/expressions.ts b/x-pack/plugins/canvas/public/services/canvas_expressions_service.ts similarity index 65% rename from x-pack/plugins/canvas/public/services/kibana/expressions.ts rename to x-pack/plugins/canvas/public/services/canvas_expressions_service.ts index 248cd462bea90..0621c3e89416c 100644 --- a/x-pack/plugins/canvas/public/services/kibana/expressions.ts +++ b/x-pack/plugins/canvas/public/services/canvas_expressions_service.ts @@ -4,34 +4,29 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { fromExpression, getType } from '@kbn/interpreter'; import { ExpressionAstExpression, ExpressionExecutionParams, ExpressionValue, } from '@kbn/expressions-plugin/common'; +import { fromExpression, getType } from '@kbn/interpreter'; import { pluck } from 'rxjs'; -import { ExpressionsServiceStart } from '@kbn/expressions-plugin/public'; -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { buildEmbeddableFilters } from '../../../common/lib/build_embeddable_filters'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasFiltersService } from './filters'; -import { CanvasNotifyService } from '../notify'; +import { buildEmbeddableFilters } from '../../common/lib/build_embeddable_filters'; +import { expressionsService } from './kibana_services'; +import { getCanvasNotifyService } from './canvas_notify_service'; +import { getCanvasFiltersService } from './canvas_filters_service'; interface Options { castToRender?: boolean; } -export class ExpressionsService { - private filters: CanvasFiltersService; - private notify: CanvasNotifyService; +class ExpressionsService { + private notifyService; + private filtersService; - constructor( - private readonly expressions: ExpressionsServiceStart, - { filters, notify }: CanvasExpressionsServiceRequiredServices - ) { - this.filters = filters; - this.notify = notify; + constructor() { + this.notifyService = getCanvasNotifyService(); + this.filtersService = getCanvasFiltersService(); } async interpretAst( @@ -51,7 +46,7 @@ export class ExpressionsService { input: ExpressionValue = null, context?: ExpressionExecutionParams ): Promise { - return await this.expressions + return await expressionsService .execute(ast, input, { ...context, namespace: 'canvas' }) .getData() .pipe(pluck('result')) @@ -92,22 +87,22 @@ export class ExpressionsService { throw new Error(`Ack! I don't know how to render a '${getType(renderable)}'`); } catch (err) { - this.notify.error(err); + this.notifyService.error(err); throw err; } } getRenderer(name: string) { - return this.expressions.getRenderer(name); + return expressionsService.getRenderer(name); } getFunctions() { - return this.expressions.getFunctions(); + return expressionsService.getFunctions(); } private async getFilters() { - const filtersList = this.filters.getFilters(); - const context = this.filters.getFiltersContext(); + const filtersList = this.filtersService.getFilters(); + const context = this.filtersService.getFiltersContext(); const filterExpression = filtersList.join(' | '); const filterAST = fromExpression(filterExpression); return await this.interpretAstWithContext(filterAST, null, context); @@ -122,19 +117,11 @@ export class ExpressionsService { } } -export type CanvasExpressionsService = ExpressionsService; -export interface CanvasExpressionsServiceRequiredServices { - notify: CanvasNotifyService; - filters: CanvasFiltersService; -} - -export type CanvasExpressionsServiceFactory = KibanaPluginServiceFactory< - CanvasExpressionsService, - CanvasStartDeps, - CanvasExpressionsServiceRequiredServices ->; +let canvasExpressionsService: ExpressionsService; -export const expressionsServiceFactory: CanvasExpressionsServiceFactory = ( - { startPlugins }, - requiredServices -) => new ExpressionsService(startPlugins.expressions, requiredServices); +export const getCanvasExpressionService = () => { + if (!canvasExpressionsService) { + canvasExpressionsService = new ExpressionsService(); + } + return canvasExpressionsService; +}; diff --git a/x-pack/plugins/canvas/public/services/kibana/filters.ts b/x-pack/plugins/canvas/public/services/canvas_filters_service.ts similarity index 51% rename from x-pack/plugins/canvas/public/services/kibana/filters.ts rename to x-pack/plugins/canvas/public/services/canvas_filters_service.ts index 793b073aaf231..e678e9b30963f 100644 --- a/x-pack/plugins/canvas/public/services/kibana/filters.ts +++ b/x-pack/plugins/canvas/public/services/canvas_filters_service.ts @@ -5,25 +5,21 @@ * 2.0. */ -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; // @ts-expect-error untyped local -import { getState, getStore } from '../../state/store'; -import { State } from '../../../types'; -import { getGlobalFilters, getWorkpadVariablesAsObject } from '../../state/selectors/workpad'; -import { CanvasStartDeps } from '../../plugin'; +import { getState, getStore } from '../state/store'; +import { State } from '../../types'; +import { getGlobalFilters, getWorkpadVariablesAsObject } from '../state/selectors/workpad'; // @ts-expect-error untyped local -import { setFilter } from '../../state/actions/elements'; - -export class FiltersService { - constructor() {} +import { setFilter } from '../state/actions/filters'; +class FiltersService { getFilters(state: State = getState()) { return getGlobalFilters(state); } updateFilter(filterId: string, filterExpression: string) { const { dispatch } = getStore(); - dispatch(setFilter(filterExpression, filterId, true)); + dispatch(setFilter(filterExpression, filterId)); } getFiltersContext(state: State = getState()) { @@ -32,11 +28,11 @@ export class FiltersService { } } -export type CanvasFiltersService = FiltersService; - -export type CanvasFiltersServiceFactory = KibanaPluginServiceFactory< - CanvasFiltersService, - CanvasStartDeps ->; +let canvasFiltersService: FiltersService; -export const filtersServiceFactory: CanvasFiltersServiceFactory = () => new FiltersService(); +export const getCanvasFiltersService = () => { + if (!canvasFiltersService) { + canvasFiltersService = new FiltersService(); + } + return canvasFiltersService; +}; diff --git a/x-pack/plugins/canvas/public/services/kibana/notify.ts b/x-pack/plugins/canvas/public/services/canvas_notify_service.ts similarity index 71% rename from x-pack/plugins/canvas/public/services/kibana/notify.ts rename to x-pack/plugins/canvas/public/services/canvas_notify_service.ts index 8448a1d515fe4..1f00190f3fff9 100644 --- a/x-pack/plugins/canvas/public/services/kibana/notify.ts +++ b/x-pack/plugins/canvas/public/services/canvas_notify_service.ts @@ -6,17 +6,10 @@ */ import { get } from 'lodash'; -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; import { ToastInputFields } from '@kbn/core/public'; -import { formatMsg } from '../../lib/format_msg'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasNotifyService } from '../notify'; - -export type CanvasNotifyServiceFactory = KibanaPluginServiceFactory< - CanvasNotifyService, - CanvasStartDeps ->; +import { formatMsg } from '../lib/format_msg'; +import { coreServices } from './kibana_services'; const getToast = (err: Error | string, opts: ToastInputFields = {}) => { const errData = (get(err, 'response') || err) as Error | string; @@ -36,8 +29,15 @@ const getToast = (err: Error | string, opts: ToastInputFields = {}) => { }; }; -export const notifyServiceFactory: CanvasNotifyServiceFactory = ({ coreStart }) => { - const toasts = coreStart.notifications.toasts; +export interface CanvasNotifyService { + error: (err: string | Error, opts?: ToastInputFields) => void; + warning: (err: string | Error, opts?: ToastInputFields) => void; + info: (err: string | Error, opts?: ToastInputFields) => void; + success: (err: string | Error, opts?: ToastInputFields) => void; +} + +export const getCanvasNotifyService = (): CanvasNotifyService => { + const toasts = coreServices.notifications.toasts; return { /* diff --git a/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts b/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts new file mode 100644 index 0000000000000..2672f6ef4a06e --- /dev/null +++ b/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts @@ -0,0 +1,200 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ResolvedSimpleSavedObject, SavedObject } from '@kbn/core/public'; +import { + API_ROUTE_SHAREABLE_ZIP, + API_ROUTE_TEMPLATES, + API_ROUTE_WORKPAD, + API_ROUTE_WORKPAD_ASSETS, + API_ROUTE_WORKPAD_STRUCTURES, + DEFAULT_WORKPAD_CSS, +} from '../../common/lib'; +import type { CanvasRenderedWorkpad } from '../../shareable_runtime/types'; +import { CanvasTemplate, CanvasWorkpad } from '../../types'; +import { coreServices } from './kibana_services'; + +export type FoundWorkpads = Array>; +export type FoundWorkpad = FoundWorkpads[number]; +export interface WorkpadFindResponse { + total: number; + workpads: FoundWorkpads; +} + +export interface TemplateFindResponse { + templates: CanvasTemplate[]; +} + +export interface ResolveWorkpadResponse { + workpad: CanvasWorkpad; + outcome: ResolvedSimpleSavedObject['outcome']; + aliasId?: ResolvedSimpleSavedObject['alias_target_id']; + aliasPurpose?: ResolvedSimpleSavedObject['alias_purpose']; +} + +/* + Remove any top level keys from the workpad which will be rejected by validation +*/ +const validKeys = [ + '@created', + '@timestamp', + 'assets', + 'colors', + 'css', + 'variables', + 'height', + 'id', + 'isWriteable', + 'name', + 'page', + 'pages', + 'width', +]; + +const sanitizeWorkpad = function (workpad: CanvasWorkpad) { + const workpadKeys = Object.keys(workpad); + + for (const key of workpadKeys) { + if (!validKeys.includes(key)) { + delete (workpad as { [key: string]: any })[key]; + } + } + + return workpad; +}; + +class CanvasWorkpadService { + private apiPath = `${API_ROUTE_WORKPAD}`; + + public async get(id: string): Promise { + const workpad = await coreServices.http.get(`${this.apiPath}/${id}`, { version: '1' }); + + return { css: DEFAULT_WORKPAD_CSS, variables: [], ...workpad }; + } + + public async export(id: string) { + const workpad = await coreServices.http.get>( + `${this.apiPath}/export/${id}`, + { version: '1' } + ); + const { attributes } = workpad; + + return { + ...workpad, + attributes: { + ...attributes, + css: attributes.css ?? DEFAULT_WORKPAD_CSS, + variables: attributes.variables ?? [], + }, + }; + } + + public async resolve(id: string): Promise { + const { workpad, ...resolveProps } = await coreServices.http.get( + `${this.apiPath}/resolve/${id}`, + { version: '1' } + ); + + return { + ...resolveProps, + workpad: { + // @ts-ignore: Shimming legacy workpads that might not have CSS + css: DEFAULT_WORKPAD_CSS, + // @ts-ignore: Shimming legacy workpads that might not have variables + variables: [], + ...workpad, + }, + }; + } + + public async create(workpad: CanvasWorkpad): Promise { + return coreServices.http.post(this.apiPath, { + body: JSON.stringify({ + ...sanitizeWorkpad({ ...workpad }), + assets: workpad.assets || {}, + variables: workpad.variables || [], + }), + version: '1', + }); + } + + public async import(workpad: CanvasWorkpad): Promise { + return coreServices.http.post(`${this.apiPath}/import`, { + body: JSON.stringify({ + ...sanitizeWorkpad({ ...workpad }), + assets: workpad.assets || {}, + variables: workpad.variables || [], + }), + version: '1', + }); + } + + public async createFromTemplate(templateId: string): Promise { + return coreServices.http.post(this.apiPath, { + body: JSON.stringify({ templateId }), + version: '1', + }); + } + + public async findTemplates(): Promise { + return coreServices.http.get(API_ROUTE_TEMPLATES, { version: '1' }); + } + + public async find(searchTerm: string): Promise { + // TODO: this shouldn't be necessary. Check for usage. + const validSearchTerm = typeof searchTerm === 'string' && searchTerm.length > 0; + + return coreServices.http.get(`${this.apiPath}/find`, { + query: { + perPage: 10000, + name: validSearchTerm ? searchTerm : '', + }, + version: '1', + }); + } + + public async remove(id: string) { + coreServices.http.delete(`${this.apiPath}/${id}`, { version: '1' }); + } + + public async update(id: string, workpad: CanvasWorkpad) { + coreServices.http.put(`${this.apiPath}/${id}`, { + body: JSON.stringify({ ...sanitizeWorkpad({ ...workpad }) }), + version: '1', + }); + } + + public async updateWorkpad(id: string, workpad: CanvasWorkpad) { + coreServices.http.put(`${API_ROUTE_WORKPAD_STRUCTURES}/${id}`, { + body: JSON.stringify({ ...sanitizeWorkpad({ ...workpad }) }), + version: '1', + }); + } + + public async updateAssets(id: string, assets: CanvasWorkpad['assets']) { + coreServices.http.put(`${API_ROUTE_WORKPAD_ASSETS}/${id}`, { + body: JSON.stringify(assets), + version: '1', + }); + } + + public async getRuntimeZip(workpad: CanvasRenderedWorkpad): Promise { + return coreServices.http.post(API_ROUTE_SHAREABLE_ZIP, { + body: JSON.stringify(workpad), + version: '1', + }); + } +} + +let canvasWorkpadService: CanvasWorkpadService; + +export const getCanvasWorkpadService: () => CanvasWorkpadService = () => { + if (!canvasWorkpadService) { + canvasWorkpadService = new CanvasWorkpadService(); + } + return canvasWorkpadService; +}; diff --git a/x-pack/plugins/canvas/public/services/custom_element.ts b/x-pack/plugins/canvas/public/services/custom_element.ts deleted file mode 100644 index 675a5a2f23c01..0000000000000 --- a/x-pack/plugins/canvas/public/services/custom_element.ts +++ /dev/null @@ -1,21 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CustomElement } from '../../types'; - -export interface CustomElementFindResponse { - total: number; - customElements: CustomElement[]; -} - -export interface CanvasCustomElementService { - create: (customElement: CustomElement) => Promise; - get: (customElementId: string) => Promise; - update: (id: string, element: Partial) => Promise; - remove: (id: string) => Promise; - find: (searchTerm: string) => Promise; -} diff --git a/x-pack/plugins/canvas/public/services/data_views.ts b/x-pack/plugins/canvas/public/services/data_views.ts deleted file mode 100644 index 86faa87bfaa59..0000000000000 --- a/x-pack/plugins/canvas/public/services/data_views.ts +++ /dev/null @@ -1,14 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DataView } from '@kbn/data-views-plugin/common'; - -export interface CanvasDataViewsService { - getFields: (index: string) => Promise; - getDataViews: () => Promise>>; - getDefaultDataView: () => Promise | undefined>; -} diff --git a/x-pack/plugins/canvas/public/services/embeddables.ts b/x-pack/plugins/canvas/public/services/embeddables.ts deleted file mode 100644 index b8f3d7d14b5e5..0000000000000 --- a/x-pack/plugins/canvas/public/services/embeddables.ts +++ /dev/null @@ -1,22 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EmbeddableFactory, - type EmbeddableStateTransfer, - ReactEmbeddableSavedObject, -} from '@kbn/embeddable-plugin/public'; -import { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common'; - -export interface CanvasEmbeddablesService { - reactEmbeddableRegistryHasKey: (key: string) => boolean; - getReactEmbeddableSavedObjects: < - TSavedObjectAttributes extends FinderAttributes - >() => IterableIterator<[string, ReactEmbeddableSavedObject]>; - getEmbeddableFactories: () => IterableIterator; - getStateTransfer: () => EmbeddableStateTransfer; -} diff --git a/x-pack/plugins/canvas/public/services/expressions.ts b/x-pack/plugins/canvas/public/services/expressions.ts deleted file mode 100644 index 456a1314bdfff..0000000000000 --- a/x-pack/plugins/canvas/public/services/expressions.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type { CanvasExpressionsService } from './kibana/expressions'; diff --git a/x-pack/plugins/canvas/public/services/filters.ts b/x-pack/plugins/canvas/public/services/filters.ts deleted file mode 100644 index 1ced3d15f6e10..0000000000000 --- a/x-pack/plugins/canvas/public/services/filters.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type { CanvasFiltersService } from './kibana/filters'; diff --git a/x-pack/plugins/canvas/public/services/index.ts b/x-pack/plugins/canvas/public/services/index.ts index dd035fcd3b1ad..92b5f0ef3936a 100644 --- a/x-pack/plugins/canvas/public/services/index.ts +++ b/x-pack/plugins/canvas/public/services/index.ts @@ -6,55 +6,11 @@ */ export * from './legacy'; +import { useMemo } from 'react'; -import { PluginServices } from '@kbn/presentation-util-plugin/public'; +import { getCanvasNotifyService } from './canvas_notify_service'; -import { CanvasCustomElementService } from './custom_element'; -import { CanvasDataViewsService } from './data_views'; -import { CanvasEmbeddablesService } from './embeddables'; -import { CanvasExpressionsService } from './expressions'; -import { CanvasFiltersService } from './filters'; -import { CanvasLabsService } from './labs'; -import { CanvasNavLinkService } from './nav_link'; -import { CanvasNotifyService } from './notify'; -import { CanvasPlatformService } from './platform'; -import { CanvasReportingService } from './reporting'; -import { CanvasVisualizationsService } from './visualizations'; -import { CanvasWorkpadService } from './workpad'; -import { CanvasUiActionsService } from './ui_actions'; - -export interface CanvasPluginServices { - customElement: CanvasCustomElementService; - dataViews: CanvasDataViewsService; - embeddables: CanvasEmbeddablesService; - expressions: CanvasExpressionsService; - filters: CanvasFiltersService; - labs: CanvasLabsService; - navLink: CanvasNavLinkService; - notify: CanvasNotifyService; - platform: CanvasPlatformService; - reporting: CanvasReportingService; - visualizations: CanvasVisualizationsService; - workpad: CanvasWorkpadService; - uiActions: CanvasUiActionsService; -} - -export const pluginServices = new PluginServices(); - -export const useCustomElementService = () => - (() => pluginServices.getHooks().customElement.useService())(); -export const useDataViewsService = () => (() => pluginServices.getHooks().dataViews.useService())(); -export const useEmbeddablesService = () => - (() => pluginServices.getHooks().embeddables.useService())(); -export const useExpressionsService = () => - (() => pluginServices.getHooks().expressions.useService())(); -export const useFiltersService = () => (() => pluginServices.getHooks().filters.useService())(); -export const useLabsService = () => (() => pluginServices.getHooks().labs.useService())(); -export const useNavLinkService = () => (() => pluginServices.getHooks().navLink.useService())(); -export const useNotifyService = () => (() => pluginServices.getHooks().notify.useService())(); -export const usePlatformService = () => (() => pluginServices.getHooks().platform.useService())(); -export const useReportingService = () => (() => pluginServices.getHooks().reporting.useService())(); -export const useVisualizationsService = () => - (() => pluginServices.getHooks().visualizations.useService())(); -export const useWorkpadService = () => (() => pluginServices.getHooks().workpad.useService())(); -export const useUiActionsService = () => (() => pluginServices.getHooks().uiActions.useService())(); +export const useNotifyService = () => { + const canvasNotifyService = useMemo(() => getCanvasNotifyService(), []); + return canvasNotifyService; +}; diff --git a/x-pack/plugins/canvas/public/services/kibana/custom_element.ts b/x-pack/plugins/canvas/public/services/kibana/custom_element.ts deleted file mode 100644 index a548ccdc23b2f..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/custom_element.ts +++ /dev/null @@ -1,44 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { API_ROUTE_CUSTOM_ELEMENT } from '../../../common/lib/constants'; -import { CustomElement } from '../../../types'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasCustomElementService } from '../custom_element'; - -export type CanvasCustomElementServiceFactory = KibanaPluginServiceFactory< - CanvasCustomElementService, - CanvasStartDeps ->; - -export const customElementServiceFactory: CanvasCustomElementServiceFactory = ({ coreStart }) => { - const { http } = coreStart; - const apiPath = `${API_ROUTE_CUSTOM_ELEMENT}`; - - return { - create: (customElement) => - http.post(apiPath, { body: JSON.stringify(customElement), version: '1' }), - get: (customElementId) => - http - .get<{ data: CustomElement }>(`${apiPath}/${customElementId}`, { version: '1' }) - .then(({ data: element }) => element), - update: (id, element) => - http.put(`${apiPath}/${id}`, { body: JSON.stringify(element), version: '1' }), - remove: (id) => http.delete(`${apiPath}/${id}`, { version: '1' }), - find: async (name) => { - return http.get(`${apiPath}/find`, { - query: { - name, - perPage: 10000, - }, - version: '1', - }); - }, - }; -}; diff --git a/x-pack/plugins/canvas/public/services/kibana/data_views.ts b/x-pack/plugins/canvas/public/services/kibana/data_views.ts deleted file mode 100644 index 27ec0bb1c5fc6..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/data_views.ts +++ /dev/null @@ -1,50 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DataView } from '@kbn/data-views-plugin/public'; -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { ErrorStrings } from '../../../i18n'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasDataViewsService } from '../data_views'; -import { CanvasNotifyService } from '../notify'; - -const { esService: strings } = ErrorStrings; - -export type DataViewsServiceFactory = KibanaPluginServiceFactory< - CanvasDataViewsService, - CanvasStartDeps, - { - notify: CanvasNotifyService; - } ->; - -export const dataViewsServiceFactory: DataViewsServiceFactory = ({ startPlugins }, { notify }) => ({ - getDataViews: async () => { - try { - const dataViews = await startPlugins.dataViews.getIdsWithTitle(); - return dataViews.map(({ id, name, title }) => ({ id, name, title } as DataView)); - } catch (e) { - notify.error(e, { title: strings.getIndicesFetchErrorMessage() }); - } - - return []; - }, - getFields: async (dataViewTitle: string) => { - const dataView = await startPlugins.dataViews.create({ title: dataViewTitle }); - - return dataView.fields - .filter((field) => !field.name.startsWith('_')) - .map((field) => field.name); - }, - getDefaultDataView: async () => { - const dataView = await startPlugins.dataViews.getDefaultDataView(); - - return dataView - ? { id: dataView.id, name: dataView.name, title: dataView.getIndexPattern() } - : undefined; - }, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts b/x-pack/plugins/canvas/public/services/kibana/embeddables.ts deleted file mode 100644 index 20f6f3feec8a4..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts +++ /dev/null @@ -1,22 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasEmbeddablesService } from '../embeddables'; - -export type EmbeddablesServiceFactory = KibanaPluginServiceFactory< - CanvasEmbeddablesService, - CanvasStartDeps ->; - -export const embeddablesServiceFactory: EmbeddablesServiceFactory = ({ startPlugins }) => ({ - reactEmbeddableRegistryHasKey: startPlugins.embeddable.reactEmbeddableRegistryHasKey, - getReactEmbeddableSavedObjects: startPlugins.embeddable.getReactEmbeddableSavedObjects, - getEmbeddableFactories: startPlugins.embeddable.getEmbeddableFactories, - getStateTransfer: startPlugins.embeddable.getStateTransfer, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/index.ts b/x-pack/plugins/canvas/public/services/kibana/index.ts deleted file mode 100644 index cab569133f70f..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/index.ts +++ /dev/null @@ -1,66 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - PluginServiceProviders, - PluginServiceProvider, - PluginServiceRegistry, - KibanaPluginServiceParams, -} from '@kbn/presentation-util-plugin/public'; - -import { CanvasPluginServices } from '..'; -import { CanvasStartDeps } from '../../plugin'; -import { customElementServiceFactory } from './custom_element'; -import { dataViewsServiceFactory } from './data_views'; -import { embeddablesServiceFactory } from './embeddables'; -import { expressionsServiceFactory } from './expressions'; -import { labsServiceFactory } from './labs'; -import { navLinkServiceFactory } from './nav_link'; -import { notifyServiceFactory } from './notify'; -import { platformServiceFactory } from './platform'; -import { reportingServiceFactory } from './reporting'; -import { visualizationsServiceFactory } from './visualizations'; -import { workpadServiceFactory } from './workpad'; -import { filtersServiceFactory } from './filters'; -import { uiActionsServiceFactory } from './ui_actions'; - -export { customElementServiceFactory } from './custom_element'; -export { dataViewsServiceFactory } from './data_views'; -export { embeddablesServiceFactory } from './embeddables'; -export { expressionsServiceFactory } from './expressions'; -export { filtersServiceFactory } from './filters'; -export { labsServiceFactory } from './labs'; -export { notifyServiceFactory } from './notify'; -export { platformServiceFactory } from './platform'; -export { reportingServiceFactory } from './reporting'; -export { visualizationsServiceFactory } from './visualizations'; -export { workpadServiceFactory } from './workpad'; -export { uiActionsServiceFactory } from './ui_actions'; - -export const pluginServiceProviders: PluginServiceProviders< - CanvasPluginServices, - KibanaPluginServiceParams -> = { - customElement: new PluginServiceProvider(customElementServiceFactory), - dataViews: new PluginServiceProvider(dataViewsServiceFactory, ['notify']), - embeddables: new PluginServiceProvider(embeddablesServiceFactory), - expressions: new PluginServiceProvider(expressionsServiceFactory, ['filters', 'notify']), - filters: new PluginServiceProvider(filtersServiceFactory), - labs: new PluginServiceProvider(labsServiceFactory), - navLink: new PluginServiceProvider(navLinkServiceFactory), - notify: new PluginServiceProvider(notifyServiceFactory), - platform: new PluginServiceProvider(platformServiceFactory), - reporting: new PluginServiceProvider(reportingServiceFactory), - visualizations: new PluginServiceProvider(visualizationsServiceFactory), - workpad: new PluginServiceProvider(workpadServiceFactory), - uiActions: new PluginServiceProvider(uiActionsServiceFactory), -}; - -export const pluginServiceRegistry = new PluginServiceRegistry< - CanvasPluginServices, - KibanaPluginServiceParams ->(pluginServiceProviders); diff --git a/x-pack/plugins/canvas/public/services/kibana/labs.ts b/x-pack/plugins/canvas/public/services/kibana/labs.ts deleted file mode 100644 index 69613ae67fd85..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/labs.ts +++ /dev/null @@ -1,23 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { projectIDs } from '@kbn/presentation-util-plugin/common'; -import { UI_SETTINGS } from '../../../common'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasLabsService } from '../labs'; - -export type CanvasLabsServiceFactory = KibanaPluginServiceFactory< - CanvasLabsService, - CanvasStartDeps ->; - -export const labsServiceFactory: CanvasLabsServiceFactory = ({ startPlugins, coreStart }) => ({ - projectIDs, - isLabsEnabled: () => coreStart.uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI), - ...startPlugins.presentationUtil.labsService, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/nav_link.ts b/x-pack/plugins/canvas/public/services/kibana/nav_link.ts deleted file mode 100644 index 8470c688f5b2b..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/nav_link.ts +++ /dev/null @@ -1,28 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { SESSIONSTORAGE_LASTPATH } from '../../../common/lib/constants'; -import { getSessionStorage } from '../../lib/storage'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasNavLinkService } from '../nav_link'; - -export type CanvasNavLinkServiceFactory = KibanaPluginServiceFactory< - CanvasNavLinkService, - CanvasStartDeps ->; - -export const navLinkServiceFactory: CanvasNavLinkServiceFactory = ({ coreStart, appUpdater }) => ({ - updatePath: (path: string) => { - appUpdater?.next(() => ({ - defaultPath: `${path}`, - })); - - getSessionStorage().set(`${SESSIONSTORAGE_LASTPATH}:${coreStart.http.basePath.get()}`, path); - }, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/platform.ts b/x-pack/plugins/canvas/public/services/kibana/platform.ts deleted file mode 100644 index 1518280ab0688..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/platform.ts +++ /dev/null @@ -1,46 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasStartDeps } from '../../plugin'; -import { CanvasPlatformService } from '../platform'; - -export type CanvaPlatformServiceFactory = KibanaPluginServiceFactory< - CanvasPlatformService, - CanvasStartDeps ->; - -export const platformServiceFactory: CanvaPlatformServiceFactory = ({ - coreStart, - initContext, - startPlugins, -}) => { - if (!initContext) { - throw new Error('Canvas platform service requires init context'); - } - - return { - getBasePath: coreStart.http.basePath.get, - getBasePathInterface: () => coreStart.http.basePath, - getElasticWebsiteUrl: () => coreStart.docLinks.ELASTIC_WEBSITE_URL, - getDocLinkVersion: () => coreStart.docLinks.DOC_LINK_VERSION, - getKibanaVersion: () => initContext.env.packageInfo.version, - // TODO: is there a better type for this? The capabilities type allows for a Record, - // though we don't do this. So this cast may be the best option. - getHasWriteAccess: () => coreStart.application.capabilities.canvas.save as boolean, - getUISetting: coreStart.uiSettings.get.bind(coreStart.uiSettings), - hasHeaderBanner$: coreStart.chrome.hasHeaderBanner$, - setBreadcrumbs: coreStart.chrome.setBreadcrumbs, - setRecentlyAccessed: coreStart.chrome.recentlyAccessed.add, - setFullscreen: coreStart.chrome.setIsVisible, - redirectLegacyUrl: startPlugins.spaces?.ui.redirectLegacyUrl, - getLegacyUrlConflict: startPlugins.spaces?.ui.components.getLegacyUrlConflict, - getUISettings: () => coreStart.uiSettings, - getHttp: () => coreStart.http, - getContentManagement: () => startPlugins.contentManagement, - }; -}; diff --git a/x-pack/plugins/canvas/public/services/kibana/reporting.ts b/x-pack/plugins/canvas/public/services/kibana/reporting.ts deleted file mode 100644 index 56b9b91e45fc6..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/reporting.ts +++ /dev/null @@ -1,45 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasStartDeps } from '../../plugin'; -import { CanvasReportingService } from '../reporting'; - -export type CanvasReportingServiceFactory = KibanaPluginServiceFactory< - CanvasReportingService, - CanvasStartDeps ->; - -export const reportingServiceFactory: CanvasReportingServiceFactory = ({ - startPlugins, - coreStart, -}) => { - const { reporting } = startPlugins; - - const reportingEnabled = () => ({ - getReportingPanelPDFComponent: () => reporting?.components.ReportingPanelPDFV2 || null, - }); - const reportingDisabled = () => ({ getReportingPanelPDFComponent: () => null }); - - if (!reporting) { - // Reporting is not enabled - return reportingDisabled(); - } - - if (reporting.usesUiCapabilities()) { - if (coreStart.application.capabilities.canvas?.generatePdf === true) { - // Canvas has declared Reporting as a subfeature with the `generatePdf` UI Capability - return reportingEnabled(); - } else { - return reportingDisabled(); - } - } - - // Legacy/Deprecated: Reporting is enabled as an Elasticsearch feature - return reportingEnabled(); -}; diff --git a/x-pack/plugins/canvas/public/services/kibana/ui_actions.ts b/x-pack/plugins/canvas/public/services/kibana/ui_actions.ts deleted file mode 100644 index bb621206082d1..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/ui_actions.ts +++ /dev/null @@ -1,19 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasUiActionsService } from '../ui_actions'; - -export type UiActionsServiceFactory = KibanaPluginServiceFactory< - CanvasUiActionsService, - CanvasStartDeps ->; - -export const uiActionsServiceFactory: UiActionsServiceFactory = ({ startPlugins }) => ({ - getTriggerCompatibleActions: startPlugins.uiActions.getTriggerCompatibleActions, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/visualizations.ts b/x-pack/plugins/canvas/public/services/kibana/visualizations.ts deleted file mode 100644 index 6f1728953ee8e..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/visualizations.ts +++ /dev/null @@ -1,21 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasVisualizationsService } from '../visualizations'; - -export type VisualizationsServiceFactory = KibanaPluginServiceFactory< - CanvasVisualizationsService, - CanvasStartDeps ->; - -export const visualizationsServiceFactory: VisualizationsServiceFactory = ({ startPlugins }) => ({ - showNewVisModal: startPlugins.visualizations.showNewVisModal, - getByGroup: startPlugins.visualizations.getByGroup, - getAliases: startPlugins.visualizations.getAliases, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/workpad.ts b/x-pack/plugins/canvas/public/services/kibana/workpad.ts deleted file mode 100644 index 3b70244440cc8..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/workpad.ts +++ /dev/null @@ -1,170 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SavedObject } from '@kbn/core/public'; -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasStartDeps } from '../../plugin'; -import { CanvasWorkpadService, ResolveWorkpadResponse } from '../workpad'; - -import { - API_ROUTE_WORKPAD, - DEFAULT_WORKPAD_CSS, - API_ROUTE_TEMPLATES, - API_ROUTE_WORKPAD_ASSETS, - API_ROUTE_WORKPAD_STRUCTURES, - API_ROUTE_SHAREABLE_ZIP, -} from '../../../common/lib/constants'; -import { CanvasWorkpad } from '../../../types'; - -export type CanvasWorkpadServiceFactory = KibanaPluginServiceFactory< - CanvasWorkpadService, - CanvasStartDeps ->; - -/* - Remove any top level keys from the workpad which will be rejected by validation -*/ -const validKeys = [ - '@created', - '@timestamp', - 'assets', - 'colors', - 'css', - 'variables', - 'height', - 'id', - 'isWriteable', - 'name', - 'page', - 'pages', - 'width', -]; - -const sanitizeWorkpad = function (workpad: CanvasWorkpad) { - const workpadKeys = Object.keys(workpad); - - for (const key of workpadKeys) { - if (!validKeys.includes(key)) { - delete (workpad as { [key: string]: any })[key]; - } - } - - return workpad; -}; - -export const workpadServiceFactory: CanvasWorkpadServiceFactory = ({ coreStart, startPlugins }) => { - const getApiPath = function () { - return `${API_ROUTE_WORKPAD}`; - }; - - return { - get: async (id: string) => { - const workpad = await coreStart.http.get(`${getApiPath()}/${id}`, { version: '1' }); - - return { css: DEFAULT_WORKPAD_CSS, variables: [], ...workpad }; - }, - export: async (id: string) => { - const workpad = await coreStart.http.get>( - `${getApiPath()}/export/${id}`, - { version: '1' } - ); - const { attributes } = workpad; - - return { - ...workpad, - attributes: { - ...attributes, - css: attributes.css ?? DEFAULT_WORKPAD_CSS, - variables: attributes.variables ?? [], - }, - }; - }, - resolve: async (id: string) => { - const { workpad, ...resolveProps } = await coreStart.http.get( - `${getApiPath()}/resolve/${id}`, - { version: '1' } - ); - - return { - ...resolveProps, - workpad: { - // @ts-ignore: Shimming legacy workpads that might not have CSS - css: DEFAULT_WORKPAD_CSS, - // @ts-ignore: Shimming legacy workpads that might not have variables - variables: [], - ...workpad, - }, - }; - }, - create: (workpad: CanvasWorkpad) => { - return coreStart.http.post(getApiPath(), { - body: JSON.stringify({ - ...sanitizeWorkpad({ ...workpad }), - assets: workpad.assets || {}, - variables: workpad.variables || [], - }), - version: '1', - }); - }, - import: (workpad: CanvasWorkpad) => - coreStart.http.post(`${getApiPath()}/import`, { - body: JSON.stringify({ - ...sanitizeWorkpad({ ...workpad }), - assets: workpad.assets || {}, - variables: workpad.variables || [], - }), - version: '1', - }), - createFromTemplate: (templateId: string) => { - return coreStart.http.post(getApiPath(), { - body: JSON.stringify({ templateId }), - version: '1', - }); - }, - findTemplates: async () => coreStart.http.get(API_ROUTE_TEMPLATES, { version: '1' }), - find: (searchTerm: string) => { - // TODO: this shouldn't be necessary. Check for usage. - const validSearchTerm = typeof searchTerm === 'string' && searchTerm.length > 0; - - return coreStart.http.get(`${getApiPath()}/find`, { - query: { - perPage: 10000, - name: validSearchTerm ? searchTerm : '', - }, - version: '1', - }); - }, - remove: (id: string) => { - return coreStart.http.delete(`${getApiPath()}/${id}`, { version: '1' }); - }, - update: (id, workpad) => { - return coreStart.http.put(`${getApiPath()}/${id}`, { - body: JSON.stringify({ ...sanitizeWorkpad({ ...workpad }) }), - version: '1', - }); - }, - updateWorkpad: (id, workpad) => { - return coreStart.http.put(`${API_ROUTE_WORKPAD_STRUCTURES}/${id}`, { - body: JSON.stringify({ ...sanitizeWorkpad({ ...workpad }) }), - version: '1', - }); - }, - updateAssets: (id, assets) => { - return coreStart.http.put(`${API_ROUTE_WORKPAD_ASSETS}/${id}`, { - body: JSON.stringify(assets), - version: '1', - }); - }, - getRuntimeZip: (workpad) => { - return coreStart.http.post(API_ROUTE_SHAREABLE_ZIP, { - body: JSON.stringify(workpad), - version: '1', - }); - }, - }; -}; diff --git a/x-pack/plugins/canvas/public/services/kibana_services.ts b/x-pack/plugins/canvas/public/services/kibana_services.ts new file mode 100644 index 0000000000000..2b966e698a874 --- /dev/null +++ b/x-pack/plugins/canvas/public/services/kibana_services.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BehaviorSubject } from 'rxjs'; + +import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import type { CoreStart, PluginInitializerContext } from '@kbn/core/public'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { EmbeddableStart } from '@kbn/embeddable-plugin/public/plugin'; +import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; +import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; +import type { ReportingStart } from '@kbn/reporting-plugin/public'; +import type { SpacesApi } from '@kbn/spaces-plugin/public'; +import type { UiActionsPublicStart } from '@kbn/ui-actions-plugin/public/plugin'; +import type { VisualizationsStart } from '@kbn/visualizations-plugin/public'; + +import type { CanvasStartDeps } from '../plugin'; + +export let kibanaVersion: string; + +export let coreServices: CoreStart; +export let contentManagementService: ContentManagementPublicStart; +export let dataService: DataPublicPluginStart; +export let dataViewsService: DataViewsPublicPluginStart; +export let embeddableService: EmbeddableStart; +export let expressionsService: ExpressionsStart; +export let presentationUtilService: PresentationUtilPluginStart; +export let reportingService: ReportingStart | undefined; +export let spacesService: SpacesApi | undefined; +export let uiActionsService: UiActionsPublicStart; +export let visualizationsService: VisualizationsStart; + +const servicesReady$ = new BehaviorSubject(false); + +export const setKibanaServices = ( + kibanaCore: CoreStart, + deps: CanvasStartDeps, + initContext: PluginInitializerContext +) => { + kibanaVersion = initContext.env.packageInfo.version; + + coreServices = kibanaCore; + contentManagementService = deps.contentManagement; + dataService = deps.data; + dataViewsService = deps.dataViews; + embeddableService = deps.embeddable; + expressionsService = deps.expressions; + presentationUtilService = deps.presentationUtil; + reportingService = Boolean( + deps.reporting?.usesUiCapabilities() && !kibanaCore.application.capabilities.canvas?.generatePdf + ) + ? undefined + : deps.reporting; + spacesService = deps.spaces; + uiActionsService = deps.uiActions; + visualizationsService = deps.visualizations; + + servicesReady$.next(true); +}; + +export const untilPluginStartServicesReady = () => { + if (servicesReady$.value) return Promise.resolve(); + return new Promise((resolve) => { + const subscription = servicesReady$.subscribe((isInitialized) => { + if (isInitialized) { + subscription.unsubscribe(); + resolve(); + } + }); + }); +}; diff --git a/x-pack/plugins/canvas/public/services/labs.ts b/x-pack/plugins/canvas/public/services/labs.ts deleted file mode 100644 index 0f20e25f31d60..0000000000000 --- a/x-pack/plugins/canvas/public/services/labs.ts +++ /dev/null @@ -1,14 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PresentationLabsService } from '@kbn/presentation-util-plugin/public'; -import { projectIDs } from '@kbn/presentation-util-plugin/common'; - -export interface CanvasLabsService extends PresentationLabsService { - projectIDs: typeof projectIDs; - isLabsEnabled: () => boolean; -} diff --git a/x-pack/plugins/canvas/public/services/legacy/reporting.ts b/x-pack/plugins/canvas/public/services/legacy/reporting.ts deleted file mode 100644 index 411a892baed29..0000000000000 --- a/x-pack/plugins/canvas/public/services/legacy/reporting.ts +++ /dev/null @@ -1,42 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReportingStart } from '@kbn/reporting-plugin/public'; -import { CanvasServiceFactory } from '.'; - -export interface ReportingService { - start?: ReportingStart; -} - -export const reportingServiceFactory: CanvasServiceFactory = ( - _coreSetup, - coreStart, - _setupPlugins, - startPlugins -): ReportingService => { - const { reporting } = startPlugins; - - const reportingEnabled = () => ({ start: reporting }); - const reportingDisabled = () => ({ start: undefined }); - - if (!reporting) { - // Reporting is not enabled - return reportingDisabled(); - } - - if (reporting.usesUiCapabilities()) { - if (coreStart.application.capabilities.canvas?.generatePdf === true) { - // Canvas has declared Reporting as a subfeature with the `generatePdf` UI Capability - return reportingEnabled(); - } else { - return reportingDisabled(); - } - } - - // Legacy/Deprecated: Reporting is enabled as an Elasticsearch feature - return reportingEnabled(); -}; diff --git a/x-pack/plugins/canvas/public/services/mocks.ts b/x-pack/plugins/canvas/public/services/mocks.ts new file mode 100644 index 0000000000000..c35d8834253be --- /dev/null +++ b/x-pack/plugins/canvas/public/services/mocks.ts @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import moment from 'moment'; + +import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; +import { CoreStart } from '@kbn/core/public'; +import { coreMock } from '@kbn/core/public/mocks'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; +import { expressionsPluginMock } from '@kbn/expressions-plugin/public/mocks'; +import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks'; +import { presentationUtilPluginMock } from '@kbn/presentation-util-plugin/public/mocks'; +import { reportingPluginMock } from '@kbn/reporting-plugin/public/mocks'; +import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; +import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; +import { visualizationsPluginMock } from '@kbn/visualizations-plugin/public/mocks'; + +import { setKibanaServices } from './kibana_services'; +import { getId } from '../lib/get_id'; +// @ts-expect-error +import { getDefaultWorkpad } from '../state/defaults'; + +const setDefaultPresentationUtilCapabilities = (core: CoreStart) => { + core.application.capabilities = { + ...core.application.capabilities, + dashboard: { + show: true, + createNew: true, + }, + visualize: { + save: true, + }, + advancedSettings: { + save: true, + }, + }; +}; + +export const setStubKibanaServices = () => { + const core: CoreStart = coreMock.createStart(); + + setDefaultPresentationUtilCapabilities(core); + setKibanaServices( + core, + { + charts: chartPluginMock.createStartContract(), + contentManagement: contentManagementMock.createStartContract(), + data: dataPluginMock.createStartContract(), + dataViews: dataViewPluginMocks.createStartContract(), + embeddable: embeddablePluginMock.createStartContract(), + expressions: expressionsPluginMock.createStartContract(), + inspector: inspectorPluginMock.createStartContract(), + presentationUtil: presentationUtilPluginMock.createStartContract(), + reporting: reportingPluginMock.createStartContract(), + spaces: spacesPluginMock.createStartContract(), + uiActions: uiActionsPluginMock.createStartContract(), + visualizations: visualizationsPluginMock.createStartContract(), + }, + coreMock.createPluginInitializerContext() + ); +}; + +const TIMEOUT = 500; + +export const getSomeWorkpads = (count = 3, useStaticData = false) => { + if (useStaticData) { + const DAY = 86400000; + const JAN_1_2000 = 946684800000; + + const workpads = []; + for (let i = 0; i < count; i++) { + workpads[i] = { + ...getDefaultWorkpad(), + name: `Workpad ${i}`, + id: `workpad-${i}`, + '@created': moment(JAN_1_2000 + DAY * i).toDate(), + '@timestamp': moment(JAN_1_2000 + DAY * (i + 1)).toDate(), + }; + } + return workpads; + } else { + return Array.from({ length: count }, () => ({ + '@created': getRandomDate( + moment().subtract(3, 'days').toDate(), + moment().subtract(10, 'days').toDate() + ), + '@timestamp': getRandomDate(), + id: getId('workpad'), + name: getRandomName(), + })); + } +}; + +export const findSomeWorkpads = + (count = 3, useStaticData = false, timeout = TIMEOUT) => + (_term: string) => { + return Promise.resolve() + .then(promiseTimeout(timeout)) + .then(() => ({ + total: count, + workpads: getSomeWorkpads(count, useStaticData), + })); + }; + +const promiseTimeout = (time: number) => () => new Promise((resolve) => setTimeout(resolve, time)); + +const getRandomName = () => { + const lorem = + 'Lorem ipsum dolor sit amet consectetur adipiscing elit Fusce lobortis aliquet arcu ut turpis duis'.split( + ' ' + ); + return [1, 2, 3].map(() => lorem[Math.floor(Math.random() * lorem.length)]).join(' '); +}; + +const getRandomDate = ( + start: Date = moment().toDate(), + end: Date = moment().subtract(7, 'days').toDate() +) => new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toISOString(); diff --git a/x-pack/plugins/canvas/public/services/notify.ts b/x-pack/plugins/canvas/public/services/notify.ts deleted file mode 100644 index 83e7b4e71ee72..0000000000000 --- a/x-pack/plugins/canvas/public/services/notify.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ToastInputFields } from '@kbn/core/public'; - -export interface CanvasNotifyService { - error: (err: string | Error, opts?: ToastInputFields) => void; - warning: (err: string | Error, opts?: ToastInputFields) => void; - info: (err: string | Error, opts?: ToastInputFields) => void; - success: (err: string | Error, opts?: ToastInputFields) => void; -} diff --git a/x-pack/plugins/canvas/public/services/platform.ts b/x-pack/plugins/canvas/public/services/platform.ts deleted file mode 100644 index 555f8643fff9b..0000000000000 --- a/x-pack/plugins/canvas/public/services/platform.ts +++ /dev/null @@ -1,37 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Observable } from 'rxjs'; -import { - IUiSettingsClient, - ChromeBreadcrumb, - IBasePath, - ChromeStart, - HttpStart, -} from '@kbn/core/public'; - -import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; -import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; - -export interface CanvasPlatformService { - getBasePath: () => string; - getBasePathInterface: () => IBasePath; - getDocLinkVersion: () => string; - getElasticWebsiteUrl: () => string; - getKibanaVersion: () => string; - getHasWriteAccess: () => boolean; - getUISetting: (key: string, defaultValue?: any) => any; - hasHeaderBanner$: () => Observable; - setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; - setRecentlyAccessed: (link: string, label: string, id: string) => void; - setFullscreen: ChromeStart['setIsVisible']; - redirectLegacyUrl?: SpacesPluginStart['ui']['redirectLegacyUrl']; - getLegacyUrlConflict?: SpacesPluginStart['ui']['components']['getLegacyUrlConflict']; - getUISettings: () => IUiSettingsClient; - getHttp: () => HttpStart; - getContentManagement: () => ContentManagementPublicStart; -} diff --git a/x-pack/plugins/canvas/public/services/reporting.ts b/x-pack/plugins/canvas/public/services/reporting.ts deleted file mode 100644 index 71d90421eafa8..0000000000000 --- a/x-pack/plugins/canvas/public/services/reporting.ts +++ /dev/null @@ -1,13 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReportingStart } from '@kbn/reporting-plugin/public'; - -type ReportingPanelPDFComponent = ReportingStart['components']['ReportingPanelPDFV2']; -export interface CanvasReportingService { - getReportingPanelPDFComponent: () => ReportingPanelPDFComponent | null; -} diff --git a/x-pack/plugins/canvas/public/services/storybook/index.ts b/x-pack/plugins/canvas/public/services/storybook/index.ts deleted file mode 100644 index 52cad460662b2..0000000000000 --- a/x-pack/plugins/canvas/public/services/storybook/index.ts +++ /dev/null @@ -1,60 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - PluginServiceProviders, - PluginServiceProvider, -} from '@kbn/presentation-util-plugin/public'; - -import { CanvasPluginServices } from '..'; -import { pluginServiceProviders as stubProviders } from '../stubs'; -import { workpadServiceFactory } from './workpad'; -import { notifyServiceFactory } from './notify'; - -export interface StorybookParams { - hasTemplates?: boolean; - useStaticData?: boolean; - workpadCount?: number; -} - -export const pluginServiceProviders: PluginServiceProviders = - { - ...stubProviders, - workpad: new PluginServiceProvider(workpadServiceFactory), - notify: new PluginServiceProvider(notifyServiceFactory), - }; - -export const argTypes = { - hasTemplates: { - name: 'Has templates?', - type: { - name: 'boolean', - }, - defaultValue: true, - control: { - type: 'boolean', - }, - }, - useStaticData: { - name: 'Use static data?', - type: { - name: 'boolean', - }, - defaultValue: false, - control: { - type: 'boolean', - }, - }, - workpadCount: { - name: 'Number of workpads', - type: { name: 'number' }, - defaultValue: 5, - control: { - type: 'range', - }, - }, -}; diff --git a/x-pack/plugins/canvas/public/services/storybook/notify.ts b/x-pack/plugins/canvas/public/services/storybook/notify.ts deleted file mode 100644 index f6f97c42a1741..0000000000000 --- a/x-pack/plugins/canvas/public/services/storybook/notify.ts +++ /dev/null @@ -1,22 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { action } from '@storybook/addon-actions'; - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { StorybookParams } from '.'; -import { CanvasNotifyService } from '../notify'; - -type CanvasNotifyServiceFactory = PluginServiceFactory; - -export const notifyServiceFactory: CanvasNotifyServiceFactory = () => ({ - success: (message) => action(`success: ${message}`)(), - error: (message) => action(`error: ${message}`)(), - info: (message) => action(`info: ${message}`)(), - warning: (message) => action(`warning: ${message}`)(), -}); diff --git a/x-pack/plugins/canvas/public/services/storybook/workpad.ts b/x-pack/plugins/canvas/public/services/storybook/workpad.ts deleted file mode 100644 index 9f40ccccafb3d..0000000000000 --- a/x-pack/plugins/canvas/public/services/storybook/workpad.ts +++ /dev/null @@ -1,122 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import moment from 'moment'; - -import { action } from '@storybook/addon-actions'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { getId } from '../../lib/get_id'; -// @ts-expect-error -import { getDefaultWorkpad } from '../../state/defaults'; - -import { StorybookParams } from '.'; -import { CanvasWorkpadService } from '../workpad'; - -import * as stubs from '../stubs/workpad'; - -export { - findNoTemplates, - findNoWorkpads, - findSomeTemplates, - getNoTemplates, - getSomeTemplates, -} from '../stubs/workpad'; - -type CanvasWorkpadServiceFactory = PluginServiceFactory; - -const TIMEOUT = 500; -const promiseTimeout = (time: number) => () => new Promise((resolve) => setTimeout(resolve, time)); - -const { findNoTemplates, findNoWorkpads, findSomeTemplates, importWorkpad } = stubs; - -const getRandomName = () => { - const lorem = - 'Lorem ipsum dolor sit amet consectetur adipiscing elit Fusce lobortis aliquet arcu ut turpis duis'.split( - ' ' - ); - return [1, 2, 3].map(() => lorem[Math.floor(Math.random() * lorem.length)]).join(' '); -}; - -const getRandomDate = ( - start: Date = moment().toDate(), - end: Date = moment().subtract(7, 'days').toDate() -) => new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toISOString(); - -export const getSomeWorkpads = (count = 3) => - Array.from({ length: count }, () => ({ - '@created': getRandomDate( - moment().subtract(3, 'days').toDate(), - moment().subtract(10, 'days').toDate() - ), - '@timestamp': getRandomDate(), - id: getId('workpad'), - name: getRandomName(), - })); - -export const findSomeWorkpads = - (count = 3, useStaticData = false, timeout = TIMEOUT) => - (_term: string) => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => ({ - total: count, - workpads: useStaticData ? stubs.getSomeWorkpads(count) : getSomeWorkpads(count), - })); - }; - -export const workpadServiceFactory: CanvasWorkpadServiceFactory = ({ - workpadCount, - hasTemplates, - useStaticData, -}) => ({ - get: (id: string) => { - action('workpadService.get')(id); - return Promise.resolve({ ...getDefaultWorkpad(), id }); - }, - resolve: (id: string) => { - action('workpadService.resolve')(id); - return Promise.resolve({ outcome: 'exactMatch', workpad: { ...getDefaultWorkpad(), id } }); - }, - findTemplates: () => { - action('workpadService.findTemplates')(); - return (hasTemplates ? findSomeTemplates() : findNoTemplates())(); - }, - import: (workpad) => { - action('workpadService.import')(workpad); - return importWorkpad(workpad); - }, - create: (workpad) => { - action('workpadService.create')(workpad); - return Promise.resolve(workpad); - }, - createFromTemplate: (templateId: string) => { - action('workpadService.createFromTemplate')(templateId); - return Promise.resolve(getDefaultWorkpad()); - }, - find: (term: string) => { - action('workpadService.find')(term); - return (workpadCount ? findSomeWorkpads(workpadCount, useStaticData) : findNoWorkpads())(term); - }, - remove: (id: string) => { - action('workpadService.remove')(id); - return Promise.resolve(); - }, - update: (id, workpad) => { - action('worpadService.update')(workpad, id); - return Promise.resolve(); - }, - updateWorkpad: (id, workpad) => { - action('workpadService.updateWorkpad')(workpad, id); - return Promise.resolve(); - }, - updateAssets: (id, assets) => { - action('workpadService.updateAssets')(assets, id); - return Promise.resolve(); - }, - getRuntimeZip: (workpad) => - Promise.resolve(new Blob([JSON.stringify(workpad)], { type: 'application/json' })), -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/custom_element.ts b/x-pack/plugins/canvas/public/services/stubs/custom_element.ts deleted file mode 100644 index 551c06ef4b65e..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/custom_element.ts +++ /dev/null @@ -1,21 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasCustomElementService } from '../custom_element'; - -type CanvasCustomElementServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const customElementServiceFactory: CanvasCustomElementServiceFactory = () => ({ - create: noop, - find: noop, - get: noop, - remove: noop, - update: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/data_views.ts b/x-pack/plugins/canvas/public/services/stubs/data_views.ts deleted file mode 100644 index 1b1227dba4d3f..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/data_views.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasDataViewsService } from '../data_views'; - -type DataViewsServiceFactory = PluginServiceFactory; - -export const dataViewsServiceFactory: DataViewsServiceFactory = () => ({ - getDataViews: () => - Promise.resolve([ - { id: 'dataview1', title: 'dataview1', name: 'Data view 1' }, - { id: 'dataview2', title: 'dataview2', name: 'Data view 2' }, - ]), - getFields: () => Promise.resolve(['field1', 'field2']), - getDefaultDataView: () => - Promise.resolve({ - id: 'defaultDataViewId', - title: 'defaultDataView', - name: 'Default data view', - }), -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts b/x-pack/plugins/canvas/public/services/stubs/embeddables.ts deleted file mode 100644 index 95131efec2bde..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts +++ /dev/null @@ -1,20 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasEmbeddablesService } from '../embeddables'; - -type EmbeddablesServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const embeddablesServiceFactory: EmbeddablesServiceFactory = () => ({ - reactEmbeddableRegistryHasKey: noop, - getReactEmbeddableSavedObjects: noop, - getEmbeddableFactories: noop, - getStateTransfer: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/expressions.ts b/x-pack/plugins/canvas/public/services/stubs/expressions.ts deleted file mode 100644 index 177eb1e50d75f..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/expressions.ts +++ /dev/null @@ -1,41 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { AnyExpressionRenderDefinition } from '@kbn/expressions-plugin/common'; -import { plugin } from '@kbn/expressions-plugin/public'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { functions as functionDefinitions } from '../../../canvas_plugin_src/functions/common'; -import { renderFunctions } from '../../../canvas_plugin_src/renderers/core'; -import { - CanvasExpressionsService, - CanvasExpressionsServiceRequiredServices, - ExpressionsService, -} from '../kibana/expressions'; - -type CanvasExpressionsServiceFactory = PluginServiceFactory< - CanvasExpressionsService, - {}, - CanvasExpressionsServiceRequiredServices ->; - -export const expressionsServiceFactory: CanvasExpressionsServiceFactory = ( - params, - requiredServices -) => { - const placeholder = {} as any; - const expressionsPlugin = plugin(placeholder); - const setup = expressionsPlugin.setup(placeholder); - const fork = setup.fork('canvas'); - const expressionsService = fork.setup(); - - functionDefinitions.forEach((fn) => expressionsService.registerFunction(fn)); - renderFunctions.forEach((fn) => { - setup.registerRenderer(fn as unknown as AnyExpressionRenderDefinition); - }); - - return new ExpressionsService(fork.start(), requiredServices); -}; diff --git a/x-pack/plugins/canvas/public/services/stubs/filters.ts b/x-pack/plugins/canvas/public/services/stubs/filters.ts deleted file mode 100644 index 19d237bb9c390..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/filters.ts +++ /dev/null @@ -1,23 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasFiltersService } from '../filters'; - -export type CanvasFiltersServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const filtersServiceFactory: CanvasFiltersServiceFactory = () => ({ - getFilters: () => [ - 'exactly value="machine-learning" column="project1" filterGroup="Group 1"', - 'exactly value="kibana" column="project2" filterGroup="Group 1"', - 'time column="@timestamp1" from="2021-11-02 17:13:18" to="2021-11-09 17:13:18" filterGroup="Some group"', - ], - updateFilter: noop, - getFiltersContext: () => ({ variables: {} }), -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/index.ts b/x-pack/plugins/canvas/public/services/stubs/index.ts deleted file mode 100644 index c129441b07825..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/index.ts +++ /dev/null @@ -1,61 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from '../legacy/stubs'; - -import { - PluginServiceProviders, - PluginServiceProvider, - PluginServiceRegistry, -} from '@kbn/presentation-util-plugin/public'; - -import { CanvasPluginServices } from '..'; -import { customElementServiceFactory } from './custom_element'; -import { dataViewsServiceFactory } from './data_views'; -import { embeddablesServiceFactory } from './embeddables'; -import { expressionsServiceFactory } from './expressions'; -import { labsServiceFactory } from './labs'; -import { navLinkServiceFactory } from './nav_link'; -import { notifyServiceFactory } from './notify'; -import { platformServiceFactory } from './platform'; -import { reportingServiceFactory } from './reporting'; -import { visualizationsServiceFactory } from './visualizations'; -import { workpadServiceFactory } from './workpad'; -import { filtersServiceFactory } from './filters'; -import { uiActionsServiceFactory } from './ui_actions'; - -export { customElementServiceFactory } from './custom_element'; -export { dataViewsServiceFactory } from './data_views'; -export { expressionsServiceFactory } from './expressions'; -export { filtersServiceFactory } from './filters'; -export { labsServiceFactory } from './labs'; -export { navLinkServiceFactory } from './nav_link'; -export { notifyServiceFactory } from './notify'; -export { platformServiceFactory } from './platform'; -export { reportingServiceFactory } from './reporting'; -export { visualizationsServiceFactory } from './visualizations'; -export { workpadServiceFactory } from './workpad'; - -export const pluginServiceProviders: PluginServiceProviders = { - customElement: new PluginServiceProvider(customElementServiceFactory), - dataViews: new PluginServiceProvider(dataViewsServiceFactory), - embeddables: new PluginServiceProvider(embeddablesServiceFactory), - expressions: new PluginServiceProvider(expressionsServiceFactory, ['filters', 'notify']), - filters: new PluginServiceProvider(filtersServiceFactory), - labs: new PluginServiceProvider(labsServiceFactory), - navLink: new PluginServiceProvider(navLinkServiceFactory), - notify: new PluginServiceProvider(notifyServiceFactory), - platform: new PluginServiceProvider(platformServiceFactory), - reporting: new PluginServiceProvider(reportingServiceFactory), - visualizations: new PluginServiceProvider(visualizationsServiceFactory), - workpad: new PluginServiceProvider(workpadServiceFactory), - uiActions: new PluginServiceProvider(uiActionsServiceFactory), -}; - -export const pluginServiceRegistry = new PluginServiceRegistry( - pluginServiceProviders -); diff --git a/x-pack/plugins/canvas/public/services/stubs/labs.ts b/x-pack/plugins/canvas/public/services/stubs/labs.ts deleted file mode 100644 index d563126a15da3..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/labs.ts +++ /dev/null @@ -1,25 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { projectIDs } from '@kbn/presentation-util-plugin/common'; -import { CanvasLabsService } from '../labs'; - -type CanvasLabsServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const labsServiceFactory: CanvasLabsServiceFactory = () => ({ - getProject: noop, - getProjects: noop, - getProjectIDs: () => projectIDs, - isProjectEnabled: () => false, - isLabsEnabled: () => true, - projectIDs, - reset: noop, - setProjectStatus: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/nav_link.ts b/x-pack/plugins/canvas/public/services/stubs/nav_link.ts deleted file mode 100644 index becbdebcd6328..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/nav_link.ts +++ /dev/null @@ -1,17 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasNavLinkService } from '../nav_link'; - -type CanvasNavLinkServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const navLinkServiceFactory: CanvasNavLinkServiceFactory = () => ({ - updatePath: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/notify.ts b/x-pack/plugins/canvas/public/services/stubs/notify.ts deleted file mode 100644 index 2406afe3ca8a2..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/notify.ts +++ /dev/null @@ -1,21 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasNotifyService } from '../notify'; - -type CanvasNotifyServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const notifyServiceFactory: CanvasNotifyServiceFactory = () => ({ - error: noop, - info: noop, - success: noop, - warning: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/platform.ts b/x-pack/plugins/canvas/public/services/stubs/platform.ts deleted file mode 100644 index 0726810075251..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/platform.ts +++ /dev/null @@ -1,39 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasPlatformService } from '../platform'; - -type CanvasPlatformServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -const uiSettings: Record = { - dateFormat: 'MMM D, YYYY @ HH:mm:ss.SSS', -}; - -const getUISetting = (setting: string) => uiSettings[setting]; - -export const platformServiceFactory: CanvasPlatformServiceFactory = () => ({ - getBasePath: () => '/base/path', - getBasePathInterface: noop, - getDocLinkVersion: () => 'docLinkVersion', - getElasticWebsiteUrl: () => 'https://elastic.co', - getKibanaVersion: () => 'kibanaVersion', - getHasWriteAccess: () => true, - getUISetting, - hasHeaderBanner$: noop, - setBreadcrumbs: noop, - setRecentlyAccessed: noop, - getUISettings: noop, - setFullscreen: noop, - redirectLegacyUrl: noop, - getLegacyUrlConflict: undefined, - getHttp: noop, - getContentManagement: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/reporting.tsx b/x-pack/plugins/canvas/public/services/stubs/reporting.tsx deleted file mode 100644 index 71c376efbaba9..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/reporting.tsx +++ /dev/null @@ -1,17 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasReportingService } from '../reporting'; - -type CanvasReportingServiceFactory = PluginServiceFactory; - -export const reportingServiceFactory: CanvasReportingServiceFactory = () => ({ - getReportingPanelPDFComponent: () => () =>
Reporting Panel PDF
, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/ui_actions.ts b/x-pack/plugins/canvas/public/services/stubs/ui_actions.ts deleted file mode 100644 index 84039e0888be8..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/ui_actions.ts +++ /dev/null @@ -1,17 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; -import { CanvasUiActionsService } from '../ui_actions'; - -type UiActionsServiceFactory = PluginServiceFactory; - -export const uiActionsServiceFactory: UiActionsServiceFactory = () => { - const pluginMock = uiActionsPluginMock.createStartContract(); - return { getTriggerCompatibleActions: pluginMock.getTriggerCompatibleActions }; -}; diff --git a/x-pack/plugins/canvas/public/services/stubs/visualizations.ts b/x-pack/plugins/canvas/public/services/stubs/visualizations.ts deleted file mode 100644 index 812287bf078fb..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/visualizations.ts +++ /dev/null @@ -1,19 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasVisualizationsService } from '../visualizations'; - -type VisualizationsServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const visualizationsServiceFactory: VisualizationsServiceFactory = () => ({ - showNewVisModal: noop, - getByGroup: noop, - getAliases: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/workpad.ts b/x-pack/plugins/canvas/public/services/stubs/workpad.ts deleted file mode 100644 index 51be4e150ebe5..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/workpad.ts +++ /dev/null @@ -1,115 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import moment from 'moment'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -// @ts-expect-error -import { getDefaultWorkpad } from '../../state/defaults'; -import { CanvasWorkpadService } from '../workpad'; -import { CanvasTemplate, CanvasWorkpad } from '../../../types'; - -type CanvasWorkpadServiceFactory = PluginServiceFactory; - -export const TIMEOUT = 500; -export const promiseTimeout = (time: number) => () => - new Promise((resolve) => setTimeout(resolve, time)); - -const DAY = 86400000; -const JAN_1_2000 = 946684800000; - -const getWorkpads = (count = 3) => { - const workpads = []; - for (let i = 0; i < count; i++) { - workpads[i] = { - ...getDefaultWorkpad(), - name: `Workpad ${i}`, - id: `workpad-${i}`, - '@created': moment(JAN_1_2000 + DAY * i).toDate(), - '@timestamp': moment(JAN_1_2000 + DAY * (i + 1)).toDate(), - }; - } - return workpads; -}; - -export const getSomeWorkpads = (count = 3) => getWorkpads(count); - -export const findSomeWorkpads = - (count = 3, timeout = TIMEOUT) => - (_term: string) => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => ({ - total: count, - workpads: getSomeWorkpads(count), - })); - }; - -const templates: CanvasTemplate[] = [ - { - id: 'test1-id', - name: 'test1', - help: 'This is a test template', - tags: ['tag1', 'tag2'], - template_key: 'test1-key', - }, - { - id: 'test2-id', - name: 'test2', - help: 'This is a second test template', - tags: ['tag2', 'tag3'], - template_key: 'test2-key', - }, -]; - -export const findNoWorkpads = - (timeout = TIMEOUT) => - (_term: string) => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => ({ - total: 0, - workpads: [], - })); - }; - -export const findSomeTemplates = - (timeout = TIMEOUT) => - () => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => getSomeTemplates()); - }; - -export const findNoTemplates = - (timeout = TIMEOUT) => - () => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => getNoTemplates()); - }; - -export const importWorkpad = (workpad: CanvasWorkpad) => Promise.resolve(workpad); -export const getNoTemplates = () => ({ templates: [] }); -export const getSomeTemplates = () => ({ templates }); - -export const workpadServiceFactory: CanvasWorkpadServiceFactory = () => ({ - get: (id: string) => Promise.resolve({ ...getDefaultWorkpad(), id }), - resolve: (id: string) => - Promise.resolve({ outcome: 'exactMatch', workpad: { ...getDefaultWorkpad(), id } }), - findTemplates: findNoTemplates(), - create: (workpad) => Promise.resolve(workpad), - import: (workpad) => importWorkpad(workpad), - createFromTemplate: (_templateId: string) => Promise.resolve(getDefaultWorkpad()), - find: findNoWorkpads(), - remove: (_id: string) => Promise.resolve(), - update: (id, workpad) => Promise.resolve(), - updateWorkpad: (id, workpad) => Promise.resolve(), - updateAssets: (id, assets) => Promise.resolve(), - getRuntimeZip: (workpad) => - Promise.resolve(new Blob([JSON.stringify(workpad)], { type: 'application/json' })), -}); diff --git a/x-pack/plugins/canvas/public/services/ui_actions.ts b/x-pack/plugins/canvas/public/services/ui_actions.ts deleted file mode 100644 index 62f99facce023..0000000000000 --- a/x-pack/plugins/canvas/public/services/ui_actions.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; - -export interface CanvasUiActionsService { - getTriggerCompatibleActions: UiActionsStart['getTriggerCompatibleActions']; -} diff --git a/x-pack/plugins/canvas/public/services/visualizations.ts b/x-pack/plugins/canvas/public/services/visualizations.ts deleted file mode 100644 index dc816f764e5ec..0000000000000 --- a/x-pack/plugins/canvas/public/services/visualizations.ts +++ /dev/null @@ -1,14 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { VisualizationsStart } from '@kbn/visualizations-plugin/public'; - -export interface CanvasVisualizationsService { - showNewVisModal: VisualizationsStart['showNewVisModal']; - getByGroup: VisualizationsStart['getByGroup']; - getAliases: VisualizationsStart['getAliases']; -} diff --git a/x-pack/plugins/canvas/public/services/workpad.ts b/x-pack/plugins/canvas/public/services/workpad.ts deleted file mode 100644 index 72996f54c158d..0000000000000 --- a/x-pack/plugins/canvas/public/services/workpad.ts +++ /dev/null @@ -1,43 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ResolvedSimpleSavedObject } from '@kbn/core/public'; -import { CanvasWorkpad, CanvasTemplate } from '../../types'; -import type { CanvasRenderedWorkpad } from '../../shareable_runtime/types'; - -export type FoundWorkpads = Array>; -export type FoundWorkpad = FoundWorkpads[number]; -export interface WorkpadFindResponse { - total: number; - workpads: FoundWorkpads; -} - -export interface TemplateFindResponse { - templates: CanvasTemplate[]; -} - -export interface ResolveWorkpadResponse { - workpad: CanvasWorkpad; - outcome: ResolvedSimpleSavedObject['outcome']; - aliasId?: ResolvedSimpleSavedObject['alias_target_id']; - aliasPurpose?: ResolvedSimpleSavedObject['alias_purpose']; -} - -export interface CanvasWorkpadService { - get: (id: string) => Promise; - resolve: (id: string) => Promise; - create: (workpad: CanvasWorkpad) => Promise; - import: (workpad: CanvasWorkpad) => Promise; - createFromTemplate: (templateId: string) => Promise; - find: (term: string) => Promise; - remove: (id: string) => Promise; - findTemplates: () => Promise; - update: (id: string, workpad: CanvasWorkpad) => Promise; - updateWorkpad: (id: string, workpad: CanvasWorkpad) => Promise; - updateAssets: (id: string, assets: CanvasWorkpad['assets']) => Promise; - getRuntimeZip: (workpad: CanvasRenderedWorkpad) => Promise; -} diff --git a/x-pack/plugins/canvas/public/state/actions/elements.js b/x-pack/plugins/canvas/public/state/actions/elements.js index b94a198ee4be9..57b7da1ce1fef 100644 --- a/x-pack/plugins/canvas/public/state/actions/elements.js +++ b/x-pack/plugins/canvas/public/state/actions/elements.js @@ -23,9 +23,11 @@ import { getValue as getResolvedArgsValue } from '../selectors/resolved_args'; import { getDefaultElement } from '../defaults'; import { ErrorStrings } from '../../../i18n'; import { subMultitree } from '../../lib/aeroelastic/functional'; -import { pluginServices } from '../../services'; +import { getCanvasExpressionService } from '../../services/canvas_expressions_service'; +import { getCanvasNotifyService } from '../../services/canvas_notify_service'; import { selectToplevelNodes } from './transient'; import * as args from './resolved_args'; +import { setFilter } from './filters'; const { actionsElements: strings } = ErrorStrings; @@ -101,7 +103,7 @@ const fetchContextFn = ({ dispatch, getState }, index, element, fullRefresh = fa const variables = getWorkpadVariablesAsObject(getState()); - const { expressions } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); const elementWithNewAst = set(element, pathToTarget, astChain); // get context data from a partial AST @@ -129,7 +131,8 @@ const fetchRenderableWithContextFn = ({ dispatch, getState }, element, ast, cont }); const variables = getWorkpadVariablesAsObject(getState()); - const { expressions, notify } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); + const notify = getCanvasNotifyService(); return expressions .runInterpreter(ast, context, variables, { castToRender: true }) @@ -177,7 +180,8 @@ export const fetchAllRenderables = createThunk( const argumentPath = [element.id, 'expressionRenderable']; const variables = getWorkpadVariablesAsObject(getState()); - const { expressions, notify } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); + const notify = getCanvasNotifyService(); return expressions .runInterpreter(ast, null, variables, { castToRender: true }) @@ -260,18 +264,6 @@ export const removeElements = createThunk( } ); -export const setFilter = createThunk( - 'setFilter', - ({ dispatch }, filter, elementId, doRender = true) => { - const _setFilter = createAction('setFilter'); - dispatch(_setFilter({ filter, elementId })); - - if (doRender === true) { - dispatch(fetchAllRenderables()); - } - } -); - export const setExpression = createThunk('setExpression', setExpressionFn); function setExpressionFn({ dispatch, getState }, expression, elementId, pageId, doRender = true) { // dispatch action to update the element in state @@ -290,7 +282,11 @@ function setExpressionFn({ dispatch, getState }, expression, elementId, pageId, ) ) { const filter = ''; - dispatch(setFilter(filter, elementId, pageId, doRender)); + dispatch(setFilter(filter, elementId, pageId)); + + if (doRender) { + dispatch(fetchAllRenderables(updatedElement)); + } // setFilter will trigger a re-render so we can skip the fetch here } else if (doRender === true) { dispatch(fetchRenderable(updatedElement)); @@ -302,7 +298,7 @@ const setAst = createThunk('setAst', ({ dispatch }, ast, element, pageId, doRend const expression = toExpression(ast); dispatch(setExpression(expression, element.id, pageId, doRender)); } catch (err) { - const notifyService = pluginServices.getServices().notify; + const notifyService = getCanvasNotifyService(); notifyService.error(err); // TODO: remove this, may have been added just to cause a re-render, but why? diff --git a/x-pack/plugins/canvas/public/state/actions/filters.js b/x-pack/plugins/canvas/public/state/actions/filters.js new file mode 100644 index 0000000000000..3347925dc5a15 --- /dev/null +++ b/x-pack/plugins/canvas/public/state/actions/filters.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { createAction } from 'redux-actions'; +import { createThunk } from '../../lib/create_thunk'; + +export const setFilter = createThunk('setFilter', ({ dispatch }, filter, elementId) => { + const _setFilter = createAction('setFilter'); + dispatch(_setFilter({ filter, elementId })); +}); diff --git a/x-pack/plugins/canvas/public/state/initial_state.js b/x-pack/plugins/canvas/public/state/initial_state.js index 88330c92d867b..fd509c952ef18 100644 --- a/x-pack/plugins/canvas/public/state/initial_state.js +++ b/x-pack/plugins/canvas/public/state/initial_state.js @@ -6,18 +6,15 @@ */ import { get } from 'lodash'; -import { pluginServices } from '../services'; +import { coreServices } from '../services/kibana_services'; import { getDefaultWorkpad, getDefaultSidebar, getDefaultFlyouts } from './defaults'; export const getInitialState = (path) => { - const platformService = pluginServices.getServices().platform; - const { getHasWriteAccess } = platformService; - const state = { app: {}, // Kibana stuff in here assets: {}, // assets end up here transient: { - canUserWrite: getHasWriteAccess(), + canUserWrite: coreServices.application.capabilities.canvas.save, zoomScale: 1, elementStats: { total: 0, diff --git a/x-pack/plugins/canvas/public/state/reducers/elements.js b/x-pack/plugins/canvas/public/state/reducers/elements.js index 2be1cf519ee13..fdb15a5621222 100644 --- a/x-pack/plugins/canvas/public/state/reducers/elements.js +++ b/x-pack/plugins/canvas/public/state/reducers/elements.js @@ -8,7 +8,6 @@ import { handleActions } from 'redux-actions'; import immutable from 'object-path-immutable'; import { get } from 'lodash'; -import * as actions from '../actions/elements'; const { assign, push, del, set } = immutable; @@ -102,17 +101,16 @@ const getPageWithElementId = (workpad, elementId) => { export const elementsReducer = handleActions( { - // TODO: This takes the entire element, which is not necessary, it could just take the id. - [actions.setExpression]: (workpadState, { payload }) => { + ['setExpression']: (workpadState, { payload }) => { const { expression, pageId, elementId } = payload; return assignNodeProperties(workpadState, pageId, elementId, { expression }); }, - [actions.setFilter]: (workpadState, { payload }) => { + ['setFilter']: (workpadState, { payload }) => { const { filter, elementId } = payload; const pageId = getPageWithElementId(workpadState, elementId); return assignNodeProperties(workpadState, pageId, elementId, { filter }); }, - [actions.setMultiplePositions]: (workpadState, { payload }) => + ['setMultiplePositions']: (workpadState, { payload }) => payload.repositionedElements.reduce( (previousWorkpadState, { position, pageId, elementId }) => assignNodeProperties(previousWorkpadState, pageId, elementId, { @@ -120,11 +118,11 @@ export const elementsReducer = handleActions( }), workpadState ), - [actions.elementLayer]: (workpadState, { payload: { pageId, elementId, movement } }) => { + ['elementLayer']: (workpadState, { payload: { pageId, elementId, movement } }) => { const location = getLocationFromIds(workpadState, pageId, elementId); return moveNodeLayer(workpadState, pageId, elementId, movement, location); }, - [actions.addElement]: (workpadState, { payload: { pageId, element } }) => { + ['addElement']: (workpadState, { payload: { pageId, element } }) => { const pageIndex = getPageIndexById(workpadState, pageId); if (pageIndex < 0) { return workpadState; @@ -143,7 +141,7 @@ export const elementsReducer = handleActions( trimElement(element) ); }, - [actions.insertNodes]: (workpadState, { payload: { pageId, elements } }) => { + ['insertNodes']: (workpadState, { payload: { pageId, elements } }) => { const pageIndex = getPageIndexById(workpadState, pageId); if (pageIndex < 0) { return workpadState; @@ -158,7 +156,7 @@ export const elementsReducer = handleActions( workpadState ); }, - [actions.removeElements]: (workpadState, { payload: { pageId, elementIds } }) => { + ['removeElements']: (workpadState, { payload: { pageId, elementIds } }) => { const pageIndex = getPageIndexById(workpadState, pageId); if (pageIndex < 0) { return workpadState; diff --git a/x-pack/plugins/canvas/public/state/reducers/embeddable.ts b/x-pack/plugins/canvas/public/state/reducers/embeddable.ts index 5b963e2c80c7e..8f79ed529cd96 100644 --- a/x-pack/plugins/canvas/public/state/reducers/embeddable.ts +++ b/x-pack/plugins/canvas/public/state/reducers/embeddable.ts @@ -9,10 +9,7 @@ import { fromExpression, toExpression } from '@kbn/interpreter'; import { handleActions } from 'redux-actions'; import { State } from '../../../types'; -import { - UpdateEmbeddableExpressionActionType, - UpdateEmbeddableExpressionPayload, -} from '../actions/embeddable'; +import { UpdateEmbeddableExpressionPayload } from '../actions/embeddable'; // @ts-expect-error untyped local import { assignNodeProperties } from './elements'; @@ -22,7 +19,7 @@ export const embeddableReducer = handleActions< UpdateEmbeddableExpressionPayload >( { - [UpdateEmbeddableExpressionActionType]: (workpadState, { payload }) => { + ['updateEmbeddableExpression']: (workpadState, { payload }) => { if (!payload) { return workpadState; } diff --git a/x-pack/plugins/canvas/public/state/reducers/resolved_args.js b/x-pack/plugins/canvas/public/state/reducers/resolved_args.js index 3514036cafc0d..3652a8d462fb8 100644 --- a/x-pack/plugins/canvas/public/state/reducers/resolved_args.js +++ b/x-pack/plugins/canvas/public/state/reducers/resolved_args.js @@ -10,8 +10,6 @@ import immutable from 'object-path-immutable'; import { get } from 'lodash'; import { prepend } from '../../lib/modify_path'; import * as actions from '../actions/resolved_args'; -import { flushContext, flushContextAfterIndex } from '../actions/elements'; -import { setWorkpad } from '../actions/workpad'; const { set, del } = immutable; /* @@ -114,14 +112,14 @@ export const resolvedArgsReducer = handleActions( /* * Flush all cached contexts */ - [flushContext]: (transientState, { payload: elementId }) => { + ['flushContext']: (transientState, { payload: elementId }) => { return del(transientState, getFullPath([elementId, 'expressionContext'])); }, /* * Flush cached context indices from the given index to the last */ - [flushContextAfterIndex]: (transientState, { payload }) => { + ['flushContextAfterIndex']: (transientState, { payload }) => { const { elementId, index } = payload; const expressionContext = get(transientState, getFullPath([elementId, 'expressionContext'])); @@ -139,7 +137,7 @@ export const resolvedArgsReducer = handleActions( return state; }, transientState); }, - [setWorkpad]: (transientState, {}) => { + ['setWorkpad']: (transientState, {}) => { return set(transientState, 'resolvedArgs', {}); }, }, diff --git a/x-pack/plugins/canvas/public/state/reducers/transient.js b/x-pack/plugins/canvas/public/state/reducers/transient.js index e41ab5e4822a9..2f0e7bd66126c 100644 --- a/x-pack/plugins/canvas/public/state/reducers/transient.js +++ b/x-pack/plugins/canvas/public/state/reducers/transient.js @@ -7,11 +7,6 @@ import { handleActions } from 'redux-actions'; import immutable from 'object-path-immutable'; -import { restoreHistory } from '../actions/history'; -import * as pageActions from '../actions/pages'; -import * as transientActions from '../actions/transient'; -import { removeElements } from '../actions/elements'; -import { setRefreshInterval, enableAutoplay, setAutoplayInterval } from '../actions/workpad'; const { set, del } = immutable; @@ -19,9 +14,9 @@ export const transientReducer = handleActions( { // clear all the resolved args when restoring the history // TODO: we shouldn't need to reset the resolved args for history - [restoreHistory]: (transientState) => set(transientState, 'resolvedArgs', {}), + ['restoreHistory']: (transientState) => set(transientState, 'resolvedArgs', {}), - [removeElements]: (transientState, { payload: { elementIds } }) => { + ['removeElements']: (transientState, { payload: { elementIds } }) => { const { selectedToplevelNodes } = transientState; return del( { @@ -32,53 +27,53 @@ export const transientReducer = handleActions( ); }, - [transientActions.setFirstLoad]: (transientState, { payload }) => { + ['setFirstLoad']: (transientState, { payload }) => { return set(transientState, 'isFirstLoad', Boolean(payload)); }, - [transientActions.setFullscreen]: (transientState, { payload }) => { + ['setFullscreen']: (transientState, { payload }) => { return set(transientState, 'fullscreen', Boolean(payload)); }, - [transientActions.setElementStats]: (transientState, { payload }) => { + ['setElementStats']: (transientState, { payload }) => { return set(transientState, 'elementStats', payload); }, - [transientActions.selectToplevelNodes]: (transientState, { payload }) => { + ['selectToplevelNodes']: (transientState, { payload }) => { return { ...transientState, selectedToplevelNodes: payload, }; }, - [transientActions.setZoomScale]: (transientState, { payload }) => { + ['setZoomScale']: (transientState, { payload }) => { return { ...transientState, zoomScale: payload || 1, }; }, - [pageActions.setPage]: (transientState) => { + ['setPage']: (transientState) => { return { ...transientState, selectedToplevelNodes: [] }; }, - [pageActions.addPage]: (transientState) => { + ['addPage']: (transientState) => { return { ...transientState, selectedToplevelNodes: [] }; }, - [pageActions.duplicatePage]: (transientState) => { + ['duplicatePage']: (transientState) => { return { ...transientState, selectedToplevelNodes: [] }; }, - [setRefreshInterval]: (transientState, { payload }) => { + ['setRefreshInterval']: (transientState, { payload }) => { return { ...transientState, refresh: { interval: Number(payload) || 0 } }; }, - [enableAutoplay]: (transientState, { payload }) => { + ['enableAutoplay']: (transientState, { payload }) => { return set(transientState, 'autoplay.enabled', Boolean(payload) || false); }, - [setAutoplayInterval]: (transientState, { payload }) => { + ['setAutoplayInterval']: (transientState, { payload }) => { return set(transientState, 'autoplay.interval', Number(payload) || 0); }, }, diff --git a/x-pack/plugins/canvas/public/state/reducers/workpad.js b/x-pack/plugins/canvas/public/state/reducers/workpad.js index ebde0106f9c01..9c337f965ae3a 100644 --- a/x-pack/plugins/canvas/public/state/reducers/workpad.js +++ b/x-pack/plugins/canvas/public/state/reducers/workpad.js @@ -6,66 +6,52 @@ */ import { handleActions } from 'redux-actions'; -import { pluginServices } from '../../services'; +import { coreServices } from '../../services/kibana_services'; import { getDefaultWorkpad } from '../defaults'; -import { - setWorkpad, - sizeWorkpad, - setColors, - setName, - setWriteable, - setWorkpadCSS, - setWorkpadVariables, - resetWorkpad, -} from '../actions/workpad'; import { APP_ROUTE_WORKPAD } from '../../../common/lib/constants'; export const workpadReducer = handleActions( { - [setWorkpad]: (workpadState, { payload }) => { - pluginServices - .getServices() - .platform.setRecentlyAccessed( - `${APP_ROUTE_WORKPAD}/${payload.id}`, - payload.name, - payload.id - ); + ['setWorkpad']: (workpadState, { payload }) => { + coreServices.chrome.recentlyAccessed.add( + `${APP_ROUTE_WORKPAD}/${payload.id}`, + payload.name, + payload.id + ); return payload; }, - [sizeWorkpad]: (workpadState, { payload }) => { + ['sizeWorkpad']: (workpadState, { payload }) => { return { ...workpadState, ...payload }; }, - [setColors]: (workpadState, { payload }) => { + ['setColors']: (workpadState, { payload }) => { return { ...workpadState, colors: payload }; }, - [setName]: (workpadState, { payload }) => { - pluginServices - .getServices() - .platform.setRecentlyAccessed( - `${APP_ROUTE_WORKPAD}/${workpadState.id}`, - payload, - workpadState.id - ); + ['setName']: (workpadState, { payload }) => { + coreServices.chrome.recentlyAccessed.add( + `${APP_ROUTE_WORKPAD}/${workpadState.id}`, + payload, + workpadState.id + ); return { ...workpadState, name: payload }; }, - [setWriteable]: (workpadState, { payload }) => { + ['setWriteable']: (workpadState, { payload }) => { return { ...workpadState, isWriteable: Boolean(payload) }; }, - [setWorkpadCSS]: (workpadState, { payload }) => { + ['setWorkpadCSS']: (workpadState, { payload }) => { return { ...workpadState, css: payload }; }, - [setWorkpadVariables]: (workpadState, { payload }) => { + ['setWorkpadVariables']: (workpadState, { payload }) => { return { ...workpadState, variables: payload }; }, - [resetWorkpad]: () => ({ ...getDefaultWorkpad() }), + ['resetWorkpad']: () => ({ ...getDefaultWorkpad() }), }, {} ); diff --git a/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap b/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap index 010847e63a023..4aa379aa194bc 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap +++ b/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` App renders properly 1`] = `"
markdown mock
markdown mock

Page level controls

My Canvas Workpad

There is a new region landmark with page level controls at the end of the document.

"`; +exports[` App renders properly 1`] = `"
markdown mock
markdown mock

Page level controls

My Canvas Workpad

There is a new region landmark with page level controls at the end of the document.

"`; diff --git a/x-pack/plugins/canvas/shareable_runtime/components/app.test.tsx b/x-pack/plugins/canvas/shareable_runtime/components/app.test.tsx index ec4ea09e8fcc7..30d55c8531b1d 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/app.test.tsx +++ b/x-pack/plugins/canvas/shareable_runtime/components/app.test.tsx @@ -13,6 +13,7 @@ import { mount, ReactWrapper } from 'enzyme'; import React from 'react'; + // import { act } from 'react-dom/test-utils'; import { App } from './app'; import { sharedWorkpads, WorkpadNames, tick } from '../test'; @@ -34,17 +35,14 @@ import { openSettings, selectMenuItem } from '../test/interactions'; // Mock the renderers jest.mock('../supported_renderers'); +// @ts-ignore Importing this to mock +import * as Portal from '@elastic/eui/lib/components/portal/portal'; + // Mock the EuiPortal - `insertAdjacentElement is not supported in // `jsdom` 12. We're just going to render a `div` with the children // so the `enzyme` tests will be accurate. -jest.mock('@elastic/eui/lib/components/portal/portal', () => { - // Local constants are not supported in Jest mocks-- they must be - // imported within the mock. - // eslint-disable-next-line @typescript-eslint/no-shadow - const React = jest.requireActual('react'); - return { - EuiPortal: (props: any) =>
{props.children}
, - }; +jest.spyOn(Portal, 'EuiPortal').mockImplementation((props: any) => { + return
{props.children}
; }); const getWrapper: (name?: WorkpadNames) => ReactWrapper = (name = 'hello') => { diff --git a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap index bf66b5df800ec..cfe41427b1ea1 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap +++ b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap @@ -1,7 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` can navigate Autoplay Settings 1`] = ` -
+
@@ -94,7 +96,9 @@ exports[` can navigate Autoplay Settings 1`] = ` `; exports[` can navigate Autoplay Settings 2`] = ` -
+
@@ -338,7 +342,9 @@ exports[` can navigate Autoplay Settings 2`] = ` `; exports[` can navigate Toolbar Settings, closes when activated 1`] = ` -
+
@@ -431,7 +437,9 @@ exports[` can navigate Toolbar Settings, closes when activated 1`] = `; exports[` can navigate Toolbar Settings, closes when activated 2`] = ` -
+
@@ -606,7 +614,9 @@ exports[` can navigate Toolbar Settings, closes when activated 2`] = `; exports[` can navigate Toolbar Settings, closes when activated 3`] = ` -
+
diff --git a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/settings.test.tsx b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/settings.test.tsx index cc275dd983e3c..0ab9e13e36765 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/settings.test.tsx +++ b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/settings.test.tsx @@ -21,12 +21,14 @@ import { Settings } from './settings'; jest.mock('../../../supported_renderers'); -jest.mock('@elastic/eui/lib/components/portal/portal', () => { - // eslint-disable-next-line @typescript-eslint/no-shadow - const React = jest.requireActual('react'); - return { - EuiPortal: (props: any) =>
{props.children}
, - }; +// @ts-ignore Importing this to mock +import * as Portal from '@elastic/eui/lib/components/portal/portal'; + +// Mock the EuiPortal - `insertAdjacentElement is not supported in +// `jsdom` 12. We're just going to render a `div` with the children +// so the `enzyme` tests will be accurate. +jest.spyOn(Portal, 'EuiPortal').mockImplementation((props: any) => { + return
{props.children}
; }); describe('', () => { diff --git a/x-pack/plugins/canvas/shareable_runtime/test/selectors.ts b/x-pack/plugins/canvas/shareable_runtime/test/selectors.ts index bcfe94adf94be..f4d4f8ac442d7 100644 --- a/x-pack/plugins/canvas/shareable_runtime/test/selectors.ts +++ b/x-pack/plugins/canvas/shareable_runtime/test/selectors.ts @@ -42,7 +42,7 @@ export const getSettingsTrigger = (wrapper: ReactWrapper) => export const getPopover = (wrapper: ReactWrapper) => wrapper.find('EuiPopover'); -export const getPortal = (wrapper: ReactWrapper) => wrapper.find('EuiPortal'); +export const getPortal = (wrapper: ReactWrapper) => wrapper.find('.mockedEuiPortal'); export const getContextMenu = (wrapper: ReactWrapper) => wrapper.find('EuiContextMenuClass'); diff --git a/x-pack/plugins/canvas/storybook/constants.ts b/x-pack/plugins/canvas/storybook/constants.ts index 711b939179452..4f0ad2a602da0 100644 --- a/x-pack/plugins/canvas/storybook/constants.ts +++ b/x-pack/plugins/canvas/storybook/constants.ts @@ -8,3 +8,34 @@ import path from 'path'; export const KIBANA_ROOT = path.resolve(__dirname, '../../../..'); + +export const argTypes = { + hasTemplates: { + name: 'Has templates?', + type: { + name: 'boolean', + }, + defaultValue: true, + control: { + type: 'boolean', + }, + }, + useStaticData: { + name: 'Use static data?', + type: { + name: 'boolean', + }, + defaultValue: false, + control: { + type: 'boolean', + }, + }, + workpadCount: { + name: 'Number of workpads', + type: { name: 'number' }, + defaultValue: 5, + control: { + type: 'range', + }, + }, +}; diff --git a/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx b/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx index b5bb0710c3de2..c99f5df184cd4 100644 --- a/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx +++ b/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx @@ -10,19 +10,10 @@ import React from 'react'; import { DecoratorFn } from '@storybook/react'; import { I18nProvider } from '@kbn/i18n-react'; -import { PluginServiceRegistry } from '@kbn/presentation-util-plugin/public'; -import { pluginServices, CanvasPluginServices } from '../../public/services'; -import { pluginServiceProviders, StorybookParams } from '../../public/services/storybook'; import { LegacyServicesProvider } from '../../public/services/legacy'; -import { startServices } from '../../public/services/legacy/stubs'; +import { setStubKibanaServices } from '../../public/services/mocks'; export const servicesContextDecorator = (): DecoratorFn => { - const pluginServiceRegistry = new PluginServiceRegistry( - pluginServiceProviders - ); - - pluginServices.setRegistry(pluginServiceRegistry.start({})); - return (story: Function, storybook) => { if (process.env.JEST_WORKER_ID !== undefined) { storybook.args.useStaticData = true; @@ -33,6 +24,7 @@ export const servicesContextDecorator = (): DecoratorFn => { }; export const legacyContextDecorator = () => { - startServices(); + setStubKibanaServices(); + return (story: Function) => {story()}; }; diff --git a/x-pack/plugins/canvas/tsconfig.json b/x-pack/plugins/canvas/tsconfig.json index 85121b72c868c..251deca87c4ee 100644 --- a/x-pack/plugins/canvas/tsconfig.json +++ b/x-pack/plugins/canvas/tsconfig.json @@ -12,6 +12,7 @@ "allowJs": false }, "include": [ + "*.ts", "../../../typings/**/*", "__fixtures__/**/*", "canvas_plugin_src/**/*", @@ -88,9 +89,7 @@ "@kbn/presentation-containers", "@kbn/presentation-publishing", "@kbn/react-kibana-context-render", - "@kbn/search-types", + "@kbn/search-types" ], - "exclude": [ - "target/**/*", - ] + "exclude": ["target/**/*"] } From 445a2bd5baed49a7e07ab3e6c1b86bc1e5821496 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 8 Oct 2024 21:39:29 +0100 Subject: [PATCH 025/110] skip flaky suite (#187182) --- x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts index d84d3aa691d1e..ca0692b310606 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts @@ -84,7 +84,8 @@ describe('Alert Event Details - Cases', { tags: ['@ess', '@serverless'] }, () => }); }); - describe('Case', () => { + // FLAKY: https://github.com/elastic/kibana/issues/187182 + describe.skip('Case', () => { let caseId: string; beforeEach(() => { From 2dfd8f1bedaa01453f8d1fbd4e6375cf1bca2843 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 8 Oct 2024 21:47:25 +0100 Subject: [PATCH 026/110] skip flaky suite (#170371) --- .../response_actions/response_console/process_operations.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts index 9484122c013d7..ed05f5a26e356 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts @@ -27,6 +27,7 @@ import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_ const AGENT_BEAT_FILE_PATH_SUFFIX = '/components/agentbeat'; // FLAKY: https://github.com/elastic/kibana/issues/170370 +// FLAKY: https://github.com/elastic/kibana/issues/170371 describe.skip('Response console', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { beforeEach(() => { login(); From 51b9be6ff310ef28840fee225e2cfcccc0bbe183 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 8 Oct 2024 21:49:59 +0100 Subject: [PATCH 027/110] skip flaky suite (#195144) --- .../reporting_functional/reporting_and_security/management.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/reporting_functional/reporting_and_security/management.ts b/x-pack/test/reporting_functional/reporting_and_security/management.ts index f48dbd3271f70..570c1bbdda4c7 100644 --- a/x-pack/test/reporting_functional/reporting_and_security/management.ts +++ b/x-pack/test/reporting_functional/reporting_and_security/management.ts @@ -56,7 +56,8 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { await PageObjects.dashboard.expectOnDashboard(dashboardTitle); }); - describe('Download report', () => { + // FLAKY: https://github.com/elastic/kibana/issues/195144 + describe.skip('Download report', () => { // use archived reports to allow reporting_user to view report jobs they've created before('log in as reporting user', async () => { await esArchiver.load('x-pack/test/functional/es_archives/reporting/archived_reports'); From 776f05a1b017d333f33ccd915c7fbc2a81e838fd Mon Sep 17 00:00:00 2001 From: Kfir Peled <61654899+kfirpeled@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:55:04 +0100 Subject: [PATCH 028/110] [Cloud Security] Refactoring, removed duplicated code from tests (#195492) ## Summary Removed duplicated code cloud_security_posture_api_integration tests folder ### Checklist - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed --- .../test/cloud_security_posture_api/config.ts | 12 +- .../routes/benchmarks.ts | 107 +++-------- .../routes/csp_benchmark_rules_bulk_update.ts | 25 +-- .../routes/csp_benchmark_rules_get_states.ts | 25 +-- ...ection_engine_alerts_count_by_rule_tags.ts | 20 +- .../routes/index.ts | 1 - .../routes/stats.ts | 181 +++++++----------- .../routes/status.ts | 20 +- .../routes/vulnerabilities_dashboard.ts | 94 ++------- .../telemetry/index.ts | 17 ++ .../telemetry/telemetry.ts | 57 ++---- .../test/cloud_security_posture_api/utils.ts | 75 ++++++++ 12 files changed, 241 insertions(+), 393 deletions(-) create mode 100644 x-pack/test/cloud_security_posture_api/telemetry/index.ts create mode 100644 x-pack/test/cloud_security_posture_api/utils.ts diff --git a/x-pack/test/cloud_security_posture_api/config.ts b/x-pack/test/cloud_security_posture_api/config.ts index 08dfc89bf1800..4e0ecd1f26e43 100644 --- a/x-pack/test/cloud_security_posture_api/config.ts +++ b/x-pack/test/cloud_security_posture_api/config.ts @@ -9,20 +9,18 @@ import type { FtrConfigProviderContext } from '@kbn/test'; import { CLOUD_SECURITY_PLUGIN_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { - const xpackFunctionalConfig = await readConfigFile( - require.resolve('../functional/config.base.js') - ); + const xPackAPITestsConfig = await readConfigFile(require.resolve('../api_integration/config.ts')); return { - ...xpackFunctionalConfig.getAll(), - testFiles: [resolve(__dirname, './routes')], + ...xPackAPITestsConfig.getAll(), + testFiles: [resolve(__dirname, './routes'), resolve(__dirname, './telemetry')], junit: { reportName: 'X-Pack Cloud Security Posture API Tests', }, kbnTestServer: { - ...xpackFunctionalConfig.get('kbnTestServer'), + ...xPackAPITestsConfig.get('kbnTestServer'), serverArgs: [ - ...xpackFunctionalConfig.get('kbnTestServer.serverArgs'), + ...xPackAPITestsConfig.get('kbnTestServer.serverArgs'), /** * Package version is fixed (not latest) so FTR won't suddenly break when package is changed. * diff --git a/x-pack/test/cloud_security_posture_api/routes/benchmarks.ts b/x-pack/test/cloud_security_posture_api/routes/benchmarks.ts index 93ee947cef4a5..d28ffcd73d16d 100644 --- a/x-pack/test/cloud_security_posture_api/routes/benchmarks.ts +++ b/x-pack/test/cloud_security_posture_api/routes/benchmarks.ts @@ -9,7 +9,6 @@ import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST, } from '@kbn/core-http-common'; import { - BENCHMARK_SCORE_INDEX_DEFAULT_NS, CSP_BENCHMARK_RULE_SAVED_OBJECT_TYPE, LATEST_FINDINGS_INDEX_DEFAULT_NS, } from '@kbn/cloud-security-posture-plugin/common/constants'; @@ -18,6 +17,7 @@ import Chance from 'chance'; import { CspBenchmarkRule } from '@kbn/cloud-security-posture-common/schema/rules/latest'; import { FtrProviderContext } from '../ftr_provider_context'; import { CspSecurityCommonProvider } from './helper/user_roles_utilites'; +import { waitForPluginInitialized, EsIndexDataProvider } from '../utils'; const chance = new Chance(); @@ -28,9 +28,10 @@ export default function (providerContext: FtrProviderContext) { const es = getService('es'); const kibanaServer = getService('kibanaServer'); const supertest = getService('supertest'); - const log = getService('log'); + const logger = getService('log'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const cspSecurity = CspSecurityCommonProvider(providerContext); + const findingsIndex = new EsIndexDataProvider(es, LATEST_FINDINGS_INDEX_DEFAULT_NS); const getCspBenchmarkRules = async (benchmarkId: string): Promise => { let cspBenchmarkRules: CspBenchmarkRule[] = []; @@ -78,86 +79,21 @@ export default function (providerContext: FtrProviderContext) { }, }); - /** - * required before indexing findings - */ - const waitForPluginInitialized = (): Promise => - retry.try(async () => { - log.debug('Check CSP plugin is initialized'); - const response = await supertest - .get('/internal/cloud_security_posture/status?check=init') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .expect(200); - expect(response.body).to.eql({ isPluginInitialized: true }); - log.debug('CSP plugin is initialized'); - }); - - const index = { - addFindings: async (findingsMock: T[]) => { - await Promise.all( - findingsMock.map((findingsDoc) => - es.index({ - index: LATEST_FINDINGS_INDEX_DEFAULT_NS, - body: { ...findingsDoc, '@timestamp': new Date().toISOString() }, - refresh: true, - }) - ) - ); - }, - - addScores: async (scoresMock: T[]) => { - await Promise.all( - scoresMock.map((scoreDoc) => - es.index({ - index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, - body: { ...scoreDoc, '@timestamp': new Date().toISOString() }, - refresh: true, - }) - ) - ); - }, - - removeFindings: async () => { - const indexExists = await es.indices.exists({ index: LATEST_FINDINGS_INDEX_DEFAULT_NS }); - - if (indexExists) { - es.deleteByQuery({ - index: LATEST_FINDINGS_INDEX_DEFAULT_NS, - query: { match_all: {} }, - refresh: true, - }); - } - }, - - removeScores: async () => { - const indexExists = await es.indices.exists({ index: BENCHMARK_SCORE_INDEX_DEFAULT_NS }); - - if (indexExists) { - es.deleteByQuery({ - index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, - query: { match_all: {} }, - refresh: true, - }); - } - }, - - deleteFindingsIndex: async () => { - const indexExists = await es.indices.exists({ index: LATEST_FINDINGS_INDEX_DEFAULT_NS }); - - if (indexExists) { - await es.indices.delete({ index: LATEST_FINDINGS_INDEX_DEFAULT_NS }); - } - }, - }; - describe('GET /internal/cloud_security_posture/benchmarks', () => { describe('Get Benchmark API', async () => { beforeEach(async () => { - await index.removeFindings(); + await findingsIndex.deleteAll(); + await kibanaServer.savedObjects.clean({ + types: ['cloud-security-posture-settings'], + }); + await waitForPluginInitialized({ retry, logger, supertest }); + }); + + afterEach(async () => { + await findingsIndex.deleteAll(); await kibanaServer.savedObjects.clean({ types: ['cloud-security-posture-settings'], }); - await waitForPluginInitialized(); }); it('Verify cspm benchmark score is updated when muting rules', async () => { @@ -166,7 +102,7 @@ export default function (providerContext: FtrProviderContext) { const cspmFinding = getMockFinding(benchmarkRules[0], 'passed'); - await index.addFindings([cspmFinding]); + await findingsIndex.addBulk([cspmFinding]); const { body: benchmarksBeforeMute } = await supertest .get('/internal/cloud_security_posture/benchmarks') @@ -219,7 +155,7 @@ export default function (providerContext: FtrProviderContext) { const kspmFinding = getMockFinding(benchmarkRules[0], 'passed'); - await index.addFindings([kspmFinding]); + await findingsIndex.addBulk([kspmFinding]); const { body: benchmarksBeforeMute } = await supertest .get('/internal/cloud_security_posture/benchmarks') .set(ELASTIC_HTTP_VERSION_HEADER, '2') @@ -268,11 +204,18 @@ export default function (providerContext: FtrProviderContext) { describe('Get Benchmark API', async () => { beforeEach(async () => { - await index.removeFindings(); + await findingsIndex.deleteAll(); + await kibanaServer.savedObjects.clean({ + types: ['cloud-security-posture-settings'], + }); + await waitForPluginInitialized({ retry, logger, supertest }); + }); + + afterEach(async () => { + await findingsIndex.deleteAll(); await kibanaServer.savedObjects.clean({ types: ['cloud-security-posture-settings'], }); - await waitForPluginInitialized(); }); it('Calling Benchmark API as User with no read access to Security', async () => { @@ -281,7 +224,7 @@ export default function (providerContext: FtrProviderContext) { const cspmFinding1 = getMockFinding(benchmarkRules[0], 'passed'); - await index.addFindings([cspmFinding1]); + await findingsIndex.addBulk([cspmFinding1]); const { body: benchmarksResult } = await supertestWithoutAuth .get('/internal/cloud_security_posture/benchmarks') @@ -303,7 +246,7 @@ export default function (providerContext: FtrProviderContext) { const cspmFinding1 = getMockFinding(benchmarkRules[0], 'passed'); - await index.addFindings([cspmFinding1]); + await findingsIndex.addBulk([cspmFinding1]); const { status } = await supertestWithoutAuth .get('/internal/cloud_security_posture/benchmarks') diff --git a/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts index b46ecd1ef2943..490eb6453a6be 100644 --- a/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts +++ b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts @@ -22,13 +22,14 @@ import type { CspBenchmarkRule } from '@kbn/cloud-security-posture-common/schema import { generateBenchmarkRuleTags } from '@kbn/cloud-security-posture-plugin/common/utils/detection_rules'; import type { FtrProviderContext } from '../ftr_provider_context'; import { CspSecurityCommonProvider } from './helper/user_roles_utilites'; +import { waitForPluginInitialized } from '../utils'; // eslint-disable-next-line import/no-default-export export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const retry = getService('retry'); const supertest = getService('supertest'); - const log = getService('log'); + const logger = getService('log'); const kibanaServer = getService('kibanaServer'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const cspSecurity = CspSecurityCommonProvider(providerContext); @@ -83,23 +84,9 @@ export default function (providerContext: FtrProviderContext) { return detectionRule; }; - /** - * required before indexing findings - */ - const waitForPluginInitialized = (): Promise => - retry.try(async () => { - log.debug('Check CSP plugin is initialized'); - const response = await supertest - .get('/internal/cloud_security_posture/status?check=init') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .expect(200); - expect(response.body).to.eql({ isPluginInitialized: true }); - log.debug('CSP plugin is initialized'); - }); - describe('Verify update csp rules states API', async () => { before(async () => { - await waitForPluginInitialized(); + await waitForPluginInitialized({ retry, logger, supertest }); }); beforeEach(async () => { @@ -108,6 +95,12 @@ export default function (providerContext: FtrProviderContext) { }); }); + afterEach(async () => { + await kibanaServer.savedObjects.clean({ + types: ['cloud-security-posture-settings', 'alert'], + }); + }); + it('mute benchmark rules successfully', async () => { const rule1 = await getRandomCspBenchmarkRule(); const rule2 = await getRandomCspBenchmarkRule(); diff --git a/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_get_states.ts b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_get_states.ts index 61a22a234b6d0..d2da944e80df7 100644 --- a/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_get_states.ts +++ b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_get_states.ts @@ -16,13 +16,14 @@ import { CSP_BENCHMARK_RULE_SAVED_OBJECT_TYPE } from '@kbn/cloud-security-postur import type { CspBenchmarkRule } from '@kbn/cloud-security-posture-common/schema/rules/latest'; import type { FtrProviderContext } from '../ftr_provider_context'; import { CspSecurityCommonProvider } from './helper/user_roles_utilites'; +import { waitForPluginInitialized } from '../utils'; // eslint-disable-next-line import/no-default-export export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const retry = getService('retry'); const supertest = getService('supertest'); - const log = getService('log'); + const logger = getService('log'); const kibanaServer = getService('kibanaServer'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const cspSecurity = CspSecurityCommonProvider(providerContext); @@ -42,23 +43,9 @@ export default function (providerContext: FtrProviderContext) { return cspBenchmarkRules.saved_objects[randomIndex].attributes; }; - /** - * required before indexing findings - */ - const waitForPluginInitialized = (): Promise => - retry.try(async () => { - log.debug('Check CSP plugin is initialized'); - const response = await supertest - .get('/internal/cloud_security_posture/status?check=init') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .expect(200); - expect(response.body).to.eql({ isPluginInitialized: true }); - log.debug('CSP plugin is initialized'); - }); - describe('Tests get rules states API', async () => { before(async () => { - await waitForPluginInitialized(); + await waitForPluginInitialized({ retry, logger, supertest }); }); beforeEach(async () => { @@ -67,6 +54,12 @@ export default function (providerContext: FtrProviderContext) { }); }); + afterEach(async () => { + await kibanaServer.savedObjects.clean({ + types: ['cloud-security-posture-settings'], + }); + }); + it('get rules states successfully', async () => { const rule1 = await getRandomCspBenchmarkRule(); const rule2 = await getRandomCspBenchmarkRule(); diff --git a/x-pack/test/cloud_security_posture_api/routes/get_detection_engine_alerts_count_by_rule_tags.ts b/x-pack/test/cloud_security_posture_api/routes/get_detection_engine_alerts_count_by_rule_tags.ts index 0b2ceb882ba23..ed3f89d5c6e08 100644 --- a/x-pack/test/cloud_security_posture_api/routes/get_detection_engine_alerts_count_by_rule_tags.ts +++ b/x-pack/test/cloud_security_posture_api/routes/get_detection_engine_alerts_count_by_rule_tags.ts @@ -8,6 +8,7 @@ import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../ftr_provider_context'; import { CspSecurityCommonProvider } from './helper/user_roles_utilites'; +import { waitForPluginInitialized } from '../utils'; // eslint-disable-next-line import/no-default-export export default function (providerContext: FtrProviderContext) { @@ -15,29 +16,16 @@ export default function (providerContext: FtrProviderContext) { const retry = getService('retry'); const supertest = getService('supertest'); - const log = getService('log'); + const logger = getService('log'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const cspSecurity = CspSecurityCommonProvider(providerContext); - /** - * required before indexing findings - */ - const waitForPluginInitialized = (): Promise => - retry.try(async () => { - log.debug('Check CSP plugin is initialized'); - const response = await supertest - .get('/internal/cloud_security_posture/status?check=init') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .expect(200); - expect(response.body).to.eql({ isPluginInitialized: true }); - log.debug('CSP plugin is initialized'); - }); - describe('/internal/cloud_security_posture/detection_engine_rules/alerts/_status', () => { describe('GET detection_engine_rules API with user that has specific access', async () => { before(async () => { - await waitForPluginInitialized(); + await waitForPluginInitialized({ retry, logger, supertest }); }); + it('GET detection_engine_rules API with user with read access', async () => { const { status } = await supertestWithoutAuth .get( diff --git a/x-pack/test/cloud_security_posture_api/routes/index.ts b/x-pack/test/cloud_security_posture_api/routes/index.ts index adacc80fb6f7d..bae346f880723 100644 --- a/x-pack/test/cloud_security_posture_api/routes/index.ts +++ b/x-pack/test/cloud_security_posture_api/routes/index.ts @@ -18,7 +18,6 @@ export default function (providerContext: FtrProviderContext) { await cspSecurity.createUsers(); }); - loadTestFile(require.resolve('../telemetry/telemetry.ts')); loadTestFile(require.resolve('./vulnerabilities_dashboard.ts')); loadTestFile(require.resolve('./stats.ts')); loadTestFile(require.resolve('./csp_benchmark_rules_bulk_update.ts')); diff --git a/x-pack/test/cloud_security_posture_api/routes/stats.ts b/x-pack/test/cloud_security_posture_api/routes/stats.ts index adb2952d5388e..baed734c0f18c 100644 --- a/x-pack/test/cloud_security_posture_api/routes/stats.ts +++ b/x-pack/test/cloud_security_posture_api/routes/stats.ts @@ -27,6 +27,7 @@ import { } from './mocks/benchmark_score_mock'; import { findingsMockData } from './mocks/findings_mock'; import { CspSecurityCommonProvider } from './helper/user_roles_utilites'; +import { waitForPluginInitialized, EsIndexDataProvider } from '../utils'; const removeRealtimeCalculatedFields = (trends: PostureTrend[]) => { return trends.map((trend: PostureTrend) => { @@ -64,88 +65,23 @@ export default function (providerContext: FtrProviderContext) { const log = getService('log'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const cspSecurity = CspSecurityCommonProvider(providerContext); - - /** - * required before indexing findings - */ - const waitForPluginInitialized = (): Promise => - retry.try(async () => { - log.debug('Check CSP plugin is initialized'); - const response = await supertest - .get('/internal/cloud_security_posture/status?check=init') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .expect(200); - expect(response.body).to.eql({ isPluginInitialized: true }); - log.debug('CSP plugin is initialized'); - }); - - const index = { - addFindings: async (findingsMock: T[]) => { - await Promise.all( - findingsMock.map((findingsDoc) => - es.index({ - index: LATEST_FINDINGS_INDEX_DEFAULT_NS, - body: { ...findingsDoc, '@timestamp': new Date().toISOString() }, - refresh: true, - }) - ) - ); - }, - - addScores: async (scoresMock: T[]) => { - await Promise.all( - scoresMock.map((scoreDoc) => - es.index({ - index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, - body: { ...scoreDoc, '@timestamp': new Date().toISOString() }, - refresh: true, - }) - ) - ); - }, - - removeFindings: async () => { - const indexExists = await es.indices.exists({ index: LATEST_FINDINGS_INDEX_DEFAULT_NS }); - - if (indexExists) { - es.deleteByQuery({ - index: LATEST_FINDINGS_INDEX_DEFAULT_NS, - query: { match_all: {} }, - refresh: true, - }); - } - }, - - removeScores: async () => { - const indexExists = await es.indices.exists({ index: BENCHMARK_SCORE_INDEX_DEFAULT_NS }); - - if (indexExists) { - es.deleteByQuery({ - index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, - query: { match_all: {} }, - refresh: true, - }); - } - }, - - deleteFindingsIndex: async () => { - const indexExists = await es.indices.exists({ index: LATEST_FINDINGS_INDEX_DEFAULT_NS }); - - if (indexExists) { - await es.indices.delete({ index: LATEST_FINDINGS_INDEX_DEFAULT_NS }); - } - }, - }; + const findingsIndex = new EsIndexDataProvider(es, LATEST_FINDINGS_INDEX_DEFAULT_NS); + const benchmarkScoreIndex = new EsIndexDataProvider(es, BENCHMARK_SCORE_INDEX_DEFAULT_NS); describe('GET /internal/cloud_security_posture/stats', () => { describe('CSPM Compliance Dashboard Stats API', async () => { beforeEach(async () => { - await index.removeFindings(); - await index.removeScores(); + await findingsIndex.deleteAll(); + await benchmarkScoreIndex.deleteAll(); - await waitForPluginInitialized(); - await index.addScores(getBenchmarkScoreMockData('cspm', true)); - await index.addFindings([findingsMockData[1]]); + await waitForPluginInitialized({ retry, logger: log, supertest }); + await benchmarkScoreIndex.addBulk(getBenchmarkScoreMockData('cspm', true)); + await findingsIndex.addBulk([findingsMockData[1]]); + }); + + afterEach(async () => { + await findingsIndex.deleteAll(); + await benchmarkScoreIndex.deleteAll(); }); it('should return CSPM cluster V1 ', async () => { @@ -185,12 +121,17 @@ export default function (providerContext: FtrProviderContext) { describe('KSPM Compliance Dashboard Stats API', async () => { beforeEach(async () => { - await index.removeFindings(); - await index.removeScores(); + await findingsIndex.deleteAll(); + await benchmarkScoreIndex.deleteAll(); - await waitForPluginInitialized(); - await index.addScores(getBenchmarkScoreMockData('kspm', true)); - await index.addFindings([findingsMockData[0]]); + await waitForPluginInitialized({ retry, logger: log, supertest }); + await benchmarkScoreIndex.addBulk(getBenchmarkScoreMockData('kspm', true)); + await findingsIndex.addBulk([findingsMockData[0]]); + }); + + afterEach(async () => { + await findingsIndex.deleteAll(); + await benchmarkScoreIndex.deleteAll(); }); it('should return KSPM clusters V1 ', async () => { @@ -249,15 +190,23 @@ export default function (providerContext: FtrProviderContext) { describe('Compliance dashboard based on enabled rules', async () => { beforeEach(async () => { - await index.removeFindings(); - await index.removeScores(); + await findingsIndex.deleteAll(); + await benchmarkScoreIndex.deleteAll(); + + await waitForPluginInitialized({ retry, logger: log, supertest }); + }); - await waitForPluginInitialized(); + afterEach(async () => { + await findingsIndex.deleteAll(); + await benchmarkScoreIndex.deleteAll(); }); + it('should calculate cspm benchmarks posture score based only on enabled rules', async () => { - await index.addScores(getBenchmarkScoreMockData('cspm', true)); - await index.addScores(getBenchmarkScoreMockData('cspm', false)); - await index.addFindings([findingsMockData[1]]); + await benchmarkScoreIndex.addBulk([ + ...getBenchmarkScoreMockData('cspm', true), + ...getBenchmarkScoreMockData('cspm', false), + ]); + await findingsIndex.addBulk([findingsMockData[1]]); const { body: res }: { body: ComplianceDashboardDataV2 } = await kibanaHttpClient .get(`/internal/cloud_security_posture/stats/cspm`) @@ -277,9 +226,11 @@ export default function (providerContext: FtrProviderContext) { }); it('should calculate kspm benchmarks posture score based only on enabled rules', async () => { - await index.addScores(getBenchmarkScoreMockData('kspm', true)); - await index.addScores(getBenchmarkScoreMockData('kspm', false)); - await index.addFindings([findingsMockData[0]]); + await benchmarkScoreIndex.addBulk([ + ...getBenchmarkScoreMockData('kspm', true), + ...getBenchmarkScoreMockData('kspm', false), + ]); + await findingsIndex.addBulk([findingsMockData[0]]); const { body: res }: { body: ComplianceDashboardDataV2 } = await kibanaHttpClient .get(`/internal/cloud_security_posture/stats/kspm`) @@ -301,30 +252,23 @@ export default function (providerContext: FtrProviderContext) { describe('GET stats API with user that has specific access', async () => { beforeEach(async () => { - await index.removeFindings(); - await index.removeScores(); + await findingsIndex.deleteAll(); + await benchmarkScoreIndex.deleteAll(); - await waitForPluginInitialized(); + await waitForPluginInitialized({ retry, logger: log, supertest }); }); - it('GET stats API V1 with user with read access', async () => { - await index.addScores(getBenchmarkScoreMockData('cspm', true)); - await index.addScores(getBenchmarkScoreMockData('cspm', false)); - await index.addFindings([findingsMockData[1]]); - const { status } = await supertestWithoutAuth - .get(`/internal/cloud_security_posture/stats/cspm`) - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set('kbn-xsrf', 'xxxx') - .auth( - 'role_security_read_user', - cspSecurity.getPasswordForUser('role_security_read_user') - ); - expect(status).to.be(200); + afterEach(async () => { + await findingsIndex.deleteAll(); + await benchmarkScoreIndex.deleteAll(); }); + it('GET stats API V1 with user with read access', async () => { - await index.addScores(getBenchmarkScoreMockData('cspm', true)); - await index.addScores(getBenchmarkScoreMockData('cspm', false)); - await index.addFindings([findingsMockData[1]]); + await benchmarkScoreIndex.addBulk([ + ...getBenchmarkScoreMockData('cspm', true), + ...getBenchmarkScoreMockData('cspm', false), + ]); + await findingsIndex.addBulk([findingsMockData[1]]); const { status } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/stats/cspm`) @@ -336,10 +280,13 @@ export default function (providerContext: FtrProviderContext) { ); expect(status).to.be(200); }); + it('GET stats API V2 with user with read access', async () => { - await index.addScores(getBenchmarkScoreMockData('cspm', true)); - await index.addScores(getBenchmarkScoreMockData('cspm', false)); - await index.addFindings([findingsMockData[1]]); + await benchmarkScoreIndex.addBulk([ + ...getBenchmarkScoreMockData('cspm', true), + ...getBenchmarkScoreMockData('cspm', false), + ]); + await findingsIndex.addBulk([findingsMockData[1]]); const { status } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/stats/cspm`) @@ -353,9 +300,11 @@ export default function (providerContext: FtrProviderContext) { }); it('GET stats API V2 with user without read access', async () => { - await index.addScores(getBenchmarkScoreMockData('kspm', true)); - await index.addScores(getBenchmarkScoreMockData('kspm', false)); - await index.addFindings([findingsMockData[0]]); + await benchmarkScoreIndex.addBulk([ + ...getBenchmarkScoreMockData('kspm', true), + ...getBenchmarkScoreMockData('kspm', false), + ]); + await findingsIndex.addBulk([findingsMockData[0]]); const { status } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/stats/kspm`) diff --git a/x-pack/test/cloud_security_posture_api/routes/status.ts b/x-pack/test/cloud_security_posture_api/routes/status.ts index 0004144575956..d73b059f16ecc 100644 --- a/x-pack/test/cloud_security_posture_api/routes/status.ts +++ b/x-pack/test/cloud_security_posture_api/routes/status.ts @@ -8,6 +8,7 @@ import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../ftr_provider_context'; import { CspSecurityCommonProvider } from './helper/user_roles_utilites'; +import { waitForPluginInitialized } from '../utils'; // eslint-disable-next-line import/no-default-export export default function (providerContext: FtrProviderContext) { @@ -15,29 +16,16 @@ export default function (providerContext: FtrProviderContext) { const retry = getService('retry'); const supertest = getService('supertest'); - const log = getService('log'); + const logger = getService('log'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const cspSecurity = CspSecurityCommonProvider(providerContext); - /** - * required before indexing findings - */ - const waitForPluginInitialized = (): Promise => - retry.try(async () => { - log.debug('Check CSP plugin is initialized'); - const response = await supertest - .get('/internal/cloud_security_posture/status?check=init') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .expect(200); - expect(response.body).to.eql({ isPluginInitialized: true }); - log.debug('CSP plugin is initialized'); - }); - describe('GET /internal/cloud_security_posture/status', () => { describe('GET status API with user that has specific access', async () => { before(async () => { - await waitForPluginInitialized(); + await waitForPluginInitialized({ retry, logger, supertest }); }); + it('GET stats API with user with read access', async () => { const { status } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) diff --git a/x-pack/test/cloud_security_posture_api/routes/vulnerabilities_dashboard.ts b/x-pack/test/cloud_security_posture_api/routes/vulnerabilities_dashboard.ts index 8ed4f91a61fea..30bae105df8e9 100644 --- a/x-pack/test/cloud_security_posture_api/routes/vulnerabilities_dashboard.ts +++ b/x-pack/test/cloud_security_posture_api/routes/vulnerabilities_dashboard.ts @@ -14,6 +14,7 @@ import { scoresVulnerabilitiesMock, } from './mocks/vulnerabilities_latest_mock'; import { CspSecurityCommonProvider } from './helper/user_roles_utilites'; +import { EsIndexDataProvider, waitForPluginInitialized } from '../utils'; export interface CnvmStatistics { criticalCount?: number; @@ -112,89 +113,24 @@ export default function (providerContext: FtrProviderContext) { const retry = getService('retry'); const es = getService('es'); const supertest = getService('supertest'); - const log = getService('log'); + const logger = getService('log'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const cspSecurity = CspSecurityCommonProvider(providerContext); - - /** - * required before indexing findings - */ - const waitForPluginInitialized = (): Promise => - retry.try(async () => { - log.debug('Check CSP plugin is initialized'); - const response = await supertest - .get('/internal/cloud_security_posture/status?check=init') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .expect(200); - expect(response.body).to.eql({ isPluginInitialized: true }); - log.debug('CSP plugin is initialized'); - }); - - const index = { - addFindings: async (vulnerabilitiesMock: T[]) => { - await Promise.all( - vulnerabilitiesMock.map((vulnerabilityDoc) => - es.index({ - index: VULNERABILITIES_LATEST_INDEX, - body: vulnerabilityDoc, - refresh: true, - }) - ) - ); - }, - - addScores: async (scoresMock: T[]) => { - await Promise.all( - scoresMock.map((scoreDoc) => - es.index({ - index: BENCHMARK_SCORES_INDEX, - body: scoreDoc, - refresh: true, - }) - ) - ); - }, - - removeFindings: async () => { - const indexExists = await es.indices.exists({ index: VULNERABILITIES_LATEST_INDEX }); - - if (indexExists) { - await es.deleteByQuery({ - index: VULNERABILITIES_LATEST_INDEX, - query: { match_all: {} }, - refresh: true, - }); - } - }, - - removeScores: async () => { - const indexExists = await es.indices.exists({ index: BENCHMARK_SCORES_INDEX }); - - if (indexExists) { - await es.deleteByQuery({ - index: BENCHMARK_SCORES_INDEX, - query: { match_all: {} }, - refresh: true, - }); - } - }, - - deleteFindingsIndex: async () => { - const indexExists = await es.indices.exists({ index: VULNERABILITIES_LATEST_INDEX }); - - if (indexExists) { - await es.indices.delete({ index: VULNERABILITIES_LATEST_INDEX }); - } - }, - }; + const vulnerabilitiesIndex = new EsIndexDataProvider(es, VULNERABILITIES_LATEST_INDEX); + const scoresIndex = new EsIndexDataProvider(es, BENCHMARK_SCORES_INDEX); describe('Vulnerability Dashboard API', async () => { beforeEach(async () => { - await index.removeFindings(); - await index.removeScores(); - await waitForPluginInitialized(); - await index.addScores(scoresVulnerabilitiesMock); - await index.addFindings(vulnerabilitiesLatestMock); + await vulnerabilitiesIndex.deleteAll(); + await scoresIndex.deleteAll(); + await waitForPluginInitialized({ retry, logger, supertest }); + await scoresIndex.addBulk(scoresVulnerabilitiesMock, false); + await vulnerabilitiesIndex.addBulk(vulnerabilitiesLatestMock, false); + }); + + afterEach(async () => { + await vulnerabilitiesIndex.deleteAll(); + await scoresIndex.deleteAll(); }); it('responds with a 200 status code and matching data mock', async () => { @@ -301,7 +237,7 @@ export default function (providerContext: FtrProviderContext) { }); it('returns a 400 error when necessary indices are nonexistent', async () => { - await index.deleteFindingsIndex(); + await vulnerabilitiesIndex.destroyIndex(); await supertest .get('/internal/cloud_security_posture/vulnerabilities_dashboard') diff --git a/x-pack/test/cloud_security_posture_api/telemetry/index.ts b/x-pack/test/cloud_security_posture_api/telemetry/index.ts new file mode 100644 index 0000000000000..4b0be2126e3d4 --- /dev/null +++ b/x-pack/test/cloud_security_posture_api/telemetry/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function (providerContext: FtrProviderContext) { + const { loadTestFile } = providerContext; + + describe('Cloud Security Posture', function () { + loadTestFile(require.resolve('./telemetry.ts')); + }); +} diff --git a/x-pack/test/cloud_security_posture_api/telemetry/telemetry.ts b/x-pack/test/cloud_security_posture_api/telemetry/telemetry.ts index e5867ccd74897..a3548bb255348 100644 --- a/x-pack/test/cloud_security_posture_api/telemetry/telemetry.ts +++ b/x-pack/test/cloud_security_posture_api/telemetry/telemetry.ts @@ -10,8 +10,9 @@ import { ELASTIC_HTTP_VERSION_HEADER, X_ELASTIC_INTERNAL_ORIGIN_REQUEST, } from '@kbn/core-http-common'; -import { data, MockTelemetryFindings } from './data'; +import { data } from './data'; import type { FtrProviderContext } from '../ftr_provider_context'; +import { waitForPluginInitialized, EsIndexDataProvider } from '../utils'; const FINDINGS_INDEX = 'logs-cloud_security_posture.findings_latest-default'; @@ -20,52 +21,20 @@ export default function ({ getService }: FtrProviderContext) { const retry = getService('retry'); const es = getService('es'); const supertest = getService('supertest'); - const log = getService('log'); - - /** - * required before indexing findings - */ - const waitForPluginInitialized = (): Promise => - retry.try(async () => { - log.debug('Check CSP plugin is initialized'); - const response = await supertest - .get('/internal/cloud_security_posture/status?check=init') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .expect(200); - expect(response.body).to.eql({ isPluginInitialized: true }); - log.debug('CSP plugin is initialized'); - }); - - const index = { - remove: () => - es.deleteByQuery({ - index: FINDINGS_INDEX, - query: { match_all: {} }, - refresh: true, - }), - - add: async (mockTelemetryFindings: MockTelemetryFindings[]) => { - const operations = mockTelemetryFindings.flatMap((doc) => [ - { index: { _index: FINDINGS_INDEX } }, - doc, - ]); - - const response = await es.bulk({ refresh: 'wait_for', index: FINDINGS_INDEX, operations }); - expect(response.errors).to.eql(false); - }, - }; + const logger = getService('log'); + const findingsIndexProvider = new EsIndexDataProvider(es, FINDINGS_INDEX); describe('Verify cloud_security_posture telemetry payloads', async () => { before(async () => { - await waitForPluginInitialized(); + await waitForPluginInitialized({ retry, logger, supertest }); }); afterEach(async () => { - await index.remove(); + await findingsIndexProvider.deleteAll(); }); it('includes only KSPM findings', async () => { - await index.add(data.kspmFindings); + await findingsIndexProvider.addBulk(data.kspmFindings, false); const { body: [{ stats: apiResponse }], @@ -119,7 +88,7 @@ export default function ({ getService }: FtrProviderContext) { }); it('includes only CSPM findings', async () => { - await index.add(data.cspmFindings); + await findingsIndexProvider.addBulk(data.cspmFindings, false); const { body: [{ stats: apiResponse }], @@ -165,8 +134,8 @@ export default function ({ getService }: FtrProviderContext) { }); it('includes CSPM and KSPM findings', async () => { - await index.add(data.kspmFindings); - await index.add(data.cspmFindings); + await findingsIndexProvider.addBulk(data.kspmFindings, false); + await findingsIndexProvider.addBulk(data.cspmFindings, false); const { body: [{ stats: apiResponse }], @@ -244,7 +213,7 @@ export default function ({ getService }: FtrProviderContext) { }); it(`'includes only KSPM findings without posture_type'`, async () => { - await index.add(data.kspmFindingsNoPostureType); + await findingsIndexProvider.addBulk(data.kspmFindingsNoPostureType, false); const { body: [{ stats: apiResponse }], @@ -299,8 +268,8 @@ export default function ({ getService }: FtrProviderContext) { }); it('includes KSPM findings without posture_type and CSPM findings as well', async () => { - await index.add(data.kspmFindingsNoPostureType); - await index.add(data.cspmFindings); + await findingsIndexProvider.addBulk(data.kspmFindingsNoPostureType, false); + await findingsIndexProvider.addBulk(data.cspmFindings, false); const { body: [{ stats: apiResponse }], diff --git a/x-pack/test/cloud_security_posture_api/utils.ts b/x-pack/test/cloud_security_posture_api/utils.ts new file mode 100644 index 0000000000000..6f0d86419a349 --- /dev/null +++ b/x-pack/test/cloud_security_posture_api/utils.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RetryService } from '@kbn/ftr-common-functional-services'; +import type { Agent } from 'supertest'; +import type { ToolingLog } from '@kbn/tooling-log'; +import type { Client as EsClient } from '@elastic/elasticsearch'; +import expect from '@kbn/expect'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; + +/** + * Checks if plugin initialization was done + * Required before indexing findings + */ +export const waitForPluginInitialized = ({ + retry, + logger, + supertest, +}: { + retry: RetryService; + logger: ToolingLog; + supertest: Agent; +}): Promise => + retry.try(async () => { + logger.debug('Check CSP plugin is initialized'); + const response = await supertest + .get('/internal/cloud_security_posture/status?check=init') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .expect(200); + expect(response.body).to.eql({ isPluginInitialized: true }); + logger.debug('CSP plugin is initialized'); + }); + +export class EsIndexDataProvider { + private es: EsClient; + private index: string; + + constructor(es: EsClient, index: string) { + this.es = es; + this.index = index; + } + + addBulk(docs: Array>, overrideTimestamp = true) { + const operations = docs.flatMap((doc) => [ + { index: { _index: this.index } }, + { ...doc, ...(overrideTimestamp ? { '@timestamp': new Date().toISOString() } : {}) }, + ]); + + return this.es.bulk({ refresh: 'wait_for', index: this.index, operations }); + } + + async deleteAll() { + const indexExists = await this.es.indices.exists({ index: this.index }); + + if (indexExists) { + return this.es.deleteByQuery({ + index: this.index, + query: { match_all: {} }, + refresh: true, + }); + } + } + + async destroyIndex() { + const indexExists = await this.es.indices.exists({ index: this.index }); + + if (indexExists) { + return this.es.indices.delete({ index: this.index }); + } + } +} From 26d5634b23fc76d7a87aaba53892dabb31866d54 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Tue, 8 Oct 2024 18:43:52 -0300 Subject: [PATCH 029/110] [Unified Field List] Fix issue where Unified Field List field popover gets cut off (#195147) ## Summary This PR fixes an issue where the Unified Field List field popover can get cut off if its contents exceed the view height. Now, instead of cutting off the popover, we limit the content height to `90vh` and make the main section scrollable. Before (from #194313 test failure): ![image](https://github.com/user-attachments/assets/5927a899-a18a-4431-bd1d-6bb2682cd004) After: ![scroll](https://github.com/user-attachments/assets/5071a52b-fbf4-4d05-96de-61858d9e5598) Flaky test runs: - https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7098 Fixes #194313. Fixes #193934. Fixes #193781. ### Checklist - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../field_popover/field_popover.tsx | 48 +++- .../field_list_item.tsx | 42 +++- packages/kbn-unified-field-list/tsconfig.json | 3 +- .../public/datasources/common/field_item.tsx | 225 ++++++++++-------- 4 files changed, 201 insertions(+), 117 deletions(-) diff --git a/packages/kbn-unified-field-list/src/components/field_popover/field_popover.tsx b/packages/kbn-unified-field-list/src/components/field_popover/field_popover.tsx index 0b065cc504677..efa4d8d4c9e51 100644 --- a/packages/kbn-unified-field-list/src/components/field_popover/field_popover.tsx +++ b/packages/kbn-unified-field-list/src/components/field_popover/field_popover.tsx @@ -8,12 +8,20 @@ */ import React from 'react'; -import { EuiPopover, EuiPopoverProps, EuiPopoverTitle } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiPopover, + EuiPopoverProps, + EuiPopoverTitle, +} from '@elastic/eui'; import './field_popover.scss'; +import { euiThemeVars } from '@kbn/ui-theme'; export interface FieldPopoverProps extends EuiPopoverProps { renderHeader?: () => React.ReactNode; renderContent?: () => React.ReactNode; + renderFooter?: () => React.ReactNode; } export const FieldPopover: React.FC = ({ @@ -21,10 +29,12 @@ export const FieldPopover: React.FC = ({ closePopover, renderHeader, renderContent, + renderFooter, ...otherPopoverProps }) => { - let header = null; - let content = null; + let header: React.ReactNode | null = null; + let content: React.ReactNode | null = null; + let footer: React.ReactNode | null = null; if (isOpen) { try { @@ -40,6 +50,13 @@ export const FieldPopover: React.FC = ({ // eslint-disable-next-line no-console console.error(error); } + + try { + footer = renderFooter?.() || null; + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + } } return ( @@ -54,10 +71,27 @@ export const FieldPopover: React.FC = ({ {...otherPopoverProps} > {isOpen && ( - <> - {content && header ? {header} : header} - {content} - + + {Boolean(header) && ( + + {content ? {header} : header} + + )} + {content ? ( + + {content} + + ) : ( + content + )} + {Boolean(footer) && {footer}} + )} ); diff --git a/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.tsx b/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.tsx index 658bf96dc76c9..7864976c1180f 100644 --- a/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.tsx +++ b/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.tsx @@ -309,22 +309,39 @@ function UnifiedFieldListItemComponent({ /> )} - - {searchMode === 'documents' && !!services.uiActions && ( - - )} ); }; + const renderFooter = useMemo(() => { + const uiActions = services.uiActions; + + if (searchMode !== 'documents' || !uiActions) { + return; + } + + return () => ( + + ); + }, [ + dataView, + field, + rawMultiFields, + searchMode, + services.uiActions, + stateService.creationOptions.originatingApp, + trackUiMetric, + workspaceSelectedFieldNames, + ]); + const value = useMemo( () => ({ id: field.name, @@ -393,6 +410,7 @@ function UnifiedFieldListItemComponent({ ? renderPopover : undefined } + renderFooter={renderFooter} /> ); } diff --git a/packages/kbn-unified-field-list/tsconfig.json b/packages/kbn-unified-field-list/tsconfig.json index f5015d66f0838..830e56ac6ab00 100644 --- a/packages/kbn-unified-field-list/tsconfig.json +++ b/packages/kbn-unified-field-list/tsconfig.json @@ -34,7 +34,8 @@ "@kbn/visualization-utils", "@kbn/esql-utils", "@kbn/search-types", - "@kbn/fields-metadata-plugin" + "@kbn/fields-metadata-plugin", + "@kbn/ui-theme" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/lens/public/datasources/common/field_item.tsx b/x-pack/plugins/lens/public/datasources/common/field_item.tsx index efa13eb708e5a..b76dc9f4b9641 100644 --- a/x-pack/plugins/lens/public/datasources/common/field_item.tsx +++ b/x-pack/plugins/lens/public/datasources/common/field_item.tsx @@ -74,6 +74,8 @@ export type FieldItemProps = FieldItemIndexPatternFieldProps | FieldItemDatatabl export function InnerFieldItem(props: FieldItemProps) { const { + query, + filters, field, indexPattern, highlight, @@ -193,6 +195,56 @@ export function InnerFieldItem(props: FieldItemProps) { onAddFieldToWorkspace, }; + const renderFooter = useMemo(() => { + if (hideDetails || !indexPattern) { + return; + } + + if (dataViewField.type === 'geo_point' || dataViewField.type === 'geo_shape') { + return () => ( + indexPattern.spec } as unknown as DataView} + originatingApp={APP_ID} + uiActions={services.uiActions} + buttonProps={{ + 'data-test-subj': `lensVisualize-GeoField-${dataViewField.name}`, + }} + /> + ); + } + + return function ExplorerInDiscover() { + const exploreInDiscover = useMemo( + () => + getExploreInDiscover({ + query, + filters, + indexPattern, + dataViewField, + services, + }), + [] + ); + + return exploreInDiscover ? ( + + + {i18n.translate('xpack.lens.indexPattern.fieldExploreInDiscover', { + defaultMessage: 'Explore in Discover', + })} + + + ) : null; + }; + }, [dataViewField, filters, hideDetails, indexPattern, query, services]); + return (
  • ); @@ -264,108 +317,86 @@ function FieldItemPopoverContents( const { query, filters, indexPattern, dataViewField, dateRange, onAddFilter } = props; const services = useKibana().services; - const exploreInDiscover = useMemo(() => { - if (!indexPattern) { - return null; - } - const meta = { - id: indexPattern.id, - columns: [dataViewField.name], - filters: { - enabled: { - lucene: [], - kuery: [], - }, - disabled: { - lucene: [], - kuery: [], - }, - }, - }; - const { filters: newFilters, query: newQuery } = combineQueryAndFilters( - query, - filters, - meta, - [indexPattern], - getEsQueryConfig(services.uiSettings) - ); - const discoverLocator = services.share?.url.locators.get('DISCOVER_APP_LOCATOR'); - if (!discoverLocator || !services.application.capabilities.discover.show) { - return; - } - return discoverLocator.getRedirectUrl({ - dataViewSpec: indexPattern?.spec, - timeRange: services.data.query.timefilter.timefilter.getTime(), - filters: newFilters, - query: newQuery, - columns: meta.columns, - }); - }, [dataViewField.name, filters, indexPattern, query, services]); - if (!indexPattern) { return null; } return ( - <> - { - if (params.reason === 'no-data') { - // TODO: should we replace this with a default message "Analysis is not available for this field?" - return ( - - {i18n.translate('xpack.lens.indexPattern.fieldStatsNoData', { - defaultMessage: - 'Lens is unable to create visualizations with this field because it does not contain data. To create a visualization, drag and drop a different field.', - })} - - ); - } - if (params.reason === 'unsupported') { - return ( - - {params.element} - - ); - } - return params.element; - }} - /> + { + if (params.reason === 'no-data') { + // TODO: should we replace this with a default message "Analysis is not available for this field?" + return ( + + {i18n.translate('xpack.lens.indexPattern.fieldStatsNoData', { + defaultMessage: + 'Lens is unable to create visualizations with this field because it does not contain data. To create a visualization, drag and drop a different field.', + })} + + ); + } + if (params.reason === 'unsupported') { + return ( + {params.element} + ); + } + return params.element; + }} + /> + ); +} - {dataViewField.type === 'geo_point' || dataViewField.type === 'geo_shape' ? ( - indexPattern.spec } as unknown as DataView} - originatingApp={APP_ID} - uiActions={services.uiActions} - buttonProps={{ - 'data-test-subj': `lensVisualize-GeoField-${dataViewField.name}`, - }} - /> - ) : exploreInDiscover ? ( - - - {i18n.translate('xpack.lens.indexPattern.fieldExploreInDiscover', { - defaultMessage: 'Explore in Discover', - })} - - - ) : null} - +function getExploreInDiscover({ + query, + filters, + indexPattern, + dataViewField, + services, +}: Pick & { + filters: NonNullable; + indexPattern: NonNullable; + dataViewField: DataViewField; + services: LensAppServices; +}) { + const meta = { + id: indexPattern.id, + columns: [dataViewField.name], + filters: { + enabled: { + lucene: [], + kuery: [], + }, + disabled: { + lucene: [], + kuery: [], + }, + }, + }; + const { filters: newFilters, query: newQuery } = combineQueryAndFilters( + query, + filters, + meta, + [indexPattern], + getEsQueryConfig(services.uiSettings) ); + const discoverLocator = services.share?.url.locators.get('DISCOVER_APP_LOCATOR'); + if (!discoverLocator || !services.application.capabilities.discover.show) { + return; + } + return discoverLocator.getRedirectUrl({ + dataViewSpec: indexPattern?.spec, + timeRange: services.data.query.timefilter.timefilter.getTime(), + filters: newFilters, + query: newQuery, + columns: meta.columns, + }); } From 38d0bdd3deeb72ca4e502361fb0df1f68fa7f443 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Tue, 8 Oct 2024 16:31:05 -0600 Subject: [PATCH 030/110] [Security GenAI] Remove `assistantBedrockChat` feature flag (#195461) --- .../kbn_elastic_assistant_common.devdocs.json | 10 +- api_docs/security_solution.devdocs.json | 14 +- .../impl/capabilities/index.ts | 1 - .../get_capabilities_route.gen.ts | 1 - .../get_capabilities_route.schema.yaml | 3 - .../server/lib/langchain/executors/types.ts | 1 - .../graphs/default_assistant_graph/graph.ts | 4 - .../default_assistant_graph/helpers.test.ts | 179 ++++++++++-------- .../graphs/default_assistant_graph/helpers.ts | 53 +----- .../graphs/default_assistant_graph/index.ts | 10 +- .../nodes/model_input.ts | 4 +- .../graphs/default_assistant_graph/types.ts | 2 - .../server/routes/evaluate/post_evaluate.ts | 3 +- .../server/routes/helpers.ts | 3 - .../elastic_assistant/server/routes/utils.ts | 20 +- .../plugins/elastic_assistant/server/types.ts | 4 +- .../common/experimental_features.ts | 5 - .../security_solution/server/plugin.ts | 1 - 18 files changed, 131 insertions(+), 187 deletions(-) diff --git a/api_docs/kbn_elastic_assistant_common.devdocs.json b/api_docs/kbn_elastic_assistant_common.devdocs.json index 656f443af83e8..5003d97686fa9 100644 --- a/api_docs/kbn_elastic_assistant_common.devdocs.json +++ b/api_docs/kbn_elastic_assistant_common.devdocs.json @@ -844,7 +844,7 @@ "\nInterface for features available to the elastic assistant" ], "signature": [ - "{ readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantModelEvaluation: boolean; readonly assistantBedrockChat: boolean; }" + "{ readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantModelEvaluation: boolean; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts", "deprecated": false, @@ -2604,7 +2604,7 @@ "label": "GetCapabilitiesResponse", "description": [], "signature": [ - "{ assistantKnowledgeBaseByDefault: boolean; assistantModelEvaluation: boolean; assistantBedrockChat: boolean; }" + "{ assistantKnowledgeBaseByDefault: boolean; assistantModelEvaluation: boolean; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts", "deprecated": false, @@ -4567,7 +4567,7 @@ "\nDefault features available to the elastic assistant" ], "signature": [ - "{ readonly assistantKnowledgeBaseByDefault: false; readonly assistantModelEvaluation: false; readonly assistantBedrockChat: true; }" + "{ readonly assistantKnowledgeBaseByDefault: false; readonly assistantModelEvaluation: false; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts", "deprecated": false, @@ -5032,7 +5032,7 @@ "label": "GetCapabilitiesResponse", "description": [], "signature": [ - "Zod.ZodObject<{ assistantBedrockChat: Zod.ZodBoolean; assistantKnowledgeBaseByDefault: Zod.ZodBoolean; assistantModelEvaluation: Zod.ZodBoolean; }, \"strip\", Zod.ZodTypeAny, { assistantKnowledgeBaseByDefault: boolean; assistantModelEvaluation: boolean; assistantBedrockChat: boolean; }, { assistantKnowledgeBaseByDefault: boolean; assistantModelEvaluation: boolean; assistantBedrockChat: boolean; }>" + "Zod.ZodObject<{ assistantKnowledgeBaseByDefault: Zod.ZodBoolean; assistantModelEvaluation: Zod.ZodBoolean; }, \"strip\", Zod.ZodTypeAny, { assistantKnowledgeBaseByDefault: boolean; assistantModelEvaluation: boolean; }, { assistantKnowledgeBaseByDefault: boolean; assistantModelEvaluation: boolean; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts", "deprecated": false, @@ -5986,4 +5986,4 @@ } ] } -} \ No newline at end of file +} diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index 5ad3a3044bd42..69fab0e918ea7 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -420,7 +420,7 @@ "\nExperimental flag needed to enable the link" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"assistantBedrockChat\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"assistantNaturalLanguageESQLTool\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"loggingRequestsEnabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"assistantNaturalLanguageESQLTool\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"loggingRequestsEnabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -500,7 +500,7 @@ "\nExperimental flag needed to disable the link. Opposite of experimentalKey" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"assistantBedrockChat\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"assistantNaturalLanguageESQLTool\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"loggingRequestsEnabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"assistantNaturalLanguageESQLTool\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"loggingRequestsEnabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -1864,7 +1864,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantBedrockChat: boolean; readonly assistantNaturalLanguageESQLTool: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantNaturalLanguageESQLTool: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -3032,7 +3032,7 @@ "\nThe security solution generic experimental features" ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantBedrockChat: boolean; readonly assistantNaturalLanguageESQLTool: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantNaturalLanguageESQLTool: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", "deprecated": false, @@ -3208,7 +3208,7 @@ "label": "ExperimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantBedrockChat: boolean; readonly assistantNaturalLanguageESQLTool: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantNaturalLanguageESQLTool: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3274,7 +3274,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly endpointManagementSpaceAwarenessEnabled: false; readonly securitySolutionNotesEnabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly assistantBedrockChat: true; readonly assistantNaturalLanguageESQLTool: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly loggingRequestsEnabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly responseActionsTelemetryEnabled: false; readonly jamfDataInAnalyzerEnabled: true; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: false; readonly entityStoreEnabled: false; }" + "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly endpointManagementSpaceAwarenessEnabled: false; readonly securitySolutionNotesEnabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly assistantNaturalLanguageESQLTool: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly loggingRequestsEnabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly responseActionsTelemetryEnabled: false; readonly jamfDataInAnalyzerEnabled: true; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: false; readonly entityStoreEnabled: false; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3283,4 +3283,4 @@ } ] } -} \ No newline at end of file +} diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts index d97f2aef17b4b..c1c101fd74cd8 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts @@ -21,5 +21,4 @@ export type AssistantFeatureKey = keyof AssistantFeatures; export const defaultAssistantFeatures = Object.freeze({ assistantKnowledgeBaseByDefault: false, assistantModelEvaluation: false, - assistantBedrockChat: true, }); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts index 55797f5d97847..b3ab7cca5bc02 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts @@ -18,7 +18,6 @@ import { z } from '@kbn/zod'; export type GetCapabilitiesResponse = z.infer; export const GetCapabilitiesResponse = z.object({ - assistantBedrockChat: z.boolean(), assistantKnowledgeBaseByDefault: z.boolean(), assistantModelEvaluation: z.boolean(), }); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml index 0f07d1f58afe5..01b5eb0e15823 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml @@ -20,14 +20,11 @@ paths: schema: type: object properties: - assistantBedrockChat: - type: boolean assistantKnowledgeBaseByDefault: type: boolean assistantModelEvaluation: type: boolean required: - - assistantBedrockChat - assistantKnowledgeBaseByDefault - assistantModelEvaluation '400': diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts index 5761201849c09..3e573aff2f4c8 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts @@ -37,7 +37,6 @@ export interface AgentExecutorParams { abortSignal?: AbortSignal; alertsIndexPattern?: string; actionsClient: PublicMethodsOf; - bedrockChatEnabled: boolean; assistantTools?: AssistantTool[]; connectorId: string; conversationId?: string; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/graph.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/graph.ts index 8f2f713c170ed..dba756b9f3c9e 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/graph.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/graph.ts @@ -86,10 +86,6 @@ export const getDefaultAssistantGraph = ({ value: (x: string, y?: string) => y ?? x, default: () => 'unknown', }, - bedrockChatEnabled: { - value: (x: boolean, y?: boolean) => y ?? x, - default: () => false, - }, isStream: { value: (x: boolean, y?: boolean) => y ?? x, default: () => false, diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.test.ts index f15941e9931fe..d9ccd769592ff 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.test.ts @@ -49,6 +49,18 @@ describe('streamGraph', () => { streamEvents: mockStreamEvents, } as unknown as DefaultAssistantGraph; const mockOnLlmResponse = jest.fn().mockResolvedValue(null); + const requestArgs = { + apmTracer: mockApmTracer, + assistantGraph: mockAssistantGraph, + inputs: { + input: 'input', + responseLanguage: 'English', + llmType: 'openai', + }, + logger: mockLogger, + onLlmResponse: mockOnLlmResponse, + request: mockRequest, + }; beforeEach(() => { jest.clearAllMocks(); @@ -59,8 +71,8 @@ describe('streamGraph', () => { transaction: { ids: { 'transaction.id': 'transactionId' } }, }); }); - describe('ActionsClientChatOpenAI', () => { - it('should execute the graph in streaming mode', async () => { + describe('OpenAI Function Agent streaming', () => { + it('should execute the graph in streaming mode - OpenAI + isOssModel = false', async () => { mockStreamEvents.mockReturnValue({ next: jest .fn() @@ -93,19 +105,7 @@ describe('streamGraph', () => { return: jest.fn(), }); - const response = await streamGraph({ - apmTracer: mockApmTracer, - assistantGraph: mockAssistantGraph, - inputs: { - input: 'input', - bedrockChatEnabled: false, - llmType: 'openai', - responseLanguage: 'English', - }, - logger: mockLogger, - onLlmResponse: mockOnLlmResponse, - request: mockRequest, - }); + const response = await streamGraph(requestArgs); expect(response).toBe(mockResponseWithHeaders); expect(mockPush).toHaveBeenCalledWith({ payload: 'content', type: 'content' }); @@ -119,78 +119,49 @@ describe('streamGraph', () => { }); }); - describe('ActionsClientSimpleChatModel', () => { - it('should execute the graph in streaming mode', async () => { - mockStreamEvents.mockReturnValue({ - next: jest - .fn() - .mockResolvedValueOnce({ - value: { - name: 'ActionsClientSimpleChatModel', - event: 'on_llm_stream', - data: { - chunk: { - content: - '```json\n\n "action": "Final Answer",\n "action_input": "Look at these', - }, - }, - tags: [AGENT_NODE_TAG], + describe('Tool Calling Agent and Structured Chat Agent streaming', () => { + const mockAsyncIterator = { + async *[Symbol.asyncIterator]() { + yield { + event: 'on_chat_model_stream', + data: { + chunk: { + content: 'Look at these', }, - done: false, - }) - .mockResolvedValueOnce({ - value: { - name: 'ActionsClientSimpleChatModel', - event: 'on_llm_stream', - data: { - chunk: { - content: ' rare IP', - }, - }, - tags: [AGENT_NODE_TAG], + }, + tags: [AGENT_NODE_TAG], + }; + yield { + event: 'on_chat_model_stream', + data: { + chunk: { + content: ' rare IP', }, - done: false, - }) - .mockResolvedValueOnce({ - value: { - name: 'ActionsClientSimpleChatModel', - event: 'on_llm_stream', - data: { - chunk: { - content: ' addresses." }```', - }, - }, - tags: [AGENT_NODE_TAG], + }, + tags: [AGENT_NODE_TAG], + }; + yield { + event: 'on_chat_model_stream', + data: { + chunk: { + content: ' addresses.', }, - done: false, - }) - .mockResolvedValueOnce({ - value: { - name: 'ActionsClientSimpleChatModel', - event: 'on_llm_end', - tags: [AGENT_NODE_TAG], + }, + tags: [AGENT_NODE_TAG], + }; + yield { + event: 'on_chat_model_end', + data: { + output: { + content: 'Look at these rare IP addresses.', }, - }) - .mockResolvedValue({ - done: true, - }), - return: jest.fn(), - }); - - const response = await streamGraph({ - apmTracer: mockApmTracer, - assistantGraph: mockAssistantGraph, - inputs: { - input: 'input', - bedrockChatEnabled: false, - responseLanguage: 'English', - llmType: 'gemini', - }, - logger: mockLogger, - onLlmResponse: mockOnLlmResponse, - request: mockRequest, - }); + }, + tags: [AGENT_NODE_TAG], + }; + }, + }; + const expectConditions = async (response: unknown) => { expect(response).toBe(mockResponseWithHeaders); await waitFor(() => { @@ -203,6 +174,50 @@ describe('streamGraph', () => { false ); }); + }; + it('should execute the graph in streaming mode - Gemini', async () => { + const mockAssistantGraphAsyncIterator = { + streamEvents: () => mockAsyncIterator, + } as unknown as DefaultAssistantGraph; + const response = await streamGraph({ + ...requestArgs, + assistantGraph: mockAssistantGraphAsyncIterator, + inputs: { + ...requestArgs.inputs, + llmType: 'gemini', + }, + }); + + await expectConditions(response); + }); + it('should execute the graph in streaming mode - Bedrock', async () => { + const mockAssistantGraphAsyncIterator = { + streamEvents: () => mockAsyncIterator, + } as unknown as DefaultAssistantGraph; + const response = await streamGraph({ + ...requestArgs, + assistantGraph: mockAssistantGraphAsyncIterator, + inputs: { + ...requestArgs.inputs, + llmType: 'bedrock', + }, + }); + + await expectConditions(response); + }); + it('should execute the graph in streaming mode - OpenAI + isOssModel = false', async () => { + const mockAssistantGraphAsyncIterator = { + streamEvents: () => mockAsyncIterator, + } as unknown as DefaultAssistantGraph; + const response = await streamGraph({ + ...requestArgs, + assistantGraph: mockAssistantGraphAsyncIterator, + inputs: { + ...requestArgs.inputs, + isOssModel: true, + }, + }); + await expectConditions(response); }); }); }); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts index 840b2a9ac8ce0..d1b3514b15b73 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts @@ -24,7 +24,6 @@ interface StreamGraphParams { assistantGraph: DefaultAssistantGraph; inputs: GraphInputs; logger: Logger; - isOssModel?: boolean; onLlmResponse?: OnLlmResponse; request: KibanaRequest; traceOptions?: TraceOptions; @@ -37,7 +36,6 @@ interface StreamGraphParams { * @param assistantGraph * @param inputs * @param logger - * @param isOssModel * @param onLlmResponse * @param request * @param traceOptions @@ -47,7 +45,6 @@ export const streamGraph = async ({ assistantGraph, inputs, logger, - isOssModel, onLlmResponse, request, traceOptions, @@ -82,10 +79,8 @@ export const streamGraph = async ({ streamingSpan?.end(); }; - if ( - inputs.isOssModel || - ((inputs?.llmType === 'bedrock' || inputs?.llmType === 'gemini') && inputs?.bedrockChatEnabled) - ) { + // Stream is from tool calling agent or structured chat agent + if (inputs.isOssModel || inputs?.llmType === 'bedrock' || inputs?.llmType === 'gemini') { const stream = await assistantGraph.streamEvents( inputs, { @@ -104,7 +99,6 @@ export const streamGraph = async ({ if ((tags || []).includes(AGENT_NODE_TAG)) { if (event === 'on_chat_model_stream') { const msg = data.chunk as AIMessageChunk; - if (!didEnd && !msg.tool_call_chunks?.length && msg.content.length) { push({ payload: msg.content as string, type: 'content' }); } @@ -121,6 +115,8 @@ export const streamGraph = async ({ } return responseWithHeaders; } + + // Stream is from openai functions agent let finalMessage = ''; let conversationId: string | undefined; const stream = assistantGraph.streamEvents(inputs, { @@ -131,12 +127,6 @@ export const streamGraph = async ({ version: 'v1', }); - let currentOutput = ''; - let finalOutputIndex = -1; - const finalOutputStartToken = '"action":"FinalAnswer","action_input":"'; - let streamingFinished = false; - const finalOutputStopRegex = /(? { try { const { value, done } = await stream.next(); @@ -164,41 +154,6 @@ export const streamGraph = async ({ } } } - if (event.name === 'ActionsClientSimpleChatModel') { - if (event.event === 'on_llm_stream') { - const chunk = event.data?.chunk; - - const msg = chunk.content; - if (finalOutputIndex === -1) { - currentOutput += msg; - // Remove whitespace to simplify parsing - const noWhitespaceOutput = currentOutput.replace(/\s/g, ''); - if (noWhitespaceOutput.includes(finalOutputStartToken)) { - const nonStrippedToken = '"action_input": "'; - finalOutputIndex = currentOutput.indexOf(nonStrippedToken); - const contentStartIndex = finalOutputIndex + nonStrippedToken.length; - extraOutput = currentOutput.substring(contentStartIndex); - push({ payload: extraOutput, type: 'content' }); - finalMessage += extraOutput; - } - } else if (!streamingFinished && !didEnd) { - const finalOutputEndIndex = msg.search(finalOutputStopRegex); - if (finalOutputEndIndex !== -1) { - extraOutput = msg.substring(0, finalOutputEndIndex); - streamingFinished = true; - if (extraOutput.length > 0) { - push({ payload: extraOutput, type: 'content' }); - finalMessage += extraOutput; - } - } else { - push({ payload: chunk.content, type: 'content' }); - finalMessage += chunk.content; - } - } - } else if (event.event === 'on_llm_end' && streamingFinished && !didEnd) { - handleStreamEnd(finalMessage); - } - } } void processEvent(); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.ts index daec22b436474..ada5b8a421441 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.ts @@ -28,7 +28,6 @@ export const callAssistantGraph: AgentExecutor = async ({ actionsClient, alertsIndexPattern, assistantTools = [], - bedrockChatEnabled, connectorId, conversationId, dataClients, @@ -50,7 +49,7 @@ export const callAssistantGraph: AgentExecutor = async ({ }) => { const logger = parentLogger.get('defaultAssistantGraph'); const isOpenAI = llmType === 'openai' && !isOssModel; - const llmClass = getLlmClass(llmType, bedrockChatEnabled); + const llmClass = getLlmClass(llmType); /** * Creates a new instance of llmClass. @@ -133,7 +132,7 @@ export const callAssistantGraph: AgentExecutor = async ({ prompt: formatPrompt(systemPrompts.openai, systemPrompt), streamRunnable: isStream, }) - : llmType && ['bedrock', 'gemini'].includes(llmType) && bedrockChatEnabled + : llmType && ['bedrock', 'gemini'].includes(llmType) ? await createToolCallingAgent({ llm: createLlmInstance(), tools, @@ -143,7 +142,8 @@ export const callAssistantGraph: AgentExecutor = async ({ : formatPrompt(systemPrompts.gemini, systemPrompt), streamRunnable: isStream, }) - : await createStructuredChatAgent({ + : // used with OSS models + await createStructuredChatAgent({ llm: createLlmInstance(), tools, prompt: formatPromptStructured(systemPrompts.structuredChat, systemPrompt), @@ -162,7 +162,6 @@ export const callAssistantGraph: AgentExecutor = async ({ replacements, }); const inputs: GraphInputs = { - bedrockChatEnabled, responseLanguage, conversationId, llmType, @@ -177,7 +176,6 @@ export const callAssistantGraph: AgentExecutor = async ({ assistantGraph, inputs, logger, - isOssModel, onLlmResponse, request, traceOptions, diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/model_input.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/model_input.ts index 5f46e1ad2a741..4e03b5be1bf3b 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/model_input.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/model_input.ts @@ -22,9 +22,7 @@ interface ModelInputParams extends NodeParamsBase { export function modelInput({ logger, state }: ModelInputParams): Partial { logger.debug(() => `${NodeType.MODEL_INPUT}: Node state:\n${JSON.stringify(state, null, 2)}`); - const hasRespondStep = - state.isStream && - (state.isOssModel || (state.bedrockChatEnabled && state.llmType === 'bedrock')); + const hasRespondStep = state.isStream && (state.isOssModel || state.llmType === 'bedrock'); return { hasRespondStep, diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/types.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/types.ts index 69632be2ffdcd..344bd042cc036 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/types.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/types.ts @@ -16,7 +16,6 @@ export interface AgentStateBase { } export interface GraphInputs { - bedrockChatEnabled?: boolean; conversationId?: string; llmType?: string; isStream?: boolean; @@ -33,7 +32,6 @@ export interface AgentState extends AgentStateBase { hasRespondStep: boolean; isStream: boolean; isOssModel: boolean; - bedrockChatEnabled: boolean; llmType: string; responseLanguage: string; conversation: ConversationResponse | undefined; diff --git a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts index 59436070a7125..de154a1ddd96d 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts @@ -180,7 +180,7 @@ export const postEvaluateRoute = ( const llmType = getLlmType(connector.actionTypeId); const isOssModel = isOpenSourceModel(connector); const isOpenAI = llmType === 'openai' && !isOssModel; - const llmClass = getLlmClass(llmType, true); + const llmClass = getLlmClass(llmType); const createLlmInstance = () => new llmClass({ actionsClient, @@ -302,7 +302,6 @@ export const postEvaluateRoute = ( conversationId: undefined, responseLanguage: 'English', llmType, - bedrockChatEnabled: true, isStreaming: false, isOssModel, }, // TODO: Update to use the correct input format per dataset type diff --git a/x-pack/plugins/elastic_assistant/server/routes/helpers.ts b/x-pack/plugins/elastic_assistant/server/routes/helpers.ts index ebd9fd996dfe1..5c177410b0388 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/helpers.ts @@ -391,8 +391,6 @@ export const langChainExecute = async ({ (await assistantContext.getAIAssistantKnowledgeBaseDataClient({ v2KnowledgeBaseEnabled, })) ?? undefined; - const bedrockChatEnabled = - assistantContext.getRegisteredFeatures(pluginName).assistantBedrockChat; const dataClients: AssistantDataClients = { anonymizationFieldsDataClient: anonymizationFieldsDataClient ?? undefined, @@ -406,7 +404,6 @@ export const langChainExecute = async ({ dataClients, alertsIndexPattern: request.body.alertsIndexPattern, actionsClient, - bedrockChatEnabled, assistantTools, conversationId, connectorId, diff --git a/x-pack/plugins/elastic_assistant/server/routes/utils.ts b/x-pack/plugins/elastic_assistant/server/routes/utils.ts index 5811109b94ede..ea05fc814ec69 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/utils.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/utils.ts @@ -16,7 +16,6 @@ import type { import { ActionsClientChatOpenAI, ActionsClientBedrockChatModel, - ActionsClientSimpleChatModel, ActionsClientChatVertexAI, } from '@kbn/langchain/server'; import { Connector } from '@kbn/actions-plugin/server/application/connector/types'; @@ -186,14 +185,17 @@ export const getLlmType = (actionTypeId: string): string | undefined => { return llmTypeDictionary[actionTypeId]; }; -export const getLlmClass = (llmType?: string, bedrockChatEnabled?: boolean) => - llmType === 'openai' - ? ActionsClientChatOpenAI - : llmType === 'bedrock' && bedrockChatEnabled - ? ActionsClientBedrockChatModel - : llmType === 'gemini' && bedrockChatEnabled - ? ActionsClientChatVertexAI - : ActionsClientSimpleChatModel; +export const getLlmClass = (llmType?: string) => { + switch (llmType) { + case 'bedrock': + return ActionsClientBedrockChatModel; + case 'gemini': + return ActionsClientChatVertexAI; + case 'openai': + default: + return ActionsClientChatOpenAI; + } +}; export const isOpenSourceModel = (connector?: Connector): boolean => { if (connector == null) { diff --git a/x-pack/plugins/elastic_assistant/server/types.ts b/x-pack/plugins/elastic_assistant/server/types.ts index 9062bc5a434b1..3117295810877 100755 --- a/x-pack/plugins/elastic_assistant/server/types.ts +++ b/x-pack/plugins/elastic_assistant/server/types.ts @@ -42,7 +42,6 @@ import { ActionsClientChatVertexAI, ActionsClientGeminiChatModel, ActionsClientLlm, - ActionsClientSimpleChatModel, } from '@kbn/langchain/server'; import type { InferenceServerStart } from '@kbn/inference-plugin/server'; @@ -231,8 +230,7 @@ export type AssistantToolLlm = | ActionsClientBedrockChatModel | ActionsClientChatOpenAI | ActionsClientGeminiChatModel - | ActionsClientChatVertexAI - | ActionsClientSimpleChatModel; + | ActionsClientChatVertexAI; export interface AssistantToolParams { alertsIndexPattern?: string; diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 982b102abd93e..8ee859421d012 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -113,11 +113,6 @@ export const allowedExperimentalValues = Object.freeze({ */ assistantKnowledgeBaseByDefault: false, - /** - * Enables the Assistant BedrockChat Langchain model, introduced in `8.15.0`. - */ - assistantBedrockChat: true, - /** * Enables the NaturalLanguageESQLTool and disables the ESQLKnowledgeBaseTool, introduced in `8.16.0`. */ diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index ab4a213862a5b..5ea5c7ba5cd9e 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -553,7 +553,6 @@ export class Plugin implements ISecuritySolutionPlugin { }) ); const features = { - assistantBedrockChat: config.experimentalFeatures.assistantBedrockChat, assistantKnowledgeBaseByDefault: config.experimentalFeatures.assistantKnowledgeBaseByDefault, assistantModelEvaluation: config.experimentalFeatures.assistantModelEvaluation, }; From 1053493c9c66b881c27d14a600e33a16110b58e3 Mon Sep 17 00:00:00 2001 From: Hannah Mudge Date: Tue, 8 Oct 2024 16:37:18 -0600 Subject: [PATCH 031/110] [Presentation Util] Remove the plugin services toolkit (#195502) Closes https://github.com/elastic/kibana/issues/194199 ## Summary Now that no plugins use anything from the `PresentationUtil` services toolkit, it is safe to remove all code and documentation related to this from the `PresentationUtil` plugin. ### Checklist - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- src/plugins/presentation_util/README.mdx | 206 +----------------- src/plugins/presentation_util/public/index.ts | 8 - .../create/dependency_manager.test.ts | 78 ------- .../services/create/dependency_manager.ts | 123 ----------- .../public/services/create/factory.ts | 48 ---- .../public/services/create/index.ts | 98 --------- .../public/services/create/provider.tsx | 130 ----------- .../services/create/providers_mediator.ts | 59 ----- .../public/services/create/registry.tsx | 92 -------- 9 files changed, 6 insertions(+), 836 deletions(-) delete mode 100644 src/plugins/presentation_util/public/services/create/dependency_manager.test.ts delete mode 100644 src/plugins/presentation_util/public/services/create/dependency_manager.ts delete mode 100644 src/plugins/presentation_util/public/services/create/factory.ts delete mode 100644 src/plugins/presentation_util/public/services/create/index.ts delete mode 100644 src/plugins/presentation_util/public/services/create/provider.tsx delete mode 100644 src/plugins/presentation_util/public/services/create/providers_mediator.ts delete mode 100644 src/plugins/presentation_util/public/services/create/registry.tsx diff --git a/src/plugins/presentation_util/README.mdx b/src/plugins/presentation_util/README.mdx index 8bb13a1aaedce..4a98d90b2de28 100755 --- a/src/plugins/presentation_util/README.mdx +++ b/src/plugins/presentation_util/README.mdx @@ -12,208 +12,12 @@ related: [] The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). -## Plugin Services Toolkit - -While Kibana provides a `useKibana` hook for use in a plugin, the number of services it provides is very large. This presents a set of difficulties: - -- a direct dependency upon the Kibana environment; -- a requirement to mock the full Kibana environment when testing or using Storybook; -- a lack of knowledge as to what services are being consumed at any given time. - -To mitigate these difficulties, the Presentation Team creates services within the plugin that then consume Kibana-provided (or other) services. This is a toolkit for creating simple services within a plugin. - -### Overview - -- A `PluginServiceFactory` is a function that will return a set of functions-- which comprise a `Service`-- given a set of parameters. -- A `PluginServiceProvider` is an object that use a factory to start, stop or provide a `Service`. -- A `PluginServiceRegistry` is a collection of providers for a given environment, (e.g. Kibana, Jest, Storybook, stub, etc). -- A `PluginServices` object uses a registry to provide services throughout the plugin. - -### Defining Services - -To start, a plugin should define a set of services it wants to provide to itself or other plugins. - - -```ts -export interface PresentationDashboardsService { - findDashboards: ( - query: string, - fields: string[] - ) => Promise>>; - findDashboardsByTitle: (title: string) => Promise>>; -} - -export interface PresentationFooService { - getFoo: () => string; - setFoo: (bar: string) => void; -} - -export interface PresentationUtilServices { - dashboards: PresentationDashboardsService; - foo: PresentationFooService; -} -``` - - -This definition will be used in the toolkit to ensure services are complete and as expected. - -### Plugin Services - -The `PluginServices` class hosts a registry of service providers from which a plugin can access its services. It uses the service definition as a generic. - -```ts -export const pluginServices = new PluginServices(); -``` - -This can be placed in the `index.ts` file of a `services` directory within your plugin. - -Once created, it simply requires a `PluginServiceRegistry` to be started and set. - -### Service Provider Registry - -Each environment in which components are used requires a `PluginServiceRegistry` to specify how the providers are started. For example, simple stubs of services require no parameters to start, (so the `StartParameters` generic remains unspecified) - - -```ts -export const providers: PluginServiceProviders = { - dashboards: new PluginServiceProvider(dashboardsServiceFactory), - foo: new PluginServiceProvider(fooServiceFactory), -}; - -export const serviceRegistry = new PluginServiceRegistry(providers); -``` - - -By contrast, a registry that uses Kibana can provide `KibanaPluginServiceParams` to determine how to start its providers, so the `StartParameters` generic is given: - - -```ts -export const providers: PluginServiceProviders< - PresentationUtilServices, - KibanaPluginServiceParams -> = { - dashboards: new PluginServiceProvider(dashboardsServiceFactory), - foo: new PluginServiceProvider(fooServiceFactory), -}; - -export const serviceRegistry = new PluginServiceRegistry< - PresentationUtilServices, - KibanaPluginServiceParams ->(providers); -``` - - -### Service Provider - -A `PluginServiceProvider` is a container for a Service Factory that is responsible for starting, stopping and providing a service implementation. A Service Provider doesn't change, rather the factory and the relevant `StartParameters` change. - -### Service Factories - -A Service Factory is nothing more than a function that uses `StartParameters` to return a set of functions that conforms to a portion of the `Services` specification. For each service, a factory is provided for each environment. - -Given a service definition: - -```ts -export interface PresentationFooService { - getFoo: () => string; - setFoo: (bar: string) => void; -} -``` - -a factory for a stubbed version might look like this: - -```ts -type FooServiceFactory = PluginServiceFactory; - -export const fooServiceFactory: FooServiceFactory = () => ({ - getFoo: () => 'bar', - setFoo: (bar) => { console.log(`${bar} set!`)}, -}); -``` - -and a factory for a Kibana version might look like this: - -```ts -export type FooServiceFactory = KibanaPluginServiceFactory< - PresentationFooService, - PresentationUtilPluginStart ->; - -export const fooServiceFactory: FooServiceFactory = ({ - coreStart, - startPlugins, -}) => { - // ...do something with Kibana services... - - return { - getFoo: //... - setFoo: //... - } -} -``` - -### Using Services - -Once your services and providers are defined, and you have at least one set of factories, you can use `PluginServices` to provide the services to your React components: - - -```ts -// plugin.ts -import { pluginServices } from './services'; -import { registry } from './services/kibana'; - - public start( - coreStart: CoreStart, - startPlugins: StartDeps - ): Promise { - pluginServices.setRegistry(registry.start({ coreStart, startPlugins })); - return {}; - } -``` - - -and wrap your root React component with the `PluginServices` context: - - -```ts -import { pluginServices } from './services'; - -const ContextProvider = pluginServices.getContextProvider(), - -return( - - - {application} - - -) -``` - - -and then, consume your services using provided hooks in a component: - - -```ts -// component.ts - -import { pluginServices } from '../services'; - -export function MyComponent() { - // Retrieve all context hooks from `PluginServices`, destructuring for the one we're using - const { foo } = pluginServices.getHooks(); - - // Use the `useContext` hook to access the API. - const { getFoo } = foo.useService(); - - // ... -} -``` - - ## Redux Embeddables + The Redux Embeddables system allows embeddable authors to interact with their embeddables in a standardized way using Redux toolkit. This wrapper abstracts away store and slice creation, and embeddable input sync. To use this system, a developer can use CreateReduxEmbeddableTools in the constructor of their embeddable, supplying a collection of reducers. ### Reducers + The reducer object expected by the ReduxEmbeddableWrapper is the same type as the reducers expected by [Redux Toolkit's CreateSlice](https://redux-toolkit.js.org/api/createslice). @@ -247,6 +51,8 @@ From components under the embeddable, actions, containerActions, and the current // change specialBoolean after 5 seconds setTimeout(() => embeddableInstance.dispatch.setSpecialBoolean(false), 5000); - } - ``` +} + +``` +``` diff --git a/src/plugins/presentation_util/public/index.ts b/src/plugins/presentation_util/public/index.ts index 16f33d237364a..568a691482a72 100644 --- a/src/plugins/presentation_util/public/index.ts +++ b/src/plugins/presentation_util/public/index.ts @@ -12,14 +12,6 @@ import { PresentationUtilPlugin } from './plugin'; export type { PresentationLabsService } from './services/presentation_labs_service'; -export type { - KibanaPluginServiceFactory, - PluginServiceFactory, - PluginServiceProviders, - KibanaPluginServiceParams, -} from './services/create'; -export { PluginServices, PluginServiceProvider, PluginServiceRegistry } from './services/create'; - export type { PresentationUtilPluginSetup, PresentationUtilPluginStart } from './types'; export type { SaveModalDashboardProps } from './components/types'; diff --git a/src/plugins/presentation_util/public/services/create/dependency_manager.test.ts b/src/plugins/presentation_util/public/services/create/dependency_manager.test.ts deleted file mode 100644 index eb1a4413056fa..0000000000000 --- a/src/plugins/presentation_util/public/services/create/dependency_manager.test.ts +++ /dev/null @@ -1,78 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DependencyManager } from './dependency_manager'; - -describe('DependencyManager', () => { - it('orderDependencies. Should sort topology by dependencies', () => { - const graph = { - N: [], - R: [], - A: ['B', 'C'], - B: ['D'], - C: ['F', 'B'], - F: ['E'], - E: ['D'], - D: ['L'], - }; - const sortedTopology = ['N', 'R', 'L', 'D', 'B', 'E', 'F', 'C', 'A']; - expect(DependencyManager.orderDependencies(graph)).toEqual(sortedTopology); - }); - - it('should include final vertex if it has dependencies', () => { - const graph = { - A: [], - B: [], - C: ['A', 'B'], - }; - const sortedTopology = ['A', 'B', 'C']; - expect(DependencyManager.orderDependencies(graph)).toEqual(sortedTopology); - }); - - it('orderDependencies. Should return base topology if no depended vertices', () => { - const graph = { - N: [], - R: [], - D: undefined, - }; - const sortedTopology = ['N', 'R', 'D']; - expect(DependencyManager.orderDependencies(graph)).toEqual(sortedTopology); - }); - - describe('circular dependencies', () => { - it('should detect circular dependencies and throw error with path', () => { - const graph = { - N: ['R'], - R: ['A'], - A: ['B'], - B: ['C'], - C: ['D'], - D: ['E'], - E: ['F'], - F: ['L'], - L: ['G'], - G: ['N'], - }; - const circularPath = ['G', 'L', 'F', 'E', 'D', 'C', 'B', 'A', 'R', 'N'].join(' -> '); - const errorMessage = `Circular dependency detected while setting up services: ${circularPath}`; - - expect(() => DependencyManager.orderDependencies(graph)).toThrowError(errorMessage); - }); - - it('should detect circular dependency if circular reference is the first dependency for a vertex', () => { - const graph = { - A: ['B'], - B: ['A', 'C'], - C: [], - }; - - expect(() => DependencyManager.orderDependencies(graph)).toThrow(); - }); - }); -}); diff --git a/src/plugins/presentation_util/public/services/create/dependency_manager.ts b/src/plugins/presentation_util/public/services/create/dependency_manager.ts deleted file mode 100644 index aa05544648807..0000000000000 --- a/src/plugins/presentation_util/public/services/create/dependency_manager.ts +++ /dev/null @@ -1,123 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -type GraphVertex = string | number | symbol; -type Graph = Record; -type BreadCrumbs = Record; - -interface CycleDetectionResult { - hasCycle: boolean; - path: T[]; -} - -export class DependencyManager { - static orderDependencies(graph: Graph) { - const cycleInfo = DependencyManager.getSortedDependencies(graph); - if (cycleInfo.hasCycle) { - const error = DependencyManager.getCyclePathError(cycleInfo.path); - DependencyManager.throwCyclicPathError(error); - } - - return cycleInfo.path; - } - - /** - * DFS algorithm for checking if graph is a DAG (Directed Acyclic Graph) - * and sorting topogy (dependencies) if graph is DAG. - * @param {Graph} graph - graph of dependencies. - */ - private static getSortedDependencies( - graph: Graph = {} as Graph - ): CycleDetectionResult { - const sortedVertices: Set = new Set(); - const vertices = Object.keys(graph) as T[]; - return vertices.reduce>((cycleInfo, srcVertex) => { - if (cycleInfo.hasCycle) { - return cycleInfo; - } - - return DependencyManager.sortVerticesFrom( - srcVertex, - graph, - sortedVertices, - {}, - {}, - cycleInfo - ); - }, DependencyManager.createCycleInfo()); - } - - /** - * Modified DFS algorithm for topological sort. - * @param {T extends GraphVertex} srcVertex - a source vertex - the start point of dependencies ordering. - * @param {Graph} graph - graph of dependencies, represented in the adjacency list form. - * @param {Set} sortedVertices - ordered dependencies path from the free to the dependent vertex. - * @param {BreadCrumbs} visited - record of visited vertices. - * @param {BreadCrumbs} inpath - record of vertices, which was met in the path. Is used for detecting cycles. - */ - private static sortVerticesFrom( - srcVertex: T, - graph: Graph, - sortedVertices: Set, - visited: BreadCrumbs = {}, - inpath: BreadCrumbs = {}, - cycle: CycleDetectionResult - ): CycleDetectionResult { - visited[srcVertex] = true; - inpath[srcVertex] = true; - - const vertexEdges = - graph[srcVertex] === undefined || graph[srcVertex] === null ? [] : graph[srcVertex]; - - cycle = vertexEdges!.reduce>((info, vertex) => { - if (inpath[vertex]) { - return { ...info, hasCycle: true }; - } else if (!visited[vertex]) { - return DependencyManager.sortVerticesFrom( - vertex, - graph, - sortedVertices, - visited, - inpath, - info - ); - } - return info; - }, cycle); - - inpath[srcVertex] = false; - - if (!sortedVertices.has(srcVertex)) { - sortedVertices.add(srcVertex); - } - - return { - ...cycle, - path: [...sortedVertices], - }; - } - - private static createCycleInfo( - path: T[] = [], - hasCycle: boolean = false - ): CycleDetectionResult { - return { hasCycle, path }; - } - - private static getCyclePathError( - cyclePath: CycleDetectionResult['path'] - ) { - const cycleString = cyclePath.join(' -> '); - return `Circular dependency detected while setting up services: ${cycleString}`; - } - - private static throwCyclicPathError(error: string) { - throw new Error(error); - } -} diff --git a/src/plugins/presentation_util/public/services/create/factory.ts b/src/plugins/presentation_util/public/services/create/factory.ts deleted file mode 100644 index dad0d23929e45..0000000000000 --- a/src/plugins/presentation_util/public/services/create/factory.ts +++ /dev/null @@ -1,48 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { BehaviorSubject } from 'rxjs'; -import { CoreStart, AppUpdater, PluginInitializerContext } from '@kbn/core/public'; - -/** - * A factory function for creating a service. - * - * The `Service` generic determines the shape of the API being produced. - * The `StartParameters` generic determines what parameters are expected to - * create the service. - */ -export type PluginServiceFactory = ( - params: Parameters, - requiredServices: RequiredServices -) => Service; - -/** - * Parameters necessary to create a Kibana-based service, (e.g. during Plugin - * startup or setup). - * - * The `Start` generic refers to the specific Plugin `TPluginsStart`. - */ -export interface KibanaPluginServiceParams { - coreStart: CoreStart; - startPlugins: Start; - appUpdater?: BehaviorSubject; - initContext?: PluginInitializerContext; -} - -/** - * A factory function for creating a Kibana-based service. - * - * The `Service` generic determines the shape of the API being produced. - * The `Setup` generic refers to the specific Plugin `TPluginsSetup`. - * The `Start` generic refers to the specific Plugin `TPluginsStart`. - */ -export type KibanaPluginServiceFactory = ( - params: KibanaPluginServiceParams, - requiredServices: RequiredServices -) => Service; diff --git a/src/plugins/presentation_util/public/services/create/index.ts b/src/plugins/presentation_util/public/services/create/index.ts deleted file mode 100644 index 87afe0ed4c7fa..0000000000000 --- a/src/plugins/presentation_util/public/services/create/index.ts +++ /dev/null @@ -1,98 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceRegistry } from './registry'; - -export { PluginServiceRegistry } from './registry'; -export type { PluginServiceProviders } from './provider'; -export { PluginServiceProvider } from './provider'; -export type { - PluginServiceFactory, - KibanaPluginServiceFactory, - KibanaPluginServiceParams, -} from './factory'; - -type ServiceHooks = { [K in keyof Services]: { useService: () => Services[K] } }; - -/** - * `PluginServices` is a top-level class for specifying and accessing services within a plugin. - * - * A `PluginServices` object can be provided with a `PluginServiceRegistry` at any time, which will - * then be used to provide services to any component that accesses it. - * - * The `Services` generic determines the shape of all service APIs being produced. - */ -export class PluginServices> { - private registry: PluginServiceRegistry | null = null; - - /** - * Supply a `PluginServiceRegistry` for the class to use to provide services and context. - * - * @param registry A setup and started `PluginServiceRegistry`. - */ - setRegistry(registry: PluginServiceRegistry | null) { - if (registry && !registry.isStarted()) { - throw new Error('Registry has not been started.'); - } - - this.registry = registry; - } - - /** - * Returns true if a registry has been provided, false otherwise. - */ - hasRegistry() { - return !!this.registry; - } - - /** - * Private getter that will enforce proper setup throughout the class. - */ - private getRegistry() { - if (!this.registry) { - throw new Error('No registry has been provided.'); - } - - return this.registry; - } - - /** - * Return the React Context Provider that will supply services. - */ - getContextProvider() { - return this.getRegistry().getContextProvider(); - } - - /** - * Return a map of React Hooks that can be used in React components. - */ - getHooks(): ServiceHooks { - const registry = this.getRegistry(); - const providers = registry.getServiceProviders(); - - const providerNames = Object.keys(providers) as Array; - - return providerNames.reduce((acc, providerName) => { - acc[providerName] = { useService: providers[providerName].getServiceReactHook() }; - return acc; - }, {} as ServiceHooks); - } - - getServices(): Services { - const registry = this.getRegistry(); - const providers = registry.getServiceProviders(); - - const providerNames = Object.keys(providers) as Array; - - return providerNames.reduce((acc, providerName) => { - acc[providerName] = providers[providerName].getService(); - return acc; - }, {} as Services); - } -} diff --git a/src/plugins/presentation_util/public/services/create/provider.tsx b/src/plugins/presentation_util/public/services/create/provider.tsx deleted file mode 100644 index 2418673262061..0000000000000 --- a/src/plugins/presentation_util/public/services/create/provider.tsx +++ /dev/null @@ -1,130 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { createContext, useContext, FC, PropsWithChildren } from 'react'; -import { PluginServiceFactory } from './factory'; - -/** - * A collection of `PluginServiceProvider` objects, keyed by the `Services` API generic. - * - * The `Services` generic determines the shape of all service APIs being produced. - * The `StartParameters` generic determines what parameters are expected to - * start the service. - */ -export type PluginServiceProviders< - Services extends Record, - StartParameters = {} -> = { - [K in keyof Services]: PluginServiceProvider< - Services[K], - StartParameters, - Services, - Array - >; -}; - -type ElementOfArray = ArrayType extends Array< - infer ElementType -> - ? ElementType - : never; - -export type PluginServiceRequiredServices< - RequiredServices extends Array, - AvailableServices -> = { - [K in ElementOfArray]: AvailableServices[K]; -}; - -/** - * An object which uses a given factory to start, stop or provide a service. - * - * The `Service` generic determines the shape of the API being produced. - * The `StartParameters` generic determines what parameters are expected to - * start the service. - */ -export class PluginServiceProvider< - Service extends {}, - StartParameters = {}, - Services = {}, - RequiredServices extends Array = [] -> { - private factory: PluginServiceFactory< - Service, - StartParameters, - PluginServiceRequiredServices - >; - private _requiredServices?: RequiredServices; - private context = createContext(null); - private pluginService: Service | null = null; - public readonly Provider: FC> = ({ children }) => { - return {children}; - }; - - constructor( - factory: PluginServiceFactory< - Service, - StartParameters, - PluginServiceRequiredServices - >, - requiredServices?: RequiredServices - ) { - this.factory = factory; - this._requiredServices = requiredServices; - this.context.displayName = 'PluginServiceContext'; - } - - /** - * Getter that will enforce proper setup throughout the class. - */ - public getService() { - if (!this.pluginService) { - throw new Error('Service not started'); - } - return this.pluginService; - } - - /** - * Start the service. - * - * @param params Parameters used to start the service. - */ - start( - params: StartParameters, - requiredServices: PluginServiceRequiredServices - ) { - this.pluginService = this.factory(params, requiredServices); - } - - /** - * Returns a function for providing a Context hook for the service. - */ - getServiceReactHook() { - return () => { - const service = useContext(this.context); - - if (!service) { - throw new Error('Provider is not set up correctly'); - } - - return service; - }; - } - - /** - * Stop the service. - */ - stop() { - this.pluginService = null; - } - - public get requiredServices() { - return this._requiredServices ?? []; - } -} diff --git a/src/plugins/presentation_util/public/services/create/providers_mediator.ts b/src/plugins/presentation_util/public/services/create/providers_mediator.ts deleted file mode 100644 index 45410906ec731..0000000000000 --- a/src/plugins/presentation_util/public/services/create/providers_mediator.ts +++ /dev/null @@ -1,59 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DependencyManager } from './dependency_manager'; -import { PluginServiceProviders, PluginServiceRequiredServices } from './provider'; - -export class PluginServiceProvidersMediator< - Services extends Record, - StartParameters -> { - constructor(private readonly providers: PluginServiceProviders) {} - - start(params: StartParameters) { - this.getOrderedDependencies().forEach((service) => { - this.providers[service].start(params, this.getServiceDependencies(service)); - }); - } - - stop() { - this.getOrderedDependencies().forEach((service) => this.providers[service].stop()); - } - - private getOrderedDependencies() { - const dependenciesGraph = this.getGraphOfDependencies(); - return DependencyManager.orderDependencies(dependenciesGraph); - } - - private getGraphOfDependencies() { - return this.getProvidersNames().reduce>>( - (graph, vertex) => ({ ...graph, [vertex]: this.providers[vertex].requiredServices ?? [] }), - {} as Record> - ); - } - - private getProvidersNames() { - return Object.keys(this.providers) as Array; - } - - private getServiceDependencies(service: keyof Services) { - const requiredServices = this.providers[service].requiredServices ?? []; - return this.getServicesByDeps(requiredServices); - } - - private getServicesByDeps(deps: Array) { - return deps.reduce, Services>>( - (services, dependency) => ({ - ...services, - [dependency]: this.providers[dependency].getService(), - }), - {} as PluginServiceRequiredServices, Services> - ); - } -} diff --git a/src/plugins/presentation_util/public/services/create/registry.tsx b/src/plugins/presentation_util/public/services/create/registry.tsx deleted file mode 100644 index 0cff51c6f6604..0000000000000 --- a/src/plugins/presentation_util/public/services/create/registry.tsx +++ /dev/null @@ -1,92 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { FC, PropsWithChildren } from 'react'; -import { PluginServiceProvider, PluginServiceProviders } from './provider'; -import { PluginServiceProvidersMediator } from './providers_mediator'; - -/** - * A `PluginServiceRegistry` maintains a set of service providers which can be collectively - * started, stopped or retreived. - * - * The `Services` generic determines the shape of all service APIs being produced. - * The `StartParameters` generic determines what parameters are expected to - * start the service. - */ -export class PluginServiceRegistry< - Services extends Record, - StartParameters = {} -> { - private providers: PluginServiceProviders; - private providersMediator: PluginServiceProvidersMediator; - private _isStarted = false; - - constructor(providers: PluginServiceProviders) { - this.providers = providers; - this.providersMediator = new PluginServiceProvidersMediator(providers); - } - - /** - * Returns true if the registry has been started, false otherwise. - */ - isStarted() { - return this._isStarted; - } - - /** - * Returns a map of `PluginServiceProvider` objects. - */ - getServiceProviders() { - if (!this._isStarted) { - throw new Error('Registry not started'); - } - return this.providers; - } - - /** - * Returns a React Context Provider for use in consuming applications. - */ - getContextProvider() { - const values = Object.values(this.getServiceProviders()) as Array< - PluginServiceProvider - >; - - // Collect and combine Context.Provider elements from each Service Provider into a single - // Functional Component. - const provider: FC> = ({ children }) => ( - <> - {values.reduceRight((acc, serviceProvider) => { - return {acc}; - }, children)} - - ); - - return provider; - } - - /** - * Start the registry. - * - * @param params Parameters used to start the registry. - */ - start(params: StartParameters) { - this.providersMediator.start(params); - this._isStarted = true; - return this; - } - - /** - * Stop the registry. - */ - stop() { - this.providersMediator.stop(); - this._isStarted = false; - return this; - } -} From e119d83c26387e85e9fdf3cc5d5eeceeebb04edb Mon Sep 17 00:00:00 2001 From: Davis Plumlee <56367316+dplumlee@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:46:33 -0400 Subject: [PATCH 032/110] [Security Solution] Integration tests for rule `type` field diff algorithms (#193375) ## Summary Completes https://github.com/elastic/kibana/issues/190482 Switches rule `type` field to use the implemented diff algorithms assigned to them in https://github.com/elastic/kibana/pull/193369 Adds integration tests in accordance to https://github.com/elastic/kibana/pull/193372 for the `upgrade/_review` API endpoint for the rule `type` field diff algorithm. Also fixes some nested bracket misalignment that occurred in earlier PRs with some test files ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../calculation/calculate_rule_fields_diff.ts | 19 +- .../trial_license_complete_tier/index.ts | 1 + ..._review_prebuilt_rules.kql_query_fields.ts | 22 +- ...prebuilt_rules.multi_line_string_fields.ts | 342 ++++++------ ...ade_review_prebuilt_rules.number_fields.ts | 246 ++++----- ..._review_prebuilt_rules.rule_type_fields.ts | 362 +++++++++++++ ...view_prebuilt_rules.scalar_array_fields.ts | 490 +++++++++--------- ...rebuilt_rules.single_line_string_fields.ts | 244 ++++----- 8 files changed, 1045 insertions(+), 681 deletions(-) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.rule_type_fields.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts index 80536451b6f3c..b49e04f566c4b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts @@ -47,6 +47,7 @@ import { kqlQueryDiffAlgorithm, eqlQueryDiffAlgorithm, esqlQueryDiffAlgorithm, + ruleTypeDiffAlgorithm, } from './algorithms'; const BASE_TYPE_ERROR = `Base version can't be of different rule type`; @@ -212,7 +213,7 @@ const calculateCustomQueryFieldsDiff = ( }; const customQueryFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { - type: simpleDiffAlgorithm, + type: ruleTypeDiffAlgorithm, kql_query: kqlQueryDiffAlgorithm, data_source: dataSourceDiffAlgorithm, alert_suppression: simpleDiffAlgorithm, @@ -225,7 +226,7 @@ const calculateSavedQueryFieldsDiff = ( }; const savedQueryFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { - type: simpleDiffAlgorithm, + type: ruleTypeDiffAlgorithm, kql_query: kqlQueryDiffAlgorithm, data_source: dataSourceDiffAlgorithm, alert_suppression: simpleDiffAlgorithm, @@ -238,7 +239,7 @@ const calculateEqlFieldsDiff = ( }; const eqlFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { - type: simpleDiffAlgorithm, + type: ruleTypeDiffAlgorithm, eql_query: eqlQueryDiffAlgorithm, data_source: dataSourceDiffAlgorithm, event_category_override: singleLineStringDiffAlgorithm, @@ -254,7 +255,7 @@ const calculateEsqlFieldsDiff = ( }; const esqlFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { - type: simpleDiffAlgorithm, + type: ruleTypeDiffAlgorithm, esql_query: esqlQueryDiffAlgorithm, alert_suppression: simpleDiffAlgorithm, }; @@ -266,7 +267,7 @@ const calculateThreatMatchFieldsDiff = ( }; const threatMatchFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { - type: simpleDiffAlgorithm, + type: ruleTypeDiffAlgorithm, kql_query: kqlQueryDiffAlgorithm, data_source: dataSourceDiffAlgorithm, threat_query: kqlQueryDiffAlgorithm, @@ -284,7 +285,7 @@ const calculateThresholdFieldsDiff = ( }; const thresholdFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { - type: simpleDiffAlgorithm, + type: ruleTypeDiffAlgorithm, kql_query: kqlQueryDiffAlgorithm, data_source: dataSourceDiffAlgorithm, threshold: simpleDiffAlgorithm, @@ -299,7 +300,7 @@ const calculateMachineLearningFieldsDiff = ( const machineLearningFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { - type: simpleDiffAlgorithm, + type: ruleTypeDiffAlgorithm, machine_learning_job_id: simpleDiffAlgorithm, anomaly_threshold: numberDiffAlgorithm, alert_suppression: simpleDiffAlgorithm, @@ -312,7 +313,7 @@ const calculateNewTermsFieldsDiff = ( }; const newTermsFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { - type: simpleDiffAlgorithm, + type: ruleTypeDiffAlgorithm, kql_query: kqlQueryDiffAlgorithm, data_source: dataSourceDiffAlgorithm, new_terms_fields: scalarArrayDiffAlgorithm, @@ -336,5 +337,5 @@ const allFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { ...thresholdFieldsDiffAlgorithms, ...machineLearningFieldsDiffAlgorithms, ...newTermsFieldsDiffAlgorithms, - type: simpleDiffAlgorithm, + type: ruleTypeDiffAlgorithm, }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/index.ts index 819b253dc7a66..72707393c0527 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/index.ts @@ -17,6 +17,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./upgrade_prebuilt_rules')); loadTestFile(require.resolve('./upgrade_prebuilt_rules_with_historical_versions')); loadTestFile(require.resolve('./fleet_integration')); + loadTestFile(require.resolve('./upgrade_review_prebuilt_rules.rule_type_fields')); loadTestFile(require.resolve('./upgrade_review_prebuilt_rules.number_fields')); loadTestFile(require.resolve('./upgrade_review_prebuilt_rules.single_line_string_fields')); loadTestFile(require.resolve('./upgrade_review_prebuilt_rules.scalar_array_fields')); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.kql_query_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.kql_query_fields.ts index 3de835ed42772..3afb63a4c7975 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.kql_query_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.kql_query_fields.ts @@ -199,12 +199,12 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); // `version` is considered an updated field - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // `type` is considered to be a conflict + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); }); }); @@ -273,12 +273,12 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); // `version` is considered an updated field - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // `type` is considered to be a conflict + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); }); }); }); @@ -611,9 +611,9 @@ export default ({ getService }: FtrProviderContext): void => { has_base_version: true, }); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); // `version` is considered an updated field - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); // `version` is also considered an updated field + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // `type` is also considered to be a conflict + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(2); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts index 1c414699fad2d..55a924cc5e45c 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts @@ -157,9 +157,56 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); + }); - describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { - it('should show in the upgrade/_review API response', async () => { + describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a multi line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + description: 'My GREAT description.\nThis is a second line.', + }); + + // Increment the version of the installed rule, update a multi line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + description: 'My GREAT description.\nThis is a second line.', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.description).toEqual({ + base_version: 'My description.\nThis is a second line.', + current_version: 'My GREAT description.\nThis is a second line.', + target_version: 'My GREAT description.\nThis is a second line.', + merged_version: 'My GREAT description.\nThis is a second line.', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + conflict: ThreeWayDiffConflict.NONE, + has_update: false, + has_base_version: true, + }); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); + }); + + describe('when rule field has an update and a custom value that are different - scenario ABC', () => { + describe('when all versions are mergable', () => { + it('should show in the upgrade/_review API response with a solvable conflict', async () => { // Install base prebuilt detection rule await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); @@ -175,211 +222,164 @@ export default ({ getService }: FtrProviderContext): void => { createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - description: 'My GREAT description.\nThis is a second line.', + description: 'My description.\nThis is a second line, now longer.', }), ]; await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and multi line string field update has no conflict const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields.description).toEqual({ base_version: 'My description.\nThis is a second line.', current_version: 'My GREAT description.\nThis is a second line.', - target_version: 'My GREAT description.\nThis is a second line.', - merged_version: 'My GREAT description.\nThis is a second line.', - diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, - merge_outcome: ThreeWayMergeOutcome.Current, - conflict: ThreeWayDiffConflict.NONE, - has_update: false, + target_version: 'My description.\nThis is a second line, now longer.', + merged_version: 'My GREAT description.\nThis is a second line, now longer.', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Merged, + conflict: ThreeWayDiffConflict.SOLVABLE, + has_update: true, has_base_version: true, }); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); - describe('when rule field has an update and a custom value that are different - scenario ABC', () => { - describe('when all versions are mergable', () => { - it('should show in the upgrade/_review API response with a solvable conflict', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); + describe('when all versions are not mergable', () => { + it('should show in the upgrade/_review API response with a non-solvable conflict', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); - // Customize a multi line string field on the installed rule - await patchRule(supertest, log, { - rule_id: 'rule-1', - description: 'My GREAT description.\nThis is a second line.', - }); - - // Increment the version of the installed rule, update a multi line string field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - description: 'My description.\nThis is a second line, now longer.', - }), - ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and multi line string field update has no conflict - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.description).toEqual({ - base_version: 'My description.\nThis is a second line.', - current_version: 'My GREAT description.\nThis is a second line.', - target_version: 'My description.\nThis is a second line, now longer.', - merged_version: 'My GREAT description.\nThis is a second line, now longer.', - diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Merged, - conflict: ThreeWayDiffConflict.SOLVABLE, - has_update: true, - has_base_version: true, - }); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + // Customize a multi line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + description: 'My GREAT description.\nThis is a third line.', }); - }); - - describe('when all versions are not mergable', () => { - it('should show in the upgrade/_review API response with a non-solvable conflict', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - // Customize a multi line string field on the installed rule - await patchRule(supertest, log, { + // Increment the version of the installed rule, update a multi line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ rule_id: 'rule-1', - description: 'My GREAT description.\nThis is a third line.', - }); - - // Increment the version of the installed rule, update a multi line string field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - description: 'My EXCELLENT description.\nThis is a fourth.', - }), - ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and multi line string field update has conflict - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.description).toEqual({ - base_version: 'My description.\nThis is a second line.', - current_version: 'My GREAT description.\nThis is a third line.', - target_version: 'My EXCELLENT description.\nThis is a fourth.', - merged_version: 'My GREAT description.\nThis is a third line.', - diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Current, - conflict: ThreeWayDiffConflict.NON_SOLVABLE, - has_update: true, - has_base_version: true, - }); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); - - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); + version: 2, + description: 'My EXCELLENT description.\nThis is a fourth.', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and multi line string field update has conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.description).toEqual({ + base_version: 'My description.\nThis is a second line.', + current_version: 'My GREAT description.\nThis is a third line.', + target_version: 'My EXCELLENT description.\nThis is a fourth.', + merged_version: 'My GREAT description.\nThis is a third line.', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + conflict: ThreeWayDiffConflict.NON_SOLVABLE, + has_update: true, + has_base_version: true, }); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); }); }); + }); + + describe('when rule base version does not exist', () => { + describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { + it('should not show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); - describe('when rule base version does not exist', () => { - describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { - it('should not show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); + // Customize a multi line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + description: 'My description.\nThis is a second line.', + }); - // Customize a multi line string field on the installed rule - await patchRule(supertest, log, { + // Increment the version of the installed rule, update a multi line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ rule_id: 'rule-1', + version: 2, description: 'My description.\nThis is a second line.', - }); - - // Increment the version of the installed rule, update a multi line string field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - description: 'My description.\nThis is a second line.', - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // but does NOT contain multi line string field, since -AA is treated as AAA - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.description).toBeUndefined(); - - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - }); + }), + ]; + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // but does NOT contain multi line string field, since -AA is treated as AAA + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.description).toBeUndefined(); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); }); + }); + + describe('when rule field has an update and a custom value that are different - scenario -AB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); - describe('when rule field has an update and a custom value that are different - scenario -AB', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); + // Customize a multi line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + description: 'My description.\nThis is a second line.', + }); - // Customize a multi line string field on the installed rule - await patchRule(supertest, log, { + // Increment the version of the installed rule, update a multi line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ rule_id: 'rule-1', - description: 'My description.\nThis is a second line.', - }); - - // Increment the version of the installed rule, update a multi line string field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - description: 'My GREAT description.\nThis is a second line.', - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and multi line string field update does not have a conflict - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.description).toEqual({ - current_version: 'My description.\nThis is a second line.', - target_version: 'My GREAT description.\nThis is a second line.', - merged_version: 'My GREAT description.\nThis is a second line.', - diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - conflict: ThreeWayDiffConflict.SOLVABLE, - has_update: true, - has_base_version: false, - }); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + version: 2, + description: 'My GREAT description.\nThis is a second line.', + }), + ]; + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and multi line string field update does not have a conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.description).toEqual({ + current_version: 'My description.\nThis is a second line.', + target_version: 'My GREAT description.\nThis is a second line.', + merged_version: 'My GREAT description.\nThis is a second line.', + diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + conflict: ThreeWayDiffConflict.SOLVABLE, + has_update: true, + has_base_version: false, }); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.number_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.number_fields.ts index 3d5c0d6d15527..51ab509d16904 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.number_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.number_fields.ts @@ -154,58 +154,144 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); + }); - describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); + describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); - // Customize a number field on the installed rule - await patchRule(supertest, log, { + // Customize a number field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + risk_score: 2, + }); + + // Increment the version of the installed rule, update a number field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ rule_id: 'rule-1', + version: 2, risk_score: 2, - }); + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Increment the version of the installed rule, update a number field, and create the new rule assets + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update and contains number field + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.risk_score).toEqual({ + base_version: 1, + current_version: 2, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + conflict: ThreeWayDiffConflict.NONE, + has_update: false, + has_base_version: true, + }); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); + }); + + describe('when rule field has an update and a custom value that are different - scenario ABC', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a number field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + risk_score: 2, + }); + + // Increment the version of the installed rule, update a number field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + risk_score: 3, + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and number field update has conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.risk_score).toEqual({ + base_version: 1, + current_version: 2, + target_version: 3, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + conflict: ThreeWayDiffConflict.NON_SOLVABLE, + has_update: true, + has_base_version: true, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); + }); + }); + + describe('when rule base version does not exist', () => { + describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { + it('should not show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + + // Increment the version of the installed rule with the number field maintained const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - risk_score: 2, + risk_score: 1, }), ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update and contains number field + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // but does NOT contain the risk_score number field, since -AA is treated as AAA const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.risk_score).toEqual({ - base_version: 1, - current_version: 2, - target_version: 2, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, - merge_outcome: ThreeWayMergeOutcome.Current, - conflict: ThreeWayDiffConflict.NONE, - has_update: false, - has_base_version: true, - }); + expect(reviewResponse.rules[0].diff.fields.risk_score).toBeUndefined(); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); - describe('when rule field has an update and a custom value that are different - scenario ABC', () => { + describe('when rule field has an update and a custom value that are different - scenario -AB', () => { it('should show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + // Customize a number field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', @@ -220,114 +306,28 @@ export default ({ getService }: FtrProviderContext): void => { risk_score: 3, }), ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and number field update has conflict + // and number field update does not have a conflict const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields.risk_score).toEqual({ - base_version: 1, current_version: 2, target_version: 3, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Current, - conflict: ThreeWayDiffConflict.NON_SOLVABLE, + merged_version: 3, + diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + conflict: ThreeWayDiffConflict.SOLVABLE, has_update: true, - has_base_version: true, + has_base_version: false, }); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); - }); - }); - - describe('when rule base version does not exist', () => { - describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { - it('should not show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); - - // Increment the version of the installed rule with the number field maintained - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - risk_score: 1, - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // but does NOT contain the risk_score number field, since -AA is treated as AAA - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.risk_score).toBeUndefined(); - - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); - }); - }); - - describe('when rule field has an update and a custom value that are different - scenario -AB', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); - - // Customize a number field on the installed rule - await patchRule(supertest, log, { - rule_id: 'rule-1', - risk_score: 2, - }); - - // Increment the version of the installed rule, update a number field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - risk_score: 3, - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and number field update does not have a conflict - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.risk_score).toEqual({ - current_version: 2, - target_version: 3, - merged_version: 3, - diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - conflict: ThreeWayDiffConflict.SOLVABLE, - has_update: true, - has_base_version: false, - }); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); - }); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.rule_type_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.rule_type_fields.ts new file mode 100644 index 0000000000000..0764bac554bf5 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.rule_type_fields.ts @@ -0,0 +1,362 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import expect from 'expect'; +import { + RuleUpdateProps, + ThreeWayDiffConflict, + ThreeWayDiffOutcome, + ThreeWayMergeOutcome, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { getPrebuiltRuleMock } from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules/mocks'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; +import { + deleteAllTimelines, + deleteAllPrebuiltRuleAssets, + createRuleAssetSavedObject, + installPrebuiltRules, + createPrebuiltRuleAssetSavedObjects, + reviewPrebuiltRulesToUpgrade, + patchRule, + createHistoricalPrebuiltRuleAssetSavedObjects, + updateRule, +} from '../../../../utils'; +import { deleteAllRules } from '../../../../../../../common/utils/security_solution'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless @skipInServerlessMKI review prebuilt rules updates from package with mock rule assets', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await deleteAllTimelines(es, log); + await deleteAllPrebuiltRuleAssets(es, log); + }); + + describe(`rule type fields`, () => { + const getRuleAssetSavedObjects = () => [ + createRuleAssetSavedObject({ rule_id: 'rule-1', version: 1, type: 'query' }), + ]; + + describe("when rule field doesn't have an update and has no custom value - scenario AAA", () => { + it('should not show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Increment the version of the installed rule, do NOT update the related type field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + type: 'query', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that there is 1 rule eligible for update + // but type field is NOT returned + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.type).toBeUndefined(); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); + }); + + describe("when rule field doesn't have an update but has a custom value - scenario ABA", () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a type field on the installed rule + await updateRule(supertest, { + ...getPrebuiltRuleMock(), + rule_id: 'rule-1', + type: 'saved_query', + query: undefined, + language: undefined, + filters: undefined, + saved_id: 'saved-query-id', + } as RuleUpdateProps); + + // Increment the version of the installed rule, do NOT update the related type field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + type: 'query', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that type diff field + // is returned but field does not have an update, and the merge outcome is "Target" + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.type).toEqual({ + base_version: 'query', + current_version: 'saved_query', + target_version: 'query', + merged_version: 'query', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + conflict: ThreeWayDiffConflict.NON_SOLVABLE, + has_update: false, + has_base_version: true, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); // version field counts as upgraded + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); + }); + }); + + describe('when rule field has an update but does not have a custom value - scenario AAB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Increment the version of the installed rule, update a type field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + type: 'saved_query', + saved_id: 'even-newer-saved-query-id', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.type).toEqual({ + base_version: 'query', + current_version: 'query', + target_version: 'saved_query', + merged_version: 'saved_query', + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + conflict: ThreeWayDiffConflict.NON_SOLVABLE, + has_update: true, + has_base_version: true, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(3); // version and query fields also have updates + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); + }); + }); + + describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a type field on the installed rule + await updateRule(supertest, { + ...getPrebuiltRuleMock(), + rule_id: 'rule-1', + type: 'saved_query', + query: undefined, + language: undefined, + filters: undefined, + saved_id: 'saved-query-id', + } as RuleUpdateProps); + + // Increment the version of the installed rule, update a type field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + type: 'saved_query', + saved_id: 'saved-query-id', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.type).toEqual({ + base_version: 'query', + current_version: 'saved_query', + target_version: 'saved_query', + merged_version: 'saved_query', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + conflict: ThreeWayDiffConflict.NON_SOLVABLE, + has_update: false, + has_base_version: true, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); + }); + }); + + describe('when rule field has an update and a custom value that are different - scenario ABC', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a type field on the installed rule + await updateRule(supertest, { + ...getPrebuiltRuleMock(), + rule_id: 'rule-1', + type: 'saved_query', + query: undefined, + language: undefined, + filters: undefined, + saved_id: 'saved-query-id', + } as RuleUpdateProps); + + // Increment the version of the installed rule, update a type field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + type: 'esql', + language: 'esql', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and type field update has NON_SOLVABLE conflict, and merged version is TARGET + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.type).toEqual({ + base_version: 'query', + current_version: 'saved_query', + target_version: 'esql', + merged_version: 'esql', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + conflict: ThreeWayDiffConflict.NON_SOLVABLE, + has_update: true, + has_base_version: true, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(4); // version + type + kql_query all considered updates + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // type + kql_query both considered conflicts + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(2); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); + }); + }); + + describe('when rule base version does not exist', () => { + describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { + it('should not show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + + // Increment the version of the installed rule, but keep type field unchanged + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + type: 'query', // unchanged + }), + ]; + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // but does NOT contain type field + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.type).toBeUndefined(); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered a conflict + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); + }); + + describe('when rule field has an update and a custom value that are different - scenario -AB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + + // Customize a type field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + type: 'query', + }); + + // Increment the version of the installed rule, update a type field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + type: 'saved_query', + saved_id: 'saved-query-id', + }), + ]; + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and type field update does have a non-solvable conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.type).toEqual({ + current_version: 'query', + target_version: 'saved_query', + merged_version: 'saved_query', + diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + conflict: ThreeWayDiffConflict.NON_SOLVABLE, + has_update: true, + has_base_version: false, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(3); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(3); // type + version + query are all considered conflicts + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); + }); + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.scalar_array_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.scalar_array_fields.ts index dde56d59f82ac..503a51f84f812 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.scalar_array_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.scalar_array_fields.ts @@ -156,209 +156,295 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); + }); - describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); + describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); - // Customize a scalar array field on the installed rule - await patchRule(supertest, log, { + // Customize a scalar array field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + tags: ['one', 'two', 'four'], + }); + + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ rule_id: 'rule-1', + version: 2, tags: ['one', 'two', 'four'], - }); + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Increment the version of the installed rule, update a scalar array field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - tags: ['one', 'two', 'four'], - }), - ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update and contains scalar array field + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ + base_version: ['one', 'two', 'three'], + current_version: ['one', 'two', 'four'], + target_version: ['one', 'two', 'four'], + merged_version: ['one', 'two', 'four'], + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + conflict: ThreeWayDiffConflict.NONE, + has_update: false, + has_base_version: true, + }); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update and contains scalar array field - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ - base_version: ['one', 'two', 'three'], - current_version: ['one', 'two', 'four'], - target_version: ['one', 'two', 'four'], - merged_version: ['one', 'two', 'four'], - diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, - merge_outcome: ThreeWayMergeOutcome.Current, - conflict: ThreeWayDiffConflict.NONE, - has_update: false, - has_base_version: true, - }); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); + }); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + describe('when rule field has an update and a custom value that are different - scenario ABC', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a scalar array field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + tags: ['one', 'two', 'four'], }); + + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + tags: ['one', 'two', 'five'], + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and scalar array field update has conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ + base_version: ['one', 'two', 'three'], + current_version: ['one', 'two', 'four'], + target_version: ['one', 'two', 'five'], + merged_version: ['one', 'two', 'four', 'five'], + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Merged, + conflict: ThreeWayDiffConflict.SOLVABLE, + has_update: true, + has_base_version: true, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); - describe('when rule field has an update and a custom value that are different - scenario ABC', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); + it('should compare values after deduplication', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 1, + tags: ['one', 'two', 'two'], + }), + ]); + await installPrebuiltRules(es, supertest); - // Customize a scalar array field on the installed rule - await patchRule(supertest, log, { + // Customize a scalar array field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + tags: ['two', 'one', 'three'], + }); + + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ rule_id: 'rule-1', - tags: ['one', 'two', 'four'], - }); + version: 2, + tags: ['three', 'three', 'one'], + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Increment the version of the installed rule, update a scalar array field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - tags: ['one', 'two', 'five'], - }), - ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and scalar array field update has conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ + base_version: ['one', 'two', 'two'], + current_version: ['two', 'one', 'three'], + target_version: ['three', 'three', 'one'], + merged_version: ['one', 'three'], + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Merged, + conflict: ThreeWayDiffConflict.SOLVABLE, + has_update: true, + has_base_version: true, + }); - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and scalar array field update has conflict - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ - base_version: ['one', 'two', 'three'], - current_version: ['one', 'two', 'four'], - target_version: ['one', 'two', 'five'], - merged_version: ['one', 'two', 'four', 'five'], - diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Merged, - conflict: ThreeWayDiffConflict.SOLVABLE, - has_update: true, - has_base_version: true, - }); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); - }); + it('should compare values sensitive of case', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 1, + tags: ['ONE', 'TWO'], + }), + ]); + await installPrebuiltRules(es, supertest); - it('should compare values after deduplication', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 1, - tags: ['one', 'two', 'two'], - }), - ]); - await installPrebuiltRules(es, supertest); + // Customize a scalar array field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + tags: ['one', 'ONE'], + }); - // Customize a scalar array field on the installed rule - await patchRule(supertest, log, { + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ rule_id: 'rule-1', - tags: ['two', 'one', 'three'], - }); + version: 2, + tags: ['ONE', 'THREE'], + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Increment the version of the installed rule, update a scalar array field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - tags: ['three', 'three', 'one'], - }), - ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and scalar array field update has conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ + base_version: ['ONE', 'TWO'], + current_version: ['one', 'ONE'], + target_version: ['ONE', 'THREE'], + merged_version: ['ONE', 'one', 'THREE'], + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Merged, + conflict: ThreeWayDiffConflict.SOLVABLE, + has_update: true, + has_base_version: true, + }); - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and scalar array field update has conflict - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ - base_version: ['one', 'two', 'two'], - current_version: ['two', 'one', 'three'], - target_version: ['three', 'three', 'one'], - merged_version: ['one', 'three'], - diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Merged, - conflict: ThreeWayDiffConflict.SOLVABLE, - has_update: true, - has_base_version: true, - }); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + it('should handle empty arrays', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a scalar array field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + tags: [], }); - it('should compare values sensitive of case', async () => { + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + tags: ['one', 'two', 'five'], + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and scalar array field update has conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ + base_version: ['one', 'two', 'three'], + current_version: [], + target_version: ['one', 'two', 'five'], + merged_version: ['five'], + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Merged, + conflict: ThreeWayDiffConflict.SOLVABLE, + has_update: true, + has_base_version: true, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); + }); + + describe('when rule base version does not exist', () => { + describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { + it('should not show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 1, - tags: ['ONE', 'TWO'], - }), - ]); + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); - // Customize a scalar array field on the installed rule - await patchRule(supertest, log, { - rule_id: 'rule-1', - tags: ['one', 'ONE'], - }); + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); - // Increment the version of the installed rule, update a scalar array field, and create the new rule assets + // Increment the version of the installed rule, but keep scalar array field unchanged const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - tags: ['ONE', 'THREE'], + tags: ['one', 'two', 'three'], // unchanged }), ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and scalar array field update has conflict + // but does NOT contain scalar array field (tags is not present, since scenario -AA is not included in response) const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ - base_version: ['ONE', 'TWO'], - current_version: ['one', 'ONE'], - target_version: ['ONE', 'THREE'], - merged_version: ['ONE', 'one', 'THREE'], - diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Merged, - conflict: ThreeWayDiffConflict.SOLVABLE, - has_update: true, - has_base_version: true, - }); + expect(reviewResponse.rules[0].diff.fields.tags).toBeUndefined(); - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered conflict expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); + }); - it('should handle empty arrays', async () => { + describe('when rule field has an update and a custom value that are different - scenario -AB', () => { + it('should show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + // Customize a scalar array field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', - tags: [], + tags: ['one', 'two', 'four'], }); // Increment the version of the installed rule, update a scalar array field, and create the new rule assets @@ -369,25 +455,24 @@ export default ({ getService }: FtrProviderContext): void => { tags: ['one', 'two', 'five'], }), ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and scalar array field update has conflict + // and scalar array field update does not have a conflict const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ - base_version: ['one', 'two', 'three'], - current_version: [], + current_version: ['one', 'two', 'four'], target_version: ['one', 'two', 'five'], - merged_version: ['five'], - diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Merged, + merged_version: ['one', 'two', 'five'], + diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, conflict: ThreeWayDiffConflict.SOLVABLE, has_update: true, - has_base_version: true, + has_base_version: false, }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // version + tags expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); @@ -395,91 +480,6 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); - - describe('when rule base version does not exist', () => { - describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { - it('should not show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); - - // Increment the version of the installed rule, but keep scalar array field unchanged - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - tags: ['one', 'two', 'three'], // unchanged - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // but does NOT contain scalar array field (tags is not present, since scenario -AA is not included in response) - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.tags).toBeUndefined(); - - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered conflict - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); - }); - }); - - describe('when rule field has an update and a custom value that are different - scenario -AB', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); - - // Customize a scalar array field on the installed rule - await patchRule(supertest, log, { - rule_id: 'rule-1', - tags: ['one', 'two', 'four'], - }); - - // Increment the version of the installed rule, update a scalar array field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - tags: ['one', 'two', 'five'], - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and scalar array field update does not have a conflict - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.tags).toEqual({ - current_version: ['one', 'two', 'four'], - target_version: ['one', 'two', 'five'], - merged_version: ['one', 'two', 'five'], - diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - conflict: ThreeWayDiffConflict.SOLVABLE, - has_update: true, - has_base_version: false, - }); - - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // version + tags - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); - }); - }); - }); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.single_line_string_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.single_line_string_fields.ts index aa1feb5fc70e8..b887e18813ec6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.single_line_string_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.single_line_string_fields.ts @@ -156,59 +156,145 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); + }); - describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); + describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); - // Customize a single line string field on the installed rule - await patchRule(supertest, log, { + // Customize a single line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + name: 'B', + }); + + // Increment the version of the installed rule, update a single line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ rule_id: 'rule-1', + version: 2, name: 'B', - }); + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Increment the version of the installed rule, update a single line string field, and create the new rule assets + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.name).toEqual({ + base_version: 'A', + current_version: 'B', + target_version: 'B', + merged_version: 'B', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + conflict: ThreeWayDiffConflict.NONE, + has_update: false, + has_base_version: true, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); + }); + }); + + describe('when rule field has an update and a custom value that are different - scenario ABC', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a single line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + name: 'B', + }); + + // Increment the version of the installed rule, update a single line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + name: 'C', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and single line string field update has NON_SOLVABLE conflict, and merged version is CURRENT + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields.name).toEqual({ + base_version: 'A', + current_version: 'B', + target_version: 'C', + merged_version: 'B', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + conflict: ThreeWayDiffConflict.NON_SOLVABLE, + has_update: true, + has_base_version: true, + }); + + expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); + }); + }); + + describe('when rule base version does not exist', () => { + describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { + it('should not show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + + // Increment the version of the installed rule, but keep single line string field unchanged const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - name: 'B', + name: 'A', // unchanged }), ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // but does NOT contain single line string field const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.name).toEqual({ - base_version: 'A', - current_version: 'B', - target_version: 'B', - merged_version: 'B', - diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, - merge_outcome: ThreeWayMergeOutcome.Current, - conflict: ThreeWayDiffConflict.NONE, - has_update: false, - has_base_version: true, - }); + expect(reviewResponse.rules[0].diff.fields.name).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered a conflict expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); - describe('when rule field has an update and a custom value that are different - scenario ABC', () => { + describe('when rule field has an update and a custom value that are different - scenario -AB', () => { it('should show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + // Customize a single line string field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', @@ -223,115 +309,29 @@ export default ({ getService }: FtrProviderContext): void => { name: 'C', }), ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and single line string field update has NON_SOLVABLE conflict, and merged version is CURRENT + // and single line string field update does not have a conflict const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields.name).toEqual({ - base_version: 'A', current_version: 'B', target_version: 'C', - merged_version: 'B', - diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Current, - conflict: ThreeWayDiffConflict.NON_SOLVABLE, + merged_version: 'C', + diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + conflict: ThreeWayDiffConflict.SOLVABLE, has_update: true, - has_base_version: true, + has_base_version: false, }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // name + version are both considered conflicts + expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1); - }); - }); - - describe('when rule base version does not exist', () => { - describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { - it('should not show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); - - // Increment the version of the installed rule, but keep single line string field unchanged - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - name: 'A', // unchanged - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // but does NOT contain single line string field - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.name).toBeUndefined(); - - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered a conflict - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); - }); - }); - - describe('when rule field has an update and a custom value that are different - scenario -AB', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); - - // Customize a single line string field on the installed rule - await patchRule(supertest, log, { - rule_id: 'rule-1', - name: 'B', - }); - - // Increment the version of the installed rule, update a single line string field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - name: 'C', - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and single line string field update does not have a conflict - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields.name).toEqual({ - current_version: 'B', - target_version: 'C', - merged_version: 'C', - diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - conflict: ThreeWayDiffConflict.SOLVABLE, - has_update: true, - has_base_version: false, - }); - - expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // name + version are both considered conflicts - expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); - - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); - expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); - }); + expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); }); From 7839db950e92d2dc41b53115e3d63ef0adb4755f Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Tue, 8 Oct 2024 16:14:28 -0700 Subject: [PATCH 033/110] [Docs] Update publicBaseUrl and rewriteBasePath settings (#195465) fix https://github.com/elastic/kibana/issues/114562 ![Screenshot 2024-10-08 at 09 04 20](https://github.com/user-attachments/assets/f43d592d-cc49-4f41-9bee-2a85f9c08292) ![Screenshot 2024-10-08 at 09 04 49](https://github.com/user-attachments/assets/39184960-d5ec-4485-944b-6ef4295d7101) --------- Co-authored-by: Lisa Cawley --- docs/setup/settings.asciidoc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 1a094fc37e880..4e452c63cf3b1 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -383,7 +383,7 @@ deprecation warning at startup. This setting cannot end in a slash (`/`). [[server-publicBaseUrl]] `server.publicBaseUrl`:: The publicly available URL that end-users access Kibana at. Must include the protocol, hostname, port (if different than the defaults for `http` and `https`, 80 and 443 respectively), and the -<> (if configured). This setting cannot end in a slash (`/`). +<> (when that setting is configured explicitly). This setting cannot end in a slash (`/`). [[server-compression]] `server.compression.enabled`:: Set to `false` to disable HTTP compression for all responses. *Default: `true`* @@ -487,11 +487,8 @@ Sets whether or not the `X-Opaque-Id` header should be trusted from any IP addre A list of IPv4 and IPv6 address which the `X-Opaque-Id` header should be trusted from. Normally this would be set to the IP addresses of the load balancers or reverse-proxy that end users use to access Kibana. If any are set, <> must also be set to `false.` [[server-rewriteBasePath]] `server.rewriteBasePath`:: -Specifies whether {kib} should -rewrite requests that are prefixed with <> or require that they -are rewritten by your reverse proxy. In {kib} 6.3 and earlier, the default is -`false`. In {kib} 7.x, the setting is deprecated. In {kib} 8.0 and later, the -default is `true`. *Default: `deprecated`* +Specifies whether {kib} should rewrite requests that are prefixed with <> or require that they +are rewritten by your reverse proxy. *Default: `false`* [[server-socketTimeout]] `server.socketTimeout`:: The number of milliseconds to wait before closing an From 13c2c7663546da0f6b34e5dd85932ebc74ecafa7 Mon Sep 17 00:00:00 2001 From: Ryan Hass Date: Tue, 8 Oct 2024 17:01:48 -0700 Subject: [PATCH 034/110] Fix order of operations in instructions. (#195503) ## Summary The enroll command must be executed after the elastic-agent is running. This updates the instructions so that users are told to enable and start the agent before running the `enroll` command to ensure the socket file is created and available. This fixes issues with errors like this: ``` {"log.level":"info","@timestamp":"2024-10-08T20:47:06.857Z","log.origin":{"function":"github.com/elastic/elastic-agent/internal/pkg/agent/cmd.(*enrollCmd).enrollWithBackoff","file.name":"cmd/enroll_cmd.go","file.line":518},"message":"Starting enrollment to URL: https://.fleet.us-west-2.aws.elastic.cloud:443/","ecs.version":"1.6.0"} {"log.level":"info","@timestamp":"2024-10-08T20:47:08.681Z","log.origin":{"function":"github.com/elastic/elastic-agent/internal/pkg/agent/cmd.(*enrollCmd).daemonReloadWithBackoff","file.name":"cmd/enroll_cmd.go","file.line":481},"message":"Restarting agent daemon, attempt 0","ecs.version":"1.6.0"} {"log.level":"error","@timestamp":"2024-10-08T20:47:08.683Z","log.origin":{"function":"github.com/elastic/elastic-agent/internal/pkg/agent/cmd.(*enrollCmd).daemonReloadWithBackoff","file.name":"cmd/enroll_cmd.go","file.line":495},"message":"Restart attempt 0 failed: 'rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing: dial unix /usr/share/elastic-agent/elastic-agent.sock: connect: no such file or directory\"'. Waiting for 2s","ecs.version":"1.6.0"} ``` ### Checklist N/A ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../utils/install_command_utils.test.ts | 60 +++++++++---------- .../utils/install_command_utils.ts | 4 +- .../enrollment_instructions/manual/index.tsx | 4 +- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts index c86811da2fde7..e00adaa13a414 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts @@ -74,12 +74,12 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--x86_64.rpm sudo rpm -vi elastic-agent--x86_64.rpm + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ - --fleet-server-port=8220 - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --fleet-server-port=8220" `); }); @@ -93,12 +93,12 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb sudo dpkg -i elastic-agent--amd64.deb + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ - --fleet-server-port=8220 - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --fleet-server-port=8220" `); }); @@ -196,13 +196,13 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--x86_64.rpm sudo rpm -vi elastic-agent--x86_64.rpm + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ --fleet-server-policy=policy-1 \\\\ - --fleet-server-port=8220 - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --fleet-server-port=8220" `); }); @@ -217,13 +217,13 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb sudo dpkg -i elastic-agent--amd64.deb + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ --fleet-server-policy=policy-1 \\\\ - --fleet-server-port=8220 - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --fleet-server-port=8220" `); }); }); @@ -349,6 +349,8 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--x86_64.rpm sudo rpm -vi elastic-agent--x86_64.rpm + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll --url=http://fleetserver:8220 \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ @@ -357,9 +359,7 @@ describe('getInstallCommandForPlatform', () => { --fleet-server-es-ca= \\\\ --fleet-server-cert= \\\\ --fleet-server-cert-key= \\\\ - --fleet-server-port=8220 - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --fleet-server-port=8220" `); }); @@ -376,6 +376,8 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb sudo dpkg -i elastic-agent--amd64.deb + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll --url=http://fleetserver:8220 \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ @@ -384,9 +386,7 @@ describe('getInstallCommandForPlatform', () => { --fleet-server-es-ca= \\\\ --fleet-server-cert= \\\\ --fleet-server-cert-key= \\\\ - --fleet-server-port=8220 - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --fleet-server-port=8220" `); }); }); @@ -547,14 +547,14 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--x86_64.rpm --proxy http://download-src-proxy:2222 sudo rpm -vi elastic-agent--x86_64.rpm + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ --fleet-server-policy=policy-1 \\\\ --fleet-server-port=8220 \\\\ - --proxy-url=http://es-proxy:1111 - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --proxy-url=http://es-proxy:1111" `); }); @@ -589,14 +589,14 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--amd64.deb --proxy http://download-src-proxy:2222 sudo dpkg -i elastic-agent--amd64.deb + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ --fleet-server-policy=policy-1 \\\\ --fleet-server-port=8220 \\\\ - --proxy-url=http://es-proxy:1111 - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --proxy-url=http://es-proxy:1111" `); }); }); @@ -795,6 +795,8 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--x86_64.rpm --proxy http://download-src-proxy:2222 --proxy-header \\"Accept-Language=en-US,en;q=0.5\\" --proxy-header \\"second-header=second-value\\" sudo rpm -vi elastic-agent--x86_64.rpm + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ @@ -802,9 +804,7 @@ describe('getInstallCommandForPlatform', () => { --fleet-server-port=8220 \\\\ --proxy-url=http://es-proxy:1111 \\\\ --proxy-header=\\"X-Forwarded-For=forwarded-value\\" \\\\ - --proxy-header=\\"test-header=test-value\\" - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --proxy-header=\\"test-header=test-value\\"" `); }); @@ -847,6 +847,8 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--amd64.deb --proxy http://download-src-proxy:2222 --proxy-header \\"Accept-Language=en-US,en;q=0.5\\" --proxy-header \\"second-header=second-value\\" sudo dpkg -i elastic-agent--amd64.deb + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ @@ -854,9 +856,7 @@ describe('getInstallCommandForPlatform', () => { --fleet-server-port=8220 \\\\ --proxy-url=http://es-proxy:1111 \\\\ --proxy-header=\\"X-Forwarded-For=forwarded-value\\" \\\\ - --proxy-header=\\"test-header=test-value\\" - sudo systemctl enable elastic-agent - sudo systemctl start elastic-agent" + --proxy-header=\\"test-header=test-value\\"" `); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts index 5656e49de4bc9..0264adc879907 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts @@ -154,8 +154,8 @@ export function getInstallCommandForPlatform({ linux: `${artifact.downloadCommand}\nsudo ./elastic-agent install ${commandArgumentsStr}`, mac: `${artifact.downloadCommand}\nsudo ./elastic-agent install ${commandArgumentsStr}`, windows: `${artifact.downloadCommand}\n.\\elastic-agent.exe install ${commandArgumentsStr}`, - deb: `${artifact.downloadCommand}\nsudo elastic-agent enroll ${commandArgumentsStr}\nsudo systemctl enable elastic-agent\nsudo systemctl start elastic-agent`, - rpm: `${artifact.downloadCommand}\nsudo elastic-agent enroll ${commandArgumentsStr}\nsudo systemctl enable elastic-agent\nsudo systemctl start elastic-agent`, + deb: `${artifact.downloadCommand}\nsudo systemctl enable elastic-agent\nsudo systemctl start elastic-agent\nsudo elastic-agent enroll ${commandArgumentsStr}`, + rpm: `${artifact.downloadCommand}\nsudo systemctl enable elastic-agent\nsudo systemctl start elastic-agent\nsudo elastic-agent enroll ${commandArgumentsStr}`, kubernetes: '', cloudFormation: '', googleCloudShell: '', diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx index 654b3a782649c..27b98bdc1acbe 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx @@ -107,11 +107,11 @@ cd elastic-agent-${agentVersion}-windows-x86_64 const linuxDebCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-amd64.deb ${curlDownloadSourceProxyArgs} sudo dpkg -i elastic-agent-${agentVersion}-amd64.deb -sudo elastic-agent enroll ${enrollArgs} \nsudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent`; +sudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent \nsudo elastic-agent enroll ${enrollArgs} \n`; const linuxRpmCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-x86_64.rpm ${curlDownloadSourceProxyArgs} sudo rpm -vi elastic-agent-${agentVersion}-x86_64.rpm -sudo elastic-agent enroll ${enrollArgs} \nsudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent`; +sudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent \nsudo elastic-agent enroll ${enrollArgs} \n`; const googleCloudShellCommand = `gcloud config set project ${gcpProjectId} && ${ gcpAccountType === 'organization-account' ? `ORG_ID=${gcpOrganizationId}` : `` From f2e9b607cd52ad256e32566690d2411f3a12c4ce Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 9 Oct 2024 01:37:42 +0100 Subject: [PATCH 035/110] skip flaky suite (#175841) --- .../plugins/cases/public/components/files/file_type.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/files/file_type.test.tsx b/x-pack/plugins/cases/public/components/files/file_type.test.tsx index 7e50a3b6fe876..bb6224ecc5734 100644 --- a/x-pack/plugins/cases/public/components/files/file_type.test.tsx +++ b/x-pack/plugins/cases/public/components/files/file_type.test.tsx @@ -30,7 +30,8 @@ describe('getFileType', () => { }); }); - describe('getFileAttachmentViewObject', () => { + // FLAKY: https://github.com/elastic/kibana/issues/175841 + describe.skip('getFileAttachmentViewObject', () => { let appMockRender: AppMockRenderer; const attachmentViewProps: ExternalReferenceAttachmentViewProps = { From de72ea4ae8527d83011ae58a8c6f47bad14ff444 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 9 Oct 2024 01:39:48 +0100 Subject: [PATCH 036/110] skip flaky suite (#193026) --- .../cases/public/components/custom_fields/text/create.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/custom_fields/text/create.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/text/create.test.tsx index 7edea532a529a..bb01226604d3a 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/text/create.test.tsx +++ b/x-pack/plugins/cases/public/components/custom_fields/text/create.test.tsx @@ -14,7 +14,8 @@ import { Create } from './create'; import { customFieldsConfigurationMock } from '../../../containers/mock'; import { MAX_CUSTOM_FIELD_TEXT_VALUE_LENGTH } from '../../../../common/constants'; -describe('Create ', () => { +// FLAKY: https://github.com/elastic/kibana/issues/193026 +describe.skip('Create ', () => { const onSubmit = jest.fn(); beforeEach(() => { From e9aff7dccd390513ecb8e5395b414bca8e8411ab Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 9 Oct 2024 01:42:12 +0100 Subject: [PATCH 037/110] skip flaky suite (#194703) --- .../cases/public/components/templates/template_fields.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/templates/template_fields.test.tsx b/x-pack/plugins/cases/public/components/templates/template_fields.test.tsx index 7de2233f8505c..4e7d18b12d3bf 100644 --- a/x-pack/plugins/cases/public/components/templates/template_fields.test.tsx +++ b/x-pack/plugins/cases/public/components/templates/template_fields.test.tsx @@ -13,7 +13,8 @@ import { createAppMockRenderer } from '../../common/mock'; import { FormTestComponent } from '../../common/test_utils'; import { TemplateFields } from './template_fields'; -describe('Template fields', () => { +// FLAKY: https://github.com/elastic/kibana/issues/194703 +describe.skip('Template fields', () => { let user: UserEvent; let appMockRenderer: AppMockRenderer; const onSubmit = jest.fn(); From edd61f63dbad99fe8da1e503c81db774fcb37e8f Mon Sep 17 00:00:00 2001 From: Jiawei Wu <74562234+JiaweiWu@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:01:45 -0700 Subject: [PATCH 038/110] [Response Ops][Flapping] Rule Specific Flapping - Create/Update API changes (#190019) ## Summary Issue: https://github.com/elastic/kibana/issues/190018 Implement rule specific flapping support for create and update Rule API. The new property on the rule is named `flapping`; ``` flapping: { look_back_window: number; status_change_threshold: number; } ``` Also make changes in the task runner to use the rule's flapping settings if it exists. Otherwise use the global flapping setting. # To test 1. Go to `x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts` and turn `IS_RULE_SPECIFIC_FLAPPING_ENABLED` to `true` 2. Create a rule with a rule specific flapping setting, generate the alert and let it flap 3. Assert that the flapping is now using the rule specific flapping 4. Turn space flapping off 5. Assert that it no longer flaps despite having a rule specific flapping 6. Try deleting/adding back the rule specific flapping via the UI and verify everything works. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Elastic Machine Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- oas_docs/bundle.json | 126 ++++++++++ oas_docs/bundle.serverless.json | 126 ++++++++++ .../output/kibana.serverless.staging.yaml | 96 +++++++ oas_docs/output/kibana.serverless.yaml | 96 +++++++ oas_docs/output/kibana.staging.yaml | 96 +++++++ oas_docs/output/kibana.yaml | 96 +++++++ .../kbn-alerting-types/flapping/latest.ts | 10 + .../{rule_flapping.ts => flapping/v1.ts} | 0 packages/kbn-alerting-types/index.ts | 1 - packages/kbn-alerting-types/rule_types.ts | 10 +- .../create_rule/transform_create_rule_body.ts | 8 +- .../update_rule/transform_update_rule_body.ts | 8 +- .../common/transformations/transform_rule.ts | 8 +- .../src/common/types/rule_types.ts | 2 + .../rule_settings_flapping_inputs.tsx | 2 +- .../check_registered_types.test.ts | 2 +- x-pack/plugins/alerting/common/index.ts | 2 +- .../routes/rule/apis/create/schemas/v1.ts | 2 + .../routes/rule/apis/create/types/v1.ts | 1 + .../routes/rule/apis/update/schemas/v1.ts | 2 + .../routes/rule/apis/update/types/v1.ts | 1 + .../rule/common/flapping/schemas/latest.ts | 8 + .../routes/rule/common/flapping/schemas/v1.ts | 29 +++ .../rule/common/flapping/types/latest.ts | 8 + .../routes/rule/common/flapping/types/v1.ts | 11 + .../common/routes/rule/common/index.ts | 8 + .../common/routes/rule/response/schemas/v1.ts | 2 + .../common/routes/rule/response/types/v1.ts | 1 + .../common/routes/rule/validation/index.ts | 2 + .../validation/validate_flapping/latest.ts | 8 + .../validation/validate_flapping/v1.test.ts | 57 +++++ .../rule/validation/validate_flapping/v1.ts | 36 +++ .../plugins/alerting/common/rules_settings.ts | 12 - .../common/saved_objects/rules/mappings.ts | 12 + .../rule/methods/create/create_rule.test.ts | 89 ++++++- .../rule/methods/create/create_rule.ts | 15 +- .../create/schemas/create_rule_data_schema.ts | 2 + .../methods/create/types/create_rule_data.ts | 1 + .../update/schemas/update_rule_data_schema.ts | 2 + .../methods/update/types/update_rule_data.ts | 1 + .../rule/methods/update/update_rule.test.ts | 94 +++++++ .../rule/methods/update/update_rule.ts | 46 +++- .../rule/schemas/flapping_schema.ts | 13 + .../server/application/rule/schemas/index.ts | 1 + .../application/rule/schemas/rule_schemas.ts | 3 + ...orm_rule_attributes_to_rule_domain.test.ts | 11 + ...ransform_rule_attributes_to_rule_domain.ts | 1 + .../transform_rule_domain_to_rule.test.ts | 16 ++ .../transform_rule_domain_to_rule.ts | 1 + ...orm_rule_domain_to_rule_attributes.test.ts | 122 +++++++++ ...ransform_rule_domain_to_rule_attributes.ts | 1 + .../server/application/rule/types/rule.ts | 2 + .../server/data/rule/types/rule_attributes.ts | 6 + x-pack/plugins/alerting/server/plugin.ts | 5 +- .../apis/create/create_rule_route.test.ts | 5 + .../rule/apis/create/create_rule_route.ts | 4 + .../transforms/transform_create_body/v1.ts | 15 ++ .../transform_find_rules_response/v1.ts | 2 + .../transforms/transform_update_body/v1.ts | 15 ++ .../apis/update/update_rule_route.test.ts | 1 + .../rule/apis/update/update_rule_route.ts | 4 + .../server/routes/rule/transforms/index.ts | 2 + .../transform_rule_to_rule_response/v1.ts | 12 + .../rules_client/lib/get_alert_from_raw.ts | 2 +- .../rules_settings_flapping_client.ts | 10 +- .../rules_settings_client.mock.ts | 10 +- .../model_versions/rule_model_versions.ts | 9 +- .../saved_objects/schemas/raw_rule/index.ts | 1 + .../saved_objects/schemas/raw_rule/v2.ts | 18 ++ .../server/task_runner/task_runner.ts | 13 +- .../task_runner_alerts_client.test.ts | 108 ++++++++ x-pack/plugins/alerting/server/types.ts | 6 +- .../lib/rule_api/common_transformations.ts | 12 + .../sections/rule_form/rule_form.tsx | 7 +- .../rule_form/rule_form_advanced_options.tsx | 31 ++- .../group1/tests/alerting/create.ts | 8 + .../group2/tests/alerting/update.ts | 44 ++++ .../tests/alerting/group1/create.ts | 85 +++++++ .../tests/alerting/group2/update.ts | 235 +++++++++++++++++- .../alerts_as_data/alerts_as_data_flapping.ts | 202 +++++++++++++++ 80 files changed, 2108 insertions(+), 74 deletions(-) create mode 100644 packages/kbn-alerting-types/flapping/latest.ts rename packages/kbn-alerting-types/{rule_flapping.ts => flapping/v1.ts} (100%) create mode 100644 x-pack/plugins/alerting/common/routes/rule/common/flapping/schemas/latest.ts create mode 100644 x-pack/plugins/alerting/common/routes/rule/common/flapping/schemas/v1.ts create mode 100644 x-pack/plugins/alerting/common/routes/rule/common/flapping/types/latest.ts create mode 100644 x-pack/plugins/alerting/common/routes/rule/common/flapping/types/v1.ts create mode 100644 x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/latest.ts create mode 100644 x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/v1.test.ts create mode 100644 x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/v1.ts create mode 100644 x-pack/plugins/alerting/server/application/rule/schemas/flapping_schema.ts create mode 100644 x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule_attributes.test.ts create mode 100644 x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v2.ts diff --git a/oas_docs/bundle.json b/oas_docs/bundle.json index 4597c6a6043c0..6cc3990de1b51 100644 --- a/oas_docs/bundle.json +++ b/oas_docs/bundle.json @@ -1851,6 +1851,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "id": { "description": "The identifier for the rule.", "type": "string" @@ -2667,6 +2688,27 @@ "description": "Indicates whether you want to run the rule on an interval basis after it is created.", "type": "boolean" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "name": { "description": "The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.", "type": "string" @@ -3047,6 +3089,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "id": { "description": "The identifier for the rule.", "type": "string" @@ -3853,6 +3916,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "name": { "description": "The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.", "type": "string" @@ -4226,6 +4310,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "id": { "description": "The identifier for the rule.", "type": "string" @@ -5692,6 +5797,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "id": { "description": "The identifier for the rule.", "type": "string" diff --git a/oas_docs/bundle.serverless.json b/oas_docs/bundle.serverless.json index f548497693088..6fcc247e1fb22 100644 --- a/oas_docs/bundle.serverless.json +++ b/oas_docs/bundle.serverless.json @@ -1851,6 +1851,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "id": { "description": "The identifier for the rule.", "type": "string" @@ -2667,6 +2688,27 @@ "description": "Indicates whether you want to run the rule on an interval basis after it is created.", "type": "boolean" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "name": { "description": "The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.", "type": "string" @@ -3047,6 +3089,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "id": { "description": "The identifier for the rule.", "type": "string" @@ -3853,6 +3916,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "name": { "description": "The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.", "type": "string" @@ -4226,6 +4310,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "id": { "description": "The identifier for the rule.", "type": "string" @@ -5692,6 +5797,27 @@ ], "type": "object" }, + "flapping": { + "additionalProperties": false, + "nullable": true, + "properties": { + "look_back_window": { + "maximum": 20, + "minimum": 2, + "type": "number" + }, + "status_change_threshold": { + "maximum": 20, + "minimum": 2, + "type": "number" + } + }, + "required": [ + "look_back_window", + "status_change_threshold" + ], + "type": "object" + }, "id": { "description": "The identifier for the rule.", "type": "string" diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index 66790ef3f9c17..67e2f6844a6df 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -1269,6 +1269,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -2026,6 +2042,22 @@ paths: Indicates whether you want to run the rule on an interval basis after it is created. type: boolean + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold name: description: >- The name of the rule. While this name does not have to be @@ -2410,6 +2442,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -3146,6 +3194,22 @@ paths: type: number required: - active + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold name: description: >- The name of the rule. While this name does not have to be @@ -3522,6 +3586,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -4732,6 +4812,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index 66790ef3f9c17..67e2f6844a6df 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -1269,6 +1269,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -2026,6 +2042,22 @@ paths: Indicates whether you want to run the rule on an interval basis after it is created. type: boolean + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold name: description: >- The name of the rule. While this name does not have to be @@ -2410,6 +2442,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -3146,6 +3194,22 @@ paths: type: number required: - active + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold name: description: >- The name of the rule. While this name does not have to be @@ -3522,6 +3586,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -4732,6 +4812,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index 7dbb9571f0272..372569024e114 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -1650,6 +1650,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -2407,6 +2423,22 @@ paths: Indicates whether you want to run the rule on an interval basis after it is created. type: boolean + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold name: description: >- The name of the rule. While this name does not have to be @@ -2791,6 +2823,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -3527,6 +3575,22 @@ paths: type: number required: - active + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold name: description: >- The name of the rule. While this name does not have to be @@ -3903,6 +3967,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -5113,6 +5193,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index 7dbb9571f0272..372569024e114 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -1650,6 +1650,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -2407,6 +2423,22 @@ paths: Indicates whether you want to run the rule on an interval basis after it is created. type: boolean + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold name: description: >- The name of the rule. While this name does not have to be @@ -2791,6 +2823,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -3527,6 +3575,22 @@ paths: type: number required: - active + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold name: description: >- The name of the rule. While this name does not have to be @@ -3903,6 +3967,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string @@ -5113,6 +5193,22 @@ paths: required: - status - last_execution_date + flapping: + additionalProperties: false + nullable: true + type: object + properties: + look_back_window: + maximum: 20 + minimum: 2 + type: number + status_change_threshold: + maximum: 20 + minimum: 2 + type: number + required: + - look_back_window + - status_change_threshold id: description: The identifier for the rule. type: string diff --git a/packages/kbn-alerting-types/flapping/latest.ts b/packages/kbn-alerting-types/flapping/latest.ts new file mode 100644 index 0000000000000..f278309c22b03 --- /dev/null +++ b/packages/kbn-alerting-types/flapping/latest.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export * from './v1'; diff --git a/packages/kbn-alerting-types/rule_flapping.ts b/packages/kbn-alerting-types/flapping/v1.ts similarity index 100% rename from packages/kbn-alerting-types/rule_flapping.ts rename to packages/kbn-alerting-types/flapping/v1.ts diff --git a/packages/kbn-alerting-types/index.ts b/packages/kbn-alerting-types/index.ts index f4c2c17803df7..0a930e6a9319c 100644 --- a/packages/kbn-alerting-types/index.ts +++ b/packages/kbn-alerting-types/index.ts @@ -18,5 +18,4 @@ export * from './r_rule_types'; export * from './rule_notify_when_type'; export * from './rule_type_types'; export * from './rule_types'; -export * from './rule_flapping'; export * from './search_strategy_types'; diff --git a/packages/kbn-alerting-types/rule_types.ts b/packages/kbn-alerting-types/rule_types.ts index d2f3831c2ae47..87638dff18879 100644 --- a/packages/kbn-alerting-types/rule_types.ts +++ b/packages/kbn-alerting-types/rule_types.ts @@ -205,6 +205,11 @@ export type SanitizedRuleAction = Omit & { alertsFilter?: SanitizedAlertsFilter; }; +export interface Flapping extends SavedObjectAttributes { + lookBackWindow: number; + statusChangeThreshold: number; +} + export interface Rule { id: string; enabled: boolean; @@ -240,10 +245,7 @@ export interface Rule { running?: boolean | null; viewInAppRelativeUrl?: string; alertDelay?: AlertDelay | null; - flapping?: { - lookBackWindow: number; - statusChangeThreshold: number; - }; + flapping?: Flapping | null; } export type SanitizedRule = Omit< diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/create_rule/transform_create_rule_body.ts b/packages/kbn-alerts-ui-shared/src/common/apis/create_rule/transform_create_rule_body.ts index bd3ff92a627d7..a90a94889545f 100644 --- a/packages/kbn-alerts-ui-shared/src/common/apis/create_rule/transform_create_rule_body.ts +++ b/packages/kbn-alerts-ui-shared/src/common/apis/create_rule/transform_create_rule_body.ts @@ -17,10 +17,8 @@ const transformCreateRuleFlapping = (flapping: Rule['flapping']) => { } return { - flapping: { - look_back_window: flapping.lookBackWindow, - status_change_threshold: flapping.statusChangeThreshold, - }, + look_back_window: flapping.lookBackWindow, + status_change_threshold: flapping.statusChangeThreshold, }; }; @@ -60,5 +58,5 @@ export const transformCreateRuleBody: RewriteResponseCase = ({ }; }), ...(alertDelay ? { alert_delay: alertDelay } : {}), - ...(flapping !== undefined ? transformCreateRuleFlapping(flapping) : {}), + ...(flapping !== undefined ? { flapping: transformCreateRuleFlapping(flapping) } : {}), }); diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/update_rule/transform_update_rule_body.ts b/packages/kbn-alerts-ui-shared/src/common/apis/update_rule/transform_update_rule_body.ts index 3279391bfabfb..8f4e59d80458b 100644 --- a/packages/kbn-alerts-ui-shared/src/common/apis/update_rule/transform_update_rule_body.ts +++ b/packages/kbn-alerts-ui-shared/src/common/apis/update_rule/transform_update_rule_body.ts @@ -17,10 +17,8 @@ const transformUpdateRuleFlapping = (flapping: Rule['flapping']) => { } return { - flapping: { - look_back_window: flapping.lookBackWindow, - status_change_threshold: flapping.statusChangeThreshold, - }, + look_back_window: flapping.lookBackWindow, + status_change_threshold: flapping.statusChangeThreshold, }; }; @@ -57,5 +55,5 @@ export const transformUpdateRuleBody: RewriteResponseCase = ({ }; }), ...(alertDelay ? { alert_delay: alertDelay } : {}), - ...(flapping !== undefined ? transformUpdateRuleFlapping(flapping) : {}), + ...(flapping !== undefined ? { flapping: transformUpdateRuleFlapping(flapping) } : {}), }); diff --git a/packages/kbn-alerts-ui-shared/src/common/transformations/transform_rule.ts b/packages/kbn-alerts-ui-shared/src/common/transformations/transform_rule.ts index 5aa36a4c6d592..b04e98887f2e5 100644 --- a/packages/kbn-alerts-ui-shared/src/common/transformations/transform_rule.ts +++ b/packages/kbn-alerts-ui-shared/src/common/transformations/transform_rule.ts @@ -40,10 +40,8 @@ const transformFlapping = (flapping: AsApiContract) => { } return { - flapping: { - lookBackWindow: flapping.look_back_window, - statusChangeThreshold: flapping.status_change_threshold, - }, + lookBackWindow: flapping.look_back_window, + statusChangeThreshold: flapping.status_change_threshold, }; }; @@ -91,7 +89,7 @@ export const transformRule: RewriteRequestCase = ({ ...(nextRun ? { nextRun } : {}), ...(apiKeyCreatedByUser !== undefined ? { apiKeyCreatedByUser } : {}), ...(alertDelay ? { alertDelay } : {}), - ...(flapping !== undefined ? transformFlapping(flapping) : {}), + ...(flapping !== undefined ? { flapping: transformFlapping(flapping) } : {}), ...rest, }); diff --git a/packages/kbn-alerts-ui-shared/src/common/types/rule_types.ts b/packages/kbn-alerts-ui-shared/src/common/types/rule_types.ts index 29eaf17552a2b..40498f1a27886 100644 --- a/packages/kbn-alerts-ui-shared/src/common/types/rule_types.ts +++ b/packages/kbn-alerts-ui-shared/src/common/types/rule_types.ts @@ -27,6 +27,8 @@ import { TypeRegistry } from '../type_registry'; export type { SanitizedRuleAction as RuleAction } from '@kbn/alerting-types'; +export type { Flapping } from '@kbn/alerting-types'; + export type RuleTypeWithDescription = RuleType & { description?: string }; export type RuleTypeIndexWithDescriptions = Map; diff --git a/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_inputs.tsx b/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_inputs.tsx index 6875a8b33f3ed..b81f59e7dead0 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_inputs.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_inputs.tsx @@ -14,7 +14,7 @@ import { MAX_LOOK_BACK_WINDOW, MIN_STATUS_CHANGE_THRESHOLD, MAX_STATUS_CHANGE_THRESHOLD, -} from '@kbn/alerting-types'; +} from '@kbn/alerting-types/flapping/latest'; import { i18n } from '@kbn/i18n'; import { RuleSettingsRangeInput } from './rule_settings_range_input'; diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index 86eef03b1db26..c8803a1fbd071 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -59,7 +59,7 @@ describe('checking migration metadata changes on all registered SO types', () => "action": "0e6fc0b74c7312a8c11ff6b14437b93a997358b8", "action_task_params": "b50cb5c8a493881474918e8d4985e61374ca4c30", "ad_hoc_run_params": "d4e3c5c794151d0a4f5c71e886b2aa638da73ad2", - "alert": "e920b0583b1a32338d5dbbbfabb6ff2a511f5f6c", + "alert": "05b07040b12ff45ab642f47464e8a6c903cf7b86", "api_key_pending_invalidation": "1399e87ca37b3d3a65d269c924eda70726cfe886", "apm-custom-dashboards": "b67128f78160c288bd7efe25b2da6e2afd5e82fc", "apm-indices": "8a2d68d415a4b542b26b0d292034a28ffac6fed4", diff --git a/x-pack/plugins/alerting/common/index.ts b/x-pack/plugins/alerting/common/index.ts index e0c5d7fee528e..8e5a258f15e6c 100644 --- a/x-pack/plugins/alerting/common/index.ts +++ b/x-pack/plugins/alerting/common/index.ts @@ -23,7 +23,7 @@ export type { RuleTaskState, RuleTaskParams, } from '@kbn/alerting-state-types'; -export type { AlertingFrameworkHealth } from '@kbn/alerting-types'; +export type { AlertingFrameworkHealth, Flapping } from '@kbn/alerting-types'; export * from './alert_summary'; export * from './builtin_action_groups'; export * from './bulk_edit'; diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts index 303626dc78d6e..d9157850bfd8d 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { validateDurationV1, validateHoursV1, validateTimezoneV1 } from '../../../validation'; import { notifyWhenSchemaV1, alertDelaySchemaV1 } from '../../../response'; import { alertsFilterQuerySchemaV1 } from '../../../../alerts_filter_query'; +import { flappingSchemaV1 } from '../../../common'; export const actionFrequencySchema = schema.object({ summary: schema.boolean({ @@ -186,6 +187,7 @@ export const createBodySchema = schema.object({ actions: schema.arrayOf(actionSchema, { defaultValue: [] }), notify_when: schema.maybe(schema.nullable(notifyWhenSchemaV1)), alert_delay: schema.maybe(alertDelaySchemaV1), + flapping: schema.maybe(schema.nullable(flappingSchemaV1)), }); export const createParamsSchema = schema.object({ diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/create/types/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/create/types/v1.ts index 9d5d1e39525ab..9524c05424724 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/create/types/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/create/types/v1.ts @@ -31,6 +31,7 @@ export interface CreateRuleRequestBody { actions: CreateBodySchema['actions']; notify_when?: CreateBodySchema['notify_when']; alert_delay?: CreateBodySchema['alert_delay']; + flapping?: CreateBodySchema['flapping']; } export interface CreateRuleResponse { diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/update/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/update/schemas/v1.ts index 54eef7123bba1..e83e26f119595 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/update/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/update/schemas/v1.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { validateDurationV1, validateHoursV1, validateTimezoneV1 } from '../../../validation'; import { notifyWhenSchemaV1, alertDelaySchemaV1 } from '../../../response'; import { alertsFilterQuerySchemaV1 } from '../../../../alerts_filter_query'; +import { flappingSchemaV1 } from '../../../common'; export const actionFrequencySchema = schema.object({ summary: schema.boolean({ @@ -158,6 +159,7 @@ export const updateBodySchema = schema.object({ actions: schema.arrayOf(actionSchema, { defaultValue: [] }), notify_when: schema.maybe(schema.nullable(notifyWhenSchemaV1)), alert_delay: schema.maybe(alertDelaySchemaV1), + flapping: schema.maybe(schema.nullable(flappingSchemaV1)), }); export const updateParamsSchema = schema.object({ diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/update/types/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/update/types/v1.ts index 9d02cba68e428..74ad18cac8e87 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/update/types/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/update/types/v1.ts @@ -30,6 +30,7 @@ export interface UpdateRuleRequestBody { actions: UpdateBodySchema['actions']; notify_when?: UpdateBodySchema['notify_when']; alert_delay?: UpdateBodySchema['alert_delay']; + flapping?: UpdateBodySchema['flapping']; } export interface UpdateRuleResponse { diff --git a/x-pack/plugins/alerting/common/routes/rule/common/flapping/schemas/latest.ts b/x-pack/plugins/alerting/common/routes/rule/common/flapping/schemas/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/common/flapping/schemas/latest.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './v1'; diff --git a/x-pack/plugins/alerting/common/routes/rule/common/flapping/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/common/flapping/schemas/v1.ts new file mode 100644 index 0000000000000..4844a9e808ef5 --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/common/flapping/schemas/v1.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { + MIN_LOOK_BACK_WINDOW as MIN_LOOK_BACK_WINDOW_V1, + MAX_LOOK_BACK_WINDOW as MAX_LOOK_BACK_WINDOW_V1, + MIN_STATUS_CHANGE_THRESHOLD as MIN_STATUS_CHANGE_THRESHOLD_V1, + MAX_STATUS_CHANGE_THRESHOLD as MAX_STATUS_CHANGE_THRESHOLD_V1, +} from '@kbn/alerting-types/flapping/v1'; +import { validateFlapping as validateFlappingV1 } from '../../../validation/validate_flapping/v1'; + +export const flappingSchema = schema.object( + { + look_back_window: schema.number({ + min: MIN_LOOK_BACK_WINDOW_V1, + max: MAX_LOOK_BACK_WINDOW_V1, + }), + status_change_threshold: schema.number({ + min: MIN_STATUS_CHANGE_THRESHOLD_V1, + max: MAX_STATUS_CHANGE_THRESHOLD_V1, + }), + }, + { validate: validateFlappingV1 } +); diff --git a/x-pack/plugins/alerting/common/routes/rule/common/flapping/types/latest.ts b/x-pack/plugins/alerting/common/routes/rule/common/flapping/types/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/common/flapping/types/latest.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './v1'; diff --git a/x-pack/plugins/alerting/common/routes/rule/common/flapping/types/v1.ts b/x-pack/plugins/alerting/common/routes/rule/common/flapping/types/v1.ts new file mode 100644 index 0000000000000..66e338e16ea4c --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/common/flapping/types/v1.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { TypeOf } from '@kbn/config-schema'; +import { flappingSchemaV1 } from '../..'; + +export type Flapping = TypeOf; diff --git a/x-pack/plugins/alerting/common/routes/rule/common/index.ts b/x-pack/plugins/alerting/common/routes/rule/common/index.ts index 5989a3a993e7a..d4bc102edb6e7 100644 --- a/x-pack/plugins/alerting/common/routes/rule/common/index.ts +++ b/x-pack/plugins/alerting/common/routes/rule/common/index.ts @@ -13,6 +13,8 @@ export { ruleExecutionStatusWarningReason, } from './constants/latest'; +export { flappingSchema } from './flapping/schemas/latest'; + export type { RuleNotifyWhen, RuleLastRunOutcomeValues, @@ -21,6 +23,8 @@ export type { RuleExecutionStatusWarningReason, } from './constants/latest'; +export type { Flapping } from './flapping/types/latest'; + export { ruleNotifyWhen as ruleNotifyWhenV1, ruleLastRunOutcomeValues as ruleLastRunOutcomeValuesV1, @@ -29,6 +33,8 @@ export { ruleExecutionStatusWarningReason as ruleExecutionStatusWarningReasonV1, } from './constants/v1'; +export { flappingSchema as flappingSchemaV1 } from './flapping/schemas/v1'; + export type { RuleNotifyWhen as RuleNotifyWhenV1, RuleLastRunOutcomeValues as RuleLastRunOutcomeValuesV1, @@ -36,3 +42,5 @@ export type { RuleExecutionStatusErrorReason as RuleExecutionStatusErrorReasonV1, RuleExecutionStatusWarningReason as RuleExecutionStatusWarningReasonV1, } from './constants/v1'; + +export type { Flapping as FlappingV1 } from './flapping/types/v1'; diff --git a/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts index e8c91d649b8c2..29488b98d6ca8 100644 --- a/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts @@ -16,6 +16,7 @@ import { ruleLastRunOutcomeValues as ruleLastRunOutcomeValuesV1, } from '../../common/constants/v1'; import { validateNotifyWhenV1 } from '../../validation'; +import { flappingSchemaV1 } from '../../common'; export const ruleParamsSchema = schema.recordOf(schema.string(), schema.maybe(schema.any()), { meta: { description: 'The parameters for the rule.' }, @@ -626,6 +627,7 @@ export const ruleResponseSchema = schema.object({ ) ), alert_delay: schema.maybe(alertDelaySchema), + flapping: schema.maybe(schema.nullable(flappingSchemaV1)), }); export const scheduleIdsSchema = schema.maybe(schema.arrayOf(schema.string())); diff --git a/x-pack/plugins/alerting/common/routes/rule/response/types/v1.ts b/x-pack/plugins/alerting/common/routes/rule/response/types/v1.ts index e11daa418022a..e9a37eea1fe72 100644 --- a/x-pack/plugins/alerting/common/routes/rule/response/types/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/response/types/v1.ts @@ -54,4 +54,5 @@ export interface RuleResponse { running?: RuleResponseSchemaType['running']; view_in_app_relative_url?: RuleResponseSchemaType['view_in_app_relative_url']; alert_delay?: RuleResponseSchemaType['alert_delay']; + flapping?: RuleResponseSchemaType['flapping']; } diff --git a/x-pack/plugins/alerting/common/routes/rule/validation/index.ts b/x-pack/plugins/alerting/common/routes/rule/validation/index.ts index 710f15f0d4c9d..986e6d5ee4db7 100644 --- a/x-pack/plugins/alerting/common/routes/rule/validation/index.ts +++ b/x-pack/plugins/alerting/common/routes/rule/validation/index.ts @@ -9,9 +9,11 @@ export { validateDuration } from './validate_duration/latest'; export { validateHours } from './validate_hours/latest'; export { validateTimezone } from './validate_timezone/latest'; export { validateSnoozeSchedule } from './validate_snooze_schedule/latest'; +export { validateFlapping } from './validate_flapping/latest'; export { validateDuration as validateDurationV1 } from './validate_duration/v1'; export { validateHours as validateHoursV1 } from './validate_hours/v1'; export { validateNotifyWhen as validateNotifyWhenV1 } from './validate_notify_when/v1'; export { validateTimezone as validateTimezoneV1 } from './validate_timezone/v1'; export { validateSnoozeSchedule as validateSnoozeScheduleV1 } from './validate_snooze_schedule/v1'; +export { validateFlapping as validateFlappingV1 } from './validate_flapping/v1'; diff --git a/x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/latest.ts b/x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/latest.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './v1'; diff --git a/x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/v1.test.ts b/x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/v1.test.ts new file mode 100644 index 0000000000000..de5ef6acf7390 --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/v1.test.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { validateFlapping } from './v1'; + +describe('validateFlapping', () => { + test('should error if look back window exceeds the lower bound', () => { + const result = validateFlapping({ + look_back_window: 0, + status_change_threshold: 10, + }); + + expect(result).toEqual('look back window must be between 2 and 20'); + }); + + test('should error if look back window exceeds the upper bound', () => { + const result = validateFlapping({ + look_back_window: 50, + status_change_threshold: 10, + }); + + expect(result).toEqual('look back window must be between 2 and 20'); + }); + + test('should error if status change threshold exceeds the lower bound', () => { + const result = validateFlapping({ + look_back_window: 10, + status_change_threshold: 1, + }); + + expect(result).toEqual('status change threshold must be between 2 and 20'); + }); + + test('should error if status change threshold exceeds the upper bound', () => { + const result = validateFlapping({ + look_back_window: 10, + status_change_threshold: 50, + }); + + expect(result).toEqual('status change threshold must be between 2 and 20'); + }); + + test('should error if status change threshold is greater than the look back window', () => { + const result = validateFlapping({ + look_back_window: 10, + status_change_threshold: 15, + }); + + expect(result).toEqual( + 'lookBackWindow (10) must be equal to or greater than statusChangeThreshold (15)' + ); + }); +}); diff --git a/x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/v1.ts b/x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/v1.ts new file mode 100644 index 0000000000000..47945cfba27f4 --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/validation/validate_flapping/v1.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + MIN_LOOK_BACK_WINDOW as MIN_LOOK_BACK_WINDOW_V1, + MAX_LOOK_BACK_WINDOW as MAX_LOOK_BACK_WINDOW_V1, + MIN_STATUS_CHANGE_THRESHOLD as MIN_STATUS_CHANGE_THRESHOLD_V1, + MAX_STATUS_CHANGE_THRESHOLD as MAX_STATUS_CHANGE_THRESHOLD_V1, +} from '@kbn/alerting-types/flapping/v1'; + +export const validateFlapping = (flapping: { + look_back_window: number; + status_change_threshold: number; +}) => { + const { look_back_window: lookBackWindow, status_change_threshold: statusChangeThreshold } = + flapping; + + if (lookBackWindow < MIN_LOOK_BACK_WINDOW_V1 || lookBackWindow > MAX_LOOK_BACK_WINDOW_V1) { + return `look back window must be between ${MIN_LOOK_BACK_WINDOW_V1} and ${MAX_LOOK_BACK_WINDOW_V1}`; + } + + if ( + statusChangeThreshold < MIN_STATUS_CHANGE_THRESHOLD_V1 || + statusChangeThreshold > MAX_STATUS_CHANGE_THRESHOLD_V1 + ) { + return `status change threshold must be between ${MIN_STATUS_CHANGE_THRESHOLD_V1} and ${MAX_STATUS_CHANGE_THRESHOLD_V1}`; + } + + if (lookBackWindow < statusChangeThreshold) { + return `lookBackWindow (${lookBackWindow}) must be equal to or greater than statusChangeThreshold (${statusChangeThreshold})`; + } +}; diff --git a/x-pack/plugins/alerting/common/rules_settings.ts b/x-pack/plugins/alerting/common/rules_settings.ts index 2267ce4b9cde9..2a4162ca2c5d3 100644 --- a/x-pack/plugins/alerting/common/rules_settings.ts +++ b/x-pack/plugins/alerting/common/rules_settings.ts @@ -18,11 +18,6 @@ export interface RulesSettingsFlappingProperties { statusChangeThreshold: number; } -export interface RuleSpecificFlappingProperties { - lookBackWindow: number; - statusChangeThreshold: number; -} - export type RulesSettingsFlapping = RulesSettingsFlappingProperties & RulesSettingsModificationMetadata; @@ -43,13 +38,6 @@ export interface RulesSettings { queryDelay?: RulesSettingsQueryDelay; } -export { - MIN_LOOK_BACK_WINDOW, - MAX_LOOK_BACK_WINDOW, - MIN_STATUS_CHANGE_THRESHOLD, - MAX_STATUS_CHANGE_THRESHOLD, -} from '@kbn/alerting-types'; - export const MIN_QUERY_DELAY = 0; export const MAX_QUERY_DELAY = 60; diff --git a/x-pack/plugins/alerting/common/saved_objects/rules/mappings.ts b/x-pack/plugins/alerting/common/saved_objects/rules/mappings.ts index 8bde7839f44e8..82de4efdb10f4 100644 --- a/x-pack/plugins/alerting/common/saved_objects/rules/mappings.ts +++ b/x-pack/plugins/alerting/common/saved_objects/rules/mappings.ts @@ -225,6 +225,18 @@ export const alertMappings: SavedObjectsTypeMappingDefinition = { }, }, // NO NEED TO BE INDEXED + // flapping: { + // index: false, + // properties: { + // lookBackWindow: { + // type: 'long', + // }, + // statusChangeThreshold: { + // type: 'long', + // }, + // }, + // }, + // NO NEED TO BE INDEXED // nextRun: { // type: 'date', // }, diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts index fa38c66f3b050..61a2c8aad9442 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts @@ -3182,6 +3182,81 @@ describe('create()', () => { expect(taskManager.schedule).toHaveBeenCalled(); }); + test('should create rule with flapping', async () => { + const flapping = { + lookBackWindow: 10, + statusChangeThreshold: 10, + }; + + const data = getMockData({ + name: 'my rule name', + flapping, + }); + + unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ + id: '1', + type: RULE_SAVED_OBJECT_TYPE, + attributes: { + enabled: false, + name: ' my rule name ', + alertTypeId: '123', + schedule: { interval: 10000 }, + params: { + bar: true, + }, + executionStatus: getRuleExecutionStatusPending(now), + running: false, + createdAt: now, + updatedAt: now, + actions: [], + flapping, + }, + references: [ + { + name: 'action_0', + type: 'action', + id: '1', + }, + ], + }); + + const result = await rulesClient.create({ data, isFlappingEnabled: true }); + expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + expect.objectContaining({ + flapping, + }), + { + id: 'mock-saved-object-id', + references: [ + { + id: '1', + name: 'action_0', + type: 'action', + }, + ], + } + ); + + expect(result.flapping).toEqual(flapping); + }); + + test('throws error when creating a rule with flapping if global flapping is disabled', async () => { + const flapping = { + lookBackWindow: 10, + statusChangeThreshold: 10, + }; + + const data = getMockData({ + name: 'my rule name', + flapping, + }); + + await expect(rulesClient.create({ data })).rejects.toThrowErrorMatchingInlineSnapshot( + `"Error creating rule: can not create rule with flapping if global flapping is disabled"` + ); + }); + test('throws error when creating with an interval less than the minimum configured one when enforce = true', async () => { rulesClient = new RulesClient({ ...rulesClientParams, @@ -3770,7 +3845,7 @@ describe('create()', () => { ], }); await expect(rulesClient.create({ data })).rejects.toThrowErrorMatchingInlineSnapshot( - `"Failed to validate actions due to the following error: Action's alertsFilter must have either \\"query\\" or \\"timeframe\\" : 152"` + `"Failed to validate actions due to the following error: Action's alertsFilter must have either \\"query\\" or \\"timeframe\\" : 154"` ); expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled(); expect(taskManager.schedule).not.toHaveBeenCalled(); @@ -3826,7 +3901,7 @@ describe('create()', () => { ], }); await expect(rulesClient.create({ data })).rejects.toThrowErrorMatchingInlineSnapshot( - `"Failed to validate actions due to the following error: This ruleType (Test) can't have an action with Alerts Filter. Actions: [153]"` + `"Failed to validate actions due to the following error: This ruleType (Test) can't have an action with Alerts Filter. Actions: [155]"` ); expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled(); expect(taskManager.schedule).not.toHaveBeenCalled(); @@ -3898,7 +3973,7 @@ describe('create()', () => { group: 'default', actionTypeId: 'test', params: { foo: true }, - uuid: '154', + uuid: '156', }, ], alertTypeId: '123', @@ -4127,13 +4202,13 @@ describe('create()', () => { params: { foo: true, }, - uuid: '156', + uuid: '158', }, { actionRef: 'system_action:system_action-id', actionTypeId: '.test', params: { foo: 'test' }, - uuid: '157', + uuid: '159', }, ], alertTypeId: '123', @@ -4205,13 +4280,13 @@ describe('create()', () => { params: { foo: true, }, - uuid: '158', + uuid: '160', }, { actionRef: 'system_action:system_action-id', actionTypeId: '.test', params: { foo: 'test' }, - uuid: '159', + uuid: '161', }, ]); }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts index 555429d117a30..876fb73b0c289 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts @@ -48,6 +48,7 @@ export interface CreateRuleParams { data: CreateRuleData; options?: CreateRuleOptions; allowMissingConnectorSecrets?: boolean; + isFlappingEnabled?: boolean; } export async function createRule( @@ -55,7 +56,13 @@ export async function createRule( createParams: CreateRuleParams // TODO (http-versioning): This should be of type Rule, change this when all rule types are fixed ): Promise> { - const { data: initialData, options, allowMissingConnectorSecrets } = createParams; + const { + data: initialData, + options, + allowMissingConnectorSecrets, + isFlappingEnabled = false, + } = createParams; + const actionsClient = await context.getActionsClient(); const { actions: genAction, systemActions: genSystemActions } = await addGeneratedActionValues( @@ -170,6 +177,12 @@ export async function createRule( ); } + if (initialData.flapping !== undefined && !isFlappingEnabled) { + throw Boom.badRequest( + 'Error creating rule: can not create rule with flapping if global flapping is disabled' + ); + } + const allActions = [...data.actions, ...(data.systemActions ?? [])]; // Extract saved object references for this rule const { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/schemas/create_rule_data_schema.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/schemas/create_rule_data_schema.ts index e8195fb6a95d3..0672d7929fdb2 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/schemas/create_rule_data_schema.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/schemas/create_rule_data_schema.ts @@ -12,6 +12,7 @@ import { alertDelaySchema, actionRequestSchema, systemActionRequestSchema, + flappingSchema, } from '../../../schemas'; export const createRuleDataSchema = schema.object( @@ -36,6 +37,7 @@ export const createRuleDataSchema = schema.object( ), notifyWhen: schema.maybe(schema.nullable(notifyWhenSchema)), alertDelay: schema.maybe(alertDelaySchema), + flapping: schema.maybe(schema.nullable(flappingSchema)), }, { unknowns: 'allow' } ); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/types/create_rule_data.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/types/create_rule_data.ts index fdcd477e7af66..0c7a14b9f9727 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/types/create_rule_data.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/types/create_rule_data.ts @@ -24,4 +24,5 @@ export interface CreateRuleData { systemActions?: CreateRuleDataType['systemActions']; notifyWhen?: CreateRuleDataType['notifyWhen']; alertDelay?: CreateRuleDataType['alertDelay']; + flapping?: CreateRuleDataType['flapping']; } diff --git a/x-pack/plugins/alerting/server/application/rule/methods/update/schemas/update_rule_data_schema.ts b/x-pack/plugins/alerting/server/application/rule/methods/update/schemas/update_rule_data_schema.ts index 38d4ab89c7857..0c4a1df45d44e 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/update/schemas/update_rule_data_schema.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/update/schemas/update_rule_data_schema.ts @@ -12,6 +12,7 @@ import { alertDelaySchema, actionRequestSchema, systemActionRequestSchema, + flappingSchema, } from '../../../schemas'; export const updateRuleDataSchema = schema.object( @@ -27,6 +28,7 @@ export const updateRuleDataSchema = schema.object( systemActions: schema.maybe(schema.arrayOf(systemActionRequestSchema, { defaultValue: [] })), notifyWhen: schema.maybe(schema.nullable(notifyWhenSchema)), alertDelay: schema.maybe(alertDelaySchema), + flapping: schema.maybe(schema.nullable(flappingSchema)), }, { unknowns: 'allow' } ); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/update/types/update_rule_data.ts b/x-pack/plugins/alerting/server/application/rule/methods/update/types/update_rule_data.ts index 0d60c37899f4a..cfde60b91c1f3 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/update/types/update_rule_data.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/update/types/update_rule_data.ts @@ -21,4 +21,5 @@ export interface UpdateRuleData { systemActions?: UpdateRuleDataType['systemActions']; notifyWhen?: UpdateRuleDataType['notifyWhen']; alertDelay?: UpdateRuleDataType['alertDelay']; + flapping?: UpdateRuleDataType['flapping']; } diff --git a/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.test.ts index 90f797fbf4a1a..4031d0b3175cf 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.test.ts @@ -1769,6 +1769,100 @@ describe('update()', () => { expect(rulesClientParams.createAPIKey).toHaveBeenCalledWith('Alerting: myType/my alert name'); }); + it('should update rule flapping', async () => { + const flapping = { + lookBackWindow: 10, + statusChangeThreshold: 10, + }; + + unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ + id: '1', + type: RULE_SAVED_OBJECT_TYPE, + attributes: { + enabled: true, + schedule: { interval: '1m' }, + params: { + bar: true, + }, + actions: [], + notifyWhen: 'onActiveAlert', + revision: 1, + scheduledTaskId: 'task-123', + executionStatus: { + lastExecutionDate: '2019-02-12T21:01:22.479Z', + status: 'pending', + }, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + flapping, + }, + references: [], + }); + + const result = await rulesClient.update({ + id: '1', + data: { + schedule: { interval: '1m' }, + name: 'abc', + tags: ['foo'], + params: { + bar: true, + }, + throttle: null, + notifyWhen: 'onActiveAlert', + actions: [], + systemActions: [], + flapping, + }, + isFlappingEnabled: true, + }); + + expect(unsecuredSavedObjectsClient.create).toHaveBeenNthCalledWith( + 1, + RULE_SAVED_OBJECT_TYPE, + expect.objectContaining({ + flapping, + }), + { + id: '1', + overwrite: true, + references: [], + version: '123', + } + ); + + expect(result.flapping).toEqual(flapping); + }); + + it('should throw error when updating a rule with flapping if global flapping is disabled', async () => { + const flapping = { + lookBackWindow: 10, + statusChangeThreshold: 10, + }; + + await expect( + rulesClient.update({ + id: '1', + data: { + schedule: { interval: '1m' }, + name: 'abc', + tags: ['foo'], + params: { + bar: true, + }, + throttle: null, + notifyWhen: 'onActiveAlert', + actions: [], + systemActions: [], + flapping, + }, + isFlappingEnabled: false, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Error updating rule: can not update rule flapping if global flapping is disabled"` + ); + }); + it('swallows error when invalidate API key throws', async () => { unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', diff --git a/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts index 4885882451e40..7f0663c879056 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts @@ -41,6 +41,36 @@ import { RuleAttributes } from '../../../../data/rule/types'; import { transformRuleAttributesToRuleDomain, transformRuleDomainToRule } from '../../transforms'; import { ruleDomainSchema } from '../../schemas'; +const validateCanUpdateFlapping = ( + isFlappingEnabled: boolean, + originalFlapping: RuleAttributes['flapping'], + updateFlapping: UpdateRuleParams['data']['flapping'] +) => { + // If flapping is enabled, allow rule flapping to be updated and do nothing + if (isFlappingEnabled) { + return; + } + + // If updated flapping is undefined then don't do anything, it's not being updated + if (updateFlapping === undefined) { + return; + } + + // If both versions are falsy, allow it even if its changing between undefined and null + if (!originalFlapping && !updateFlapping) { + return; + } + + // If both values are equal, allow it because it's essentially not changing anything + if (isEqual(originalFlapping, updateFlapping)) { + return; + } + + throw Boom.badRequest( + `Error updating rule: can not update rule flapping if global flapping is disabled` + ); +}; + type ShouldIncrementRevision = (params?: RuleParams) => boolean; export interface UpdateRuleParams { @@ -48,6 +78,7 @@ export interface UpdateRuleParams { data: UpdateRuleData; allowMissingConnectorSecrets?: boolean; shouldIncrementRevision?: ShouldIncrementRevision; + isFlappingEnabled?: boolean; } export async function updateRule( @@ -70,6 +101,7 @@ async function updateWithOCC( data: initialData, allowMissingConnectorSecrets, id, + isFlappingEnabled = false, shouldIncrementRevision = () => true, } = updateParams; @@ -114,8 +146,18 @@ async function updateWithOCC( systemActions: genSystemActions, }; - const { alertTypeId, consumer, enabled, schedule, name, apiKey, apiKeyCreatedByUser } = - originalRuleSavedObject.attributes; + const { + alertTypeId, + consumer, + enabled, + schedule, + name, + apiKey, + apiKeyCreatedByUser, + flapping: originalFlapping, + } = originalRuleSavedObject.attributes; + + validateCanUpdateFlapping(isFlappingEnabled, originalFlapping, initialData.flapping); let validationPayload: ValidateScheduleLimitResult = null; if (enabled && schedule.interval !== data.schedule.interval) { diff --git a/x-pack/plugins/alerting/server/application/rule/schemas/flapping_schema.ts b/x-pack/plugins/alerting/server/application/rule/schemas/flapping_schema.ts new file mode 100644 index 0000000000000..763d235de8644 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/rule/schemas/flapping_schema.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +export const flappingSchema = schema.object({ + lookBackWindow: schema.number(), + statusChangeThreshold: schema.number(), +}); diff --git a/x-pack/plugins/alerting/server/application/rule/schemas/index.ts b/x-pack/plugins/alerting/server/application/rule/schemas/index.ts index a61d04e1bef72..dc0d310f36535 100644 --- a/x-pack/plugins/alerting/server/application/rule/schemas/index.ts +++ b/x-pack/plugins/alerting/server/application/rule/schemas/index.ts @@ -8,3 +8,4 @@ export * from './rule_schemas'; export * from './action_schemas'; export * from './notify_when_schema'; +export * from './flapping_schema'; diff --git a/x-pack/plugins/alerting/server/application/rule/schemas/rule_schemas.ts b/x-pack/plugins/alerting/server/application/rule/schemas/rule_schemas.ts index 416fdc4d11c0d..7f9fcb1bd5377 100644 --- a/x-pack/plugins/alerting/server/application/rule/schemas/rule_schemas.ts +++ b/x-pack/plugins/alerting/server/application/rule/schemas/rule_schemas.ts @@ -16,6 +16,7 @@ import { rRuleSchema } from '../../r_rule/schemas'; import { dateSchema } from './date_schema'; import { notifyWhenSchema } from './notify_when_schema'; import { actionSchema, systemActionSchema } from './action_schemas'; +import { flappingSchema } from './flapping_schema'; export const ruleParamsSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); export const mappedParamsSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); @@ -177,6 +178,7 @@ export const ruleDomainSchema = schema.object({ viewInAppRelativeUrl: schema.maybe(schema.nullable(schema.string())), alertDelay: schema.maybe(alertDelaySchema), legacyId: schema.maybe(schema.nullable(schema.string())), + flapping: schema.maybe(schema.nullable(flappingSchema)), }); /** @@ -217,4 +219,5 @@ export const ruleSchema = schema.object({ viewInAppRelativeUrl: schema.maybe(schema.nullable(schema.string())), alertDelay: schema.maybe(alertDelaySchema), legacyId: schema.maybe(schema.nullable(schema.string())), + flapping: schema.maybe(schema.nullable(flappingSchema)), }); diff --git a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.test.ts b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.test.ts index 7b6fcb18ae219..6a4e1824172ca 100644 --- a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.test.ts @@ -92,6 +92,10 @@ describe('transformRuleAttributesToRuleDomain', () => { updatedBy: 'user', apiKey: MOCK_API_KEY, apiKeyOwner: 'user', + flapping: { + lookBackWindow: 20, + statusChangeThreshold: 20, + }, }; it('transforms the actions correctly', () => { @@ -106,6 +110,13 @@ describe('transformRuleAttributesToRuleDomain', () => { isSystemAction ); + expect(res.flapping).toMatchInlineSnapshot(` + Object { + "lookBackWindow": 20, + "statusChangeThreshold": 20, + } + `); + expect(res.actions).toMatchInlineSnapshot(` Array [ Object { diff --git a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.ts b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.ts index 0f0c380538107..6b4917c96010f 100644 --- a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.ts +++ b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_attributes_to_rule_domain.ts @@ -232,6 +232,7 @@ export const transformRuleAttributesToRuleDomain = { updatedBy: 'user', apiKey: MOCK_API_KEY, apiKeyOwner: 'user', + flapping: { + lookBackWindow: 20, + statusChangeThreshold: 20, + }, }; it('should transform rule domain to rule', () => { @@ -100,6 +104,10 @@ describe('transformRuleDomainToRule', () => { revision: 0, updatedBy: 'user', apiKeyOwner: 'user', + flapping: { + lookBackWindow: 20, + statusChangeThreshold: 20, + }, }); }); @@ -135,6 +143,10 @@ describe('transformRuleDomainToRule', () => { revision: 0, updatedBy: 'user', apiKeyOwner: 'user', + flapping: { + lookBackWindow: 20, + statusChangeThreshold: 20, + }, }); }); @@ -172,6 +184,10 @@ describe('transformRuleDomainToRule', () => { revision: 0, updatedBy: 'user', apiKeyOwner: 'user', + flapping: { + lookBackWindow: 20, + statusChangeThreshold: 20, + }, }); }); }); diff --git a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule.ts b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule.ts index 76e90475132b4..db9f63a5d0338 100644 --- a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule.ts @@ -53,6 +53,7 @@ export const transformRuleDomainToRule = ( viewInAppRelativeUrl: ruleDomain.viewInAppRelativeUrl, alertDelay: ruleDomain.alertDelay, legacyId: ruleDomain.legacyId, + flapping: ruleDomain.flapping, }; if (isPublic) { diff --git a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule_attributes.test.ts b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule_attributes.test.ts new file mode 100644 index 0000000000000..73c39532b9ab9 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule_attributes.test.ts @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RuleDomain } from '../types'; +import { transformRuleDomainToRuleAttributes } from './transform_rule_domain_to_rule_attributes'; + +describe('transformRuleDomainToRuleAttributes', () => { + const MOCK_API_KEY = Buffer.from('123:abc').toString('base64'); + + const defaultAction = { + id: '1', + uuid: 'test-uuid', + group: 'default', + actionTypeId: 'test', + params: {}, + }; + + const rule: RuleDomain<{}> = { + id: 'test', + enabled: false, + name: 'my rule name', + tags: ['foo'], + alertTypeId: 'myType', + consumer: 'myApp', + schedule: { interval: '1m' }, + actions: [defaultAction], + params: {}, + mapped_params: {}, + createdBy: 'user', + createdAt: new Date('2019-02-12T21:01:22.479Z'), + updatedAt: new Date('2019-02-12T21:01:22.479Z'), + legacyId: 'legacyId', + muteAll: false, + mutedInstanceIds: [], + snoozeSchedule: [], + scheduledTaskId: 'task-123', + executionStatus: { + lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'), + status: 'pending' as const, + }, + throttle: null, + notifyWhen: null, + revision: 0, + updatedBy: 'user', + apiKey: MOCK_API_KEY, + apiKeyOwner: 'user', + flapping: { + lookBackWindow: 20, + statusChangeThreshold: 20, + }, + }; + + test('should transform rule domain to rule attribute', () => { + const result = transformRuleDomainToRuleAttributes({ + rule, + actionsWithRefs: [ + { + group: 'default', + actionRef: 'action_0', + actionTypeId: 'test', + uuid: 'test-uuid', + params: {}, + }, + ], + params: { + legacyId: 'test', + paramsWithRefs: {}, + }, + }); + + expect(result).toMatchInlineSnapshot(` + Object { + "actions": Array [ + Object { + "actionRef": "action_0", + "actionTypeId": "test", + "group": "default", + "params": Object {}, + "uuid": "test-uuid", + }, + ], + "alertTypeId": "myType", + "apiKey": "MTIzOmFiYw==", + "apiKeyOwner": "user", + "consumer": "myApp", + "createdAt": "2019-02-12T21:01:22.479Z", + "createdBy": "user", + "enabled": false, + "executionStatus": Object { + "lastExecutionDate": "2019-02-12T21:01:22.479Z", + "status": "pending", + }, + "flapping": Object { + "lookBackWindow": 20, + "statusChangeThreshold": 20, + }, + "legacyId": "test", + "muteAll": false, + "mutedInstanceIds": Array [], + "name": "my rule name", + "notifyWhen": null, + "params": Object {}, + "revision": 0, + "schedule": Object { + "interval": "1m", + }, + "scheduledTaskId": "task-123", + "snoozeSchedule": Array [], + "tags": Array [ + "foo", + ], + "throttle": null, + "updatedAt": "2019-02-12T21:01:22.479Z", + "updatedBy": "user", + } + `); + }); +}); diff --git a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule_attributes.ts b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule_attributes.ts index dfa4ba7acb3cb..99c9789609761 100644 --- a/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule_attributes.ts +++ b/x-pack/plugins/alerting/server/application/rule/transforms/transform_rule_domain_to_rule_attributes.ts @@ -80,5 +80,6 @@ export const transformRuleDomainToRuleAttributes = ({ revision: rule.revision, ...(rule.running !== undefined ? { running: rule.running } : {}), ...(rule.alertDelay !== undefined ? { alertDelay: rule.alertDelay } : {}), + ...(rule.flapping !== undefined ? { flapping: rule.flapping } : {}), }; }; diff --git a/x-pack/plugins/alerting/server/application/rule/types/rule.ts b/x-pack/plugins/alerting/server/application/rule/types/rule.ts index 818e6884b7597..0b1177d31e1f7 100644 --- a/x-pack/plugins/alerting/server/application/rule/types/rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/types/rule.ts @@ -84,6 +84,7 @@ export interface Rule { viewInAppRelativeUrl?: RuleSchemaType['viewInAppRelativeUrl']; alertDelay?: RuleSchemaType['alertDelay']; legacyId?: RuleSchemaType['legacyId']; + flapping?: RuleSchemaType['flapping']; } export interface RuleDomain { @@ -122,4 +123,5 @@ export interface RuleDomain { viewInAppRelativeUrl?: RuleDomainSchemaType['viewInAppRelativeUrl']; alertDelay?: RuleSchemaType['alertDelay']; legacyId?: RuleSchemaType['legacyId']; + flapping?: RuleSchemaType['flapping']; } diff --git a/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts b/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts index bf4b6ad049683..e057662adbdf5 100644 --- a/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts +++ b/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts @@ -147,6 +147,11 @@ interface AlertDelayAttributes { active: number; } +interface FlappingAttributes { + lookBackWindow: number; + statusChangeThreshold: number; +} + export interface RuleAttributes { name: string; tags: string[]; @@ -180,4 +185,5 @@ export interface RuleAttributes { revision: number; running?: boolean | null; alertDelay?: AlertDelayAttributes; + flapping?: FlappingAttributes | null; } diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index fd209ef009d73..bf1f02d3a4910 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -676,7 +676,10 @@ export class AlertingPlugin { getRulesClient: () => { return rulesClientFactory!.create(request, savedObjects); }, - getRulesSettingsClient: () => { + getRulesSettingsClient: (withoutAuth?: boolean) => { + if (withoutAuth) { + return rulesSettingsClientFactory.create(request); + } return rulesSettingsClientFactory.createWithAuthorization(request); }, getMaintenanceWindowClient: () => { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts index ba6c3c25a1c43..cab3956161613 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts @@ -227,6 +227,7 @@ describe('createRuleRoute', () => { ], "throttle": "30s", }, + "isFlappingEnabled": true, "options": Object { "id": undefined, }, @@ -343,6 +344,7 @@ describe('createRuleRoute', () => { ], "throttle": "30s", }, + "isFlappingEnabled": true, "options": Object { "id": "custom-id", }, @@ -460,6 +462,7 @@ describe('createRuleRoute', () => { ], "throttle": "30s", }, + "isFlappingEnabled": true, "options": Object { "id": "custom-id", }, @@ -577,6 +580,7 @@ describe('createRuleRoute', () => { ], "throttle": "30s", }, + "isFlappingEnabled": true, "options": Object { "id": "custom-id", }, @@ -732,6 +736,7 @@ describe('createRuleRoute', () => { ], "throttle": "30s", }, + "isFlappingEnabled": true, "options": Object { "id": undefined, }, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts index 4e778cdf97a8f..45341fb48e9bd 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts @@ -64,6 +64,7 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt verifyAccessAndContext(licenseState, async function (context, req, res) { const rulesClient = (await context.alerting).getRulesClient(); const actionsClient = (await context.actions).getActionsClient(); + const rulesSettingsClient = (await context.alerting).getRulesSettingsClient(true); // Assert versioned inputs const createRuleData: CreateRuleRequestBodyV1 = req.body; @@ -90,6 +91,8 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt actionsClient.isSystemAction(action.id) ); + const flappingSettings = await rulesSettingsClient.flapping().get(); + // TODO (http-versioning): Remove this cast, this enables us to move forward // without fixing all of other solution types const createdRule: Rule = (await rulesClient.create({ @@ -98,6 +101,7 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt actions, systemActions, }), + isFlappingEnabled: flappingSettings.enabled, options: { id: params?.id }, })) as Rule; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/transforms/transform_create_body/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/transforms/transform_create_body/v1.ts index fa3c6e8484671..d8b646f673a64 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/transforms/transform_create_body/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/transforms/transform_create_body/v1.ts @@ -66,6 +66,18 @@ const transformCreateBodySystemActions = (actions: CreateRuleActionV1[]): System }); }; +const transformCreateBodyFlapping = ( + flapping: CreateRuleRequestBodyV1['flapping'] +) => { + if (!flapping) { + return flapping; + } + return { + lookBackWindow: flapping.look_back_window, + statusChangeThreshold: flapping.status_change_threshold, + }; +}; + export const transformCreateBody = ({ createBody, actions, @@ -88,5 +100,8 @@ export const transformCreateBody = ({ systemActions: transformCreateBodySystemActions(systemActions), ...(createBody.notify_when ? { notifyWhen: createBody.notify_when } : {}), ...(createBody.alert_delay ? { alertDelay: createBody.alert_delay } : {}), + ...(createBody.flapping !== undefined + ? { flapping: transformCreateBodyFlapping(createBody.flapping) } + : {}), }; }; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/v1.ts index 6754fa71e10d4..e80ea1604cde1 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/v1.ts @@ -16,6 +16,7 @@ import { transformRuleActionsV1, transformMonitoringV1, transformRuleLastRunV1, + transformFlappingV1, } from '../../../../transforms'; export const transformPartialRule = ( @@ -78,6 +79,7 @@ export const transformPartialRule = ( ? { view_in_app_relative_url: rule.viewInAppRelativeUrl } : {}), ...(rule.alertDelay !== undefined ? { alert_delay: rule.alertDelay } : {}), + ...(rule.flapping !== undefined ? { flapping: transformFlappingV1(rule.flapping) } : {}), }; type RuleKeys = keyof RuleResponseV1; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/update/transforms/transform_update_body/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/update/transforms/transform_update_body/v1.ts index 4999060b3787d..48e7d71285be5 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/update/transforms/transform_update_body/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/update/transforms/transform_update_body/v1.ts @@ -70,6 +70,18 @@ export const transformUpdateBodySystemActions = ( }); }; +const transformUpdateBodyFlapping = ( + flapping: UpdateRuleRequestBodyV1['flapping'] +) => { + if (!flapping) { + return flapping; + } + return { + lookBackWindow: flapping.look_back_window, + statusChangeThreshold: flapping.status_change_threshold, + }; +}; + export const transformUpdateBody = ({ updateBody, actions, @@ -89,5 +101,8 @@ export const transformUpdateBody = ({ systemActions: transformUpdateBodySystemActions(systemActions), ...(updateBody.notify_when ? { notifyWhen: updateBody.notify_when } : {}), ...(updateBody.alert_delay ? { alertDelay: updateBody.alert_delay } : {}), + ...(updateBody.flapping !== undefined + ? { flapping: transformUpdateBodyFlapping(updateBody.flapping) } + : {}), }; }; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.test.ts index e1ed7b52ae710..e26e9705fa7f4 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.test.ts @@ -215,6 +215,7 @@ describe('updateRuleRoute', () => { "throttle": "10m", }, "id": "1", + "isFlappingEnabled": true, }, ] `); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts index 507f748351ed9..5c925b05bace3 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts @@ -66,6 +66,7 @@ export const updateRuleRoute = ( verifyAccessAndContext(licenseState, async function (context, req, res) { const rulesClient = (await context.alerting).getRulesClient(); const actionsClient = (await context.actions).getActionsClient(); + const rulesSettingsClient = (await context.alerting).getRulesSettingsClient(true); // Assert versioned inputs const updateRuleData: UpdateRuleRequestBodyV1 = req.body; @@ -86,6 +87,8 @@ export const updateRuleRoute = ( actionsClient.isSystemAction(action.id) ); + const flappingSettings = await rulesSettingsClient.flapping().get(); + // TODO (http-versioning): Remove this cast, this enables us to move forward // without fixing all of other solution types const updatedRule: Rule = (await rulesClient.update({ @@ -95,6 +98,7 @@ export const updateRuleRoute = ( actions, systemActions, }), + isFlappingEnabled: flappingSettings.enabled, })) as Rule; // Assert versioned response type diff --git a/x-pack/plugins/alerting/server/routes/rule/transforms/index.ts b/x-pack/plugins/alerting/server/routes/rule/transforms/index.ts index 49661dd04f9d1..d5316ed7da3e7 100644 --- a/x-pack/plugins/alerting/server/routes/rule/transforms/index.ts +++ b/x-pack/plugins/alerting/server/routes/rule/transforms/index.ts @@ -10,10 +10,12 @@ export { transformRuleActions, transformRuleLastRun, transformMonitoring, + transformFlapping, } from './transform_rule_to_rule_response/latest'; export { transformRuleToRuleResponse as transformRuleToRuleResponseV1, transformRuleActions as transformRuleActionsV1, transformRuleLastRun as transformRuleLastRunV1, transformMonitoring as transformMonitoringV1, + transformFlapping as transformFlappingV1, } from './transform_rule_to_rule_response/v1'; diff --git a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts index 2181876f230bc..43e8a4b2b9ea6 100644 --- a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts @@ -88,6 +88,17 @@ export const transformRuleActions = ( ]; }; +export const transformFlapping = (flapping: Rule['flapping']) => { + if (!flapping) { + return flapping; + } + + return { + look_back_window: flapping.lookBackWindow, + status_change_threshold: flapping.statusChangeThreshold, + }; +}; + export const transformRuleToRuleResponse = ( rule: Rule ): RuleResponseV1 => ({ @@ -144,4 +155,5 @@ export const transformRuleToRuleResponse = ( ? { view_in_app_relative_url: rule.viewInAppRelativeUrl } : {}), ...(rule.alertDelay !== undefined ? { alert_delay: rule.alertDelay } : {}), + ...(rule.flapping !== undefined ? { flapping: transformFlapping(rule.flapping) } : {}), }); diff --git a/x-pack/plugins/alerting/server/rules_client/lib/get_alert_from_raw.ts b/x-pack/plugins/alerting/server/rules_client/lib/get_alert_from_raw.ts index 2e9964f6ebfa7..ed7155770d7f8 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/get_alert_from_raw.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/get_alert_from_raw.ts @@ -122,7 +122,7 @@ function getPartialRuleFromRaw( actions, snoozeSchedule, lastRun, - isSnoozedUntil: DoNotUseIsSNoozedUntil, + isSnoozedUntil: DoNotUseIsSnoozedUntil, ...partialRawRule } = rawRule; diff --git a/x-pack/plugins/alerting/server/rules_settings/flapping/rules_settings_flapping_client.ts b/x-pack/plugins/alerting/server/rules_settings/flapping/rules_settings_flapping_client.ts index 724da9cffa149..b9cfbe550af79 100644 --- a/x-pack/plugins/alerting/server/rules_settings/flapping/rules_settings_flapping_client.ts +++ b/x-pack/plugins/alerting/server/rules_settings/flapping/rules_settings_flapping_client.ts @@ -12,15 +12,17 @@ import { SavedObject, SavedObjectsErrorHelpers, } from '@kbn/core/server'; +import { + MAX_LOOK_BACK_WINDOW, + MAX_STATUS_CHANGE_THRESHOLD, + MIN_LOOK_BACK_WINDOW, + MIN_STATUS_CHANGE_THRESHOLD, +} from '@kbn/alerting-types/flapping/latest'; import { RulesSettings, RulesSettingsFlapping, RulesSettingsFlappingProperties, RulesSettingsModificationMetadata, - MIN_LOOK_BACK_WINDOW, - MAX_LOOK_BACK_WINDOW, - MIN_STATUS_CHANGE_THRESHOLD, - MAX_STATUS_CHANGE_THRESHOLD, RULES_SETTINGS_SAVED_OBJECT_TYPE, RULES_SETTINGS_FLAPPING_SAVED_OBJECT_ID, DEFAULT_FLAPPING_SETTINGS, diff --git a/x-pack/plugins/alerting/server/rules_settings/rules_settings_client.mock.ts b/x-pack/plugins/alerting/server/rules_settings/rules_settings_client.mock.ts index cc7601a56fcd1..3b75ed1900448 100644 --- a/x-pack/plugins/alerting/server/rules_settings/rules_settings_client.mock.ts +++ b/x-pack/plugins/alerting/server/rules_settings/rules_settings_client.mock.ts @@ -11,6 +11,7 @@ import { RulesSettingsQueryDelayClientApi, DEFAULT_FLAPPING_SETTINGS, DEFAULT_QUERY_DELAY_SETTINGS, + RulesSettingsFlappingProperties, } from '../types'; export type RulesSettingsClientMock = jest.Mocked; @@ -19,9 +20,9 @@ export type RulesSettingsQueryDelayClientMock = jest.Mocked { +const createRulesSettingsClientMock = (flappingOverride?: RulesSettingsFlappingProperties) => { const flappingMocked: RulesSettingsFlappingClientMock = { - get: jest.fn().mockReturnValue(DEFAULT_FLAPPING_SETTINGS), + get: jest.fn().mockReturnValue(flappingOverride || DEFAULT_FLAPPING_SETTINGS), update: jest.fn(), }; const queryDelayMocked: RulesSettingsQueryDelayClientMock = { @@ -36,7 +37,8 @@ const createRulesSettingsClientMock = () => { }; export const rulesSettingsClientMock: { - create: () => RulesSettingsClientMock; + create: (flappingOverride?: RulesSettingsFlappingProperties) => RulesSettingsClientMock; } = { - create: createRulesSettingsClientMock, + create: (flappingOverride?: RulesSettingsFlappingProperties) => + createRulesSettingsClientMock(flappingOverride), }; diff --git a/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts b/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts index db792a1276983..43f477f1530d2 100644 --- a/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts +++ b/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts @@ -6,7 +6,7 @@ */ import { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; -import { rawRuleSchemaV1 } from '../schemas/raw_rule'; +import { rawRuleSchemaV1, rawRuleSchemaV2 } from '../schemas/raw_rule'; export const ruleModelVersions: SavedObjectsModelVersionMap = { '1': { @@ -16,4 +16,11 @@ export const ruleModelVersions: SavedObjectsModelVersionMap = { create: rawRuleSchemaV1, }, }, + '2': { + changes: [], + schemas: { + forwardCompatibility: rawRuleSchemaV2.extends({}, { unknowns: 'ignore' }), + create: rawRuleSchemaV2, + }, + }, }; diff --git a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts index d5778bcda4a7a..f770a5418cde7 100644 --- a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts @@ -6,3 +6,4 @@ */ export { rawRuleSchema as rawRuleSchemaV1 } from './v1'; +export { rawRuleSchema as rawRuleSchemaV2 } from './v2'; diff --git a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v2.ts b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v2.ts new file mode 100644 index 0000000000000..4474c47e9e770 --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v2.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { rawRuleSchema as rawRuleSchemaV1 } from './v1'; + +export const flappingSchema = schema.object({ + lookBackWindow: schema.number(), + statusChangeThreshold: schema.number(), +}); + +export const rawRuleSchema = rawRuleSchemaV1.extends({ + flapping: schema.maybe(schema.nullable(flappingSchema)), +}); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index 25dac75b5d7c3..897937ce55a0a 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -290,11 +290,22 @@ export class TaskRunner< state: { previousStartedAt }, } = this.taskInstance; - const { queryDelaySettings, flappingSettings } = + const { queryDelaySettings, flappingSettings: spaceFlappingSettings } = await this.context.rulesSettingsService.getSettings(fakeRequest, spaceId); const ruleRunMetricsStore = new RuleRunMetricsStore(); const ruleLabel = `${this.ruleType.id}:${ruleId}: '${rule.name}'`; + const ruleFlappingSettings = rule.flapping + ? { + enabled: true, + ...rule.flapping, + } + : null; + + const flappingSettings = spaceFlappingSettings.enabled + ? ruleFlappingSettings || spaceFlappingSettings + : spaceFlappingSettings; + const ruleTypeRunnerContext = { alertingEventLogger: this.alertingEventLogger, flappingSettings, diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts index deaae7bccc479..958ecaf8d270d 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts @@ -15,6 +15,7 @@ import { AlertInstanceContext, Rule, RuleAlertData, + RawRule, MaintenanceWindowStatus, DEFAULT_FLAPPING_SETTINGS, DEFAULT_QUERY_DELAY_SETTINGS, @@ -105,6 +106,7 @@ import { import { backfillClientMock } from '../backfill_client/backfill_client.mock'; import { ConnectorAdapterRegistry } from '../connector_adapters/connector_adapter_registry'; import { createTaskRunnerLogger } from './lib'; +import { SavedObject } from '@kbn/core/server'; import { maintenanceWindowsServiceMock } from './maintenance_windows/maintenance_windows_service.mock'; import { getMockMaintenanceWindow } from '../data/maintenance_window/test_helpers'; import { rulesSettingsServiceMock } from '../rules_settings/rules_settings_service.mock'; @@ -824,6 +826,112 @@ describe('Task Runner', () => { spy1.mockRestore(); spy2.mockRestore(); }); + + test('should use rule specific flapping settings if global flapping is enabled', async () => { + mockAlertsService.createAlertsClient.mockImplementation(() => mockAlertsClient); + mockAlertsClient.getAlertsToSerialize.mockResolvedValue({ + alertsToReturn: {}, + recoveredAlertsToReturn: {}, + }); + + const taskRunner = new TaskRunner({ + ruleType: ruleTypeWithAlerts, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + previousStartedAt: new Date(Date.now() - 5 * 60 * 1000).toISOString(), + }, + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + + const ruleSpecificFlapping = { + lookBackWindow: 10, + statusChangeThreshold: 10, + }; + + mockGetAlertFromRaw.mockReturnValue({ + ...mockedRuleTypeSavedObject, + flapping: ruleSpecificFlapping, + } as Rule); + + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue({ + ...mockedRawRuleSO, + flapping: ruleSpecificFlapping, + } as SavedObject); + + await taskRunner.run(); + + expect(mockAlertsClient.initializeExecution).toHaveBeenCalledWith( + expect.objectContaining({ + flappingSettings: { + enabled: true, + ...ruleSpecificFlapping, + }, + }) + ); + }); + + test('should not use rule specific flapping settings if global flapping is disabled', async () => { + rulesSettingsService.getSettings.mockResolvedValue({ + flappingSettings: { + enabled: false, + lookBackWindow: 20, + statusChangeThreshold: 20, + }, + queryDelaySettings: DEFAULT_QUERY_DELAY_SETTINGS, + }); + + mockAlertsService.createAlertsClient.mockImplementation(() => mockAlertsClient); + mockAlertsClient.getAlertsToSerialize.mockResolvedValue({ + alertsToReturn: {}, + recoveredAlertsToReturn: {}, + }); + + const taskRunner = new TaskRunner({ + ruleType: ruleTypeWithAlerts, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + previousStartedAt: new Date(Date.now() - 5 * 60 * 1000).toISOString(), + }, + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + + const ruleSpecificFlapping = { + lookBackWindow: 10, + statusChangeThreshold: 10, + }; + + mockGetAlertFromRaw.mockReturnValue({ + ...mockedRuleTypeSavedObject, + flapping: ruleSpecificFlapping, + } as Rule); + + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue({ + ...mockedRawRuleSO, + flapping: ruleSpecificFlapping, + } as SavedObject); + + await taskRunner.run(); + + expect(mockAlertsClient.initializeExecution).toHaveBeenCalledWith( + expect.objectContaining({ + flappingSettings: { + enabled: false, + lookBackWindow: 20, + statusChangeThreshold: 20, + }, + }) + ); + }); }); function testCorrectAlertsClientUsed< diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index b543177c16cfd..656f567219c1d 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -11,7 +11,7 @@ import type { SavedObjectReference, IUiSettingsClient, } from '@kbn/core/server'; -import z from '@kbn/zod'; +import { z } from '@kbn/zod'; import { DataViewsContract } from '@kbn/data-views-plugin/common'; import { ISearchStartSearchSource } from '@kbn/data-plugin/common'; import { LicenseType } from '@kbn/licensing-plugin/server'; @@ -64,6 +64,7 @@ import { AlertsFilterTimeframe, RuleAlertData, AlertDelay, + Flapping, } from '../common'; import { PublicAlertFactory } from './alert/create_alert_factory'; import { RulesSettingsFlappingProperties } from '../common/rules_settings'; @@ -77,7 +78,7 @@ export type { RuleTypeParams }; */ export interface AlertingApiRequestHandlerContext { getRulesClient: () => RulesClient; - getRulesSettingsClient: () => RulesSettingsClient; + getRulesSettingsClient: (withoutAuth?: boolean) => RulesSettingsClient; getMaintenanceWindowClient: () => MaintenanceWindowClient; listTypes: RuleTypeRegistry['list']; getFrameworkHealth: () => Promise; @@ -505,6 +506,7 @@ export interface RawRule extends SavedObjectAttributes { revision: number; running?: boolean | null; alertDelay?: AlertDelay; + flapping?: Flapping | null; } export type { DataStreamAdapter } from './alerts_service/lib/data_stream_adapter'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts index e0ba1b232f283..39f7448957b74 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts @@ -57,6 +57,16 @@ const transformLastRun: RewriteRequestCase = ({ ...rest, }); +const transformFlapping = (flapping: AsApiContract) => { + if (!flapping) { + return flapping; + } + return { + lookBackWindow: flapping.look_back_window, + statusChangeThreshold: flapping.status_change_threshold, + }; +}; + export const transformRule: RewriteRequestCase = ({ rule_type_id: ruleTypeId, created_by: createdBy, @@ -77,6 +87,7 @@ export const transformRule: RewriteRequestCase = ({ last_run: lastRun, next_run: nextRun, alert_delay: alertDelay, + flapping, ...rest }: any) => ({ ruleTypeId, @@ -100,6 +111,7 @@ export const transformRule: RewriteRequestCase = ({ ...(nextRun ? { nextRun } : {}), ...(apiKeyCreatedByUser !== undefined ? { apiKeyCreatedByUser } : {}), ...(alertDelay ? { alertDelay } : {}), + ...(flapping !== undefined ? { flapping: transformFlapping(flapping) } : {}), ...rest, }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx index 7248ebf27db8d..c3f79c3458374 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx @@ -62,7 +62,6 @@ import { isActionGroupDisabledForActionTypeId, RuleActionAlertsFilterProperty, RuleActionKey, - RuleSpecificFlappingProperties, } from '@kbn/alerting-plugin/common'; import { AlertingConnectorFeatureId } from '@kbn/actions-plugin/common'; import { AlertConsumers } from '@kbn/rule-data-utils'; @@ -415,10 +414,6 @@ export const RuleForm = ({ dispatch({ command: { type: 'setAlertDelayProperty' }, payload: { key, value } }); }; - const setFlapping = (flapping: RuleSpecificFlappingProperties | null) => { - dispatch({ command: { type: 'setProperty' }, payload: { key: 'flapping', value: flapping } }); - }; - const onAlertDelayChange = (value: string) => { const parsedValue = value === '' ? '' : parseInt(value, 10); setAlertDelayProperty('active', parsedValue || 1); @@ -887,7 +882,7 @@ export const RuleForm = ({ alertDelay={alertDelay} flappingSettings={rule.flapping} onAlertDelayChange={onAlertDelayChange} - onFlappingChange={setFlapping} + onFlappingChange={(flapping) => setRuleProperty('flapping', flapping)} enabledFlapping={IS_RULE_SPECIFIC_FLAPPING_ENABLED} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.tsx index e51f24b53c2a4..ca6e17451c1aa 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.tsx @@ -31,8 +31,9 @@ import { } from '@elastic/eui'; import { RuleSettingsFlappingInputs } from '@kbn/alerts-ui-shared/src/rule_settings/rule_settings_flapping_inputs'; import { RuleSettingsFlappingMessage } from '@kbn/alerts-ui-shared/src/rule_settings/rule_settings_flapping_message'; -import { RuleSpecificFlappingProperties } from '@kbn/alerting-plugin/common'; +import { Rule } from '@kbn/alerts-ui-shared'; import { FormattedMessage } from '@kbn/i18n-react'; +import { Flapping } from '@kbn/alerting-plugin/common'; import { useGetFlappingSettings } from '../../hooks/use_get_flapping_settings'; import { useKibana } from '../../../common/lib/kibana'; @@ -146,7 +147,10 @@ const flappingTitlePopoverLookBack = i18n.translate( } ); -const clampFlappingValues = (flapping: RuleSpecificFlappingProperties) => { +const clampFlappingValues = (flapping: Rule['flapping']) => { + if (!flapping) { + return; + } return { ...flapping, statusChangeThreshold: Math.min(flapping.lookBackWindow, flapping.statusChangeThreshold), @@ -157,9 +161,9 @@ const INTEGER_REGEX = /^[1-9][0-9]*$/; export interface RuleFormAdvancedOptionsProps { alertDelay?: number; - flappingSettings?: RuleSpecificFlappingProperties; + flappingSettings?: Flapping | null; onAlertDelayChange: (value: string) => void; - onFlappingChange: (value: RuleSpecificFlappingProperties | null) => void; + onFlappingChange: (value: Flapping | null) => void; enabledFlapping?: boolean; } @@ -183,7 +187,7 @@ export const RuleFormAdvancedOptions = (props: RuleFormAdvancedOptionsProps) => const [isFlappingOffPopoverOpen, setIsFlappingOffPopoverOpen] = useState(false); const [isFlappingTitlePopoverOpen, setIsFlappingTitlePopoverOpen] = useState(false); - const cachedFlappingSettings = useRef(); + const cachedFlappingSettings = useRef(); const isDesktop = useIsWithinMinBreakpoint('xl'); @@ -204,8 +208,11 @@ export const RuleFormAdvancedOptions = (props: RuleFormAdvancedOptionsProps) => ); const internalOnFlappingChange = useCallback( - (flapping: RuleSpecificFlappingProperties) => { + (flapping: Flapping) => { const clampedValue = clampFlappingValues(flapping); + if (!clampedValue) { + return; + } onFlappingChange(clampedValue); cachedFlappingSettings.current = clampedValue; }, @@ -407,7 +414,7 @@ export const RuleFormAdvancedOptions = (props: RuleFormAdvancedOptionsProps) => {flappingOffTooltip} - {flappingSettings && ( + {flappingSettings && enabled && ( <> @@ -425,6 +432,9 @@ export const RuleFormAdvancedOptions = (props: RuleFormAdvancedOptionsProps) => ]); const flappingFormBody = useMemo(() => { + if (!spaceFlappingSettings || !spaceFlappingSettings.enabled) { + return null; + } if (!flappingSettings) { return null; } @@ -438,7 +448,12 @@ export const RuleFormAdvancedOptions = (props: RuleFormAdvancedOptionsProps) => /> ); - }, [flappingSettings, onLookBackWindowChange, onStatusChangeThresholdChange]); + }, [ + flappingSettings, + spaceFlappingSettings, + onLookBackWindowChange, + onStatusChangeThresholdChange, + ]); const flappingFormMessage = useMemo(() => { if (!spaceFlappingSettings || !spaceFlappingSettings.enabled) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts index 10359b53f0355..95e6f7043c90b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts @@ -66,6 +66,10 @@ export default function createAlertTests({ getService }: FtrProviderContext) { params: {}, }, ], + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, }) ); @@ -126,6 +130,10 @@ export default function createAlertTests({ getService }: FtrProviderContext) { muted_alert_ids: [], execution_status: response.body.execution_status, revision: 0, + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts index 8b9d4929d5665..198baf12e751f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts @@ -80,6 +80,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { ], throttle: '1m', notify_when: 'onThrottleInterval', + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, }; const response = await supertestWithoutAuth .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) @@ -138,6 +142,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { updated_at: response.body.updated_at, execution_status: response.body.execution_status, revision: 1, + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); @@ -185,6 +193,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { actions: [], throttle: '1m', notify_when: 'onThrottleInterval', + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, }; const response = await supertestWithoutAuth .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) @@ -231,6 +243,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { updated_at: response.body.updated_at, execution_status: response.body.execution_status, revision: 1, + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); @@ -278,6 +294,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { actions: [], throttle: '1m', notify_when: 'onThrottleInterval', + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, }; const response = await supertestWithoutAuth .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) @@ -324,6 +344,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { updated_at: response.body.updated_at, execution_status: response.body.execution_status, revision: 1, + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); @@ -371,6 +395,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { actions: [], throttle: '1m', notify_when: 'onThrottleInterval', + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, }; const response = await supertestWithoutAuth .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) @@ -424,6 +452,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { updated_at: response.body.updated_at, execution_status: response.body.execution_status, revision: 1, + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); @@ -480,6 +512,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { actions: [], throttle: '1m', notify_when: 'onThrottleInterval', + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, }; const response = await supertestWithoutAuth .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) @@ -522,6 +558,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { updated_at: response.body.updated_at, execution_status: response.body.execution_status, revision: 1, + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); @@ -564,6 +604,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { actions: [], throttle: '1m', notify_when: 'onActiveAlert', + flapping: { + look_back_window: 10, + status_change_threshold: 10, + }, }; const response = await supertestWithoutAuth .put(`${getUrlPrefix(space.id)}/api/alerting/rule/${createdAlert.id}`) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts index 8c9780aec843a..9932ee2c11a36 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts @@ -19,6 +19,7 @@ import { ObjectRemover, getUnauthorizedErrorMessage, TaskManagerDoc, + resetRulesSettings, } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -635,6 +636,90 @@ export default function createAlertTests({ getService }: FtrProviderContext) { ) .expect(400); }); + + describe('create rule flapping', () => { + afterEach(async () => { + await resetRulesSettings(supertest, 'space1'); + }); + + it('should allow flapping to be created', async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + flapping: { + look_back_window: 5, + status_change_threshold: 5, + }, + }) + ); + + expect(response.status).to.eql(200); + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); + + expect(response.body.flapping).to.eql({ + look_back_window: 5, + status_change_threshold: 5, + }); + }); + + it('should throw if flapping is created when global flapping is off', async () => { + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/settings/_flapping`) + .set('kbn-xsrf', 'foo') + .send({ + enabled: false, + look_back_window: 5, + status_change_threshold: 5, + }); + + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + flapping: { + look_back_window: 5, + status_change_threshold: 5, + }, + }) + ); + + expect(response.statusCode).eql(400); + expect(response.body.message).eql( + 'Error creating rule: can not create rule with flapping if global flapping is disabled' + ); + }); + + it('should throw if flapping is invalid', async () => { + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + flapping: { + look_back_window: 5, + status_change_threshold: 10, + }, + }) + ) + .expect(400); + + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + flapping: { + look_back_window: -5, + status_change_threshold: -5, + }, + }) + ) + .expect(400); + }); + }); }); describe('legacy', function () { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts index 9de2664338b07..029775fbba383 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts @@ -8,7 +8,13 @@ import expect from '@kbn/expect'; import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; -import { checkAAD, getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib'; +import { + checkAAD, + getUrlPrefix, + getTestRuleData, + ObjectRemover, + resetRulesSettings, +} from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -177,6 +183,233 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { }); }); + describe('update rule flapping', () => { + afterEach(async () => { + await resetRulesSettings(supertest, 'space1'); + }); + + it('should allow flapping to be updated', async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData()); + + expect(response.body.flapping).eql(undefined); + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); + + const { body: updatedRule } = await supertest + .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${response.body.id}`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'bcd', + tags: ['foo'], + params: { + foo: true, + }, + schedule: { interval: '12s' }, + actions: [], + throttle: '1m', + notify_when: 'onThrottleInterval', + flapping: { + look_back_window: 5, + status_change_threshold: 5, + }, + }); + + expect(updatedRule.flapping).eql({ + look_back_window: 5, + status_change_threshold: 5, + }); + }); + + it('should allow flapping to be removed via update', async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + flapping: { + look_back_window: 5, + status_change_threshold: 5, + }, + }) + ); + + expect(response.body.flapping).eql({ + look_back_window: 5, + status_change_threshold: 5, + }); + + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); + + const { body: updatedRule } = await supertest + .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${response.body.id}`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'bcd', + tags: ['foo'], + params: { + foo: true, + }, + schedule: { interval: '12s' }, + actions: [], + throttle: '1m', + notify_when: 'onThrottleInterval', + flapping: null, + }); + + expect(updatedRule.flapping).eql(null); + }); + + it('should throw if flapping is updated when global flapping is off', async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData()); + + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); + + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/settings/_flapping`) + .set('kbn-xsrf', 'foo') + .send({ + enabled: false, + look_back_window: 5, + status_change_threshold: 5, + }); + + await supertest + .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${response.body.id}`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'bcd', + tags: ['foo'], + params: { + foo: true, + }, + schedule: { interval: '12s' }, + actions: [], + throttle: '1m', + notify_when: 'onThrottleInterval', + flapping: { + look_back_window: 5, + status_change_threshold: 5, + }, + }) + .expect(400); + }); + + it('should allow rule to be updated when global flapping is off if not updating flapping', async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + flapping: { + look_back_window: 5, + status_change_threshold: 5, + }, + }) + ); + + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); + + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/settings/_flapping`) + .set('kbn-xsrf', 'foo') + .send({ + enabled: false, + look_back_window: 5, + status_change_threshold: 5, + }); + + await supertest + .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${response.body.id}`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'updated name 1', + tags: ['foo'], + params: { + foo: true, + }, + schedule: { interval: '12s' }, + actions: [], + throttle: '1m', + notify_when: 'onThrottleInterval', + }) + .expect(200); + + await supertest + .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${response.body.id}`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'updated name 2', + tags: ['foo'], + params: { + foo: true, + }, + schedule: { interval: '12s' }, + actions: [], + throttle: '1m', + notify_when: 'onThrottleInterval', + flapping: { + look_back_window: 5, + status_change_threshold: 5, + }, + }) + .expect(200); + }); + + it('should throw if flapping is invalid', async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData()); + + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); + + await supertest + .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${response.body.id}`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'bcd', + tags: ['foo'], + params: { + foo: true, + }, + schedule: { interval: '12s' }, + actions: [], + throttle: '1m', + notify_when: 'onThrottleInterval', + flapping: { + look_back_window: 5, + status_change_threshold: 10, + }, + }) + .expect(400); + + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'bcd', + tags: ['foo'], + params: { + foo: true, + }, + schedule: { interval: '12s' }, + actions: [], + throttle: '1m', + notify_when: 'onThrottleInterval', + flapping: { + look_back_window: -5, + status_change_threshold: -5, + }, + }) + .expect(400); + }); + }); + describe('legacy', function () { this.tags('skipFIPS'); it('should handle update alert request appropriately', async () => { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/alerts_as_data_flapping.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/alerts_as_data_flapping.ts index bf2dd0e5706c5..f2c30378def7e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/alerts_as_data_flapping.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/alerts_as_data_flapping.ts @@ -18,6 +18,7 @@ import { getTestRuleData, getUrlPrefix, ObjectRemover, + resetRulesSettings, TaskManagerDoc, } from '../../../../../common/lib'; import { TEST_CACHE_EXPIRATION_TIME } from '../../create_test_data'; @@ -45,6 +46,10 @@ export default function createAlertsAsDataFlappingTest({ getService }: FtrProvid await objectRemover.removeAll(); }); + after(async () => { + await resetRulesSettings(supertestWithoutAuth, 'space1'); + }); + // These are the same tests from x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts // but testing that flapping status & flapping history is updated as expected for AAD docs @@ -535,6 +540,203 @@ export default function createAlertsAsDataFlappingTest({ getService }: FtrProvid expect(alertDocs[0]._source![ALERT_FLAPPING]).to.equal(false); expect(state.alertInstances.alertA.meta.flapping).to.equal(false); }); + + it('should allow rule specific flapping to override space flapping', async () => { + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/settings/_flapping`) + .set('kbn-xsrf', 'foo') + .auth('superuser', 'superuser') + .send({ + enabled: true, + look_back_window: 10, + status_change_threshold: 2, + }) + .expect(200); + + const pattern = { + alertA: [true, false, true, false, true, false, true, false], + }; + + const ruleParameters = { pattern }; + const createdRule1 = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.patternFiringAad', + // set the schedule long so we can use "runSoon" to specify rule runs + schedule: { interval: '1d' }, + throttle: null, + params: ruleParameters, + actions: [], + notify_when: RuleNotifyWhen.CHANGE, + }) + ) + .expect(200); + + const rule1Id = createdRule1.body.id; + objectRemover.add(Spaces.space1.id, rule1Id, 'rule', 'alerting'); + + // Wait for the rule to run once + let run = 1; + let runWhichItFlapped = 0; + + await waitForEventLogDocs(rule1Id, new Map([['execute', { equal: 1 }]])); + // Run them all + for (let i = 0; i < 7; i++) { + await retry.try(async () => { + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${rule1Id}/_run_soon`) + .set('kbn-xsrf', 'foo'); + expect(response.status).to.eql(204); + }); + + await waitForEventLogDocs(rule1Id, new Map([['execute', { equal: ++run }]])); + + const alertDocs = await queryForAlertDocs(rule1Id); + const isFlapping = alertDocs[0]._source![ALERT_FLAPPING]; + + if (!runWhichItFlapped && isFlapping) { + runWhichItFlapped = run; + } + } + + // Flapped on the 4th run + expect(runWhichItFlapped).eql(4); + + // Create a rule with flapping + const createdRule2 = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.patternFiringAad', + // set the schedule long so we can use "runSoon" to specify rule runs + schedule: { interval: '1d' }, + throttle: null, + params: ruleParameters, + actions: [], + notify_when: RuleNotifyWhen.CHANGE, + flapping: { + look_back_window: 10, + status_change_threshold: 4, + }, + }) + ) + .expect(200); + + const rule2Id = createdRule2.body.id; + objectRemover.add(Spaces.space1.id, rule2Id, 'rule', 'alerting'); + + // Wait for the rule to run once + run = 1; + runWhichItFlapped = 0; + + await waitForEventLogDocs(rule2Id, new Map([['execute', { equal: 1 }]])); + // Run them all + for (let i = 0; i < 7; i++) { + await retry.try(async () => { + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${rule2Id}/_run_soon`) + .set('kbn-xsrf', 'foo'); + expect(response.status).to.eql(204); + }); + + await waitForEventLogDocs(rule2Id, new Map([['execute', { equal: ++run }]])); + + const alertDocs = await queryForAlertDocs(rule2Id); + const isFlapping = alertDocs[0]._source![ALERT_FLAPPING]; + + if (!runWhichItFlapped && isFlapping) { + runWhichItFlapped = run; + } + } + + // Flapped on the 6th run, which is more than the space status change threshold + expect(runWhichItFlapped).eql(6); + }); + + it('should ignore rule flapping if the space flapping is disabled', async () => { + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/settings/_flapping`) + .set('kbn-xsrf', 'foo') + .auth('superuser', 'superuser') + .send({ + enabled: true, + look_back_window: 10, + status_change_threshold: 2, + }) + .expect(200); + + const pattern = { + alertA: [true, false, true, false, true, false, true, false], + }; + + const ruleParameters = { pattern }; + // Create a rule with flapping + const createdRule = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.patternFiringAad', + // set the schedule long so we can use "runSoon" to specify rule runs + schedule: { interval: '1d' }, + throttle: null, + params: ruleParameters, + actions: [], + notify_when: RuleNotifyWhen.CHANGE, + flapping: { + look_back_window: 10, + status_change_threshold: 4, + }, + }) + ) + .expect(200); + + const ruleId = createdRule.body.id; + objectRemover.add(Spaces.space1.id, ruleId, 'rule', 'alerting'); + + // Turn global flapping off, need to do this after the rule is created because + // we do not allow rules to be created with flapping if global flapping is off. + await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/settings/_flapping`) + .set('kbn-xsrf', 'foo') + .auth('superuser', 'superuser') + .send({ + enabled: false, + look_back_window: 10, + status_change_threshold: 2, + }) + .expect(200); + + // Wait for the rule to run once + let run = 1; + let runWhichItFlapped = 0; + + await waitForEventLogDocs(ruleId, new Map([['execute', { equal: 1 }]])); + // Run them all + for (let i = 0; i < 7; i++) { + await retry.try(async () => { + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${ruleId}/_run_soon`) + .set('kbn-xsrf', 'foo'); + expect(response.status).to.eql(204); + }); + + await waitForEventLogDocs(ruleId, new Map([['execute', { equal: ++run }]])); + + const alertDocs = await queryForAlertDocs(ruleId); + const isFlapping = alertDocs[0]._source![ALERT_FLAPPING]; + + if (!runWhichItFlapped && isFlapping) { + runWhichItFlapped = run; + } + } + + // Never flapped, since globl flapping is off + expect(runWhichItFlapped).eql(0); + }); }); async function getRuleState(ruleId: string) { From 2575c8ebb64958f77428b8acd32140a676f467c2 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:13:24 +1100 Subject: [PATCH 039/110] [api-docs] 2024-10-09 Daily api_docs build (#195529) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/855 --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- .../ai_assistant_management_selection.mdx | 2 +- api_docs/aiops.devdocs.json | 21 - api_docs/aiops.mdx | 4 +- api_docs/alerting.devdocs.json | 198 ++- api_docs/alerting.mdx | 4 +- api_docs/apm.mdx | 2 +- api_docs/apm_data_access.mdx | 2 +- api_docs/banners.mdx | 2 +- api_docs/bfetch.mdx | 2 +- api_docs/canvas.mdx | 2 +- api_docs/cases.mdx | 2 +- api_docs/charts.mdx | 2 +- api_docs/cloud.mdx | 2 +- api_docs/cloud_data_migration.mdx | 2 +- api_docs/cloud_defend.mdx | 2 +- api_docs/cloud_security_posture.mdx | 2 +- api_docs/console.mdx | 2 +- api_docs/content_management.mdx | 2 +- api_docs/controls.mdx | 2 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.devdocs.json | 16 +- api_docs/data.mdx | 2 +- api_docs/data_quality.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.mdx | 2 +- api_docs/data_usage.devdocs.json | 43 +- api_docs/data_usage.mdx | 4 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.devdocs.json | 56 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/dataset_quality.mdx | 2 +- api_docs/deprecations_by_api.mdx | 38 +- api_docs/deprecations_by_plugin.mdx | 23 +- api_docs/deprecations_by_team.mdx | 6 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/discover_shared.mdx | 2 +- api_docs/ecs_data_quality_dashboard.mdx | 2 +- api_docs/elastic_assistant.mdx | 2 +- api_docs/embeddable.devdocs.json | 34 +- api_docs/embeddable.mdx | 2 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.mdx | 2 +- api_docs/entities_data_access.mdx | 2 +- api_docs/entity_manager.devdocs.json | 6 +- api_docs/entity_manager.mdx | 2 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/esql.mdx | 2 +- api_docs/esql_data_grid.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_annotation_listing.mdx | 2 +- api_docs/event_log.devdocs.json | 6 +- api_docs/event_log.mdx | 2 +- api_docs/exploratory_view.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.devdocs.json | 28 +- api_docs/expressions.mdx | 2 +- api_docs/features.devdocs.json | 8 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/fields_metadata.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/files.mdx | 2 +- api_docs/files_management.mdx | 2 +- api_docs/fleet.devdocs.json | 30 +- api_docs/fleet.mdx | 4 +- api_docs/global_search.mdx | 2 +- api_docs/guided_onboarding.mdx | 2 +- api_docs/home.devdocs.json | 6 +- api_docs/home.mdx | 2 +- api_docs/image_embeddable.mdx | 2 +- api_docs/index_lifecycle_management.mdx | 2 +- api_docs/index_management.devdocs.json | 98 +- api_docs/index_management.mdx | 7 +- api_docs/inference.mdx | 2 +- api_docs/infra.mdx | 2 +- api_docs/ingest_pipelines.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/integration_assistant.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/inventory.mdx | 2 +- api_docs/investigate.mdx | 2 +- api_docs/investigate_app.devdocs.json | 10 +- api_docs/investigate_app.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_actions_types.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_log_pattern_analysis.mdx | 2 +- api_docs/kbn_aiops_log_rate_analysis.mdx | 2 +- .../kbn_alerting_api_integration_helpers.mdx | 2 +- api_docs/kbn_alerting_comparators.mdx | 2 +- api_docs/kbn_alerting_state_types.mdx | 2 +- api_docs/kbn_alerting_types.devdocs.json | 124 +- api_docs/kbn_alerting_types.mdx | 4 +- api_docs/kbn_alerts_as_data_utils.mdx | 2 +- api_docs/kbn_alerts_grouping.mdx | 2 +- api_docs/kbn_alerts_ui_shared.devdocs.json | 53 + api_docs/kbn_alerts_ui_shared.mdx | 4 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_collection_utils.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_data_view.mdx | 2 +- api_docs/kbn_apm_synthtrace.mdx | 2 +- api_docs/kbn_apm_synthtrace_client.mdx | 2 +- api_docs/kbn_apm_types.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_avc_banner.mdx | 2 +- api_docs/kbn_axe_config.mdx | 2 +- api_docs/kbn_bfetch_error.mdx | 2 +- api_docs/kbn_calculate_auto.mdx | 2 +- .../kbn_calculate_width_from_char_count.mdx | 2 +- api_docs/kbn_cases_components.mdx | 2 +- api_docs/kbn_cbor.mdx | 2 +- api_docs/kbn_cell_actions.mdx | 2 +- api_docs/kbn_chart_expressions_common.mdx | 2 +- api_docs/kbn_chart_icons.mdx | 2 +- api_docs/kbn_ci_stats_core.mdx | 2 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 2 +- api_docs/kbn_ci_stats_reporter.mdx | 2 +- api_docs/kbn_cli_dev_mode.mdx | 2 +- api_docs/kbn_cloud_security_posture.mdx | 2 +- .../kbn_cloud_security_posture_common.mdx | 2 +- api_docs/kbn_code_editor.mdx | 2 +- api_docs/kbn_code_editor_mock.mdx | 2 +- api_docs/kbn_code_owners.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.mdx | 2 +- .../kbn_content_management_content_editor.mdx | 2 +- ...ent_management_content_insights_public.mdx | 2 +- ...ent_management_content_insights_server.mdx | 2 +- ...bn_content_management_favorites_public.mdx | 2 +- ...bn_content_management_favorites_server.mdx | 2 +- ...tent_management_tabbed_table_list_view.mdx | 2 +- ...kbn_content_management_table_list_view.mdx | 2 +- ...tent_management_table_list_view_common.mdx | 2 +- ...ntent_management_table_list_view_table.mdx | 2 +- .../kbn_content_management_user_profiles.mdx | 2 +- api_docs/kbn_content_management_utils.mdx | 2 +- .../kbn_core_analytics_browser.devdocs.json | 32 +- api_docs/kbn_core_analytics_browser.mdx | 2 +- .../kbn_core_analytics_browser_internal.mdx | 2 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 2 +- .../kbn_core_analytics_server.devdocs.json | 32 +- api_docs/kbn_core_analytics_server.mdx | 2 +- .../kbn_core_analytics_server_internal.mdx | 2 +- api_docs/kbn_core_analytics_server_mocks.mdx | 2 +- .../kbn_core_application_browser.devdocs.json | 8 +- api_docs/kbn_core_application_browser.mdx | 2 +- .../kbn_core_application_browser_internal.mdx | 2 +- .../kbn_core_application_browser_mocks.mdx | 2 +- api_docs/kbn_core_application_common.mdx | 2 +- api_docs/kbn_core_apps_browser_internal.mdx | 2 +- api_docs/kbn_core_apps_browser_mocks.mdx | 2 +- api_docs/kbn_core_apps_server_internal.mdx | 2 +- api_docs/kbn_core_base_browser_mocks.mdx | 2 +- api_docs/kbn_core_base_common.mdx | 2 +- api_docs/kbn_core_base_server_internal.mdx | 2 +- api_docs/kbn_core_base_server_mocks.mdx | 2 +- .../kbn_core_capabilities_browser_mocks.mdx | 2 +- api_docs/kbn_core_capabilities_common.mdx | 2 +- api_docs/kbn_core_capabilities_server.mdx | 2 +- .../kbn_core_capabilities_server_mocks.mdx | 2 +- api_docs/kbn_core_chrome_browser.devdocs.json | 2 +- api_docs/kbn_core_chrome_browser.mdx | 2 +- api_docs/kbn_core_chrome_browser_mocks.mdx | 2 +- api_docs/kbn_core_config_server_internal.mdx | 2 +- api_docs/kbn_core_custom_branding_browser.mdx | 2 +- ..._core_custom_branding_browser_internal.mdx | 2 +- ...kbn_core_custom_branding_browser_mocks.mdx | 2 +- api_docs/kbn_core_custom_branding_common.mdx | 2 +- api_docs/kbn_core_custom_branding_server.mdx | 2 +- ...n_core_custom_branding_server_internal.mdx | 2 +- .../kbn_core_custom_branding_server_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_browser.mdx | 2 +- ...kbn_core_deprecations_browser_internal.mdx | 2 +- .../kbn_core_deprecations_browser_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_common.mdx | 2 +- api_docs/kbn_core_deprecations_server.mdx | 2 +- .../kbn_core_deprecations_server_internal.mdx | 2 +- .../kbn_core_deprecations_server_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_browser.mdx | 2 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_server.mdx | 2 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 2 +- ...e_elasticsearch_client_server_internal.mdx | 2 +- ...core_elasticsearch_client_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_server.mdx | 2 +- ...kbn_core_elasticsearch_server_internal.mdx | 2 +- .../kbn_core_elasticsearch_server_mocks.mdx | 2 +- .../kbn_core_environment_server_internal.mdx | 2 +- .../kbn_core_environment_server_mocks.mdx | 2 +- .../kbn_core_execution_context_browser.mdx | 2 +- ...ore_execution_context_browser_internal.mdx | 2 +- ...n_core_execution_context_browser_mocks.mdx | 2 +- .../kbn_core_execution_context_common.mdx | 2 +- .../kbn_core_execution_context_server.mdx | 2 +- ...core_execution_context_server_internal.mdx | 2 +- ...bn_core_execution_context_server_mocks.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser.mdx | 2 +- .../kbn_core_fatal_errors_browser_mocks.mdx | 2 +- api_docs/kbn_core_feature_flags_browser.mdx | 2 +- ...bn_core_feature_flags_browser_internal.mdx | 2 +- .../kbn_core_feature_flags_browser_mocks.mdx | 2 +- api_docs/kbn_core_feature_flags_server.mdx | 2 +- ...kbn_core_feature_flags_server_internal.mdx | 2 +- .../kbn_core_feature_flags_server_mocks.mdx | 2 +- api_docs/kbn_core_http_browser.mdx | 2 +- api_docs/kbn_core_http_browser_internal.mdx | 2 +- api_docs/kbn_core_http_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_common.mdx | 2 +- .../kbn_core_http_context_server_mocks.mdx | 2 +- ...re_http_request_handler_context_server.mdx | 2 +- api_docs/kbn_core_http_resources_server.mdx | 2 +- ...bn_core_http_resources_server_internal.mdx | 2 +- .../kbn_core_http_resources_server_mocks.mdx | 2 +- .../kbn_core_http_router_server_internal.mdx | 2 +- .../kbn_core_http_router_server_mocks.mdx | 2 +- api_docs/kbn_core_http_server.devdocs.json | 224 ++-- api_docs/kbn_core_http_server.mdx | 2 +- api_docs/kbn_core_http_server_internal.mdx | 2 +- api_docs/kbn_core_http_server_mocks.mdx | 2 +- api_docs/kbn_core_i18n_browser.mdx | 2 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 2 +- api_docs/kbn_core_i18n_server.mdx | 2 +- api_docs/kbn_core_i18n_server_internal.mdx | 2 +- api_docs/kbn_core_i18n_server_mocks.mdx | 2 +- ...n_core_injected_metadata_browser_mocks.mdx | 2 +- ...kbn_core_integrations_browser_internal.mdx | 2 +- .../kbn_core_integrations_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_browser.mdx | 2 +- api_docs/kbn_core_lifecycle_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_server.mdx | 2 +- api_docs/kbn_core_lifecycle_server_mocks.mdx | 2 +- api_docs/kbn_core_logging_browser_mocks.mdx | 2 +- api_docs/kbn_core_logging_common_internal.mdx | 2 +- api_docs/kbn_core_logging_server.mdx | 2 +- api_docs/kbn_core_logging_server_internal.mdx | 2 +- api_docs/kbn_core_logging_server_mocks.mdx | 2 +- ...ore_metrics_collectors_server_internal.mdx | 2 +- ...n_core_metrics_collectors_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_server.mdx | 2 +- api_docs/kbn_core_metrics_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_server_mocks.mdx | 2 +- api_docs/kbn_core_mount_utils_browser.mdx | 2 +- api_docs/kbn_core_node_server.mdx | 2 +- api_docs/kbn_core_node_server_internal.mdx | 2 +- api_docs/kbn_core_node_server_mocks.mdx | 2 +- api_docs/kbn_core_notifications_browser.mdx | 2 +- ...bn_core_notifications_browser_internal.mdx | 2 +- .../kbn_core_notifications_browser_mocks.mdx | 2 +- api_docs/kbn_core_overlays_browser.mdx | 2 +- .../kbn_core_overlays_browser_internal.mdx | 2 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 2 +- api_docs/kbn_core_plugins_browser.mdx | 2 +- api_docs/kbn_core_plugins_browser_mocks.mdx | 2 +- .../kbn_core_plugins_contracts_browser.mdx | 2 +- .../kbn_core_plugins_contracts_server.mdx | 2 +- api_docs/kbn_core_plugins_server.mdx | 2 +- api_docs/kbn_core_plugins_server_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- api_docs/kbn_core_rendering_browser_mocks.mdx | 2 +- .../kbn_core_rendering_server_internal.mdx | 2 +- api_docs/kbn_core_rendering_server_mocks.mdx | 2 +- api_docs/kbn_core_root_server_internal.mdx | 2 +- ...ore_saved_objects_api_browser.devdocs.json | 32 +- .../kbn_core_saved_objects_api_browser.mdx | 2 +- ...core_saved_objects_api_server.devdocs.json | 104 +- .../kbn_core_saved_objects_api_server.mdx | 2 +- ...bn_core_saved_objects_api_server_mocks.mdx | 2 +- ...ore_saved_objects_base_server_internal.mdx | 2 +- ...n_core_saved_objects_base_server_mocks.mdx | 2 +- ...bn_core_saved_objects_browser.devdocs.json | 8 +- api_docs/kbn_core_saved_objects_browser.mdx | 2 +- ...bn_core_saved_objects_browser_internal.mdx | 2 +- .../kbn_core_saved_objects_browser_mocks.mdx | 2 +- ...kbn_core_saved_objects_common.devdocs.json | 156 +-- api_docs/kbn_core_saved_objects_common.mdx | 2 +- ..._objects_import_export_server_internal.mdx | 2 +- ...ved_objects_import_export_server_mocks.mdx | 2 +- ...aved_objects_migration_server_internal.mdx | 2 +- ...e_saved_objects_migration_server_mocks.mdx | 2 +- ...kbn_core_saved_objects_server.devdocs.json | 128 +- api_docs/kbn_core_saved_objects_server.mdx | 2 +- ...kbn_core_saved_objects_server_internal.mdx | 2 +- .../kbn_core_saved_objects_server_mocks.mdx | 2 +- .../kbn_core_saved_objects_utils_server.mdx | 2 +- api_docs/kbn_core_security_browser.mdx | 2 +- .../kbn_core_security_browser_internal.mdx | 2 +- api_docs/kbn_core_security_browser_mocks.mdx | 2 +- api_docs/kbn_core_security_common.mdx | 2 +- api_docs/kbn_core_security_server.mdx | 2 +- .../kbn_core_security_server_internal.mdx | 2 +- api_docs/kbn_core_security_server_mocks.mdx | 2 +- api_docs/kbn_core_status_common.mdx | 2 +- api_docs/kbn_core_status_common_internal.mdx | 2 +- api_docs/kbn_core_status_server.mdx | 2 +- api_docs/kbn_core_status_server_internal.mdx | 2 +- api_docs/kbn_core_status_server_mocks.mdx | 2 +- ...core_test_helpers_deprecations_getters.mdx | 2 +- ...n_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_test_helpers_kbn_server.mdx | 2 +- .../kbn_core_test_helpers_model_versions.mdx | 2 +- ...n_core_test_helpers_so_type_serializer.mdx | 2 +- api_docs/kbn_core_test_helpers_test_utils.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- .../kbn_core_ui_settings_browser_internal.mdx | 2 +- .../kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_core_ui_settings_server.mdx | 2 +- .../kbn_core_ui_settings_server_internal.mdx | 2 +- .../kbn_core_ui_settings_server_mocks.mdx | 2 +- api_docs/kbn_core_usage_data_server.mdx | 2 +- .../kbn_core_usage_data_server_internal.mdx | 2 +- api_docs/kbn_core_usage_data_server_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_browser.mdx | 2 +- ...kbn_core_user_profile_browser_internal.mdx | 2 +- .../kbn_core_user_profile_browser_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_common.mdx | 2 +- api_docs/kbn_core_user_profile_server.mdx | 2 +- .../kbn_core_user_profile_server_internal.mdx | 2 +- .../kbn_core_user_profile_server_mocks.mdx | 2 +- api_docs/kbn_core_user_settings_server.mdx | 2 +- .../kbn_core_user_settings_server_mocks.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_custom_icons.mdx | 2 +- api_docs/kbn_custom_integrations.mdx | 2 +- api_docs/kbn_cypress_config.mdx | 2 +- api_docs/kbn_data_forge.mdx | 2 +- api_docs/kbn_data_service.mdx | 2 +- api_docs/kbn_data_stream_adapter.mdx | 2 +- api_docs/kbn_data_view_utils.mdx | 2 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_deeplinks_analytics.mdx | 2 +- api_docs/kbn_deeplinks_devtools.mdx | 2 +- api_docs/kbn_deeplinks_fleet.mdx | 2 +- api_docs/kbn_deeplinks_management.mdx | 2 +- api_docs/kbn_deeplinks_ml.mdx | 2 +- api_docs/kbn_deeplinks_observability.mdx | 2 +- api_docs/kbn_deeplinks_search.devdocs.json | 2 +- api_docs/kbn_deeplinks_search.mdx | 2 +- api_docs/kbn_deeplinks_security.mdx | 2 +- api_docs/kbn_deeplinks_shared.mdx | 2 +- api_docs/kbn_default_nav_analytics.mdx | 2 +- api_docs/kbn_default_nav_devtools.mdx | 2 +- api_docs/kbn_default_nav_management.mdx | 2 +- api_docs/kbn_default_nav_ml.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_discover_utils.mdx | 2 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_dom_drag_drop.mdx | 2 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_ecs_data_quality_dashboard.mdx | 2 +- api_docs/kbn_elastic_agent_utils.mdx | 2 +- api_docs/kbn_elastic_assistant.mdx | 2 +- .../kbn_elastic_assistant_common.devdocs.json | 2 +- api_docs/kbn_elastic_assistant_common.mdx | 2 +- api_docs/kbn_entities_schema.mdx | 2 +- api_docs/kbn_es.mdx | 2 +- api_docs/kbn_es_archiver.mdx | 2 +- api_docs/kbn_es_errors.mdx | 2 +- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_es_types.mdx | 2 +- api_docs/kbn_eslint_plugin_imports.mdx | 2 +- api_docs/kbn_esql_ast.mdx | 2 +- api_docs/kbn_esql_editor.mdx | 2 +- api_docs/kbn_esql_utils.devdocs.json | 33 + api_docs/kbn_esql_utils.mdx | 4 +- ..._esql_validation_autocomplete.devdocs.json | 70 ++ api_docs/kbn_esql_validation_autocomplete.mdx | 4 +- api_docs/kbn_event_annotation_common.mdx | 2 +- api_docs/kbn_event_annotation_components.mdx | 2 +- api_docs/kbn_expandable_flyout.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_field_utils.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- api_docs/kbn_formatters.mdx | 2 +- .../kbn_ftr_common_functional_services.mdx | 2 +- .../kbn_ftr_common_functional_ui_services.mdx | 2 +- api_docs/kbn_generate.mdx | 2 +- api_docs/kbn_generate_console_definitions.mdx | 2 +- api_docs/kbn_generate_csv.mdx | 2 +- api_docs/kbn_grid_layout.mdx | 2 +- api_docs/kbn_grouping.mdx | 2 +- api_docs/kbn_guided_onboarding.mdx | 2 +- api_docs/kbn_handlebars.mdx | 2 +- api_docs/kbn_hapi_mocks.mdx | 2 +- api_docs/kbn_health_gateway_server.mdx | 2 +- api_docs/kbn_home_sample_data_card.mdx | 2 +- api_docs/kbn_home_sample_data_tab.mdx | 2 +- api_docs/kbn_i18n.mdx | 2 +- api_docs/kbn_i18n_react.mdx | 2 +- api_docs/kbn_import_resolver.mdx | 2 +- ...index_management_shared_types.devdocs.json | 110 ++ .../kbn_index_management_shared_types.mdx | 4 +- api_docs/kbn_inference_integration_flyout.mdx | 2 +- api_docs/kbn_infra_forge.mdx | 2 +- api_docs/kbn_interpreter.mdx | 2 +- .../kbn_investigation_shared.devdocs.json | 10 +- api_docs/kbn_investigation_shared.mdx | 2 +- api_docs/kbn_io_ts_utils.mdx | 2 +- api_docs/kbn_ipynb.mdx | 2 +- api_docs/kbn_jest_serializers.mdx | 2 +- api_docs/kbn_journeys.mdx | 2 +- api_docs/kbn_json_ast.mdx | 2 +- api_docs/kbn_json_schemas.mdx | 2 +- api_docs/kbn_kibana_manifest_schema.mdx | 2 +- api_docs/kbn_language_documentation.mdx | 2 +- api_docs/kbn_lens_embeddable_utils.mdx | 2 +- api_docs/kbn_lens_formula_docs.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_content_badge.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_management_cards_navigation.mdx | 2 +- .../kbn_management_settings_application.mdx | 2 +- ...ent_settings_components_field_category.mdx | 2 +- ...gement_settings_components_field_input.mdx | 2 +- ...nagement_settings_components_field_row.mdx | 2 +- ...bn_management_settings_components_form.mdx | 2 +- ...n_management_settings_field_definition.mdx | 2 +- api_docs/kbn_management_settings_ids.mdx | 2 +- ...n_management_settings_section_registry.mdx | 2 +- api_docs/kbn_management_settings_types.mdx | 2 +- .../kbn_management_settings_utilities.mdx | 2 +- api_docs/kbn_management_storybook_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_maps_vector_tile_utils.mdx | 2 +- api_docs/kbn_ml_agg_utils.devdocs.json | 3 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_anomaly_utils.mdx | 2 +- api_docs/kbn_ml_cancellable_search.mdx | 2 +- api_docs/kbn_ml_category_validator.mdx | 2 +- api_docs/kbn_ml_chi2test.mdx | 2 +- .../kbn_ml_data_frame_analytics_utils.mdx | 2 +- api_docs/kbn_ml_data_grid.mdx | 2 +- api_docs/kbn_ml_date_picker.mdx | 2 +- api_docs/kbn_ml_date_utils.mdx | 2 +- api_docs/kbn_ml_error_utils.mdx | 2 +- .../kbn_ml_field_stats_flyout.devdocs.json | 2 +- api_docs/kbn_ml_field_stats_flyout.mdx | 2 +- api_docs/kbn_ml_in_memory_table.mdx | 2 +- api_docs/kbn_ml_is_defined.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_kibana_theme.mdx | 2 +- api_docs/kbn_ml_local_storage.mdx | 2 +- api_docs/kbn_ml_nested_property.mdx | 2 +- api_docs/kbn_ml_number_utils.mdx | 2 +- api_docs/kbn_ml_parse_interval.mdx | 2 +- api_docs/kbn_ml_query_utils.mdx | 2 +- api_docs/kbn_ml_random_sampler_utils.mdx | 2 +- api_docs/kbn_ml_route_utils.mdx | 2 +- api_docs/kbn_ml_runtime_field_utils.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_ml_time_buckets.mdx | 2 +- api_docs/kbn_ml_trained_models_utils.mdx | 2 +- api_docs/kbn_ml_ui_actions.mdx | 2 +- api_docs/kbn_ml_url_state.mdx | 2 +- api_docs/kbn_ml_validators.mdx | 2 +- api_docs/kbn_mock_idp_utils.mdx | 2 +- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_object_versioning.mdx | 2 +- api_docs/kbn_object_versioning_utils.mdx | 2 +- api_docs/kbn_observability_alert_details.mdx | 2 +- .../kbn_observability_alerting_rule_utils.mdx | 2 +- .../kbn_observability_alerting_test_data.mdx | 2 +- ...ility_get_padded_alert_time_range_util.mdx | 2 +- ...kbn_observability_synthetics_test_data.mdx | 2 +- api_docs/kbn_openapi_bundler.mdx | 2 +- api_docs/kbn_openapi_generator.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- api_docs/kbn_osquery_io_ts_types.mdx | 2 +- api_docs/kbn_panel_loader.mdx | 2 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_check.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_presentation_containers.mdx | 2 +- api_docs/kbn_presentation_publishing.mdx | 2 +- api_docs/kbn_product_doc_artifact_builder.mdx | 2 +- api_docs/kbn_profiling_utils.mdx | 2 +- api_docs/kbn_random_sampling.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_react_hooks.mdx | 2 +- api_docs/kbn_react_kibana_context_common.mdx | 2 +- api_docs/kbn_react_kibana_context_render.mdx | 2 +- api_docs/kbn_react_kibana_context_root.mdx | 2 +- api_docs/kbn_react_kibana_context_styled.mdx | 2 +- api_docs/kbn_react_kibana_context_theme.mdx | 2 +- api_docs/kbn_react_kibana_mount.mdx | 2 +- api_docs/kbn_recently_accessed.mdx | 2 +- api_docs/kbn_repo_file_maps.mdx | 2 +- api_docs/kbn_repo_linter.mdx | 2 +- api_docs/kbn_repo_path.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_reporting_common.mdx | 2 +- api_docs/kbn_reporting_csv_share_panel.mdx | 2 +- api_docs/kbn_reporting_export_types_csv.mdx | 2 +- .../kbn_reporting_export_types_csv_common.mdx | 2 +- api_docs/kbn_reporting_export_types_pdf.mdx | 2 +- .../kbn_reporting_export_types_pdf_common.mdx | 2 +- api_docs/kbn_reporting_export_types_png.mdx | 2 +- .../kbn_reporting_export_types_png_common.mdx | 2 +- api_docs/kbn_reporting_mocks_server.mdx | 2 +- api_docs/kbn_reporting_public.mdx | 2 +- api_docs/kbn_reporting_server.mdx | 2 +- api_docs/kbn_resizable_layout.mdx | 2 +- .../kbn_response_ops_feature_flag_service.mdx | 2 +- api_docs/kbn_rison.mdx | 2 +- api_docs/kbn_rollup.mdx | 2 +- api_docs/kbn_router_to_openapispec.mdx | 2 +- api_docs/kbn_router_utils.mdx | 2 +- api_docs/kbn_rrule.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- api_docs/kbn_saved_objects_settings.mdx | 2 +- api_docs/kbn_screenshotting_server.mdx | 2 +- api_docs/kbn_search_api_keys_components.mdx | 2 +- api_docs/kbn_search_api_keys_server.mdx | 2 +- api_docs/kbn_search_api_panels.mdx | 2 +- api_docs/kbn_search_connectors.mdx | 2 +- api_docs/kbn_search_errors.mdx | 2 +- .../kbn_search_index_documents.devdocs.json | 4 +- api_docs/kbn_search_index_documents.mdx | 2 +- api_docs/kbn_search_response_warnings.mdx | 2 +- api_docs/kbn_search_shared_ui.mdx | 2 +- api_docs/kbn_search_types.mdx | 2 +- api_docs/kbn_security_api_key_management.mdx | 2 +- api_docs/kbn_security_authorization_core.mdx | 2 +- api_docs/kbn_security_form_components.mdx | 2 +- api_docs/kbn_security_hardening.mdx | 2 +- api_docs/kbn_security_plugin_types_common.mdx | 2 +- api_docs/kbn_security_plugin_types_public.mdx | 2 +- api_docs/kbn_security_plugin_types_server.mdx | 2 +- .../kbn_security_role_management_model.mdx | 2 +- api_docs/kbn_security_solution_common.mdx | 2 +- ...kbn_security_solution_distribution_bar.mdx | 2 +- api_docs/kbn_security_solution_features.mdx | 2 +- api_docs/kbn_security_solution_navigation.mdx | 2 +- api_docs/kbn_security_solution_side_nav.mdx | 2 +- ...kbn_security_solution_storybook_config.mdx | 2 +- api_docs/kbn_security_ui_components.mdx | 2 +- .../kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_data_table.mdx | 2 +- api_docs/kbn_securitysolution_ecs.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- ...ion_exception_list_components.devdocs.json | 10 +- ...ritysolution_exception_list_components.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ..._securitysolution_io_ts_alerting_types.mdx | 2 +- .../kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- .../kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- .../kbn_server_route_repository_client.mdx | 2 +- ...server_route_repository_utils.devdocs.json | 2 +- .../kbn_server_route_repository_utils.mdx | 2 +- api_docs/kbn_serverless_common_settings.mdx | 2 +- .../kbn_serverless_observability_settings.mdx | 2 +- api_docs/kbn_serverless_project_switcher.mdx | 2 +- api_docs/kbn_serverless_search_settings.mdx | 2 +- api_docs/kbn_serverless_security_settings.mdx | 2 +- api_docs/kbn_serverless_storybook_config.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- api_docs/kbn_shared_ux_avatar_solution.mdx | 2 +- .../kbn_shared_ux_button_exit_full_screen.mdx | 2 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_chrome_navigation.mdx | 2 +- api_docs/kbn_shared_ux_error_boundary.mdx | 2 +- api_docs/kbn_shared_ux_file_context.mdx | 2 +- api_docs/kbn_shared_ux_file_image.mdx | 2 +- api_docs/kbn_shared_ux_file_image_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_picker.mdx | 2 +- api_docs/kbn_shared_ux_file_types.mdx | 2 +- api_docs/kbn_shared_ux_file_upload.mdx | 2 +- api_docs/kbn_shared_ux_file_util.mdx | 2 +- api_docs/kbn_shared_ux_link_redirect_app.mdx | 2 +- .../kbn_shared_ux_link_redirect_app_mocks.mdx | 2 +- api_docs/kbn_shared_ux_markdown.mdx | 2 +- api_docs/kbn_shared_ux_markdown_mocks.mdx | 2 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 2 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 2 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_template.mdx | 2 +- ...n_shared_ux_page_kibana_template_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data.mdx | 2 +- .../kbn_shared_ux_page_no_data_config.mdx | 2 +- ...bn_shared_ux_page_no_data_config_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_prompt_not_found.mdx | 2 +- api_docs/kbn_shared_ux_router.mdx | 2 +- api_docs/kbn_shared_ux_router_mocks.mdx | 2 +- api_docs/kbn_shared_ux_storybook_config.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_tabbed_modal.mdx | 2 +- api_docs/kbn_shared_ux_table_persist.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_slo_schema.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_sort_predicates.mdx | 2 +- api_docs/kbn_sse_utils.mdx | 2 +- api_docs/kbn_sse_utils_client.mdx | 2 +- api_docs/kbn_sse_utils_server.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_synthetics_e2e.mdx | 2 +- api_docs/kbn_synthetics_private_location.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.mdx | 2 +- api_docs/kbn_test_eui_helpers.mdx | 2 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_test_subj_selector.mdx | 2 +- api_docs/kbn_timerange.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_triggers_actions_ui_types.mdx | 2 +- api_docs/kbn_try_in_console.mdx | 2 +- api_docs/kbn_ts_projects.mdx | 2 +- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kbn_ui_actions_browser.mdx | 2 +- api_docs/kbn_ui_shared_deps_src.mdx | 2 +- api_docs/kbn_ui_theme.mdx | 2 +- api_docs/kbn_unified_data_table.mdx | 2 +- api_docs/kbn_unified_doc_viewer.mdx | 2 +- api_docs/kbn_unified_field_list.devdocs.json | 20 +- api_docs/kbn_unified_field_list.mdx | 4 +- api_docs/kbn_unsaved_changes_badge.mdx | 2 +- api_docs/kbn_unsaved_changes_prompt.mdx | 2 +- api_docs/kbn_use_tracked_promise.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_visualization_ui_components.mdx | 2 +- api_docs/kbn_visualization_utils.mdx | 2 +- api_docs/kbn_xstate_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kbn_zod.devdocs.json | 2 +- api_docs/kbn_zod.mdx | 2 +- api_docs/kbn_zod_helpers.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.mdx | 2 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/links.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/logs_data_access.mdx | 2 +- api_docs/logs_explorer.mdx | 2 +- api_docs/logs_shared.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/metrics_data_access.mdx | 2 +- api_docs/ml.mdx | 2 +- api_docs/mock_idp_plugin.mdx | 2 +- api_docs/monitoring.mdx | 2 +- api_docs/monitoring_collection.mdx | 2 +- api_docs/navigation.mdx | 2 +- api_docs/newsfeed.mdx | 2 +- api_docs/no_data_page.mdx | 2 +- api_docs/notifications.mdx | 2 +- api_docs/observability.mdx | 2 +- api_docs/observability_a_i_assistant.mdx | 2 +- api_docs/observability_a_i_assistant_app.mdx | 2 +- .../observability_ai_assistant_management.mdx | 2 +- api_docs/observability_logs_explorer.mdx | 2 +- api_docs/observability_onboarding.mdx | 2 +- api_docs/observability_shared.mdx | 2 +- api_docs/osquery.devdocs.json | 4 +- api_docs/osquery.mdx | 2 +- api_docs/painless_lab.mdx | 2 +- api_docs/plugin_directory.mdx | 32 +- api_docs/presentation_panel.mdx | 2 +- api_docs/presentation_util.devdocs.json | 1095 +---------------- api_docs/presentation_util.mdx | 7 +- api_docs/profiling.mdx | 2 +- api_docs/profiling_data_access.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.devdocs.json | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.devdocs.json | 16 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_finder.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- .../saved_objects_tagging_oss.devdocs.json | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/saved_search.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/search_assistant.mdx | 2 +- api_docs/search_connectors.mdx | 2 +- api_docs/search_homepage.mdx | 2 +- api_docs/search_indices.devdocs.json | 91 +- api_docs/search_indices.mdx | 4 +- .../search_inference_endpoints.devdocs.json | 18 +- api_docs/search_inference_endpoints.mdx | 7 +- api_docs/search_notebooks.mdx | 2 +- api_docs/search_playground.mdx | 2 +- api_docs/security.mdx | 2 +- api_docs/security_solution.devdocs.json | 2 +- api_docs/security_solution.mdx | 2 +- api_docs/security_solution_ess.mdx | 2 +- api_docs/security_solution_serverless.mdx | 2 +- api_docs/serverless.mdx | 2 +- api_docs/serverless_observability.mdx | 2 +- api_docs/serverless_search.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.devdocs.json | 8 +- api_docs/share.mdx | 2 +- api_docs/slo.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/stack_connectors.mdx | 2 +- api_docs/task_manager.mdx | 2 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/threat_intelligence.mdx | 2 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.devdocs.json | 4 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_doc_viewer.mdx | 2 +- api_docs/unified_histogram.mdx | 2 +- api_docs/unified_search.mdx | 2 +- api_docs/unified_search_autocomplete.mdx | 2 +- api_docs/uptime.mdx | 2 +- api_docs/url_forwarding.mdx | 2 +- api_docs/usage_collection.mdx | 2 +- api_docs/ux.mdx | 2 +- api_docs/vis_default_editor.mdx | 2 +- api_docs/vis_type_gauge.mdx | 2 +- api_docs/vis_type_heatmap.mdx | 2 +- api_docs/vis_type_pie.mdx | 2 +- api_docs/vis_type_table.mdx | 2 +- api_docs/vis_type_timelion.mdx | 2 +- api_docs/vis_type_timeseries.mdx | 2 +- api_docs/vis_type_vega.mdx | 2 +- api_docs/vis_type_vislib.mdx | 2 +- api_docs/vis_type_xy.mdx | 2 +- api_docs/visualizations.mdx | 2 +- 798 files changed, 2065 insertions(+), 2536 deletions(-) diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 6a1ebe045be0e..f1ad14949f3ff 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 5ec22aa78f3bf..26f5bfd7d162a 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/ai_assistant_management_selection.mdx b/api_docs/ai_assistant_management_selection.mdx index dd3bb870fcf6c..2ba9b66b832e9 100644 --- a/api_docs/ai_assistant_management_selection.mdx +++ b/api_docs/ai_assistant_management_selection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiAssistantManagementSelection title: "aiAssistantManagementSelection" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementSelection plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; diff --git a/api_docs/aiops.devdocs.json b/api_docs/aiops.devdocs.json index 9c9a31e489d9c..b4fa59195b4c9 100644 --- a/api_docs/aiops.devdocs.json +++ b/api_docs/aiops.devdocs.json @@ -632,27 +632,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "aiops", - "id": "def-public.AiopsAppContextValue.presentationUtil", - "type": "Object", - "tags": [], - "label": "presentationUtil", - "description": [], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PresentationUtilPluginStart", - "text": "PresentationUtilPluginStart" - }, - " | undefined" - ], - "path": "x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "aiops", "id": "def-public.AiopsAppContextValue.embeddable", diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index e73de19247cfa..b52c7323929ab 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 72 | 0 | 9 | 2 | +| 71 | 0 | 8 | 2 | ## Client diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index 07bb3a108bdfb..28a1530f6b1db 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -1613,13 +1613,29 @@ "label": "getRulesSettingsClient", "description": [], "signature": [ - "() => ", + "(withoutAuth?: boolean | undefined) => ", "RulesSettingsClient" ], "path": "x-pack/plugins/alerting/server/types.ts", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "alerting", + "id": "def-server.AlertingApiRequestHandlerContext.getRulesSettingsClient.$1", + "type": "CompoundType", + "tags": [], + "label": "withoutAuth", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/alerting/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], "returnComment": [] }, { @@ -3428,6 +3444,20 @@ "path": "x-pack/plugins/alerting/server/application/rule/types/rule.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "alerting", + "id": "def-server.Rule.flapping", + "type": "CompoundType", + "tags": [], + "label": "flapping", + "description": [], + "signature": [ + "Readonly<{} & { lookBackWindow: number; statusChangeThreshold: number; }> | null | undefined" + ], + "path": "x-pack/plugins/alerting/server/application/rule/types/rule.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -4094,7 +4124,7 @@ "label": "schemas", "description": [], "signature": [ - "{ params?: { type: \"zod\"; schema: any; } | { type: \"config-schema\"; schema: ", + "{ params?: { type: \"zod\"; schema: Zod.ZodObject | Zod.ZodIntersection; } | { type: \"config-schema\"; schema: ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -7165,6 +7195,59 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "alerting", + "id": "def-common.Flapping", + "type": "Interface", + "tags": [], + "label": "Flapping", + "description": [], + "signature": [ + { + "pluginId": "@kbn/alerting-types", + "scope": "common", + "docId": "kibKbnAlertingTypesPluginApi", + "section": "def-common.Flapping", + "text": "Flapping" + }, + " extends ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + } + ], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "alerting", + "id": "def-common.Flapping.lookBackWindow", + "type": "number", + "tags": [], + "label": "lookBackWindow", + "description": [], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "alerting", + "id": "def-common.Flapping.statusChangeThreshold", + "type": "number", + "tags": [], + "label": "statusChangeThreshold", + "description": [], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "alerting", "id": "def-common.IExecutionErrors", @@ -8499,12 +8582,19 @@ { "parentPluginId": "alerting", "id": "def-common.Rule.flapping", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "flapping", "description": [], "signature": [ - "{ lookBackWindow: number; statusChangeThreshold: number; } | undefined" + { + "pluginId": "@kbn/alerting-types", + "scope": "common", + "docId": "kibKbnAlertingTypesPluginApi", + "section": "def-common.Flapping", + "text": "Flapping" + }, + " | null | undefined" ], "path": "packages/kbn-alerting-types/rule_types.ts", "deprecated": false, @@ -9396,42 +9486,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "alerting", - "id": "def-common.RuleSpecificFlappingProperties", - "type": "Interface", - "tags": [], - "label": "RuleSpecificFlappingProperties", - "description": [], - "path": "x-pack/plugins/alerting/common/rules_settings.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "alerting", - "id": "def-common.RuleSpecificFlappingProperties.lookBackWindow", - "type": "number", - "tags": [], - "label": "lookBackWindow", - "description": [], - "path": "x-pack/plugins/alerting/common/rules_settings.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "alerting", - "id": "def-common.RuleSpecificFlappingProperties.statusChangeThreshold", - "type": "number", - "tags": [], - "label": "statusChangeThreshold", - "description": [], - "path": "x-pack/plugins/alerting/common/rules_settings.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "alerting", "id": "def-common.RulesSettings", @@ -11086,21 +11140,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "alerting", - "id": "def-common.MAX_LOOK_BACK_WINDOW", - "type": "number", - "tags": [], - "label": "MAX_LOOK_BACK_WINDOW", - "description": [], - "signature": [ - "20" - ], - "path": "packages/kbn-alerting-types/rule_flapping.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "alerting", "id": "def-common.MAX_QUERY_DELAY", @@ -11116,36 +11155,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "alerting", - "id": "def-common.MAX_STATUS_CHANGE_THRESHOLD", - "type": "number", - "tags": [], - "label": "MAX_STATUS_CHANGE_THRESHOLD", - "description": [], - "signature": [ - "20" - ], - "path": "packages/kbn-alerting-types/rule_flapping.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "alerting", - "id": "def-common.MIN_LOOK_BACK_WINDOW", - "type": "number", - "tags": [], - "label": "MIN_LOOK_BACK_WINDOW", - "description": [], - "signature": [ - "2" - ], - "path": "packages/kbn-alerting-types/rule_flapping.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "alerting", "id": "def-common.MIN_QUERY_DELAY", @@ -11161,21 +11170,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "alerting", - "id": "def-common.MIN_STATUS_CHANGE_THRESHOLD", - "type": "number", - "tags": [], - "label": "MIN_STATUS_CHANGE_THRESHOLD", - "description": [], - "signature": [ - "2" - ], - "path": "packages/kbn-alerting-types/rule_flapping.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "alerting", "id": "def-common.MONITORING_HISTORY_LIMIT", @@ -13351,7 +13345,7 @@ "tags": [], "label": "executionStatus", "description": [ - "// NO NEED TO BE INDEXED\n// nextRun: {\n// type: 'date',\n// },\n// Deprecated, if you need to add new property please do it in `last_run`" + "// NO NEED TO BE INDEXED\n// flapping: {\n// index: false,\n// properties: {\n// lookBackWindow: {\n// type: 'long',\n// },\n// statusChangeThreshold: {\n// type: 'long',\n// },\n// },\n// },\n// NO NEED TO BE INDEXED\n// nextRun: {\n// type: 'date',\n// },\n// Deprecated, if you need to add new property please do it in `last_run`" ], "path": "x-pack/plugins/alerting/common/saved_objects/rules/mappings.ts", "deprecated": false, diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 5e578d3a8329a..d15dc8457dd4d 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 875 | 1 | 843 | 50 | +| 873 | 1 | 841 | 50 | ## Client diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 21fe74fe71029..da9a3013e1058 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index a05a6b4a38a76..eb139721565bf 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 02c64665ed1c1..f919804deaae2 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 94a95b9258545..7e9a32e01e0c1 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index 72c64f513132c..396275908833f 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 392ff41336699..f9008043e038b 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index fd8b63a78edff..6de6f736f5a92 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index ef494e7e97590..0cc66faacc6fd 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index c1ce3cf038bf9..f85b6dd7bf9e0 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index e402ae37f677b..f7f6307c07350 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 8de0fdd5c6b3c..c14aa45f86096 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index dbe732b5fa02f..ae1cf86d0ea10 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index 0789a9254ba4a..acfbe89a9e9df 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 5250a89dc3e08..2025066c4dcb2 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index eba6c1684a30a..21c5dcf8f6172 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index d7ea91b3e05d3..bb9da49385e1f 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index afc4d951917f9..5fc78a53b580b 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 627a3730f7afb..3effda755639b 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -8073,10 +8073,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" - }, { "plugin": "@kbn/core-saved-objects-api-server-internal", "path": "packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/internal_utils.ts" @@ -8089,6 +8085,10 @@ "plugin": "@kbn/core-saved-objects-server-internal", "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts" }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" + }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" @@ -24602,10 +24602,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" - }, { "plugin": "@kbn/core-saved-objects-api-server-internal", "path": "packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/internal_utils.ts" @@ -24618,6 +24614,10 @@ "plugin": "@kbn/core-saved-objects-server-internal", "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts" }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" + }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" diff --git a/api_docs/data.mdx b/api_docs/data.mdx index d3c3c17ac4e85..c42645d119137 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_quality.mdx b/api_docs/data_quality.mdx index a864a7f539cf0..c2c2ba7ffc156 100644 --- a/api_docs/data_quality.mdx +++ b/api_docs/data_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataQuality title: "dataQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the dataQuality plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataQuality'] --- import dataQualityObj from './data_quality.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 5e85848bfd171..da3fad5af6e9f 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 42a30c74b374a..0014237f83948 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_usage.devdocs.json b/api_docs/data_usage.devdocs.json index 835cb7f1ef9a3..934e8ba7e64af 100644 --- a/api_docs/data_usage.devdocs.json +++ b/api_docs/data_usage.devdocs.json @@ -50,7 +50,7 @@ "tags": [], "label": "DataUsageServerSetup", "description": [], - "path": "x-pack/plugins/data_usage/server/types.ts", + "path": "x-pack/plugins/data_usage/server/types/types.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -64,7 +64,7 @@ "tags": [], "label": "DataUsageServerStart", "description": [], - "path": "x-pack/plugins/data_usage/server/types.ts", + "path": "x-pack/plugins/data_usage/server/types/types.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -78,6 +78,45 @@ "interfaces": [], "enums": [], "misc": [ + { + "parentPluginId": "dataUsage", + "id": "def-common.DATA_USAGE_API_ROUTE_PREFIX", + "type": "string", + "tags": [], + "label": "DATA_USAGE_API_ROUTE_PREFIX", + "description": [], + "signature": [ + "\"/api/data_usage/\"" + ], + "path": "x-pack/plugins/data_usage/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "dataUsage", + "id": "def-common.DATA_USAGE_DATA_STREAMS_API_ROUTE", + "type": "string", + "tags": [], + "label": "DATA_USAGE_DATA_STREAMS_API_ROUTE", + "description": [], + "path": "x-pack/plugins/data_usage/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "dataUsage", + "id": "def-common.DATA_USAGE_METRICS_API_ROUTE", + "type": "string", + "tags": [], + "label": "DATA_USAGE_METRICS_API_ROUTE", + "description": [], + "path": "x-pack/plugins/data_usage/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "dataUsage", "id": "def-common.PLUGIN_ID", diff --git a/api_docs/data_usage.mdx b/api_docs/data_usage.mdx index 8b6118c6d400b..d0346fe1346c5 100644 --- a/api_docs/data_usage.mdx +++ b/api_docs/data_usage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataUsage title: "dataUsage" image: https://source.unsplash.com/400x175/?github description: API docs for the dataUsage plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataUsage'] --- import dataUsageObj from './data_usage.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 6 | 0 | 6 | 0 | +| 9 | 0 | 9 | 0 | ## Client diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 94dc957a6475e..f94529d1433bb 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 32b79e8760623..3616f8e94d45e 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 3919757c00da8..33531843f8bc9 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.devdocs.json b/api_docs/data_views.devdocs.json index e502dd82ccc7a..aee66ddb33b96 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -12140,9 +12140,7 @@ "\nA record of capabilities (aggregations) for an index rollup job" ], "signature": [ - "[index: string]: { aggs?: ", - "Dictionary", - "<", + "[index: string]: { aggs?: _.Dictionary<", { "pluginId": "dataViews", "scope": "common", @@ -14024,6 +14022,10 @@ "plugin": "@kbn/unified-field-list", "path": "packages/kbn-unified-field-list/src/hooks/use_existing_fields.ts" }, + { + "plugin": "controls", + "path": "src/plugins/controls/public/controls/data_controls/options_list_control/options_list_fetch_cache.ts" + }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/data_views_service/loader.ts" @@ -14032,10 +14034,6 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx" }, - { - "plugin": "controls", - "path": "src/plugins/controls/public/controls/data_controls/options_list_control/options_list_fetch_cache.ts" - }, { "plugin": "@kbn/lens-embeddable-utils", "path": "packages/kbn-lens-embeddable-utils/config_builder/columns/breakdown.ts" @@ -14048,46 +14046,10 @@ "plugin": "dataVisualizer", "path": "x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_data_visualizer_grid_data.ts" }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx" - }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx" - }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx" - }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx" - }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx" - }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx" - }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/services/kibana/data_views.ts" - }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/services/kibana/data_views.ts" - }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/public/components/datasource/datasource_component.js" }, - { - "plugin": "presentationUtil", - "path": "src/plugins/presentation_util/public/services/data_views/data_views.story.ts" - }, { "plugin": "logsShared", "path": "x-pack/plugins/observability_solution/logs_shared/common/log_views/resolved_log_view.ts" @@ -26082,10 +26044,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" - }, { "plugin": "@kbn/core-saved-objects-api-server-internal", "path": "packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/internal_utils.ts" @@ -26098,6 +26056,10 @@ "plugin": "@kbn/core-saved-objects-server-internal", "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts" }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" + }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 28c2a20e502e9..bb77f07fd5425 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index 9b3ad91f6d7b6..b9104b5e6c0ce 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 9e72e0cb9a9cf..ec457626c8118 100644 --- a/api_docs/dataset_quality.mdx +++ b/api_docs/dataset_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/datasetQuality title: "datasetQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the datasetQuality plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'datasetQuality'] --- import datasetQualityObj from './dataset_quality.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 2be5eb2369632..4a20225140822 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -17,12 +17,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Referencing plugin(s) | Remove By | | ---------------|-----------|-----------| | | ml, stackAlerts | - | -| | data, @kbn/search-errors, savedObjectsManagement, unifiedSearch, @kbn/unified-field-list, lens, controls, @kbn/lens-embeddable-utils, triggersActionsUi, dataVisualizer, canvas, presentationUtil, logsShared, fleet, ml, @kbn/ml-data-view-utils, enterpriseSearch, graph, visTypeTimeseries, exploratoryView, stackAlerts, infra, securitySolution, timelines, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, eventAnnotationListing, inputControlVis, visDefaultEditor, visTypeTimelion, visTypeVega | - | +| | data, @kbn/search-errors, savedObjectsManagement, unifiedSearch, @kbn/unified-field-list, controls, lens, @kbn/lens-embeddable-utils, triggersActionsUi, dataVisualizer, canvas, logsShared, fleet, ml, @kbn/ml-data-view-utils, enterpriseSearch, graph, visTypeTimeseries, exploratoryView, stackAlerts, infra, securitySolution, timelines, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, eventAnnotationListing, inputControlVis, visDefaultEditor, visTypeTimelion, visTypeVega | - | | | ml, securitySolution | - | | | actions, savedObjectsTagging, ml, enterpriseSearch | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core, savedObjects, visualizations, aiops, dataVisualizer, ml, dashboardEnhanced, graph, lens, securitySolution, eventAnnotation, @kbn/core-saved-objects-browser-mocks | - | | | @kbn/core, embeddable, savedObjects, visualizations, canvas, graph, ml | - | -| | @kbn/core-saved-objects-base-server-internal, @kbn/core-saved-objects-migration-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-ui-settings-server-internal, @kbn/core-usage-data-server-internal, taskManager, spaces, actions, @kbn/core-saved-objects-migration-server-mocks, share, dataViews, data, alerting, lens, cases, savedSearch, canvas, fleet, cloudSecurityPosture, ml, logsShared, graph, lists, maps, visualizations, infra, apmDataAccess, securitySolution, apm, slo, synthetics, uptime, dashboard, eventAnnotation, links, savedObjectsManagement, @kbn/core-test-helpers-so-type-serializer, @kbn/core-saved-objects-api-server-internal | - | +| | @kbn/core-saved-objects-base-server-internal, @kbn/core-saved-objects-migration-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-ui-settings-server-internal, @kbn/core-usage-data-server-internal, taskManager, dataViews, spaces, actions, share, data, alerting, @kbn/core-saved-objects-migration-server-mocks, lens, cases, savedSearch, canvas, fleet, cloudSecurityPosture, ml, logsShared, graph, lists, maps, visualizations, infra, apmDataAccess, securitySolution, apm, slo, synthetics, uptime, dashboard, eventAnnotation, links, savedObjectsManagement, @kbn/core-test-helpers-so-type-serializer, @kbn/core-saved-objects-api-server-internal | - | | | stackAlerts, alerting, securitySolution, inputControlVis | - | | | graph, stackAlerts, inputControlVis, securitySolution | - | | | dataVisualizer, stackAlerts, expressionPartitionVis | - | @@ -33,8 +33,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | ruleRegistry, securitySolution, slo | - | | | security, actions, alerting, ruleRegistry, files, cases, fleet, securitySolution | - | | | alerting, securitySolution | - | -| | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, fleet, graph, lists, osquery, securitySolution, alerting | - | -| | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, fleet, graph, lists, osquery, securitySolution, alerting | - | +| | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-browser-mocks, fleet, graph, lists, osquery, securitySolution, alerting | - | +| | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-browser-mocks, fleet, graph, lists, osquery, securitySolution, alerting | - | | | alerting, securitySolution | - | | | securitySolution | - | | | cloudDefend, securitySolution, synthetics | - | @@ -46,10 +46,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/securitysolution-data-table, securitySolution | - | | | securitySolution | - | | | securitySolution | - | -| | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, fleet, graph, lists, osquery, securitySolution, alerting | - | -| | @kbn/core-saved-objects-common, @kbn/core-saved-objects-server, @kbn/core, actions, @kbn/alerting-types, alerting, savedSearch, canvas, enterpriseSearch, securitySolution, taskManager, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-server | - | -| | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, home, savedObjectsTagging, canvas, savedObjects, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-import-export-server-internal, savedObjectsTaggingOss, lists, securitySolution, upgradeAssistant, savedObjectsManagement, @kbn/core-ui-settings-server-internal | - | -| | @kbn/core-saved-objects-migration-server-internal, actions, dataViews, data, alerting, lens, cases, savedSearch, canvas, savedObjectsTagging, graph, lists, maps, visualizations, securitySolution, dashboard, @kbn/core-test-helpers-so-type-serializer | - | +| | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-browser-mocks, fleet, graph, lists, osquery, securitySolution, alerting | - | +| | @kbn/core-saved-objects-common, @kbn/core-saved-objects-server, @kbn/core, @kbn/alerting-types, alerting, actions, savedSearch, canvas, enterpriseSearch, securitySolution, taskManager, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-server | - | +| | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, home, savedObjectsTagging, canvas, savedObjects, savedObjectsTaggingOss, lists, securitySolution, upgradeAssistant, savedObjectsManagement, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-ui-settings-server-internal | - | +| | @kbn/core-saved-objects-migration-server-internal, dataViews, actions, data, alerting, lens, cases, savedSearch, canvas, savedObjectsTagging, graph, lists, maps, visualizations, securitySolution, dashboard, @kbn/core-test-helpers-so-type-serializer | - | | | @kbn/esql-utils, @kbn/securitysolution-utils, securitySolution | - | | | security, securitySolution, cloudLinks, cases | - | | | security, cases, searchPlayground, securitySolution | - | @@ -72,11 +72,11 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | monitoring | - | | | @kbn/core-saved-objects-api-browser, @kbn/core, savedObjectsManagement, savedObjects, visualizations, savedObjectsTagging, eventAnnotation, lens, maps, graph, dashboard, kibanaUtils, expressions, data, savedObjectsTaggingOss, embeddable, uiActionsEnhanced, canvas, dashboardEnhanced, globalSearchProviders, controls | - | | | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, home, savedObjects, visualizations, lens, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | -| | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, savedObjects | - | -| | @kbn/core-saved-objects-browser-mocks, home, @kbn/core-saved-objects-browser-internal | - | +| | @kbn/core-saved-objects-browser-internal, savedObjects, @kbn/core-saved-objects-browser-mocks | - | +| | home, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, visualizations | - | | | @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-browser-internal | - | -| | @kbn/core-saved-objects-browser-mocks, savedObjects, dashboardEnhanced, @kbn/core-saved-objects-browser-internal | - | +| | savedObjects, @kbn/core-saved-objects-browser-mocks, dashboardEnhanced, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-mocks, dashboardEnhanced, savedObjects, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-mocks, discover, @kbn/core-saved-objects-browser-internal | - | @@ -99,11 +99,11 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-browser-internal, @kbn/core | - | | | @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-lifecycle-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, visualizations, exploratoryView, transform, @kbn/core-saved-objects-browser-mocks | - | -| | @kbn/core-root-browser-internal, @kbn/core-saved-objects-browser-mocks | - | | | @kbn/core-saved-objects-api-server-internal | - | | | @kbn/core-saved-objects-api-server-internal | - | | | @kbn/core-saved-objects-api-server-internal, canvas | - | | | @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-migration-server-internal, spaces, data, savedSearch, cloudSecurityPosture, visualizations, dashboard, @kbn/core-test-helpers-so-type-serializer | - | +| | @kbn/core-root-browser-internal, @kbn/core-saved-objects-browser-mocks | - | | | fleet, exploratoryView, osquery, synthetics | - | | | graph, visTypeTimeseries, dataViewManagement, dataViews | - | | | graph, visTypeTimeseries, dataViewManagement, dataViews | - | @@ -126,10 +126,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | spaces, savedObjectsManagement | - | | | unifiedSearch | - | | | unifiedSearch | - | -| | lens, dashboard, canvas | - | +| | dashboard, lens, canvas | - | | | lens | - | | | lens, dashboard | - | -| | lens, dashboard, investigateApp | - | +| | dashboard, lens, investigateApp | - | | | @kbn/core, lens, savedObjects | - | | | canvas | - | | | canvas | - | @@ -156,7 +156,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | security | - | | | observabilityShared | - | | | @kbn/react-kibana-context-styled, kibanaReact | - | -| | discover, @kbn/reporting-public | - | +| | @kbn/reporting-public, discover | - | | | discover, @kbn/management-settings-field-definition | - | | | @kbn/content-management-table-list-view, filesManagement | - | | | @kbn/core | - | @@ -177,9 +177,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | spaces, security, actions, alerting, aiops, remoteClusters, ml, graph, indexLifecycleManagement, osquery, securitySolution, painlessLab, rollup, searchprofiler, snapshotRestore, transform, upgradeAssistant | 8.8.0 | | | fleet, apm, security, securitySolution | 8.8.0 | | | fleet, apm, security, securitySolution | 8.8.0 | -| | spaces, @kbn/security-authorization-core, security, alerting, cases, @kbn/security-role-management-model | 8.8.0 | -| | @kbn/core-application-browser-internal, @kbn/core-application-browser-mocks, management, fleet, security, kibanaOverview, @kbn/core | 8.8.0 | -| | embeddable, presentationUtil, lens, dashboard, discover, graph, links | 8.8.0 | +| | @kbn/security-authorization-core, spaces, security, alerting, cases, @kbn/security-role-management-model | 8.8.0 | +| | @kbn/core-application-browser-internal, management, @kbn/core-application-browser-mocks, fleet, security, kibanaOverview, @kbn/core | 8.8.0 | +| | embeddable, presentationUtil, dashboard, lens, discover, graph, links | 8.8.0 | | | security, @kbn/security-role-management-model | 8.8.0 | | | apm | 8.8.0 | | | @kbn/core-plugins-server-internal, @kbn/core | 8.8.0 | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 878a7a8bf9525..af47389ad65c1 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -16,7 +16,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes)+ 14 more | - | +| | [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes), [rule_types.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-alerting-types/rule_types.ts#:~:text=SavedObjectAttributes)+ 16 more | - | @@ -504,7 +504,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/plugin.ts#:~:text=license%24), [license_state.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/lib/license_state.test.ts#:~:text=license%24), [license_state.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/lib/license_state.test.ts#:~:text=license%24) | 8.8.0 | | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/plugin.ts#:~:text=authz) | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/plugin.ts#:~:text=index) | - | -| | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts#:~:text=SavedObjectAttributes), [update.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/update.ts#:~:text=SavedObjectAttributes), [update.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/update.ts#:~:text=SavedObjectAttributes), [update.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/update.ts#:~:text=SavedObjectAttributes), [actions_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/actions_client/actions_client.ts#:~:text=SavedObjectAttributes), [actions_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/actions_client/actions_client.ts#:~:text=SavedObjectAttributes), [actions_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/actions_client/actions_client.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/types.ts#:~:text=SavedObjectAttributes)+ 14 more | - | +| | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts#:~:text=SavedObjectAttributes), [update.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/update.ts#:~:text=SavedObjectAttributes), [update.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/update.ts#:~:text=SavedObjectAttributes), [update.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/application/connector/methods/update/update.ts#:~:text=SavedObjectAttributes), [actions_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/actions_client/actions_client.ts#:~:text=SavedObjectAttributes)+ 14 more | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/saved_objects/index.ts#:~:text=migrations), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/saved_objects/index.ts#:~:text=migrations) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/saved_objects/index.ts#:~:text=convertToMultiNamespaceTypeVersion), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/saved_objects/index.ts#:~:text=convertToMultiNamespaceTypeVersion) | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/plugin.ts#:~:text=audit), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/plugin.ts#:~:text=audit) | - | @@ -568,23 +568,23 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [es_data_view_select.component.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx#:~:text=title), [es_data_view_select.component.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx#:~:text=title), [es_data_view_select.component.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx#:~:text=title), [es_data_view_select.component.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx#:~:text=title), [es_data_view_select.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx#:~:text=title), [es_data_view_select.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx#:~:text=title), [data_views.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/kibana/data_views.ts#:~:text=title), [data_views.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/kibana/data_views.ts#:~:text=title), [datasource_component.js](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/datasource/datasource_component.js#:~:text=title) | - | +| | [datasource_component.js](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/datasource/datasource_component.js#:~:text=title) | - | | | [embeddable.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx#:~:text=EmbeddablePanel), [embeddable.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx#:~:text=EmbeddablePanel) | - | -| | [embeddable.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx#:~:text=getEmbeddableFactories), [embeddables.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/kibana/embeddables.ts#:~:text=getEmbeddableFactories) | - | -| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/demodata/index.ts#:~:text=context), [embeddable.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts#:~:text=context), [esdocs.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts#:~:text=context), [escount.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts#:~:text=context), [filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/common/functions/filters.ts#:~:text=context), [neq.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/neq.ts#:~:text=context), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts#:~:text=context) | - | +| | [embeddable.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx#:~:text=getEmbeddableFactories), [editor_menu.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx#:~:text=getEmbeddableFactories), [flyout.component.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx#:~:text=getEmbeddableFactories), [flyout.component.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx#:~:text=getEmbeddableFactories) | - | +| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/demodata/index.ts#:~:text=context), [embeddable.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts#:~:text=context), [escount.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts#:~:text=context), [esdocs.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts#:~:text=context), [filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/common/functions/filters.ts#:~:text=context), [neq.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/neq.ts#:~:text=context), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts#:~:text=context) | - | | | [setup_expressions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/setup_expressions.ts#:~:text=getFunction) | - | | | [functions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/functions/functions.ts#:~:text=getFunctions), [functions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/functions/functions.ts#:~:text=getFunctions), [functions.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/functions/functions.test.ts#:~:text=getFunctions) | - | | | [setup_expressions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/setup_expressions.ts#:~:text=getTypes), [application.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/application.tsx#:~:text=getTypes), [functions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/functions/functions.ts#:~:text=getTypes) | - | -| | [markdown.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/markdown.ts#:~:text=Render), [markdown.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/markdown.ts#:~:text=Render), [state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/types/state.ts#:~:text=Render), [state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/types/state.ts#:~:text=Render), [timefilterControl.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts#:~:text=Render), [timefilterControl.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts#:~:text=Render), [pie.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/functions/pie.ts#:~:text=Render), [pie.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/functions/pie.ts#:~:text=Render), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/functions/plot/index.ts#:~:text=Render), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/functions/plot/index.ts#:~:text=Render)+ 2 more | - | -| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/demodata/index.ts#:~:text=context), [embeddable.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts#:~:text=context), [esdocs.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts#:~:text=context), [escount.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts#:~:text=context), [filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/common/functions/filters.ts#:~:text=context), [neq.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/neq.ts#:~:text=context), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts#:~:text=context) | - | +| | [markdown.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/markdown.ts#:~:text=Render), [markdown.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/markdown.ts#:~:text=Render), [state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/types/state.ts#:~:text=Render), [state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/types/state.ts#:~:text=Render), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/functions/plot/index.ts#:~:text=Render), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/functions/plot/index.ts#:~:text=Render), [pie.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/functions/pie.ts#:~:text=Render), [pie.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/functions/pie.ts#:~:text=Render), [table.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/table.ts#:~:text=Render), [table.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/table.ts#:~:text=Render)+ 2 more | - | +| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/demodata/index.ts#:~:text=context), [embeddable.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts#:~:text=context), [escount.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts#:~:text=context), [esdocs.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts#:~:text=context), [filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/common/functions/filters.ts#:~:text=context), [neq.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/neq.ts#:~:text=context), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts#:~:text=context) | - | | | [setup_expressions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/setup_expressions.ts#:~:text=getFunction) | - | | | [functions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/functions/functions.ts#:~:text=getFunctions), [functions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/functions/functions.ts#:~:text=getFunctions), [functions.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/functions/functions.test.ts#:~:text=getFunctions) | - | | | [setup_expressions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/setup_expressions.ts#:~:text=getTypes), [application.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/application.tsx#:~:text=getTypes), [functions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/functions/functions.ts#:~:text=getTypes) | - | -| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/demodata/index.ts#:~:text=context), [embeddable.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts#:~:text=context), [esdocs.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts#:~:text=context), [escount.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts#:~:text=context), [filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/common/functions/filters.ts#:~:text=context), [neq.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/neq.ts#:~:text=context), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts#:~:text=context) | - | -| | [workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/workpad.ts#:~:text=ResolvedSimpleSavedObject), [workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/workpad.ts#:~:text=ResolvedSimpleSavedObject), [workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/workpad.ts#:~:text=ResolvedSimpleSavedObject), [workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/workpad.ts#:~:text=ResolvedSimpleSavedObject) | - | +| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/demodata/index.ts#:~:text=context), [embeddable.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts#:~:text=context), [escount.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts#:~:text=context), [esdocs.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts#:~:text=context), [filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/common/functions/filters.ts#:~:text=context), [neq.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/common/neq.ts#:~:text=context), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts#:~:text=context) | - | +| | [canvas_workpad_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts#:~:text=ResolvedSimpleSavedObject), [canvas_workpad_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts#:~:text=ResolvedSimpleSavedObject), [canvas_workpad_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts#:~:text=ResolvedSimpleSavedObject), [canvas_workpad_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts#:~:text=ResolvedSimpleSavedObject) | - | | | [workpad_route_context.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/workpad_route_context.ts#:~:text=migrationVersion) | - | | | [find.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/custom_elements/find.ts#:~:text=SavedObjectAttributes), [find.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/custom_elements/find.ts#:~:text=SavedObjectAttributes), [find.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/workpad/find.ts#:~:text=SavedObjectAttributes), [find.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/workpad/find.ts#:~:text=SavedObjectAttributes), [find.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/custom_elements/find.ts#:~:text=SavedObjectAttributes), [find.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/custom_elements/find.ts#:~:text=SavedObjectAttributes), [find.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/workpad/find.ts#:~:text=SavedObjectAttributes), [find.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/routes/workpad/find.ts#:~:text=SavedObjectAttributes) | - | -| | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/shareable_runtime/types.ts#:~:text=SavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/shareable_runtime/types.ts#:~:text=SavedObject), [workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/kibana/workpad.ts#:~:text=SavedObject), [workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/kibana/workpad.ts#:~:text=SavedObject), [use_upload_workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/home/hooks/use_upload_workpad.ts#:~:text=SavedObject), [use_upload_workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/home/hooks/use_upload_workpad.ts#:~:text=SavedObject) | - | +| | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/shareable_runtime/types.ts#:~:text=SavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/shareable_runtime/types.ts#:~:text=SavedObject), [canvas_workpad_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts#:~:text=SavedObject), [canvas_workpad_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts#:~:text=SavedObject), [use_upload_workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/home/hooks/use_upload_workpad.ts#:~:text=SavedObject), [use_upload_workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/public/components/home/hooks/use_upload_workpad.ts#:~:text=SavedObject) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/shareable_runtime/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/shareable_runtime/types.ts#:~:text=SavedObjectAttributes) | - | | | [saved_lens.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts#:~:text=SavedObjectReference), [saved_lens.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts#:~:text=SavedObjectReference), [saved_map.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts#:~:text=SavedObjectReference), [saved_map.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts#:~:text=SavedObjectReference), [saved_search.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_search.ts#:~:text=SavedObjectReference), [saved_search.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_search.ts#:~:text=SavedObjectReference), [saved_visualization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts#:~:text=SavedObjectReference), [saved_visualization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts#:~:text=SavedObjectReference), [embeddable.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts#:~:text=SavedObjectReference), [embeddable.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts#:~:text=SavedObjectReference) | - | | | [workpad.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/saved_objects/workpad.ts#:~:text=migrations), [custom_element.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/saved_objects/custom_element.ts#:~:text=migrations), [workpad_template.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/canvas/server/saved_objects/workpad_template.ts#:~:text=migrations) | - | @@ -1186,7 +1186,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [data_views.story.ts](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_util/public/services/data_views/data_views.story.ts#:~:text=title) | - | | | [saved_object_save_modal_dashboard.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard.tsx#:~:text=SavedObjectSaveModal), [saved_object_save_modal_dashboard.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 6b482b4ed1327..fd2b3a4cacc4d 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -61,7 +61,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Plugin | Deprecated API | Reference location(s) | Remove By | | --------|-------|-----------|-----------| -| presentationUtil | | [saved_object_save_modal_dashboard.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard.tsx#:~:text=SavedObjectSaveModal), [saved_object_save_modal_dashboard.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard.tsx#:~:text=SavedObjectSaveModal), [save_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx#:~:text=SavedObjectSaveModal), [save_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx#:~:text=SavedObjectSaveModal), [add_to_library_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx#:~:text=SavedObjectSaveModal), [add_to_library_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx#:~:text=SavedObjectSaveModal), [attribute_service.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx#:~:text=SavedObjectSaveModal), [attribute_service.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx#:~:text=SavedObjectSaveModal), [save_to_library.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/links/public/content_management/save_to_library.tsx#:~:text=SavedObjectSaveModal), [save_to_library.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/links/public/content_management/save_to_library.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | +| dashboard | | [save_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx#:~:text=SavedObjectSaveModal), [save_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx#:~:text=SavedObjectSaveModal), [add_to_library_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx#:~:text=SavedObjectSaveModal), [add_to_library_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx#:~:text=SavedObjectSaveModal), [attribute_service.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx#:~:text=SavedObjectSaveModal), [attribute_service.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx#:~:text=SavedObjectSaveModal), [saved_object_save_modal_dashboard.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard.tsx#:~:text=SavedObjectSaveModal), [saved_object_save_modal_dashboard.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard.tsx#:~:text=SavedObjectSaveModal), [save_to_library.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/links/public/content_management/save_to_library.tsx#:~:text=SavedObjectSaveModal), [save_to_library.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/links/public/content_management/save_to_library.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | @@ -77,7 +77,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ This is relied on by the reporting feature, and should be removed once reporting migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/issues/19914 | -| security | | [app_authorization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.ts#:~:text=getKibanaFeatures), [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getKibanaFeatures), [app_authorization.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.test.ts#:~:text=getKibanaFeatures), [on_post_auth_interceptor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts#:~:text=getKibanaFeatures), [spaces_usage_collector.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts#:~:text=getKibanaFeatures), [on_post_auth_interceptor.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts#:~:text=getKibanaFeatures), [privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts#:~:text=getKibanaFeatures)+ 28 more | 8.8.0 | +| security | | [app_authorization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.ts#:~:text=getKibanaFeatures), [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getKibanaFeatures), [app_authorization.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.test.ts#:~:text=getKibanaFeatures), [privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts#:~:text=getKibanaFeatures)+ 28 more | 8.8.0 | | security | | [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getElasticsearchFeatures), [kibana_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/packages/security/role_management_model/src/__fixtures__/kibana_privileges.ts#:~:text=getElasticsearchFeatures) | 8.8.0 | | security | | [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode) | 8.8.0 | | security | | [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/plugin.tsx#:~:text=license%24) | 8.8.0 | diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index ef39c15e05e3e..4f4414f69f174 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 62333cddd8d1e..761a3f0cf886d 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index de56f62a995fe..11c68abc6199c 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/discover_shared.mdx b/api_docs/discover_shared.mdx index b0bf17be9c134..46a85446b85e4 100644 --- a/api_docs/discover_shared.mdx +++ b/api_docs/discover_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverShared title: "discoverShared" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverShared plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverShared'] --- import discoverSharedObj from './discover_shared.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index c83da6b3334ca..93fa675ee3d27 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index 358c368ca8c3d..f9bbe3e465a16 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.devdocs.json b/api_docs/embeddable.devdocs.json index 24eebae51a423..ed1847f098c98 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -7998,14 +7998,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx" - }, - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx" - }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx" @@ -8014,6 +8006,14 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx" }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx" + }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx" @@ -14870,10 +14870,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx" - }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/services/dashboard_content_management_service/lib/migrate_dashboard_input.ts" @@ -14890,6 +14886,10 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx" }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx" + }, { "plugin": "investigateApp", "path": "x-pack/plugins/observability_solution/investigate_app/public/items/embeddable_item/register_embeddable_item.tsx" @@ -15024,7 +15024,15 @@ }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/services/kibana/embeddables.ts" + "path": "x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx" + }, + { + "plugin": "canvas", + "path": "x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx" + }, + { + "plugin": "canvas", + "path": "x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx" } ], "children": [], diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index ada614981c1b6..e34a6b22f25ff 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 6a0a910489b2c..a752bea1fac17 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index c87fd2b4ef416..5ae1e37e9195e 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index 43f34481f6834..df9ac5a7b9bb2 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/entities_data_access.mdx b/api_docs/entities_data_access.mdx index 5eed0f6eceae6..2ffa3675e4d1b 100644 --- a/api_docs/entities_data_access.mdx +++ b/api_docs/entities_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entitiesDataAccess title: "entitiesDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the entitiesDataAccess plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entitiesDataAccess'] --- import entitiesDataAccessObj from './entities_data_access.devdocs.json'; diff --git a/api_docs/entity_manager.devdocs.json b/api_docs/entity_manager.devdocs.json index 0e10719557be2..c8bccd03386d1 100644 --- a/api_docs/entity_manager.devdocs.json +++ b/api_docs/entity_manager.devdocs.json @@ -307,7 +307,7 @@ "section": "def-common.BasicAggregations", "text": "BasicAggregations" }, - "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; identityFields?: (string | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; } | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { installOnly: boolean; }; body: { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; history?: { interval?: string | undefined; settings?: { lookbackPeriod: string; frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; backfillSyncDelay?: string | undefined; backfillLookbackPeriod?: string | undefined; backfillFrequency?: string | undefined; } | undefined; timestampField?: string | undefined; } | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; identityFields?: (string | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; } | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { installOnly: boolean; }; path: { id: string; }; body: { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; history?: { interval?: string | undefined; settings?: { lookbackPeriod: string; frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; backfillSyncDelay?: string | undefined; backfillLookbackPeriod?: string | undefined; backfillFrequency?: string | undefined; } | undefined; timestampField?: string | undefined; } | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", { "pluginId": "@kbn/entities-schema", "scope": "common", @@ -315,7 +315,7 @@ "section": "def-common.BasicAggregations", "text": "BasicAggregations" }, - "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; }; })[] | undefined; identityFields?: ({ field: string; optional: boolean; } | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; } | undefined; }; path: { id: string; }; }, { query: { installOnly?: boolean | \"true\" | \"false\" | undefined; }; body: { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; history?: { interval?: string | undefined; settings?: { frequency?: string | undefined; lookbackPeriod?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; backfillSyncDelay?: string | undefined; backfillLookbackPeriod?: string | undefined; backfillFrequency?: string | undefined; } | undefined; timestampField?: string | undefined; } | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; }; })[] | undefined; identityFields?: ({ field: string; optional: boolean; } | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; } | undefined; }; }, { query: { installOnly?: boolean | \"true\" | \"false\" | undefined; }; path: { id: string; }; body: { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; history?: { interval?: string | undefined; settings?: { frequency?: string | undefined; lookbackPeriod?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; backfillSyncDelay?: string | undefined; backfillLookbackPeriod?: string | undefined; backfillFrequency?: string | undefined; } | undefined; timestampField?: string | undefined; } | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", { "pluginId": "@kbn/entities-schema", "scope": "common", @@ -323,7 +323,7 @@ "section": "def-common.BasicAggregations", "text": "BasicAggregations" }, - "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; identityFields?: (string | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; } | undefined; }; path: { id: string; }; }>, ", + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; identityFields?: (string | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; } | undefined; }; }>, ", "EntityManagerRouteHandlerResources", ", ", { diff --git a/api_docs/entity_manager.mdx b/api_docs/entity_manager.mdx index 8227508654f51..7e5e1c090ca6c 100644 --- a/api_docs/entity_manager.mdx +++ b/api_docs/entity_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entityManager title: "entityManager" image: https://source.unsplash.com/400x175/?github description: API docs for the entityManager plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entityManager'] --- import entityManagerObj from './entity_manager.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index b55d9377d4226..d08c317f55f7e 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/esql.mdx b/api_docs/esql.mdx index c409fdd302db3..65fa4243a04fd 100644 --- a/api_docs/esql.mdx +++ b/api_docs/esql.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esql title: "esql" image: https://source.unsplash.com/400x175/?github description: API docs for the esql plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esql'] --- import esqlObj from './esql.devdocs.json'; diff --git a/api_docs/esql_data_grid.mdx b/api_docs/esql_data_grid.mdx index b5b48fa0f9c83..c909a0e6c06be 100644 --- a/api_docs/esql_data_grid.mdx +++ b/api_docs/esql_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esqlDataGrid title: "esqlDataGrid" image: https://source.unsplash.com/400x175/?github description: API docs for the esqlDataGrid plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esqlDataGrid'] --- import esqlDataGridObj from './esql_data_grid.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index e198280077747..2b4bde4ef6d0f 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index 39d69eaffdc7e..5d7004a1636ce 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.devdocs.json b/api_docs/event_log.devdocs.json index 8e12d781ee276..38cb6edc47b4d 100644 --- a/api_docs/event_log.devdocs.json +++ b/api_docs/event_log.devdocs.json @@ -1514,7 +1514,7 @@ "label": "data", "description": [], "signature": [ - "(Readonly<{ log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; error?: Readonly<{ id?: string | undefined; type?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; message?: string | undefined; tags?: string[] | undefined; rule?: Readonly<{ id?: string | undefined; version?: string | undefined; name?: string | undefined; license?: string | undefined; description?: string | undefined; uuid?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; } & {}> | undefined; kibana?: Readonly<{ task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; action?: Readonly<{ id?: string | undefined; name?: string | undefined; execution?: Readonly<{ source?: string | undefined; uuid?: string | undefined; gen_ai?: Readonly<{ usage?: Readonly<{ prompt_tokens?: string | number | undefined; completion_tokens?: string | number | undefined; total_tokens?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; usage?: Readonly<{ request_body_bytes?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; type_id?: string | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ outcome?: string | undefined; status?: string | undefined; summary?: Readonly<{ recovered?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; new?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; ongoing?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; revision?: string | number | undefined; execution?: Readonly<{ uuid?: string | undefined; status?: string | undefined; metrics?: Readonly<{ total_search_duration_ms?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_delayed_alerts?: string | number | undefined; number_of_searches?: string | number | undefined; es_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; persist_alerts_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; status_order?: string | number | undefined; backfill?: Readonly<{ id?: string | undefined; start?: string | undefined; interval?: string | undefined; } & {}> | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; flapping?: boolean | undefined; uuid?: string | undefined; maintenance_window_ids?: string[] | undefined; } & {}> | undefined; space_ids?: string[] | undefined; server_uuid?: string | undefined; saved_objects?: Readonly<{ id?: string | undefined; type?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; space_agnostic?: boolean | undefined; } & {}>[] | undefined; } & {}> | undefined; event?: Readonly<{ id?: string | undefined; type?: string[] | undefined; reason?: string | undefined; action?: string | undefined; start?: string | undefined; end?: string | undefined; outcome?: string | undefined; duration?: string | number | undefined; severity?: string | number | undefined; category?: string[] | undefined; timezone?: string | undefined; risk_score?: number | undefined; code?: string | undefined; url?: string | undefined; created?: string | undefined; provider?: string | undefined; dataset?: string | undefined; hash?: string | undefined; ingested?: string | undefined; kind?: string | undefined; module?: string | undefined; original?: string | undefined; reference?: string | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; user?: Readonly<{ id?: string | undefined; name?: string | undefined; } & {}> | undefined; } & {}> | undefined)[]" + "(Readonly<{ log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; error?: Readonly<{ id?: string | undefined; type?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; message?: string | undefined; tags?: string[] | undefined; rule?: Readonly<{ id?: string | undefined; version?: string | undefined; name?: string | undefined; license?: string | undefined; description?: string | undefined; uuid?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; } & {}> | undefined; kibana?: Readonly<{ task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; action?: Readonly<{ id?: string | undefined; name?: string | undefined; execution?: Readonly<{ source?: string | undefined; uuid?: string | undefined; gen_ai?: Readonly<{ usage?: Readonly<{ prompt_tokens?: string | number | undefined; completion_tokens?: string | number | undefined; total_tokens?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; usage?: Readonly<{ request_body_bytes?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; type_id?: string | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ outcome?: string | undefined; status?: string | undefined; summary?: Readonly<{ recovered?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; new?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; ongoing?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; revision?: string | number | undefined; execution?: Readonly<{ uuid?: string | undefined; status?: string | undefined; metrics?: Readonly<{ total_search_duration_ms?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_delayed_alerts?: string | number | undefined; number_of_searches?: string | number | undefined; es_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; persist_alerts_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; status_order?: string | number | undefined; backfill?: Readonly<{ id?: string | undefined; start?: string | undefined; interval?: string | undefined; } & {}> | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; flapping?: boolean | undefined; uuid?: string | undefined; maintenance_window_ids?: string[] | undefined; } & {}> | undefined; space_ids?: string[] | undefined; server_uuid?: string | undefined; saved_objects?: Readonly<{ id?: string | undefined; type?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; space_agnostic?: boolean | undefined; } & {}>[] | undefined; } & {}> | undefined; event?: Readonly<{ id?: string | undefined; type?: string[] | undefined; reason?: string | undefined; action?: string | undefined; start?: string | undefined; end?: string | undefined; outcome?: string | undefined; duration?: string | number | undefined; code?: string | undefined; severity?: string | number | undefined; category?: string[] | undefined; timezone?: string | undefined; risk_score?: number | undefined; url?: string | undefined; created?: string | undefined; provider?: string | undefined; dataset?: string | undefined; hash?: string | undefined; ingested?: string | undefined; kind?: string | undefined; module?: string | undefined; original?: string | undefined; reference?: string | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; user?: Readonly<{ id?: string | undefined; name?: string | undefined; } & {}> | undefined; } & {}> | undefined)[]" ], "path": "x-pack/plugins/event_log/server/es/cluster_client_adapter.ts", "deprecated": false, @@ -1534,7 +1534,7 @@ "label": "IEvent", "description": [], "signature": [ - "DeepPartial | undefined; error?: Readonly<{ id?: string | undefined; type?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; message?: string | undefined; tags?: string[] | undefined; rule?: Readonly<{ id?: string | undefined; version?: string | undefined; name?: string | undefined; license?: string | undefined; description?: string | undefined; uuid?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; } & {}> | undefined; kibana?: Readonly<{ task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; action?: Readonly<{ id?: string | undefined; name?: string | undefined; execution?: Readonly<{ source?: string | undefined; uuid?: string | undefined; gen_ai?: Readonly<{ usage?: Readonly<{ prompt_tokens?: string | number | undefined; completion_tokens?: string | number | undefined; total_tokens?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; usage?: Readonly<{ request_body_bytes?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; type_id?: string | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ outcome?: string | undefined; status?: string | undefined; summary?: Readonly<{ recovered?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; new?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; ongoing?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; revision?: string | number | undefined; execution?: Readonly<{ uuid?: string | undefined; status?: string | undefined; metrics?: Readonly<{ total_search_duration_ms?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_delayed_alerts?: string | number | undefined; number_of_searches?: string | number | undefined; es_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; persist_alerts_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; status_order?: string | number | undefined; backfill?: Readonly<{ id?: string | undefined; start?: string | undefined; interval?: string | undefined; } & {}> | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; flapping?: boolean | undefined; uuid?: string | undefined; maintenance_window_ids?: string[] | undefined; } & {}> | undefined; space_ids?: string[] | undefined; server_uuid?: string | undefined; saved_objects?: Readonly<{ id?: string | undefined; type?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; space_agnostic?: boolean | undefined; } & {}>[] | undefined; } & {}> | undefined; event?: Readonly<{ id?: string | undefined; type?: string[] | undefined; reason?: string | undefined; action?: string | undefined; start?: string | undefined; end?: string | undefined; outcome?: string | undefined; duration?: string | number | undefined; severity?: string | number | undefined; category?: string[] | undefined; timezone?: string | undefined; risk_score?: number | undefined; code?: string | undefined; url?: string | undefined; created?: string | undefined; provider?: string | undefined; dataset?: string | undefined; hash?: string | undefined; ingested?: string | undefined; kind?: string | undefined; module?: string | undefined; original?: string | undefined; reference?: string | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; user?: Readonly<{ id?: string | undefined; name?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" + "DeepPartial | undefined; error?: Readonly<{ id?: string | undefined; type?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; message?: string | undefined; tags?: string[] | undefined; rule?: Readonly<{ id?: string | undefined; version?: string | undefined; name?: string | undefined; license?: string | undefined; description?: string | undefined; uuid?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; } & {}> | undefined; kibana?: Readonly<{ task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; action?: Readonly<{ id?: string | undefined; name?: string | undefined; execution?: Readonly<{ source?: string | undefined; uuid?: string | undefined; gen_ai?: Readonly<{ usage?: Readonly<{ prompt_tokens?: string | number | undefined; completion_tokens?: string | number | undefined; total_tokens?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; usage?: Readonly<{ request_body_bytes?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; type_id?: string | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ outcome?: string | undefined; status?: string | undefined; summary?: Readonly<{ recovered?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; new?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; ongoing?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; revision?: string | number | undefined; execution?: Readonly<{ uuid?: string | undefined; status?: string | undefined; metrics?: Readonly<{ total_search_duration_ms?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_delayed_alerts?: string | number | undefined; number_of_searches?: string | number | undefined; es_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; persist_alerts_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; status_order?: string | number | undefined; backfill?: Readonly<{ id?: string | undefined; start?: string | undefined; interval?: string | undefined; } & {}> | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; flapping?: boolean | undefined; uuid?: string | undefined; maintenance_window_ids?: string[] | undefined; } & {}> | undefined; space_ids?: string[] | undefined; server_uuid?: string | undefined; saved_objects?: Readonly<{ id?: string | undefined; type?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; space_agnostic?: boolean | undefined; } & {}>[] | undefined; } & {}> | undefined; event?: Readonly<{ id?: string | undefined; type?: string[] | undefined; reason?: string | undefined; action?: string | undefined; start?: string | undefined; end?: string | undefined; outcome?: string | undefined; duration?: string | number | undefined; code?: string | undefined; severity?: string | number | undefined; category?: string[] | undefined; timezone?: string | undefined; risk_score?: number | undefined; url?: string | undefined; created?: string | undefined; provider?: string | undefined; dataset?: string | undefined; hash?: string | undefined; ingested?: string | undefined; kind?: string | undefined; module?: string | undefined; original?: string | undefined; reference?: string | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; user?: Readonly<{ id?: string | undefined; name?: string | undefined; } & {}> | undefined; } & {}>>> | undefined" ], "path": "x-pack/plugins/event_log/generated/schemas.ts", "deprecated": false, @@ -1549,7 +1549,7 @@ "label": "IValidatedEvent", "description": [], "signature": [ - "Readonly<{ log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; error?: Readonly<{ id?: string | undefined; type?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; message?: string | undefined; tags?: string[] | undefined; rule?: Readonly<{ id?: string | undefined; version?: string | undefined; name?: string | undefined; license?: string | undefined; description?: string | undefined; uuid?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; } & {}> | undefined; kibana?: Readonly<{ task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; action?: Readonly<{ id?: string | undefined; name?: string | undefined; execution?: Readonly<{ source?: string | undefined; uuid?: string | undefined; gen_ai?: Readonly<{ usage?: Readonly<{ prompt_tokens?: string | number | undefined; completion_tokens?: string | number | undefined; total_tokens?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; usage?: Readonly<{ request_body_bytes?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; type_id?: string | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ outcome?: string | undefined; status?: string | undefined; summary?: Readonly<{ recovered?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; new?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; ongoing?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; revision?: string | number | undefined; execution?: Readonly<{ uuid?: string | undefined; status?: string | undefined; metrics?: Readonly<{ total_search_duration_ms?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_delayed_alerts?: string | number | undefined; number_of_searches?: string | number | undefined; es_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; persist_alerts_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; status_order?: string | number | undefined; backfill?: Readonly<{ id?: string | undefined; start?: string | undefined; interval?: string | undefined; } & {}> | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; flapping?: boolean | undefined; uuid?: string | undefined; maintenance_window_ids?: string[] | undefined; } & {}> | undefined; space_ids?: string[] | undefined; server_uuid?: string | undefined; saved_objects?: Readonly<{ id?: string | undefined; type?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; space_agnostic?: boolean | undefined; } & {}>[] | undefined; } & {}> | undefined; event?: Readonly<{ id?: string | undefined; type?: string[] | undefined; reason?: string | undefined; action?: string | undefined; start?: string | undefined; end?: string | undefined; outcome?: string | undefined; duration?: string | number | undefined; severity?: string | number | undefined; category?: string[] | undefined; timezone?: string | undefined; risk_score?: number | undefined; code?: string | undefined; url?: string | undefined; created?: string | undefined; provider?: string | undefined; dataset?: string | undefined; hash?: string | undefined; ingested?: string | undefined; kind?: string | undefined; module?: string | undefined; original?: string | undefined; reference?: string | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; user?: Readonly<{ id?: string | undefined; name?: string | undefined; } & {}> | undefined; } & {}> | undefined" + "Readonly<{ log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; error?: Readonly<{ id?: string | undefined; type?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; message?: string | undefined; tags?: string[] | undefined; rule?: Readonly<{ id?: string | undefined; version?: string | undefined; name?: string | undefined; license?: string | undefined; description?: string | undefined; uuid?: string | undefined; category?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; } & {}> | undefined; kibana?: Readonly<{ task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; action?: Readonly<{ id?: string | undefined; name?: string | undefined; execution?: Readonly<{ source?: string | undefined; uuid?: string | undefined; gen_ai?: Readonly<{ usage?: Readonly<{ prompt_tokens?: string | number | undefined; completion_tokens?: string | number | undefined; total_tokens?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; usage?: Readonly<{ request_body_bytes?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; type_id?: string | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ outcome?: string | undefined; status?: string | undefined; summary?: Readonly<{ recovered?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; new?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; ongoing?: Readonly<{ count?: string | number | undefined; } & {}> | undefined; } & {}> | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; revision?: string | number | undefined; execution?: Readonly<{ uuid?: string | undefined; status?: string | undefined; metrics?: Readonly<{ total_search_duration_ms?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_delayed_alerts?: string | number | undefined; number_of_searches?: string | number | undefined; es_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; persist_alerts_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; status_order?: string | number | undefined; backfill?: Readonly<{ id?: string | undefined; start?: string | undefined; interval?: string | undefined; } & {}> | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; flapping?: boolean | undefined; uuid?: string | undefined; maintenance_window_ids?: string[] | undefined; } & {}> | undefined; space_ids?: string[] | undefined; server_uuid?: string | undefined; saved_objects?: Readonly<{ id?: string | undefined; type?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; space_agnostic?: boolean | undefined; } & {}>[] | undefined; } & {}> | undefined; event?: Readonly<{ id?: string | undefined; type?: string[] | undefined; reason?: string | undefined; action?: string | undefined; start?: string | undefined; end?: string | undefined; outcome?: string | undefined; duration?: string | number | undefined; code?: string | undefined; severity?: string | number | undefined; category?: string[] | undefined; timezone?: string | undefined; risk_score?: number | undefined; url?: string | undefined; created?: string | undefined; provider?: string | undefined; dataset?: string | undefined; hash?: string | undefined; ingested?: string | undefined; kind?: string | undefined; module?: string | undefined; original?: string | undefined; reference?: string | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; user?: Readonly<{ id?: string | undefined; name?: string | undefined; } & {}> | undefined; } & {}> | undefined" ], "path": "x-pack/plugins/event_log/generated/schemas.ts", "deprecated": false, diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 86da9f38d942a..5d33ca423031c 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/exploratory_view.mdx b/api_docs/exploratory_view.mdx index 912ffc107ab33..5956bdff5b5f1 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'exploratoryView'] --- import exploratoryViewObj from './exploratory_view.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index d99b6c04ae5b2..ef1d704e373cd 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 2975dabc9b0b8..3637e9106041f 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index c556383155dbb..9f88b27fb0c8c 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index 6803a402ce8f0..e201523d2d5e8 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index 0258c6caa1ff0..6f84680f2891e 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index b59c61eb15074..f1f6d3a3ffdb4 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index 5b6a1ff7afaa7..c6ed70180e15c 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index 58bb74fe1d9f7..1a75daeb62df7 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index ef205d5afe49b..7f881354d2e5b 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index e7c8a560eb607..8414afedf5403 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index 6324c58a92a83..ae079fb6b79f0 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index c152e4942c170..218df5f03acf7 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index e8c3c3c361e55..c813c17a32a8b 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.devdocs.json b/api_docs/expressions.devdocs.json index a04af6f32581d..1cd17f4880a56 100644 --- a/api_docs/expressions.devdocs.json +++ b/api_docs/expressions.devdocs.json @@ -8634,11 +8634,11 @@ }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts" }, { "plugin": "canvas", @@ -20111,11 +20111,11 @@ }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts" }, { "plugin": "canvas", @@ -33138,11 +33138,11 @@ }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts" }, { "plugin": "canvas", @@ -38171,11 +38171,11 @@ }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts" + "path": "x-pack/plugins/canvas/public/functions/plot/index.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts" + "path": "x-pack/plugins/canvas/public/functions/plot/index.ts" }, { "plugin": "canvas", @@ -38187,19 +38187,19 @@ }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/functions/plot/index.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/common/table.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/functions/plot/index.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/common/table.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/common/table.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/common/table.ts" + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts" } ], "initialIsOpen": false @@ -39704,9 +39704,7 @@ "section": "def-common.SerializedDatatable", "text": "SerializedDatatable" }, - ") => { rows: ", - "Dictionary", - "[]; type: \"datatable\"; columns: ", + ") => { rows: _.Dictionary[]; type: \"datatable\"; columns: ", { "pluginId": "expressions", "scope": "common", diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index fc4914a444f74..8117425cd8381 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.devdocs.json b/api_docs/features.devdocs.json index 3013013b1bfb8..4a3b4f0fcc0eb 100644 --- a/api_docs/features.devdocs.json +++ b/api_docs/features.devdocs.json @@ -2194,6 +2194,10 @@ "removeBy": "8.8.0", "trackAdoption": false, "references": [ + { + "plugin": "@kbn/security-authorization-core", + "path": "x-pack/packages/security/authorization_core/src/privileges/privileges.ts" + }, { "plugin": "spaces", "path": "x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts" @@ -2202,10 +2206,6 @@ "plugin": "spaces", "path": "x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts" }, - { - "plugin": "@kbn/security-authorization-core", - "path": "x-pack/packages/security/authorization_core/src/privileges/privileges.ts" - }, { "plugin": "security", "path": "x-pack/plugins/security/server/authorization/app_authorization.ts" diff --git a/api_docs/features.mdx b/api_docs/features.mdx index d8076d6fe5b3a..41049f1fcff45 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index 104f4c044e017..c582ab9558032 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/fields_metadata.mdx b/api_docs/fields_metadata.mdx index a373c2a5d8fdf..538b4363bb452 100644 --- a/api_docs/fields_metadata.mdx +++ b/api_docs/fields_metadata.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldsMetadata title: "fieldsMetadata" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldsMetadata plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldsMetadata'] --- import fieldsMetadataObj from './fields_metadata.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index b0ce0fdc56e92..98b11140dd1ec 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 4cc9d6287dd89..3433713b3a1de 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index de391c1dce668..31bf65cbf2408 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index 9cd1c9f1a3b7f..d65f90a169b4c 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -2393,6 +2393,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "fleet", + "id": "def-public.PackageListGridProps.calloutTopSpacerSize", + "type": "CompoundType", + "tags": [], + "label": "calloutTopSpacerSize", + "description": [], + "signature": [ + "\"m\" | \"s\" | \"l\" | \"xs\" | \"xl\" | \"xxl\" | undefined" + ], + "path": "x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/index.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "fleet", "id": "def-public.PackageListGridProps.showCardLabels", @@ -2530,6 +2544,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "fleet", + "id": "def-public.PackageListGridProps.sortByFeaturedIntegrations", + "type": "CompoundType", + "tags": [], + "label": "sortByFeaturedIntegrations", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/index.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "fleet", "id": "def-public.PackageListGridProps.spacer", @@ -28533,7 +28561,7 @@ "label": "RegistrySearchResult", "description": [], "signature": [ - "{ type?: \"input\" | \"integration\" | undefined; version: string; name: string; title: string; description?: string | undefined; internal?: boolean | undefined; path?: string | undefined; download?: string | undefined; icons?: (", + "{ type?: \"input\" | \"integration\" | undefined; version: string; name: string; title: string; description?: string | undefined; path?: string | undefined; internal?: boolean | undefined; download?: string | undefined; icons?: (", { "pluginId": "fleet", "scope": "common", diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 229cd1972087a..fb8082d46d45b 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1410 | 5 | 1287 | 74 | +| 1412 | 5 | 1289 | 74 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index f9ad8d1ec1504..c05b5e1854725 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index 72d23f89719f7..a072b79315fad 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.devdocs.json b/api_docs/home.devdocs.json index 1b22af8001d6b..1a5701a17b4f3 100644 --- a/api_docs/home.devdocs.json +++ b/api_docs/home.devdocs.json @@ -1810,7 +1810,7 @@ "label": "ArtifactsSchema", "description": [], "signature": [ - "{ readonly application?: Readonly<{} & { label: string; path: string; }> | undefined; readonly exportedFields?: Readonly<{} & { documentationUrl: string; }> | undefined; readonly dashboards: Readonly<{ linkLabel?: string | undefined; } & { id: string; isOverview: boolean; }>[]; }" + "{ readonly application?: Readonly<{} & { path: string; label: string; }> | undefined; readonly exportedFields?: Readonly<{} & { documentationUrl: string; }> | undefined; readonly dashboards: Readonly<{ linkLabel?: string | undefined; } & { id: string; isOverview: boolean; }>[]; }" ], "path": "src/plugins/home/server/services/tutorials/lib/tutorial_schema.ts", "deprecated": false, @@ -1984,7 +1984,7 @@ "section": "def-server.TutorialContext", "text": "TutorialContext" }, - ") => Readonly<{ artifacts?: Readonly<{ application?: Readonly<{} & { label: string; path: string; }> | undefined; exportedFields?: Readonly<{} & { documentationUrl: string; }> | undefined; } & { dashboards: Readonly<{ linkLabel?: string | undefined; } & { id: string; isOverview: boolean; }>[]; }> | undefined; savedObjects?: any[] | undefined; euiIconType?: string | undefined; isBeta?: boolean | undefined; previewImagePath?: string | undefined; moduleName?: string | undefined; completionTimeMinutes?: number | undefined; elasticCloud?: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }> | undefined; onPremElasticCloud?: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }> | undefined; savedObjectsInstallMsg?: string | undefined; customStatusCheckName?: string | undefined; integrationBrowserCategories?: string[] | undefined; eprPackageOverlap?: string | undefined; } & { id: string; name: string; category: \"security\" | \"metrics\" | \"other\" | \"logging\"; shortDescription: string; longDescription: string; onPrem: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }>; }>" + ") => Readonly<{ artifacts?: Readonly<{ application?: Readonly<{} & { path: string; label: string; }> | undefined; exportedFields?: Readonly<{} & { documentationUrl: string; }> | undefined; } & { dashboards: Readonly<{ linkLabel?: string | undefined; } & { id: string; isOverview: boolean; }>[]; }> | undefined; savedObjects?: any[] | undefined; euiIconType?: string | undefined; isBeta?: boolean | undefined; previewImagePath?: string | undefined; moduleName?: string | undefined; completionTimeMinutes?: number | undefined; elasticCloud?: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }> | undefined; onPremElasticCloud?: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }> | undefined; savedObjectsInstallMsg?: string | undefined; customStatusCheckName?: string | undefined; integrationBrowserCategories?: string[] | undefined; eprPackageOverlap?: string | undefined; } & { id: string; name: string; category: \"security\" | \"metrics\" | \"other\" | \"logging\"; shortDescription: string; longDescription: string; onPrem: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }>; }>" ], "path": "src/plugins/home/server/services/tutorials/lib/tutorials_registry_types.ts", "deprecated": false, @@ -2022,7 +2022,7 @@ "label": "TutorialSchema", "description": [], "signature": [ - "{ readonly artifacts?: Readonly<{ application?: Readonly<{} & { label: string; path: string; }> | undefined; exportedFields?: Readonly<{} & { documentationUrl: string; }> | undefined; } & { dashboards: Readonly<{ linkLabel?: string | undefined; } & { id: string; isOverview: boolean; }>[]; }> | undefined; readonly savedObjects?: any[] | undefined; readonly euiIconType?: string | undefined; readonly isBeta?: boolean | undefined; readonly previewImagePath?: string | undefined; readonly moduleName?: string | undefined; readonly completionTimeMinutes?: number | undefined; readonly elasticCloud?: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }> | undefined; readonly onPremElasticCloud?: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }> | undefined; readonly savedObjectsInstallMsg?: string | undefined; readonly customStatusCheckName?: string | undefined; readonly integrationBrowserCategories?: string[] | undefined; readonly eprPackageOverlap?: string | undefined; readonly id: string; readonly name: string; readonly category: \"security\" | \"metrics\" | \"other\" | \"logging\"; readonly shortDescription: string; readonly longDescription: string; readonly onPrem: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }>; }" + "{ readonly artifacts?: Readonly<{ application?: Readonly<{} & { path: string; label: string; }> | undefined; exportedFields?: Readonly<{} & { documentationUrl: string; }> | undefined; } & { dashboards: Readonly<{ linkLabel?: string | undefined; } & { id: string; isOverview: boolean; }>[]; }> | undefined; readonly savedObjects?: any[] | undefined; readonly euiIconType?: string | undefined; readonly isBeta?: boolean | undefined; readonly previewImagePath?: string | undefined; readonly moduleName?: string | undefined; readonly completionTimeMinutes?: number | undefined; readonly elasticCloud?: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }> | undefined; readonly onPremElasticCloud?: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }> | undefined; readonly savedObjectsInstallMsg?: string | undefined; readonly customStatusCheckName?: string | undefined; readonly integrationBrowserCategories?: string[] | undefined; readonly eprPackageOverlap?: string | undefined; readonly id: string; readonly name: string; readonly category: \"security\" | \"metrics\" | \"other\" | \"logging\"; readonly shortDescription: string; readonly longDescription: string; readonly onPrem: Readonly<{ params?: Readonly<{ defaultValue?: any; } & { id: string; type: \"string\" | \"number\"; label: string; }>[] | undefined; } & { instructionSets: Readonly<{ title?: string | undefined; callOut?: Readonly<{ message?: string | undefined; iconType?: string | undefined; } & { title: string; }> | undefined; statusCheck?: Readonly<{ error?: string | undefined; text?: string | undefined; title?: string | undefined; success?: string | undefined; btnLabel?: string | undefined; } & { esHitsCheck: Readonly<{} & { index: string | string[]; query: Record; }>; }> | undefined; } & { instructionVariants: Readonly<{ initialSelected?: boolean | undefined; } & { id: string; instructions: Readonly<{ title?: string | undefined; textPre?: string | undefined; commands?: string[] | undefined; textPost?: string | undefined; customComponentName?: string | undefined; } & {}>[]; }>[]; }>[]; }>; }" ], "path": "src/plugins/home/server/services/tutorials/lib/tutorial_schema.ts", "deprecated": false, diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 4997f342007b5..1674c6739d416 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index a65597eeb9269..d26a58b803d26 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index 319ff336206cf..96d9cdfc0a28e 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.devdocs.json b/api_docs/index_management.devdocs.json index 3c17b83af210e..6292265f7e3ea 100644 --- a/api_docs/index_management.devdocs.json +++ b/api_docs/index_management.devdocs.json @@ -347,6 +347,65 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "indexManagement", + "id": "def-public.IndexManagementLocatorParams", + "type": "Interface", + "tags": [], + "label": "IndexManagementLocatorParams", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-management-shared-types", + "scope": "common", + "docId": "kibKbnIndexManagementSharedTypesPluginApi", + "section": "def-common.IndexManagementLocatorParams", + "text": "IndexManagementLocatorParams" + }, + " extends ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.SerializableRecord", + "text": "SerializableRecord" + } + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "indexManagement", + "id": "def-public.IndexManagementLocatorParams.page", + "type": "string", + "tags": [], + "label": "page", + "description": [], + "signature": [ + "\"data_streams_details\"" + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "indexManagement", + "id": "def-public.IndexManagementLocatorParams.dataStreamName", + "type": "string", + "tags": [], + "label": "dataStreamName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "indexManagement", "id": "def-public.IndexMappingProps", @@ -398,7 +457,23 @@ } ], "enums": [], - "misc": [], + "misc": [ + { + "parentPluginId": "indexManagement", + "id": "def-public.INDEX_MANAGEMENT_LOCATOR_ID", + "type": "string", + "tags": [], + "label": "INDEX_MANAGEMENT_LOCATOR_ID", + "description": [], + "signature": [ + "\"INDEX_MANAGEMENT_LOCATOR_ID\"" + ], + "path": "x-pack/plugins/index_management/public/locator.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "objects": [], "setup": { "parentPluginId": "indexManagement", @@ -450,6 +525,27 @@ "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "indexManagement", + "id": "def-public.IndexManagementPluginSetup.locator", + "type": "Object", + "tags": [], + "label": "locator", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-management-shared-types", + "scope": "common", + "docId": "kibKbnIndexManagementSharedTypesPluginApi", + "section": "def-common.IndexManagementLocator", + "text": "IndexManagementLocator" + }, + " | undefined" + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false } ], "lifecycle": "setup", diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 9f220633167f5..7d18491532adf 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 246 | 0 | 241 | 1 | +| 251 | 0 | 246 | 1 | ## Client @@ -37,6 +37,9 @@ Contact [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kiban ### Interfaces +### Consts, variables and types + + ## Server ### Setup diff --git a/api_docs/inference.mdx b/api_docs/inference.mdx index fb80f7fea97b7..7c64a85128fa3 100644 --- a/api_docs/inference.mdx +++ b/api_docs/inference.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inference title: "inference" image: https://source.unsplash.com/400x175/?github description: API docs for the inference plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inference'] --- import inferenceObj from './inference.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 506bcf022e68e..dc42bf5293501 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/ingest_pipelines.mdx b/api_docs/ingest_pipelines.mdx index 3d1999576a229..9ec66e4493807 100644 --- a/api_docs/ingest_pipelines.mdx +++ b/api_docs/ingest_pipelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ingestPipelines title: "ingestPipelines" image: https://source.unsplash.com/400x175/?github description: API docs for the ingestPipelines plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ingestPipelines'] --- import ingestPipelinesObj from './ingest_pipelines.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 7c92a27467349..9cdd2e73abc61 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/integration_assistant.mdx b/api_docs/integration_assistant.mdx index 77c2b0353f52f..521caa218a79f 100644 --- a/api_docs/integration_assistant.mdx +++ b/api_docs/integration_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/integrationAssistant title: "integrationAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the integrationAssistant plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'integrationAssistant'] --- import integrationAssistantObj from './integration_assistant.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 1c7bd2b7f7839..e9c0bb03bb642 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/inventory.mdx b/api_docs/inventory.mdx index 44774a98ce617..36fe05fb926c5 100644 --- a/api_docs/inventory.mdx +++ b/api_docs/inventory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inventory title: "inventory" image: https://source.unsplash.com/400x175/?github description: API docs for the inventory plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inventory'] --- import inventoryObj from './inventory.devdocs.json'; diff --git a/api_docs/investigate.mdx b/api_docs/investigate.mdx index e4208a0148d6e..af5d3de4c9098 100644 --- a/api_docs/investigate.mdx +++ b/api_docs/investigate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigate title: "investigate" image: https://source.unsplash.com/400x175/?github description: API docs for the investigate plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigate'] --- import investigateObj from './investigate.devdocs.json'; diff --git a/api_docs/investigate_app.devdocs.json b/api_docs/investigate_app.devdocs.json index 7a64341aac333..4e1097762b9e1 100644 --- a/api_docs/investigate_app.devdocs.json +++ b/api_docs/investigate_app.devdocs.json @@ -118,7 +118,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"PUT /api/observability/investigations/{investigationId}/items/{itemId} 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; itemId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { itemId: string; investigationId: string; }, { itemId: string; investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodString; type: Zod.ZodString; params: Zod.ZodRecord; }, \"strip\", Zod.ZodTypeAny, { params: Record; type: string; title: string; }, { params: Record; type: string; title: string; }>; }, \"strip\", Zod.ZodTypeAny, { body: { params: Record; type: string; title: string; }; path: { itemId: string; investigationId: string; }; }, { body: { params: Record; type: string; title: string; }; path: { itemId: string; investigationId: string; }; }>, ", + "<\"PUT /api/observability/investigations/{investigationId}/items/{itemId} 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; itemId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { itemId: string; investigationId: string; }, { itemId: string; investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodString; type: Zod.ZodString; params: Zod.ZodRecord; }, \"strip\", Zod.ZodTypeAny, { params: Record; type: string; title: string; }, { params: Record; type: string; title: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { itemId: string; investigationId: string; }; body: { params: Record; type: string; title: string; }; }, { path: { itemId: string; investigationId: string; }; body: { params: Record; type: string; title: string; }; }>, ", "InvestigateAppRouteHandlerResources", ", void, ", "InvestigateAppRouteCreateOptions", @@ -142,7 +142,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/observability/investigations/{investigationId}/items 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodString; type: Zod.ZodString; params: Zod.ZodRecord; }, \"strip\", Zod.ZodTypeAny, { params: Record; type: string; title: string; }, { params: Record; type: string; title: string; }>; }, \"strip\", Zod.ZodTypeAny, { body: { params: Record; type: string; title: string; }; path: { investigationId: string; }; }, { body: { params: Record; type: string; title: string; }; path: { investigationId: string; }; }>, ", + "<\"POST /api/observability/investigations/{investigationId}/items 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodString; type: Zod.ZodString; params: Zod.ZodRecord; }, \"strip\", Zod.ZodTypeAny, { params: Record; type: string; title: string; }, { params: Record; type: string; title: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { investigationId: string; }; body: { params: Record; type: string; title: string; }; }, { path: { investigationId: string; }; body: { params: Record; type: string; title: string; }; }>, ", "InvestigateAppRouteHandlerResources", ", { id: string; createdBy: string; createdAt: number; updatedAt: number; } & { params: Record; type: string; title: string; }, ", "InvestigateAppRouteCreateOptions", @@ -166,7 +166,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"PUT /api/observability/investigations/{investigationId}/notes/{noteId} 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; noteId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; noteId: string; }, { investigationId: string; noteId: string; }>; body: Zod.ZodObject<{ content: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { content: string; }, { content: string; }>; }, \"strip\", Zod.ZodTypeAny, { body: { content: string; }; path: { investigationId: string; noteId: string; }; }, { body: { content: string; }; path: { investigationId: string; noteId: string; }; }>, ", + "<\"PUT /api/observability/investigations/{investigationId}/notes/{noteId} 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; noteId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; noteId: string; }, { investigationId: string; noteId: string; }>; body: Zod.ZodObject<{ content: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { content: string; }, { content: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { investigationId: string; noteId: string; }; body: { content: string; }; }, { path: { investigationId: string; noteId: string; }; body: { content: string; }; }>, ", "InvestigateAppRouteHandlerResources", ", void, ", "InvestigateAppRouteCreateOptions", @@ -190,7 +190,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/observability/investigations/{investigationId}/notes 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ content: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { content: string; }, { content: string; }>; }, \"strip\", Zod.ZodTypeAny, { body: { content: string; }; path: { investigationId: string; }; }, { body: { content: string; }; path: { investigationId: string; }; }>, ", + "<\"POST /api/observability/investigations/{investigationId}/notes 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ content: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { content: string; }, { content: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { investigationId: string; }; body: { content: string; }; }, { path: { investigationId: string; }; body: { content: string; }; }>, ", "InvestigateAppRouteHandlerResources", ", { id: string; createdBy: string; createdAt: number; updatedAt: number; content: string; }, ", "InvestigateAppRouteCreateOptions", @@ -214,7 +214,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"PUT /api/observability/investigations/{investigationId} 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodOptional; status: Zod.ZodOptional, Zod.ZodLiteral<\"active\">, Zod.ZodLiteral<\"mitigated\">, Zod.ZodLiteral<\"resolved\">, Zod.ZodLiteral<\"cancelled\">]>>; params: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { timeRange: { from: number; to: number; }; }, { timeRange: { from: number; to: number; }; }>>; tags: Zod.ZodOptional>; externalIncidentUrl: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }, { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }; path: { investigationId: string; }; }, { body: { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }; path: { investigationId: string; }; }>, ", + "<\"PUT /api/observability/investigations/{investigationId} 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodOptional; status: Zod.ZodOptional, Zod.ZodLiteral<\"active\">, Zod.ZodLiteral<\"mitigated\">, Zod.ZodLiteral<\"resolved\">, Zod.ZodLiteral<\"cancelled\">]>>; params: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { timeRange: { from: number; to: number; }; }, { timeRange: { from: number; to: number; }; }>>; tags: Zod.ZodOptional>; externalIncidentUrl: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }, { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { path: { investigationId: string; }; body: { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }; }, { path: { investigationId: string; }; body: { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }; }>, ", "InvestigateAppRouteHandlerResources", ", { params: { timeRange: { from: number; to: number; }; }; id: string; tags: string[]; title: string; createdBy: string; createdAt: number; updatedAt: number; status: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\"; items: ({ id: string; createdBy: string; createdAt: number; updatedAt: number; } & { params: Record; type: string; title: string; })[]; origin: { id: string; type: \"alert\"; } | { type: \"blank\"; }; externalIncidentUrl: string | null; notes: { id: string; createdBy: string; createdAt: number; updatedAt: number; content: string; }[]; }, ", "InvestigateAppRouteCreateOptions", diff --git a/api_docs/investigate_app.mdx b/api_docs/investigate_app.mdx index 7c082c76a52c1..0653b5be67443 100644 --- a/api_docs/investigate_app.mdx +++ b/api_docs/investigate_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigateApp title: "investigateApp" image: https://source.unsplash.com/400x175/?github description: API docs for the investigateApp plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigateApp'] --- import investigateAppObj from './investigate_app.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 6913623091327..64aba3c6788e8 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index 9c807675bdf4d..531bdec5d1636 100644 --- a/api_docs/kbn_actions_types.mdx +++ b/api_docs/kbn_actions_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-actions-types title: "@kbn/actions-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/actions-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 611787265630d..8cf2f33269bf3 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_pattern_analysis.mdx b/api_docs/kbn_aiops_log_pattern_analysis.mdx index 73ff07c68fdc0..c397c0feb662f 100644 --- a/api_docs/kbn_aiops_log_pattern_analysis.mdx +++ b/api_docs/kbn_aiops_log_pattern_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-pattern-analysis title: "@kbn/aiops-log-pattern-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-pattern-analysis plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-pattern-analysis'] --- import kbnAiopsLogPatternAnalysisObj from './kbn_aiops_log_pattern_analysis.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_rate_analysis.mdx b/api_docs/kbn_aiops_log_rate_analysis.mdx index 644237e1b06a9..df88b7246a2c7 100644 --- a/api_docs/kbn_aiops_log_rate_analysis.mdx +++ b/api_docs/kbn_aiops_log_rate_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-rate-analysis title: "@kbn/aiops-log-rate-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-rate-analysis plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-rate-analysis'] --- import kbnAiopsLogRateAnalysisObj from './kbn_aiops_log_rate_analysis.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index 38bdd0c53bd68..6321dcb3999df 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_comparators.mdx b/api_docs/kbn_alerting_comparators.mdx index 0ff23d229c0dc..26fd6647ae971 100644 --- a/api_docs/kbn_alerting_comparators.mdx +++ b/api_docs/kbn_alerting_comparators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-comparators title: "@kbn/alerting-comparators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-comparators plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-comparators'] --- import kbnAlertingComparatorsObj from './kbn_alerting_comparators.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 0665bad430edc..e16783e7db331 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerting_types.devdocs.json b/api_docs/kbn_alerting_types.devdocs.json index b4b14b827cfb6..6c61f87db34a1 100644 --- a/api_docs/kbn_alerting_types.devdocs.json +++ b/api_docs/kbn_alerting_types.devdocs.json @@ -957,6 +957,59 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/alerting-types", + "id": "def-common.Flapping", + "type": "Interface", + "tags": [], + "label": "Flapping", + "description": [], + "signature": [ + { + "pluginId": "@kbn/alerting-types", + "scope": "common", + "docId": "kibKbnAlertingTypesPluginApi", + "section": "def-common.Flapping", + "text": "Flapping" + }, + " extends ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + } + ], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/alerting-types", + "id": "def-common.Flapping.lookBackWindow", + "type": "number", + "tags": [], + "label": "lookBackWindow", + "description": [], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/alerting-types", + "id": "def-common.Flapping.statusChangeThreshold", + "type": "number", + "tags": [], + "label": "statusChangeThreshold", + "description": [], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/alerting-types", "id": "def-common.IntervalSchedule", @@ -1581,12 +1634,19 @@ { "parentPluginId": "@kbn/alerting-types", "id": "def-common.Rule.flapping", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "flapping", "description": [], "signature": [ - "{ lookBackWindow: number; statusChangeThreshold: number; } | undefined" + { + "pluginId": "@kbn/alerting-types", + "scope": "common", + "docId": "kibKbnAlertingTypesPluginApi", + "section": "def-common.Flapping", + "text": "Flapping" + }, + " | null | undefined" ], "path": "packages/kbn-alerting-types/rule_types.ts", "deprecated": false, @@ -3220,66 +3280,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/alerting-types", - "id": "def-common.MAX_LOOK_BACK_WINDOW", - "type": "number", - "tags": [], - "label": "MAX_LOOK_BACK_WINDOW", - "description": [], - "signature": [ - "20" - ], - "path": "packages/kbn-alerting-types/rule_flapping.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/alerting-types", - "id": "def-common.MAX_STATUS_CHANGE_THRESHOLD", - "type": "number", - "tags": [], - "label": "MAX_STATUS_CHANGE_THRESHOLD", - "description": [], - "signature": [ - "20" - ], - "path": "packages/kbn-alerting-types/rule_flapping.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/alerting-types", - "id": "def-common.MIN_LOOK_BACK_WINDOW", - "type": "number", - "tags": [], - "label": "MIN_LOOK_BACK_WINDOW", - "description": [], - "signature": [ - "2" - ], - "path": "packages/kbn-alerting-types/rule_flapping.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/alerting-types", - "id": "def-common.MIN_STATUS_CHANGE_THRESHOLD", - "type": "number", - "tags": [], - "label": "MIN_STATUS_CHANGE_THRESHOLD", - "description": [], - "signature": [ - "2" - ], - "path": "packages/kbn-alerting-types/rule_flapping.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/alerting-types", "id": "def-common.RecoveredActionGroupId", diff --git a/api_docs/kbn_alerting_types.mdx b/api_docs/kbn_alerting_types.mdx index 620d81a4e84b1..70b807aade831 100644 --- a/api_docs/kbn_alerting_types.mdx +++ b/api_docs/kbn_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-types title: "@kbn/alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-types'] --- import kbnAlertingTypesObj from './kbn_alerting_types.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 222 | 0 | 219 | 0 | +| 221 | 0 | 218 | 0 | ## Common diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 0f59b58dc4aac..85fbd3e666307 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_grouping.mdx b/api_docs/kbn_alerts_grouping.mdx index cb07a354a4146..36aafe0e36b3e 100644 --- a/api_docs/kbn_alerts_grouping.mdx +++ b/api_docs/kbn_alerts_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-grouping title: "@kbn/alerts-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-grouping plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-grouping'] --- import kbnAlertsGroupingObj from './kbn_alerts_grouping.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.devdocs.json b/api_docs/kbn_alerts_ui_shared.devdocs.json index c30709ffb3dab..af694b601886d 100644 --- a/api_docs/kbn_alerts_ui_shared.devdocs.json +++ b/api_docs/kbn_alerts_ui_shared.devdocs.json @@ -3620,6 +3620,59 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/alerts-ui-shared", + "id": "def-public.Flapping", + "type": "Interface", + "tags": [], + "label": "Flapping", + "description": [], + "signature": [ + { + "pluginId": "@kbn/alerting-types", + "scope": "common", + "docId": "kibKbnAlertingTypesPluginApi", + "section": "def-common.Flapping", + "text": "Flapping" + }, + " extends ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + } + ], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/alerts-ui-shared", + "id": "def-public.Flapping.lookBackWindow", + "type": "number", + "tags": [], + "label": "lookBackWindow", + "description": [], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/alerts-ui-shared", + "id": "def-public.Flapping.statusChangeThreshold", + "type": "number", + "tags": [], + "label": "statusChangeThreshold", + "description": [], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/alerts-ui-shared", "id": "def-public.GenericValidationResult", diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index a0b538f87b1c1..feec6abae33c9 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 318 | 0 | 302 | 8 | +| 321 | 0 | 305 | 8 | ## Client diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index e37656dcd0bb2..2cbd5ebb17ce7 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index 4ab326065bf23..75dea93be36f9 100644 --- a/api_docs/kbn_analytics_collection_utils.mdx +++ b/api_docs/kbn_analytics_collection_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-collection-utils title: "@kbn/analytics-collection-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-collection-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 74f4fcb005eb9..a8bf2eb6ccb4f 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_data_view.mdx b/api_docs/kbn_apm_data_view.mdx index 35bee7ed5558d..6531be5458288 100644 --- a/api_docs/kbn_apm_data_view.mdx +++ b/api_docs/kbn_apm_data_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-data-view title: "@kbn/apm-data-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-data-view plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-data-view'] --- import kbnApmDataViewObj from './kbn_apm_data_view.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index a71e541533ddd..b8b0b93e211b5 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 36e97eb0e42e7..143b3595eddaf 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_types.mdx b/api_docs/kbn_apm_types.mdx index 2484fa669bc66..b65c99166fb97 100644 --- a/api_docs/kbn_apm_types.mdx +++ b/api_docs/kbn_apm_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-types title: "@kbn/apm-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-types'] --- import kbnApmTypesObj from './kbn_apm_types.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index c5af9565848ae..d03a776d702a4 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_avc_banner.mdx b/api_docs/kbn_avc_banner.mdx index e088c72136af2..9e0b58e320338 100644 --- a/api_docs/kbn_avc_banner.mdx +++ b/api_docs/kbn_avc_banner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-avc-banner title: "@kbn/avc-banner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/avc-banner plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/avc-banner'] --- import kbnAvcBannerObj from './kbn_avc_banner.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index 98e03b63548e2..fe5f02d94532b 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bfetch_error.mdx b/api_docs/kbn_bfetch_error.mdx index 427ca4597daaa..ca54f4cec7c7a 100644 --- a/api_docs/kbn_bfetch_error.mdx +++ b/api_docs/kbn_bfetch_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bfetch-error title: "@kbn/bfetch-error" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bfetch-error plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bfetch-error'] --- import kbnBfetchErrorObj from './kbn_bfetch_error.devdocs.json'; diff --git a/api_docs/kbn_calculate_auto.mdx b/api_docs/kbn_calculate_auto.mdx index 0364d6c44fa04..ecb5596a144ff 100644 --- a/api_docs/kbn_calculate_auto.mdx +++ b/api_docs/kbn_calculate_auto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-auto title: "@kbn/calculate-auto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-auto plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-auto'] --- import kbnCalculateAutoObj from './kbn_calculate_auto.devdocs.json'; diff --git a/api_docs/kbn_calculate_width_from_char_count.mdx b/api_docs/kbn_calculate_width_from_char_count.mdx index afd02a493f469..68898271bad95 100644 --- a/api_docs/kbn_calculate_width_from_char_count.mdx +++ b/api_docs/kbn_calculate_width_from_char_count.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-width-from-char-count title: "@kbn/calculate-width-from-char-count" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-width-from-char-count plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-width-from-char-count'] --- import kbnCalculateWidthFromCharCountObj from './kbn_calculate_width_from_char_count.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index aab989895ff3e..bed2b8fe0af68 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cbor.mdx b/api_docs/kbn_cbor.mdx index ac769265eb01a..592cb1874b6ac 100644 --- a/api_docs/kbn_cbor.mdx +++ b/api_docs/kbn_cbor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cbor title: "@kbn/cbor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cbor plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cbor'] --- import kbnCborObj from './kbn_cbor.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 10225645d1543..7c4b4089ed8df 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index 92c3324604c30..978be5a1692c8 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index f0f1a92e702f0..5c0ea9b65760c 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-icons'] --- import kbnChartIconsObj from './kbn_chart_icons.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 2bc044982363c..53202762c6195 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index 52393d4206f75..aa8d4d2927cb7 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 5a751419bf264..e65cf9a36d584 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index 11fcd04a992ec..f0295794bbd96 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_cloud_security_posture.mdx b/api_docs/kbn_cloud_security_posture.mdx index 9c75d640b56a2..416a29ee3bcc2 100644 --- a/api_docs/kbn_cloud_security_posture.mdx +++ b/api_docs/kbn_cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture title: "@kbn/cloud-security-posture" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture'] --- import kbnCloudSecurityPostureObj from './kbn_cloud_security_posture.devdocs.json'; diff --git a/api_docs/kbn_cloud_security_posture_common.mdx b/api_docs/kbn_cloud_security_posture_common.mdx index c8eb8f37d52da..d289c02c4a7b5 100644 --- a/api_docs/kbn_cloud_security_posture_common.mdx +++ b/api_docs/kbn_cloud_security_posture_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture-common title: "@kbn/cloud-security-posture-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture-common'] --- import kbnCloudSecurityPostureCommonObj from './kbn_cloud_security_posture_common.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index feec81314c3cc..13a16262c45a5 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mock.mdx b/api_docs/kbn_code_editor_mock.mdx index 842dcfc3695ab..3318e51b6fd93 100644 --- a/api_docs/kbn_code_editor_mock.mdx +++ b/api_docs/kbn_code_editor_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mock title: "@kbn/code-editor-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mock plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mock'] --- import kbnCodeEditorMockObj from './kbn_code_editor_mock.devdocs.json'; diff --git a/api_docs/kbn_code_owners.mdx b/api_docs/kbn_code_owners.mdx index 076dcf51ee826..57483c0353d01 100644 --- a/api_docs/kbn_code_owners.mdx +++ b/api_docs/kbn_code_owners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-owners title: "@kbn/code-owners" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-owners plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-owners'] --- import kbnCodeOwnersObj from './kbn_code_owners.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index c6b663c0d669c..40c566ad1e57f 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index b21b6599d29ef..9867bc573eb39 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index fc4f1b3b4542f..62e96ab9c718f 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 0072daa0979eb..a1e4440417155 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index be4134f820190..70b8cee7f1323 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_public.mdx b/api_docs/kbn_content_management_content_insights_public.mdx index 5e4ce83b8a668..f02c4d314cee4 100644 --- a/api_docs/kbn_content_management_content_insights_public.mdx +++ b/api_docs/kbn_content_management_content_insights_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-public title: "@kbn/content-management-content-insights-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-public plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-public'] --- import kbnContentManagementContentInsightsPublicObj from './kbn_content_management_content_insights_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_server.mdx b/api_docs/kbn_content_management_content_insights_server.mdx index 181c4e9798303..9a63e26e6b182 100644 --- a/api_docs/kbn_content_management_content_insights_server.mdx +++ b/api_docs/kbn_content_management_content_insights_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-server title: "@kbn/content-management-content-insights-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-server'] --- import kbnContentManagementContentInsightsServerObj from './kbn_content_management_content_insights_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_public.mdx b/api_docs/kbn_content_management_favorites_public.mdx index 6752e39ea59f9..e9d36009b12b7 100644 --- a/api_docs/kbn_content_management_favorites_public.mdx +++ b/api_docs/kbn_content_management_favorites_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-public title: "@kbn/content-management-favorites-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-public plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-public'] --- import kbnContentManagementFavoritesPublicObj from './kbn_content_management_favorites_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_server.mdx b/api_docs/kbn_content_management_favorites_server.mdx index 800c7d99daa4c..f44a83a26dad0 100644 --- a/api_docs/kbn_content_management_favorites_server.mdx +++ b/api_docs/kbn_content_management_favorites_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-server title: "@kbn/content-management-favorites-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-server'] --- import kbnContentManagementFavoritesServerObj from './kbn_content_management_favorites_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index e720cd219ea91..fd7b05b7de7b3 100644 --- a/api_docs/kbn_content_management_tabbed_table_list_view.mdx +++ b/api_docs/kbn_content_management_tabbed_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-tabbed-table-list-view title: "@kbn/content-management-tabbed-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-tabbed-table-list-view plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-tabbed-table-list-view'] --- import kbnContentManagementTabbedTableListViewObj from './kbn_content_management_tabbed_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view.mdx b/api_docs/kbn_content_management_table_list_view.mdx index e028a6a4c167a..728e519f480f0 100644 --- a/api_docs/kbn_content_management_table_list_view.mdx +++ b/api_docs/kbn_content_management_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view title: "@kbn/content-management-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view'] --- import kbnContentManagementTableListViewObj from './kbn_content_management_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_common.mdx b/api_docs/kbn_content_management_table_list_view_common.mdx index a04af24ca7f8b..b679e3384e3ad 100644 --- a/api_docs/kbn_content_management_table_list_view_common.mdx +++ b/api_docs/kbn_content_management_table_list_view_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-common title: "@kbn/content-management-table-list-view-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-common'] --- import kbnContentManagementTableListViewCommonObj from './kbn_content_management_table_list_view_common.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index 2fb595a4cfc22..303dbd6fd25aa 100644 --- a/api_docs/kbn_content_management_table_list_view_table.mdx +++ b/api_docs/kbn_content_management_table_list_view_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-table title: "@kbn/content-management-table-list-view-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-table plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_user_profiles.mdx b/api_docs/kbn_content_management_user_profiles.mdx index 1b544904eb3f6..aaff2893ad4a3 100644 --- a/api_docs/kbn_content_management_user_profiles.mdx +++ b/api_docs/kbn_content_management_user_profiles.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-user-profiles title: "@kbn/content-management-user-profiles" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-user-profiles plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-user-profiles'] --- import kbnContentManagementUserProfilesObj from './kbn_content_management_user_profiles.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index ec6861e6c7bb0..53f0eb4a62438 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.devdocs.json b/api_docs/kbn_core_analytics_browser.devdocs.json index b127f21f14a3e..4470b2ca6d693 100644 --- a/api_docs/kbn_core_analytics_browser.devdocs.json +++ b/api_docs/kbn_core_analytics_browser.devdocs.json @@ -574,22 +574,6 @@ "plugin": "@kbn/core-root-server-internal", "path": "packages/core/root/core-root-server-internal/src/events/kibana_started.ts" }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" - }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" - }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/lib/action_executor.ts" - }, { "plugin": "@kbn/cloud", "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" @@ -638,6 +622,22 @@ "plugin": "spaces", "path": "x-pack/plugins/spaces/public/analytics/event_tracker.ts" }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/lib/action_executor.ts" + }, { "plugin": "observabilityAIAssistant", "path": "x-pack/plugins/observability_solution/observability_ai_assistant/server/utils/recall/recall_and_score.ts" diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 79d485f15f503..6821bf423ec7b 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index 7b55533c84255..3f2444f1e6a42 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 6cd8f2526a588..443b864e7caae 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.devdocs.json b/api_docs/kbn_core_analytics_server.devdocs.json index 83662ab53492f..23ddd71cf7fec 100644 --- a/api_docs/kbn_core_analytics_server.devdocs.json +++ b/api_docs/kbn_core_analytics_server.devdocs.json @@ -582,22 +582,6 @@ "plugin": "@kbn/core-root-server-internal", "path": "packages/core/root/core-root-server-internal/src/events/kibana_started.ts" }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" - }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" - }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/lib/action_executor.ts" - }, { "plugin": "@kbn/cloud", "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" @@ -646,6 +630,22 @@ "plugin": "spaces", "path": "x-pack/plugins/spaces/public/analytics/event_tracker.ts" }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/lib/action_executor.ts" + }, { "plugin": "observabilityAIAssistant", "path": "x-pack/plugins/observability_solution/observability_ai_assistant/server/utils/recall/recall_and_score.ts" diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 65103f245d60c..8e79991a6db82 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index 580e826978d30..8743473bc4169 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index a92953b409aa6..5c56f8bda8852 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser.devdocs.json b/api_docs/kbn_core_application_browser.devdocs.json index 006c517538dd8..3197d828a92d1 100644 --- a/api_docs/kbn_core_application_browser.devdocs.json +++ b/api_docs/kbn_core_application_browser.devdocs.json @@ -1154,14 +1154,14 @@ "plugin": "@kbn/core-application-browser-internal", "path": "packages/core/application/core-application-browser-internal/src/ui/app_container.tsx" }, - { - "plugin": "@kbn/core-application-browser-mocks", - "path": "packages/core/application/core-application-browser-mocks/src/application_service.mock.ts" - }, { "plugin": "management", "path": "src/plugins/management/public/application.tsx" }, + { + "plugin": "@kbn/core-application-browser-mocks", + "path": "packages/core/application/core-application-browser-mocks/src/application_service.mock.ts" + }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/public/applications/integrations/index.tsx" diff --git a/api_docs/kbn_core_application_browser.mdx b/api_docs/kbn_core_application_browser.mdx index 9cf93332f79c9..6dedbe277f42e 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser'] --- import kbnCoreApplicationBrowserObj from './kbn_core_application_browser.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_internal.mdx b/api_docs/kbn_core_application_browser_internal.mdx index 716bc663f4e59..7d4bb649b13bd 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-internal'] --- import kbnCoreApplicationBrowserInternalObj from './kbn_core_application_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_mocks.mdx b/api_docs/kbn_core_application_browser_mocks.mdx index fc45f1fb944f5..c07f1991195e1 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-mocks'] --- import kbnCoreApplicationBrowserMocksObj from './kbn_core_application_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_common.mdx b/api_docs/kbn_core_application_common.mdx index 241224ca66a45..dec5772cfc4cb 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-common'] --- import kbnCoreApplicationCommonObj from './kbn_core_application_common.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_internal.mdx b/api_docs/kbn_core_apps_browser_internal.mdx index 97dad00d75f0e..c73de26ee0671 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-internal'] --- import kbnCoreAppsBrowserInternalObj from './kbn_core_apps_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_mocks.mdx b/api_docs/kbn_core_apps_browser_mocks.mdx index 49d516c0b71d9..2ff08b3fce0fe 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index b499f0cdfc03f..d5d867558f317 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index fc69d356fe532..993f03c2be7ed 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index b092fb908207b..0c266d5325e22 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index f3f8336636a1a..b310c27284e2d 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index 87866ef191672..5e57ed430af95 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_browser_mocks.mdx b/api_docs/kbn_core_capabilities_browser_mocks.mdx index 1a0315110ace1..25fa9ef579917 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-browser-mocks'] --- import kbnCoreCapabilitiesBrowserMocksObj from './kbn_core_capabilities_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 30892865b9621..1de4d78e45623 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index 5627a3876cb70..b3999d49e74b6 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 4ef19b6b72674..668e87cd244b9 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.devdocs.json b/api_docs/kbn_core_chrome_browser.devdocs.json index b3fa184ea0c6b..973a5d7c3dbc7 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -3714,7 +3714,7 @@ "label": "AppDeepLinkId", "description": [], "signature": [ - "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"enterpriseSearchRelevance\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchInferenceEndpoints\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"enterpriseSearchRelevance:inferenceEndpoints\" | \"observability-logs-explorer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"enterpriseSearchRelevance\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchInferenceEndpoints\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"enterpriseSearchRelevance:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"observability-logs-explorer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" ], "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 5234aa1bd88ee..6de14fa85d1e3 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index 08986733b6365..6241c917dff31 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser-mocks'] --- import kbnCoreChromeBrowserMocksObj from './kbn_core_chrome_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 0f0365a66c86b..345128dc8254b 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 0a94becd3e182..343c748415048 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index 7abdbda46ddf7..769ac6be323c1 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index 168816f60aa74..7be4e4f464681 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index d0fc29bcc80d7..c05d867136243 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index 041bdb3ee2a2d..e05c037b4dba5 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index a1afdba8577c3..3c8e95846b36e 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index 5223af7d4571c..84ae55b352530 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 9611768bc1125..b039cd4c02bf2 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index 5c55dd5ea14f5..c2fa239c68d87 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index c75cd115f9af3..b3aa43552850a 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index 50d4addcf7695..2f179d7c52082 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server.mdx b/api_docs/kbn_core_deprecations_server.mdx index 78ee768dfb4a5..8197737b520d8 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server'] --- import kbnCoreDeprecationsServerObj from './kbn_core_deprecations_server.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_internal.mdx b/api_docs/kbn_core_deprecations_server_internal.mdx index 70c4afc26bfa2..3d180c232ac12 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-internal'] --- import kbnCoreDeprecationsServerInternalObj from './kbn_core_deprecations_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_mocks.mdx b/api_docs/kbn_core_deprecations_server_mocks.mdx index 4ac39091d58fc..7fa33edca69ed 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-mocks'] --- import kbnCoreDeprecationsServerMocksObj from './kbn_core_deprecations_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index 1a147c4b9f2c3..7357dcc5f709a 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index 8020b45c4b0c0..5ca6ad715f6ba 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index d9eb7a5a0cf5e..33f210fe32bf0 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 361b5bb8598b5..0980e7e9d5130 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index 7a6b5d3bf5e4e..25c8360362127 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 2ef2ec7caf718..8d8e6aab36238 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 6833cade5aab3..7952d71b59882 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 401912ac02ef4..beb41a4cb8a5f 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 3c33654694c39..ae7c7a0dd78de 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index 39945f791756f..4b7c62050cc98 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index 41c044969cc02..34dbf212ecf5a 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index d57b0a4f3a79a..1f60299a069b4 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 757ce87f6d458..a9000ada70a45 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index c86d7c9943012..abdb16f8ecb71 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index 0dbd478fc95e6..36bd98374def6 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index cdcd3b0a0b35d..15a7e94eda3e6 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index c0ca9b10520fe..d59626e5af2a2 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index a060a3482cce4..98150e534b434 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index 27f0603ee9e27..3aba7c9b6bb8c 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index 3e6a3f913d9ce..c8b94905eccaa 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser.mdx b/api_docs/kbn_core_feature_flags_browser.mdx index 287fd8b7f9d3a..1a258638e7616 100644 --- a/api_docs/kbn_core_feature_flags_browser.mdx +++ b/api_docs/kbn_core_feature_flags_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser title: "@kbn/core-feature-flags-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser'] --- import kbnCoreFeatureFlagsBrowserObj from './kbn_core_feature_flags_browser.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser_internal.mdx b/api_docs/kbn_core_feature_flags_browser_internal.mdx index 485213f39903c..4a47bd10dfcb6 100644 --- a/api_docs/kbn_core_feature_flags_browser_internal.mdx +++ b/api_docs/kbn_core_feature_flags_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser-internal title: "@kbn/core-feature-flags-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser-internal'] --- import kbnCoreFeatureFlagsBrowserInternalObj from './kbn_core_feature_flags_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser_mocks.mdx b/api_docs/kbn_core_feature_flags_browser_mocks.mdx index 4cddee792a23e..2306d3b3c7c49 100644 --- a/api_docs/kbn_core_feature_flags_browser_mocks.mdx +++ b/api_docs/kbn_core_feature_flags_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser-mocks title: "@kbn/core-feature-flags-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser-mocks'] --- import kbnCoreFeatureFlagsBrowserMocksObj from './kbn_core_feature_flags_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server.mdx b/api_docs/kbn_core_feature_flags_server.mdx index 9457043cd4804..3b7c7884e9833 100644 --- a/api_docs/kbn_core_feature_flags_server.mdx +++ b/api_docs/kbn_core_feature_flags_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server title: "@kbn/core-feature-flags-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server'] --- import kbnCoreFeatureFlagsServerObj from './kbn_core_feature_flags_server.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server_internal.mdx b/api_docs/kbn_core_feature_flags_server_internal.mdx index dc44866e05c32..a04fb30cf0e66 100644 --- a/api_docs/kbn_core_feature_flags_server_internal.mdx +++ b/api_docs/kbn_core_feature_flags_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server-internal title: "@kbn/core-feature-flags-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server-internal'] --- import kbnCoreFeatureFlagsServerInternalObj from './kbn_core_feature_flags_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server_mocks.mdx b/api_docs/kbn_core_feature_flags_server_mocks.mdx index 10adb7c03cfbd..72bdc48a0ea51 100644 --- a/api_docs/kbn_core_feature_flags_server_mocks.mdx +++ b/api_docs/kbn_core_feature_flags_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server-mocks title: "@kbn/core-feature-flags-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server-mocks'] --- import kbnCoreFeatureFlagsServerMocksObj from './kbn_core_feature_flags_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index dfa28c60e6742..61bbf7cbae13a 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 26612fdf542e0..056b1b9717187 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index 7522ca72bf5a2..62353e5a3cf51 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index 049cb0284b881..bcd52be704e48 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index 1329027f33445..3bc7f9c6b8685 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index be2a1944a9506..b46cdc0ca03a6 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index 13f24caac15ca..a2c16c5c1031a 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index 51c834ebaf4b1..f5cd15e3fe6e4 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index 8baa8318e0096..1c542965768e9 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index b4680a302ed65..69d6d399b4b8c 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index ca2682abee21c..c5bc3b4f41a5c 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index 43f061dee0659..dfa45b94e08d6 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -3678,16 +3678,8 @@ "path": "src/plugins/usage_collection/server/routes/stats/stats.ts" }, { - "plugin": "taskManager", - "path": "x-pack/plugins/task_manager/server/routes/health.ts" - }, - { - "plugin": "taskManager", - "path": "x-pack/plugins/task_manager/server/routes/background_task_utilization.ts" - }, - { - "plugin": "taskManager", - "path": "x-pack/plugins/task_manager/server/routes/metrics.ts" + "plugin": "@kbn/content-management-favorites-server", + "path": "packages/content-management/favorites/favorites_server/src/favorites_routes.ts" }, { "plugin": "licensing", @@ -3701,6 +3693,18 @@ "plugin": "features", "path": "x-pack/plugins/features/server/routes/index.ts" }, + { + "plugin": "taskManager", + "path": "x-pack/plugins/task_manager/server/routes/health.ts" + }, + { + "plugin": "taskManager", + "path": "x-pack/plugins/task_manager/server/routes/background_task_utilization.ts" + }, + { + "plugin": "taskManager", + "path": "x-pack/plugins/task_manager/server/routes/metrics.ts" + }, { "plugin": "customIntegrations", "path": "src/plugins/custom_integrations/server/routes/define_routes.ts" @@ -3853,10 +3857,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/legacy/list_action_types.ts" }, - { - "plugin": "@kbn/content-management-favorites-server", - "path": "packages/content-management/favorites/favorites_server/src/favorites_routes.ts" - }, { "plugin": "share", "path": "src/plugins/share/server/url_service/http/short_urls/register_get_route.ts" @@ -6351,6 +6351,18 @@ "plugin": "usageCollection", "path": "src/plugins/usage_collection/server/routes/ui_counters.ts" }, + { + "plugin": "@kbn/content-management-favorites-server", + "path": "packages/content-management/favorites/favorites_server/src/favorites_routes.ts" + }, + { + "plugin": "@kbn/content-management-favorites-server", + "path": "packages/content-management/favorites/favorites_server/src/favorites_routes.ts" + }, + { + "plugin": "contentManagement", + "path": "src/plugins/content_management/server/rpc/routes/routes.ts" + }, { "plugin": "licensing", "path": "x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts" @@ -6467,17 +6479,13 @@ "plugin": "security", "path": "x-pack/plugins/security/server/routes/analytics/record_violations.ts" }, - { - "plugin": "encryptedSavedObjects", - "path": "x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts" - }, { "plugin": "serverless", "path": "x-pack/plugins/serverless/server/plugin.ts" }, { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/get_oauth_access_token.ts" + "plugin": "encryptedSavedObjects", + "path": "x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts" }, { "plugin": "actions", @@ -6487,6 +6495,10 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/execute.ts" }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/routes/get_oauth_access_token.ts" + }, { "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/legacy/create.ts" @@ -6503,18 +6515,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/get_global_execution_kpi.ts" }, - { - "plugin": "@kbn/content-management-favorites-server", - "path": "packages/content-management/favorites/favorites_server/src/favorites_routes.ts" - }, - { - "plugin": "@kbn/content-management-favorites-server", - "path": "packages/content-management/favorites/favorites_server/src/favorites_routes.ts" - }, - { - "plugin": "contentManagement", - "path": "src/plugins/content_management/server/rpc/routes/routes.ts" - }, { "plugin": "share", "path": "src/plugins/share/server/url_service/http/short_urls/register_create_route.ts" @@ -9921,6 +9921,10 @@ "plugin": "reporting", "path": "x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts" }, + { + "plugin": "searchIndices", + "path": "x-pack/plugins/search_indices/server/routes/documents.ts" + }, { "plugin": "searchInferenceEndpoints", "path": "x-pack/plugins/search_inference_endpoints/server/routes.ts" @@ -14714,30 +14718,6 @@ "plugin": "cloud", "path": "x-pack/plugins/cloud/server/routes/elasticsearch_routes.ts" }, - { - "plugin": "spaces", - "path": "x-pack/plugins/spaces/server/routes/api/external/get.ts" - }, - { - "plugin": "spaces", - "path": "x-pack/plugins/spaces/server/routes/api/external/get_all.ts" - }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/routes/authorization/roles/get.ts" - }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/routes/authorization/roles/get_all.ts" - }, - { - "plugin": "@kbn/core-http-router-server-mocks", - "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" - }, - { - "plugin": "bfetch", - "path": "src/plugins/bfetch/server/plugin.ts" - }, { "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/public/runtime_fields/get_runtime_field.ts" @@ -14782,6 +14762,26 @@ "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/internal/fields.ts" }, + { + "plugin": "spaces", + "path": "x-pack/plugins/spaces/server/routes/api/external/get.ts" + }, + { + "plugin": "spaces", + "path": "x-pack/plugins/spaces/server/routes/api/external/get_all.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/routes/authorization/roles/get.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/routes/authorization/roles/get_all.ts" + }, + { + "plugin": "bfetch", + "path": "src/plugins/bfetch/server/plugin.ts" + }, { "plugin": "data", "path": "src/plugins/data/server/search/routes/session.ts" @@ -14802,6 +14802,10 @@ "plugin": "data", "path": "src/plugins/data/server/scripts/route.ts" }, + { + "plugin": "@kbn/core-http-router-server-mocks", + "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" + }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/custom_elements/find.ts" @@ -14886,6 +14890,14 @@ "plugin": "cloudSecurityPosture", "path": "x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/get_states.ts" }, + { + "plugin": "dataUsage", + "path": "x-pack/plugins/data_usage/server/routes/internal/usage_metrics.ts" + }, + { + "plugin": "dataUsage", + "path": "x-pack/plugins/data_usage/server/routes/internal/data_streams.ts" + }, { "plugin": "dataVisualizer", "path": "x-pack/plugins/data_visualizer/server/routes.ts" @@ -15845,22 +15857,6 @@ "plugin": "@kbn/core-apps-server-internal", "path": "packages/core/apps/core-apps-server-internal/src/core_app.ts" }, - { - "plugin": "spaces", - "path": "x-pack/plugins/spaces/server/routes/api/external/put.ts" - }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/routes/authorization/roles/put.ts" - }, - { - "plugin": "@kbn/core-http-router-server-mocks", - "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" - }, - { - "plugin": "bfetch", - "path": "src/plugins/bfetch/server/plugin.ts" - }, { "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/public/runtime_fields/put_runtime_field.ts" @@ -15873,6 +15869,18 @@ "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/internal/fields_for.ts" }, + { + "plugin": "spaces", + "path": "x-pack/plugins/spaces/server/routes/api/external/put.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/routes/authorization/roles/put.ts" + }, + { + "plugin": "bfetch", + "path": "src/plugins/bfetch/server/plugin.ts" + }, { "plugin": "data", "path": "src/plugins/data/server/search/routes/session.ts" @@ -15881,6 +15889,10 @@ "plugin": "data", "path": "src/plugins/data/server/query/routes.ts" }, + { + "plugin": "@kbn/core-http-router-server-mocks", + "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" + }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/custom_elements/update.ts" @@ -16156,22 +16168,6 @@ "deprecated": false, "trackAdoption": true, "references": [ - { - "plugin": "spaces", - "path": "x-pack/plugins/spaces/server/routes/api/external/post.ts" - }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/routes/authorization/roles/post.ts" - }, - { - "plugin": "@kbn/core-http-router-server-mocks", - "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" - }, - { - "plugin": "bfetch", - "path": "src/plugins/bfetch/server/plugin.ts" - }, { "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/public/fields/update_fields.ts" @@ -16212,6 +16208,18 @@ "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/internal/fields_for.ts" }, + { + "plugin": "spaces", + "path": "x-pack/plugins/spaces/server/routes/api/external/post.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/routes/authorization/roles/post.ts" + }, + { + "plugin": "bfetch", + "path": "src/plugins/bfetch/server/plugin.ts" + }, { "plugin": "data", "path": "src/plugins/data/server/search/routes/session.ts" @@ -16252,6 +16260,10 @@ "plugin": "unifiedSearch", "path": "src/plugins/unified_search/server/autocomplete/value_suggestions_route.ts" }, + { + "plugin": "@kbn/core-http-router-server-mocks", + "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" + }, { "plugin": "aiops", "path": "x-pack/plugins/aiops/server/routes/log_rate_analysis_field_candidates/define_route.ts" @@ -17056,6 +17068,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/suggestions/index.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/endpoint/routes/suggestions/index.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/protection_updates_note/index.ts" @@ -17422,22 +17438,6 @@ "deprecated": false, "trackAdoption": true, "references": [ - { - "plugin": "spaces", - "path": "x-pack/plugins/spaces/server/routes/api/external/delete.ts" - }, - { - "plugin": "security", - "path": "x-pack/plugins/security/server/routes/authorization/roles/delete.ts" - }, - { - "plugin": "@kbn/core-http-router-server-mocks", - "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" - }, - { - "plugin": "bfetch", - "path": "src/plugins/bfetch/server/plugin.ts" - }, { "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/public/runtime_fields/delete_runtime_field.ts" @@ -17450,6 +17450,18 @@ "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/public/delete_data_view.ts" }, + { + "plugin": "spaces", + "path": "x-pack/plugins/spaces/server/routes/api/external/delete.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/routes/authorization/roles/delete.ts" + }, + { + "plugin": "bfetch", + "path": "src/plugins/bfetch/server/plugin.ts" + }, { "plugin": "data", "path": "src/plugins/data/server/search/routes/session.ts" @@ -17462,6 +17474,10 @@ "plugin": "data", "path": "src/plugins/data/server/query/routes.ts" }, + { + "plugin": "@kbn/core-http-router-server-mocks", + "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" + }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/custom_elements/delete.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 033da74bc4344..0178ad69be6d7 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 6485d89ab6ef2..37743b04ed347 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index a82af4a2e9e3a..02e2bbaf3f974 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index cec29633d7b51..382ba910a457e 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index 2b6fe06775002..747ffa691a152 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index cdc7a7b46b920..ffd484cf6864a 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index b9e50ccad7491..e1960d115ce3f 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index 85efd8f5f34eb..49cd0b70aa0b6 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index c91a078fbf95f..3dea6335633c1 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 103e0c120b599..167799f6139d8 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index 3a537870608f6..6cbe96596e551 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index 2a24eeff55956..16c221066f78a 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index 2268bc6fe7ae2..b960725449d33 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index d4a13a6200164..c0b3827dfdc95 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index d88bb1f20c5a3..be14aabb5d88f 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index 441f5b5aa11e6..0389948344017 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index fdd63e561fabc..bef307e30af28 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index da2062df428ea..154e1d90b37ad 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index aa277f9ce7869..8b56cac8f9c57 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index ab1c51ba3263b..c0fdacea0ea99 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index ca4545a7012bf..ce7f4648346b8 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 2fcbe78f511ca..2bd97cfeb8c95 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index a573407fea533..bfc402120fc62 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 980c139c1dc51..aae7ff9fde41e 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index 5e39ad50e52f4..6b50358c7259a 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 438064632414e..c470bfc7ed820 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index aee01f10d1a3e..20f5b90fb9003 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index 38c29213b1956..601839b9dc40f 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index dbe4e2bddcc6a..dd5f5c942b5f3 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index 5aa4feeb3a298..69205272fdc4b 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index 0bad21f64c502..64589368f8d64 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index cfb233c76c279..6f3185c8e2aa5 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 149e19c7f2283..c14f2443cfed4 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index 94098dfc72746..8b21cb5b0e206 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 215b2ddc95e07..1b281ec829e7a 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index 328e6e20d39a1..dc5279aa75e73 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index f03a6473cb326..945e313e49b85 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index eacca38672aff..ae1f6c1077c51 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index 46325063a10d3..afc4b40f6a083 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 8aa44c71d10df..db1130e7cf5b8 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index cfdabf68dc4bb..78776d98479b8 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index b94a3d7b7ec5e..18ad647d519a0 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index d392df7f1b741..d6bb3701f69c8 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index 8b084195b0ac3..9116170234d92 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index a7447c5803091..258c7b4509b64 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index 7d9953314eeb1..272f0017e4c9e 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 1353c0f900b80..a83aadb787fc9 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.devdocs.json b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json index 9c52167b88c89..0a442923c41cc 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json @@ -139,19 +139,19 @@ }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/services/workpad.ts" + "path": "x-pack/plugins/canvas/public/services/canvas_workpad_service.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/services/workpad.ts" + "path": "x-pack/plugins/canvas/public/services/canvas_workpad_service.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/services/workpad.ts" + "path": "x-pack/plugins/canvas/public/services/canvas_workpad_service.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/services/workpad.ts" + "path": "x-pack/plugins/canvas/public/services/canvas_workpad_service.ts" }, { "plugin": "graph", @@ -1042,10 +1042,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/saved_objects_service.mock.ts" - }, { "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.ts" @@ -1066,6 +1062,10 @@ "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/helpers/save_saved_object.ts" }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/saved_objects_service.mock.ts" + }, { "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.test.ts" @@ -1225,14 +1225,14 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/saved_objects_service.mock.ts" - }, { "plugin": "home", "path": "src/plugins/home/public/application/components/home_app.js" }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/saved_objects_service.mock.ts" + }, { "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts" @@ -1575,14 +1575,14 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/saved_objects_service.mock.ts" - }, { "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts" }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/saved_objects_service.mock.ts" + }, { "plugin": "dashboardEnhanced", "path": "x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/components/collect_config_container.tsx" diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 919e3eb84f9e6..21fed06868aa6 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.devdocs.json b/api_docs/kbn_core_saved_objects_api_server.devdocs.json index 2164e7818975d..1524753c3fb7c 100644 --- a/api_docs/kbn_core_saved_objects_api_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_server.devdocs.json @@ -2330,10 +2330,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" - }, { "plugin": "@kbn/core-saved-objects-api-server-internal", "path": "packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/internal_utils.ts" @@ -2346,6 +2342,10 @@ "plugin": "@kbn/core-saved-objects-server-internal", "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts" }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" + }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" @@ -2627,52 +2627,8 @@ "path": "src/core/server/index.ts" }, { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/types.ts" + "plugin": "@kbn/alerting-types", + "path": "packages/kbn-alerting-types/rule_types.ts" }, { "plugin": "@kbn/alerting-types", @@ -2730,6 +2686,54 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/common/rule.ts" }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 3e590c1c876ce..f2f2071e654d4 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index c86da38f7d697..baf7d226ed538 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index d4a7da1c97aa9..d9bde56f26e84 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index 9875d7827b6b5..66ae7a26054c2 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.devdocs.json b/api_docs/kbn_core_saved_objects_browser.devdocs.json index a56a73cbcd2d1..f44ecda0e4b3b 100644 --- a/api_docs/kbn_core_saved_objects_browser.devdocs.json +++ b/api_docs/kbn_core_saved_objects_browser.devdocs.json @@ -70,16 +70,16 @@ "path": "x-pack/plugins/transform/public/app/app_dependencies.tsx" }, { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/saved_objects_service.mock.ts" + "plugin": "@kbn/core", + "path": "src/core/server/index.ts" }, { "plugin": "@kbn/core-saved-objects-browser-mocks", "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/saved_objects_service.mock.ts" }, { - "plugin": "@kbn/core", - "path": "src/core/server/index.ts" + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/saved_objects_service.mock.ts" } ], "children": [ diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index 6d4d8aa1db5cc..8a8836c89f08a 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index af5a3cdfdfddb..e30b74bc7823c 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 1bad976a0139b..e87a88419d087 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.devdocs.json b/api_docs/kbn_core_saved_objects_common.devdocs.json index 9545a931775cb..3e87ab4f75860 100644 --- a/api_docs/kbn_core_saved_objects_common.devdocs.json +++ b/api_docs/kbn_core_saved_objects_common.devdocs.json @@ -1251,11 +1251,11 @@ }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/services/kibana/workpad.ts" + "path": "x-pack/plugins/canvas/public/services/canvas_workpad_service.ts" }, { "plugin": "canvas", - "path": "x-pack/plugins/canvas/public/services/kibana/workpad.ts" + "path": "x-pack/plugins/canvas/public/services/canvas_workpad_service.ts" }, { "plugin": "canvas", @@ -1273,74 +1273,6 @@ "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts" }, - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" - }, - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" - }, - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/errors.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/errors.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/lib/regenerate_ids.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/lib/regenerate_ids.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, - { - "plugin": "@kbn/core-saved-objects-import-export-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" - }, { "plugin": "@kbn/core", "path": "src/core/types/index.ts" @@ -1457,6 +1389,74 @@ "plugin": "savedObjectsManagement", "path": "src/plugins/saved_objects_management/server/lib/find_relationships.test.ts" }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/errors.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/errors.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/lib/regenerate_ids.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/import/lib/regenerate_ids.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-import-export-server-internal", + "path": "packages/core/saved-objects/core-saved-objects-import-export-server-internal/src/export/apply_export_transforms.ts" + }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" + }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" + }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" + }, { "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.test.ts" @@ -2438,14 +2438,6 @@ "plugin": "lens", "path": "x-pack/plugins/lens/common/embeddable_factory/index.ts" }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts" - }, - { - "plugin": "canvas", - "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts" - }, { "plugin": "maps", "path": "x-pack/plugins/maps/common/migrations/references.ts" @@ -2466,6 +2458,14 @@ "plugin": "maps", "path": "x-pack/plugins/maps/common/migrations/references.ts" }, + { + "plugin": "canvas", + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts" + }, + { + "plugin": "canvas", + "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts" + }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts" diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index bda1a56f296ed..6e65e60bf90e3 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index 02246c93a91a9..fae1a64492bc0 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index 70a2a4a8cf75e..247c597828ca7 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index d1177ebf72bab..e48a956b716c8 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index f9a6d2fd3f11c..ed97f4ecd635f 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.devdocs.json b/api_docs/kbn_core_saved_objects_server.devdocs.json index c853fea93c1e2..ff45bcbb7b16c 100644 --- a/api_docs/kbn_core_saved_objects_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_server.devdocs.json @@ -5821,10 +5821,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "@kbn/core-saved-objects-browser-mocks", - "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" - }, { "plugin": "@kbn/core-saved-objects-api-server-internal", "path": "packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/internal_utils.ts" @@ -5837,6 +5833,10 @@ "plugin": "@kbn/core-saved-objects-server-internal", "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts" }, + { + "plugin": "@kbn/core-saved-objects-browser-mocks", + "path": "packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts" + }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" @@ -6118,52 +6118,8 @@ "path": "src/core/server/index.ts" }, { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/types.ts" - }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/types.ts" + "plugin": "@kbn/alerting-types", + "path": "packages/kbn-alerting-types/rule_types.ts" }, { "plugin": "@kbn/alerting-types", @@ -6221,6 +6177,54 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/common/rule.ts" }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/types/types.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/application/connector/methods/update/update.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" + }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/actions_client/actions_client.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts" @@ -10605,6 +10609,10 @@ "plugin": "taskManager", "path": "x-pack/plugins/task_manager/server/saved_objects/index.ts" }, + { + "plugin": "dataViews", + "path": "src/plugins/data_views/server/saved_objects/data_views.ts" + }, { "plugin": "spaces", "path": "x-pack/plugins/spaces/server/saved_objects/saved_objects_service.ts" @@ -10621,18 +10629,10 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/saved_objects/index.ts" }, - { - "plugin": "@kbn/core-saved-objects-migration-server-mocks", - "path": "packages/core/saved-objects/core-saved-objects-migration-server-mocks/src/kibana_migrator.mock.ts" - }, { "plugin": "share", "path": "src/plugins/share/server/url_service/saved_objects/register_url_service_saved_object_type.ts" }, - { - "plugin": "dataViews", - "path": "src/plugins/data_views/server/saved_objects/data_views.ts" - }, { "plugin": "data", "path": "src/plugins/data/server/saved_objects/query.ts" @@ -10649,6 +10649,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/saved_objects/index.ts" }, + { + "plugin": "@kbn/core-saved-objects-migration-server-mocks", + "path": "packages/core/saved-objects/core-saved-objects-migration-server-mocks/src/kibana_migrator.mock.ts" + }, { "plugin": "lens", "path": "x-pack/plugins/lens/server/saved_objects.ts" @@ -11465,16 +11469,16 @@ "path": "packages/core/saved-objects/core-saved-objects-migration-server-internal/src/document_migrator/validate_migrations.ts" }, { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/saved_objects/index.ts" + "plugin": "dataViews", + "path": "src/plugins/data_views/server/saved_objects/data_views.ts" }, { "plugin": "actions", "path": "x-pack/plugins/actions/server/saved_objects/index.ts" }, { - "plugin": "dataViews", - "path": "src/plugins/data_views/server/saved_objects/data_views.ts" + "plugin": "actions", + "path": "x-pack/plugins/actions/server/saved_objects/index.ts" }, { "plugin": "data", diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 027faaf3d14e6..2d5f1c08d3f60 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 05d328c2a3d17..0d2c0e90f0d6b 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index a7a94a572ff36..b0fbbcbba72e4 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index fbf4fe9d43a39..6ae1c94e371c9 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser.mdx b/api_docs/kbn_core_security_browser.mdx index 6357cf38555d3..9748155deb0f8 100644 --- a/api_docs/kbn_core_security_browser.mdx +++ b/api_docs/kbn_core_security_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser title: "@kbn/core-security-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser'] --- import kbnCoreSecurityBrowserObj from './kbn_core_security_browser.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_internal.mdx b/api_docs/kbn_core_security_browser_internal.mdx index 6f3963f991574..79937e031b977 100644 --- a/api_docs/kbn_core_security_browser_internal.mdx +++ b/api_docs/kbn_core_security_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-internal title: "@kbn/core-security-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-internal'] --- import kbnCoreSecurityBrowserInternalObj from './kbn_core_security_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_mocks.mdx b/api_docs/kbn_core_security_browser_mocks.mdx index d593fe1bc292f..742af3dd1781e 100644 --- a/api_docs/kbn_core_security_browser_mocks.mdx +++ b/api_docs/kbn_core_security_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-mocks title: "@kbn/core-security-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-mocks'] --- import kbnCoreSecurityBrowserMocksObj from './kbn_core_security_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_security_common.mdx b/api_docs/kbn_core_security_common.mdx index 4e31205eddaf5..707383ca03316 100644 --- a/api_docs/kbn_core_security_common.mdx +++ b/api_docs/kbn_core_security_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-common title: "@kbn/core-security-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-common'] --- import kbnCoreSecurityCommonObj from './kbn_core_security_common.devdocs.json'; diff --git a/api_docs/kbn_core_security_server.mdx b/api_docs/kbn_core_security_server.mdx index 0c9163b1c37ae..6c40aeeed9b3e 100644 --- a/api_docs/kbn_core_security_server.mdx +++ b/api_docs/kbn_core_security_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server title: "@kbn/core-security-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server'] --- import kbnCoreSecurityServerObj from './kbn_core_security_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_internal.mdx b/api_docs/kbn_core_security_server_internal.mdx index 746159aaf393f..11442d558030b 100644 --- a/api_docs/kbn_core_security_server_internal.mdx +++ b/api_docs/kbn_core_security_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-internal title: "@kbn/core-security-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-internal'] --- import kbnCoreSecurityServerInternalObj from './kbn_core_security_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_mocks.mdx b/api_docs/kbn_core_security_server_mocks.mdx index d49f4c0c54cd9..78e69a5e0e50b 100644 --- a/api_docs/kbn_core_security_server_mocks.mdx +++ b/api_docs/kbn_core_security_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-mocks title: "@kbn/core-security-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-mocks'] --- import kbnCoreSecurityServerMocksObj from './kbn_core_security_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index f0a974157fccd..08a58dbee2424 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index dd5693bc9c2cd..88685dfccca0b 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index 7cf98a7274abd..1262dc118f85c 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index c8663f64f8cd3..7938d950165fd 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index 6e7c5c32ba824..933364afddc67 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index d28a71d44dffe..90d07d67ebefa 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index 6f980e99949c5..7478aea7b5b00 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index 9408405555e0c..79891708fdd97 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index 32dbb953b3d37..0e495aa76f3b9 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index c260ab039b718..5fa9af538a8ea 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index c095dc7c734b9..aea1997abed32 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 88100717aa5b1..6e350064be6ba 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 8d911c94a279e..9a798ad15343e 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 80bd185ace3da..7605098827aaf 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 73e0a7ee4d627..5c3d4af5d755c 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index 61f20393b595b..54699ee643822 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index 75a26c97160b8..3e09362c358b0 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index 6b39a1fb67166..f2c10c9e11ad2 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index 18e66e0b4fa79..4b92850b35535 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index cce29d0f3609c..82208523fcdad 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index 2aed6db13830a..a95140380b920 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index 33c3bd14a34c2..2c91054782ac1 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index 46033815d6601..d725b78d67e4e 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser.mdx b/api_docs/kbn_core_user_profile_browser.mdx index 916b024cf93ef..2e63b79fa2c54 100644 --- a/api_docs/kbn_core_user_profile_browser.mdx +++ b/api_docs/kbn_core_user_profile_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser title: "@kbn/core-user-profile-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser'] --- import kbnCoreUserProfileBrowserObj from './kbn_core_user_profile_browser.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_internal.mdx b/api_docs/kbn_core_user_profile_browser_internal.mdx index feade375a7771..5057496d93ad8 100644 --- a/api_docs/kbn_core_user_profile_browser_internal.mdx +++ b/api_docs/kbn_core_user_profile_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-internal title: "@kbn/core-user-profile-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-internal'] --- import kbnCoreUserProfileBrowserInternalObj from './kbn_core_user_profile_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_mocks.mdx b/api_docs/kbn_core_user_profile_browser_mocks.mdx index d87efdcf1cc0b..b68127361cd4b 100644 --- a/api_docs/kbn_core_user_profile_browser_mocks.mdx +++ b/api_docs/kbn_core_user_profile_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-mocks title: "@kbn/core-user-profile-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-mocks'] --- import kbnCoreUserProfileBrowserMocksObj from './kbn_core_user_profile_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_common.mdx b/api_docs/kbn_core_user_profile_common.mdx index 2c85e1b9bbf38..adc7edf7ff52c 100644 --- a/api_docs/kbn_core_user_profile_common.mdx +++ b/api_docs/kbn_core_user_profile_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-common title: "@kbn/core-user-profile-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-common'] --- import kbnCoreUserProfileCommonObj from './kbn_core_user_profile_common.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server.mdx b/api_docs/kbn_core_user_profile_server.mdx index 96b16039fedc0..190e1bd7169d6 100644 --- a/api_docs/kbn_core_user_profile_server.mdx +++ b/api_docs/kbn_core_user_profile_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server title: "@kbn/core-user-profile-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server'] --- import kbnCoreUserProfileServerObj from './kbn_core_user_profile_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_internal.mdx b/api_docs/kbn_core_user_profile_server_internal.mdx index 2cd76952bf6fa..15f86146ac186 100644 --- a/api_docs/kbn_core_user_profile_server_internal.mdx +++ b/api_docs/kbn_core_user_profile_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-internal title: "@kbn/core-user-profile-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-internal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-internal'] --- import kbnCoreUserProfileServerInternalObj from './kbn_core_user_profile_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_mocks.mdx b/api_docs/kbn_core_user_profile_server_mocks.mdx index d35db82e39b5f..b853d6385843e 100644 --- a/api_docs/kbn_core_user_profile_server_mocks.mdx +++ b/api_docs/kbn_core_user_profile_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-mocks title: "@kbn/core-user-profile-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-mocks'] --- import kbnCoreUserProfileServerMocksObj from './kbn_core_user_profile_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index a8e590176444c..1379a7252baaa 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index bbb9714500911..f6609f70e0b1f 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index ae537252393ca..4f08f9d35052d 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index 9d755289750c3..be4aec1d41b46 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_icons.mdx b/api_docs/kbn_custom_icons.mdx index a0cefe014ba2b..0bb609e748373 100644 --- a/api_docs/kbn_custom_icons.mdx +++ b/api_docs/kbn_custom_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-icons title: "@kbn/custom-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-icons plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-icons'] --- import kbnCustomIconsObj from './kbn_custom_icons.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index caffedb15472e..468d4383ebf39 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index ea86c5f44b226..489b709370d0b 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_forge.mdx b/api_docs/kbn_data_forge.mdx index fcb252eff6072..2e2cd2bfca6aa 100644 --- a/api_docs/kbn_data_forge.mdx +++ b/api_docs/kbn_data_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-forge title: "@kbn/data-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-forge plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-forge'] --- import kbnDataForgeObj from './kbn_data_forge.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index ed23cdb0655ab..7e18e3e19a7cd 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_data_stream_adapter.mdx b/api_docs/kbn_data_stream_adapter.mdx index 0623f6d3a889e..61ce2557e1620 100644 --- a/api_docs/kbn_data_stream_adapter.mdx +++ b/api_docs/kbn_data_stream_adapter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-stream-adapter title: "@kbn/data-stream-adapter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-stream-adapter plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-stream-adapter'] --- import kbnDataStreamAdapterObj from './kbn_data_stream_adapter.devdocs.json'; diff --git a/api_docs/kbn_data_view_utils.mdx b/api_docs/kbn_data_view_utils.mdx index 20d39376848f4..c22d7264c1a3f 100644 --- a/api_docs/kbn_data_view_utils.mdx +++ b/api_docs/kbn_data_view_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-view-utils title: "@kbn/data-view-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-view-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-view-utils'] --- import kbnDataViewUtilsObj from './kbn_data_view_utils.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 37ffce145a61a..8ddec0c424d53 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index b3397b37b04a9..210d307d16f87 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index b27201d211c4e..5166564c0ef42 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_fleet.mdx b/api_docs/kbn_deeplinks_fleet.mdx index 042b1d94672b3..229666a594ee5 100644 --- a/api_docs/kbn_deeplinks_fleet.mdx +++ b/api_docs/kbn_deeplinks_fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-fleet title: "@kbn/deeplinks-fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-fleet plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-fleet'] --- import kbnDeeplinksFleetObj from './kbn_deeplinks_fleet.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index d8fa7e41018b6..51ae871b444cc 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index eca2d107c631b..7634c90451703 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index 278e080d08243..163eb57758933 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.devdocs.json b/api_docs/kbn_deeplinks_search.devdocs.json index d3659c3bf083c..ab97c3e504a2d 100644 --- a/api_docs/kbn_deeplinks_search.devdocs.json +++ b/api_docs/kbn_deeplinks_search.devdocs.json @@ -30,7 +30,7 @@ "label": "DeepLinkId", "description": [], "signature": [ - "\"appSearch\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"enterpriseSearchRelevance\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchInferenceEndpoints\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"enterpriseSearchRelevance:inferenceEndpoints\"" + "\"appSearch\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"enterpriseSearchRelevance\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchInferenceEndpoints\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"enterpriseSearchRelevance:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\"" ], "path": "packages/deeplinks/search/deep_links.ts", "deprecated": false, diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index 2c4ca22b1c938..dcfd53e6f2261 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_security.mdx b/api_docs/kbn_deeplinks_security.mdx index 753e72a94c58f..4f69121721be2 100644 --- a/api_docs/kbn_deeplinks_security.mdx +++ b/api_docs/kbn_deeplinks_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-security title: "@kbn/deeplinks-security" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-security plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-security'] --- import kbnDeeplinksSecurityObj from './kbn_deeplinks_security.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_shared.mdx b/api_docs/kbn_deeplinks_shared.mdx index 9f3fc21fc33f2..7f55dacbe366d 100644 --- a/api_docs/kbn_deeplinks_shared.mdx +++ b/api_docs/kbn_deeplinks_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-shared title: "@kbn/deeplinks-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-shared plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-shared'] --- import kbnDeeplinksSharedObj from './kbn_deeplinks_shared.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index c2603f5855b45..0b9bde1280ddf 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index c8ce19d5eaeb9..daa63e953b30c 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index 93f9137dfcb0f..ea8395356bf54 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index 1e28d9ef892a9..2a12d37513d58 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 3f9a437f6bcfd..96eb898001ed9 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 97b8a1c55c430..4f8fa542f9129 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index f306bf224de81..e36eb31cd1aa4 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 2a1c21aa5bab2..ea3a5282cc613 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 33c640dafab45..4412f157132ff 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 588b64f66aeaf..492dfa3aafa4c 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index daf06909512c6..64e70a286d9ea 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index 27759a122bf1b..184fcad0e8b68 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index 8677a8912e42f..762bb0261384a 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index 07f1a3b31af7b..20f6d26b1504d 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_agent_utils.mdx b/api_docs/kbn_elastic_agent_utils.mdx index ea04c9dd0b4ee..bd18627b52761 100644 --- a/api_docs/kbn_elastic_agent_utils.mdx +++ b/api_docs/kbn_elastic_agent_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-agent-utils title: "@kbn/elastic-agent-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-agent-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index b735b4b9496be..d456171a5baf2 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant_common.devdocs.json b/api_docs/kbn_elastic_assistant_common.devdocs.json index 5003d97686fa9..d06fdf76fcd6e 100644 --- a/api_docs/kbn_elastic_assistant_common.devdocs.json +++ b/api_docs/kbn_elastic_assistant_common.devdocs.json @@ -5986,4 +5986,4 @@ } ] } -} +} \ No newline at end of file diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index 50a5326c84c36..95e4258ef71ed 100644 --- a/api_docs/kbn_elastic_assistant_common.mdx +++ b/api_docs/kbn_elastic_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant-common title: "@kbn/elastic-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_entities_schema.mdx b/api_docs/kbn_entities_schema.mdx index 8aa2cf9071a2d..5c1cc414ecb61 100644 --- a/api_docs/kbn_entities_schema.mdx +++ b/api_docs/kbn_entities_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-entities-schema title: "@kbn/entities-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/entities-schema plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/entities-schema'] --- import kbnEntitiesSchemaObj from './kbn_entities_schema.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index 213732721639a..c8edc7bf660f1 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index 4e3fef4799c59..8911c7102bbdf 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 743d7a76a20f0..d658ddf4ca4af 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 615ac504f0afa..253462f81c92f 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 9cd4b9fea1042..7e5944548614f 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 7c659126668dd..20833bbd0634a 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_esql_ast.mdx b/api_docs/kbn_esql_ast.mdx index 056ef80915e58..aa958e6bd88ab 100644 --- a/api_docs/kbn_esql_ast.mdx +++ b/api_docs/kbn_esql_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-ast title: "@kbn/esql-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-ast plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-ast'] --- import kbnEsqlAstObj from './kbn_esql_ast.devdocs.json'; diff --git a/api_docs/kbn_esql_editor.mdx b/api_docs/kbn_esql_editor.mdx index d7d7572a30367..e5424a7054755 100644 --- a/api_docs/kbn_esql_editor.mdx +++ b/api_docs/kbn_esql_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-editor title: "@kbn/esql-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-editor plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-editor'] --- import kbnEsqlEditorObj from './kbn_esql_editor.devdocs.json'; diff --git a/api_docs/kbn_esql_utils.devdocs.json b/api_docs/kbn_esql_utils.devdocs.json index b4460293b2430..efa4346e38833 100644 --- a/api_docs/kbn_esql_utils.devdocs.json +++ b/api_docs/kbn_esql_utils.devdocs.json @@ -1157,6 +1157,39 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getQueryColumnsFromESQLQuery", + "type": "Function", + "tags": [], + "label": "getQueryColumnsFromESQLQuery", + "description": [], + "signature": [ + "(esql: string) => string[]" + ], + "path": "packages/kbn-esql-utils/src/utils/query_parsing_helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getQueryColumnsFromESQLQuery.$1", + "type": "string", + "tags": [], + "label": "esql", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-esql-utils/src/utils/query_parsing_helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/esql-utils", "id": "def-common.getStartEndParams", diff --git a/api_docs/kbn_esql_utils.mdx b/api_docs/kbn_esql_utils.mdx index 327992786ed20..90f3cb7f87e4a 100644 --- a/api_docs/kbn_esql_utils.mdx +++ b/api_docs/kbn_esql_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-utils title: "@kbn/esql-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-utils'] --- import kbnEsqlUtilsObj from './kbn_esql_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 73 | 0 | 69 | 0 | +| 75 | 0 | 71 | 0 | ## Common diff --git a/api_docs/kbn_esql_validation_autocomplete.devdocs.json b/api_docs/kbn_esql_validation_autocomplete.devdocs.json index dd8f595a501ab..84123ec79a728 100644 --- a/api_docs/kbn_esql_validation_autocomplete.devdocs.json +++ b/api_docs/kbn_esql_validation_autocomplete.devdocs.json @@ -1528,6 +1528,62 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.getRecommendedQueries", + "type": "Function", + "tags": [], + "label": "getRecommendedQueries", + "description": [], + "signature": [ + "({ fromCommand, timeField, }: { fromCommand: string; timeField?: string | undefined; }) => { label: string; description: string; queryString: string; }[]" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/autocomplete/recommended_queries/templates.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.getRecommendedQueries.$1", + "type": "Object", + "tags": [], + "label": "{\n fromCommand,\n timeField,\n}", + "description": [], + "path": "packages/kbn-esql-validation-autocomplete/src/autocomplete/recommended_queries/templates.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.getRecommendedQueries.$1.fromCommand", + "type": "string", + "tags": [], + "label": "fromCommand", + "description": [], + "path": "packages/kbn-esql-validation-autocomplete/src/autocomplete/recommended_queries/templates.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.getRecommendedQueries.$1.timeField", + "type": "string", + "tags": [], + "label": "timeField", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/autocomplete/recommended_queries/templates.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.getSourcesHelper", @@ -2814,6 +2870,20 @@ "path": "packages/kbn-esql-validation-autocomplete/src/definitions/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.CommandDefinition.hasRecommendedQueries", + "type": "CompoundType", + "tags": [], + "label": "hasRecommendedQueries", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/definitions/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index b23d34c9cd9dd..f52d76153bdd7 100644 --- a/api_docs/kbn_esql_validation_autocomplete.mdx +++ b/api_docs/kbn_esql_validation_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-validation-autocomplete title: "@kbn/esql-validation-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-validation-autocomplete plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-validation-autocomplete'] --- import kbnEsqlValidationAutocompleteObj from './kbn_esql_validation_autocomplete.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 199 | 0 | 187 | 12 | +| 204 | 0 | 192 | 12 | ## Common diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index 77540a513ae94..76a575a1d86a8 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index 75c8ca738b377..719ce823fa816 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index c6fe63bd50eb0..4835a3606d060 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 8b897267cd2b0..dd6a4505f089d 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index 32e53bc2f2cc2..e891d822048c2 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 7c500303acca2..70af8eb43e9ec 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_formatters.mdx b/api_docs/kbn_formatters.mdx index d16cd71d30e1d..09af7d496adc6 100644 --- a/api_docs/kbn_formatters.mdx +++ b/api_docs/kbn_formatters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-formatters title: "@kbn/formatters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/formatters plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/formatters'] --- import kbnFormattersObj from './kbn_formatters.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 061dafabb04cf..edacc9b3e6bfa 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_ui_services.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index d8bcd11daa0e8..3903f80f70f53 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.mdx +++ b/api_docs/kbn_ftr_common_functional_ui_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-ui-services title: "@kbn/ftr-common-functional-ui-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-ui-services plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-ui-services'] --- import kbnFtrCommonFunctionalUiServicesObj from './kbn_ftr_common_functional_ui_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index fcaf5e7dc6c79..7f46de3c819fb 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index 5bebd891d6812..371e69d0f8969 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index 6c3cfa656c728..ee28e34df3bea 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grid_layout.mdx b/api_docs/kbn_grid_layout.mdx index 09abf2a9e8ea0..1f818ba1bcb38 100644 --- a/api_docs/kbn_grid_layout.mdx +++ b/api_docs/kbn_grid_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grid-layout title: "@kbn/grid-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grid-layout plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grid-layout'] --- import kbnGridLayoutObj from './kbn_grid_layout.devdocs.json'; diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index 81195547a9bcf..beb45ccbcc6bd 100644 --- a/api_docs/kbn_grouping.mdx +++ b/api_docs/kbn_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grouping title: "@kbn/grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grouping plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grouping'] --- import kbnGroupingObj from './kbn_grouping.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 568ba31679dc4..4b0422ba623da 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 561024510cd7d..4c8072d3b1328 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index e7a723f34332c..fa212de483c82 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index 2b2f6885039c9..5ca64be05f809 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 1d9637adfdafd..c8acdf3bae4c9 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index 1de70fb4002c3..e92474004298e 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index 7e90113ab8c68..eafc38a999ed3 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index ff9a6278f21df..3873d04c3aebb 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 24673ccb206d4..78b5aae5ffc70 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_index_management_shared_types.devdocs.json b/api_docs/kbn_index_management_shared_types.devdocs.json index 692858a05ed31..06162e0164629 100644 --- a/api_docs/kbn_index_management_shared_types.devdocs.json +++ b/api_docs/kbn_index_management_shared_types.devdocs.json @@ -1192,6 +1192,65 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/index-management-shared-types", + "id": "def-common.IndexManagementLocatorParams", + "type": "Interface", + "tags": [], + "label": "IndexManagementLocatorParams", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-management-shared-types", + "scope": "common", + "docId": "kibKbnIndexManagementSharedTypesPluginApi", + "section": "def-common.IndexManagementLocatorParams", + "text": "IndexManagementLocatorParams" + }, + " extends ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.SerializableRecord", + "text": "SerializableRecord" + } + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-management-shared-types", + "id": "def-common.IndexManagementLocatorParams.page", + "type": "string", + "tags": [], + "label": "page", + "description": [], + "signature": [ + "\"data_streams_details\"" + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-management-shared-types", + "id": "def-common.IndexManagementLocatorParams.dataStreamName", + "type": "string", + "tags": [], + "label": "dataStreamName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/index-management-shared-types", "id": "def-common.IndexManagementPluginSetup", @@ -1242,6 +1301,27 @@ "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-management-shared-types", + "id": "def-common.IndexManagementPluginSetup.locator", + "type": "Object", + "tags": [], + "label": "locator", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-management-shared-types", + "scope": "common", + "docId": "kibKbnIndexManagementSharedTypesPluginApi", + "section": "def-common.IndexManagementLocator", + "text": "IndexManagementLocator" + }, + " | undefined" + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -1941,6 +2021,36 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-management-shared-types", + "id": "def-common.IndexManagementLocator", + "type": "Type", + "tags": [], + "label": "IndexManagementLocator", + "description": [], + "signature": [ + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + { + "pluginId": "@kbn/index-management-shared-types", + "scope": "common", + "docId": "kibKbnIndexManagementSharedTypesPluginApi", + "section": "def-common.IndexManagementLocatorParams", + "text": "IndexManagementLocatorParams" + }, + ">" + ], + "path": "x-pack/packages/index-management/index_management_shared_types/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/kbn_index_management_shared_types.mdx b/api_docs/kbn_index_management_shared_types.mdx index edff541a8bd3a..c494c8a74f2dc 100644 --- a/api_docs/kbn_index_management_shared_types.mdx +++ b/api_docs/kbn_index_management_shared_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-management-shared-types title: "@kbn/index-management-shared-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-management-shared-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-management-shared-types'] --- import kbnIndexManagementSharedTypesObj from './kbn_index_management_shared_types.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 114 | 3 | 114 | 0 | +| 119 | 3 | 119 | 0 | ## Common diff --git a/api_docs/kbn_inference_integration_flyout.mdx b/api_docs/kbn_inference_integration_flyout.mdx index 641eda9933cd3..d0492904cd81a 100644 --- a/api_docs/kbn_inference_integration_flyout.mdx +++ b/api_docs/kbn_inference_integration_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-inference_integration_flyout title: "@kbn/inference_integration_flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/inference_integration_flyout plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/inference_integration_flyout'] --- import kbnInferenceIntegrationFlyoutObj from './kbn_inference_integration_flyout.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index c3b4ca0f787b6..31a1ff0b934f8 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 8d17b61d762b2..706093dba3ad1 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_investigation_shared.devdocs.json b/api_docs/kbn_investigation_shared.devdocs.json index 0394d26c3f6db..b4089edd839b5 100644 --- a/api_docs/kbn_investigation_shared.devdocs.json +++ b/api_docs/kbn_investigation_shared.devdocs.json @@ -617,7 +617,7 @@ "label": "createInvestigationItemParamsSchema", "description": [], "signature": [ - "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodString; type: Zod.ZodString; params: Zod.ZodRecord; }, \"strip\", Zod.ZodTypeAny, { params: Record; type: string; title: string; }, { params: Record; type: string; title: string; }>; }, \"strip\", Zod.ZodTypeAny, { body: { params: Record; type: string; title: string; }; path: { investigationId: string; }; }, { body: { params: Record; type: string; title: string; }; path: { investigationId: string; }; }>" + "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodString; type: Zod.ZodString; params: Zod.ZodRecord; }, \"strip\", Zod.ZodTypeAny, { params: Record; type: string; title: string; }, { params: Record; type: string; title: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { investigationId: string; }; body: { params: Record; type: string; title: string; }; }, { path: { investigationId: string; }; body: { params: Record; type: string; title: string; }; }>" ], "path": "packages/kbn-investigation-shared/src/rest_specs/create_item.ts", "deprecated": false, @@ -647,7 +647,7 @@ "label": "createInvestigationNoteParamsSchema", "description": [], "signature": [ - "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ content: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { content: string; }, { content: string; }>; }, \"strip\", Zod.ZodTypeAny, { body: { content: string; }; path: { investigationId: string; }; }, { body: { content: string; }; path: { investigationId: string; }; }>" + "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ content: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { content: string; }, { content: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { investigationId: string; }; body: { content: string; }; }, { path: { investigationId: string; }; body: { content: string; }; }>" ], "path": "packages/kbn-investigation-shared/src/rest_specs/create_note.ts", "deprecated": false, @@ -1172,7 +1172,7 @@ "label": "updateInvestigationItemParamsSchema", "description": [], "signature": [ - "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; itemId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { itemId: string; investigationId: string; }, { itemId: string; investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodString; type: Zod.ZodString; params: Zod.ZodRecord; }, \"strip\", Zod.ZodTypeAny, { params: Record; type: string; title: string; }, { params: Record; type: string; title: string; }>; }, \"strip\", Zod.ZodTypeAny, { body: { params: Record; type: string; title: string; }; path: { itemId: string; investigationId: string; }; }, { body: { params: Record; type: string; title: string; }; path: { itemId: string; investigationId: string; }; }>" + "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; itemId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { itemId: string; investigationId: string; }, { itemId: string; investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodString; type: Zod.ZodString; params: Zod.ZodRecord; }, \"strip\", Zod.ZodTypeAny, { params: Record; type: string; title: string; }, { params: Record; type: string; title: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { itemId: string; investigationId: string; }; body: { params: Record; type: string; title: string; }; }, { path: { itemId: string; investigationId: string; }; body: { params: Record; type: string; title: string; }; }>" ], "path": "packages/kbn-investigation-shared/src/rest_specs/update_item.ts", "deprecated": false, @@ -1202,7 +1202,7 @@ "label": "updateInvestigationNoteParamsSchema", "description": [], "signature": [ - "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; noteId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; noteId: string; }, { investigationId: string; noteId: string; }>; body: Zod.ZodObject<{ content: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { content: string; }, { content: string; }>; }, \"strip\", Zod.ZodTypeAny, { body: { content: string; }; path: { investigationId: string; noteId: string; }; }, { body: { content: string; }; path: { investigationId: string; noteId: string; }; }>" + "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; noteId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; noteId: string; }, { investigationId: string; noteId: string; }>; body: Zod.ZodObject<{ content: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { content: string; }, { content: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { investigationId: string; noteId: string; }; body: { content: string; }; }, { path: { investigationId: string; noteId: string; }; body: { content: string; }; }>" ], "path": "packages/kbn-investigation-shared/src/rest_specs/update_note.ts", "deprecated": false, @@ -1232,7 +1232,7 @@ "label": "updateInvestigationParamsSchema", "description": [], "signature": [ - "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodOptional; status: Zod.ZodOptional, Zod.ZodLiteral<\"active\">, Zod.ZodLiteral<\"mitigated\">, Zod.ZodLiteral<\"resolved\">, Zod.ZodLiteral<\"cancelled\">]>>; params: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { timeRange: { from: number; to: number; }; }, { timeRange: { from: number; to: number; }; }>>; tags: Zod.ZodOptional>; externalIncidentUrl: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }, { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }; path: { investigationId: string; }; }, { body: { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }; path: { investigationId: string; }; }>" + "Zod.ZodObject<{ path: Zod.ZodObject<{ investigationId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { investigationId: string; }, { investigationId: string; }>; body: Zod.ZodObject<{ title: Zod.ZodOptional; status: Zod.ZodOptional, Zod.ZodLiteral<\"active\">, Zod.ZodLiteral<\"mitigated\">, Zod.ZodLiteral<\"resolved\">, Zod.ZodLiteral<\"cancelled\">]>>; params: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { timeRange: { from: number; to: number; }; }, { timeRange: { from: number; to: number; }; }>>; tags: Zod.ZodOptional>; externalIncidentUrl: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }, { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { path: { investigationId: string; }; body: { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }; }, { path: { investigationId: string; }; body: { params?: { timeRange: { from: number; to: number; }; } | undefined; tags?: string[] | undefined; title?: string | undefined; status?: \"active\" | \"triage\" | \"mitigated\" | \"resolved\" | \"cancelled\" | undefined; externalIncidentUrl?: string | null | undefined; }; }>" ], "path": "packages/kbn-investigation-shared/src/rest_specs/update.ts", "deprecated": false, diff --git a/api_docs/kbn_investigation_shared.mdx b/api_docs/kbn_investigation_shared.mdx index 64e56af633568..27d7fb0876cd5 100644 --- a/api_docs/kbn_investigation_shared.mdx +++ b/api_docs/kbn_investigation_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-investigation-shared title: "@kbn/investigation-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/investigation-shared plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/investigation-shared'] --- import kbnInvestigationSharedObj from './kbn_investigation_shared.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 2f7c3f0c51630..9ec297513cc61 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_ipynb.mdx b/api_docs/kbn_ipynb.mdx index ffbde1cedb813..47cfda8071dac 100644 --- a/api_docs/kbn_ipynb.mdx +++ b/api_docs/kbn_ipynb.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ipynb title: "@kbn/ipynb" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ipynb plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ipynb'] --- import kbnIpynbObj from './kbn_ipynb.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 1890fe736e6e7..2b6f476c84b8d 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index 1a983c98e3e33..2fabdcda431f5 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index c19740d0d69b1..599ba9f68c929 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_json_schemas.mdx b/api_docs/kbn_json_schemas.mdx index bef66f9007b5d..3824290da59a5 100644 --- a/api_docs/kbn_json_schemas.mdx +++ b/api_docs/kbn_json_schemas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-schemas title: "@kbn/json-schemas" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-schemas plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-schemas'] --- import kbnJsonSchemasObj from './kbn_json_schemas.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 558302a135f03..fbc5a4e3b9a13 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation.mdx b/api_docs/kbn_language_documentation.mdx index a0c04aaf3b670..2b4f861fa6579 100644 --- a/api_docs/kbn_language_documentation.mdx +++ b/api_docs/kbn_language_documentation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation title: "@kbn/language-documentation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation'] --- import kbnLanguageDocumentationObj from './kbn_language_documentation.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index 3f9d940dd2661..df135d2ebb24c 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_lens_formula_docs.mdx b/api_docs/kbn_lens_formula_docs.mdx index 8a0664b9d4c1e..b009f77910151 100644 --- a/api_docs/kbn_lens_formula_docs.mdx +++ b/api_docs/kbn_lens_formula_docs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-formula-docs title: "@kbn/lens-formula-docs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-formula-docs plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-formula-docs'] --- import kbnLensFormulaDocsObj from './kbn_lens_formula_docs.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 0572b7101861f..8b663957e9b3c 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index c4346b296a2b3..b2160f040fc62 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_content_badge.mdx b/api_docs/kbn_managed_content_badge.mdx index 60204a4d4e635..529d12adb42d2 100644 --- a/api_docs/kbn_managed_content_badge.mdx +++ b/api_docs/kbn_managed_content_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-content-badge title: "@kbn/managed-content-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-content-badge plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-content-badge'] --- import kbnManagedContentBadgeObj from './kbn_managed_content_badge.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index 92d4286230bef..4a2440d464037 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index a5c1671366906..de5b85ce8f00e 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index 4079f0fe0d3f1..b99e0926710f8 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index c65f51a1657f6..e8181a426e5aa 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index 83d7015960c10..5531397895ec4 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index d9c04ae3b1f2f..e9912821e0d90 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index 0fee47beacba5..adc48e882c60c 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index e2fa73613faaf..64742be517ab4 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index dfaec6174fcfb..892250c18f476 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index adc46b53b46c7..ef8bd807ae9d4 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index 686de2ca8ec2c..f1f47f3ac90d8 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index 349bebf209cd4..6f7758dbb1c45 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index f0f49995f1b94..e516ea0f02289 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 4df05c2372709..5889db1b46c0b 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index 0f8c50d2c724b..fa1ea030ab768 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.devdocs.json b/api_docs/kbn_ml_agg_utils.devdocs.json index b782d41217b5e..8b6e1af49d539 100644 --- a/api_docs/kbn_ml_agg_utils.devdocs.json +++ b/api_docs/kbn_ml_agg_utils.devdocs.json @@ -471,8 +471,7 @@ "section": "def-common.NumberValidationResult", "text": "NumberValidationResult" }, - " | null) & ", - "MemoizedFunction" + " | null) & _.MemoizedFunction" ], "path": "x-pack/packages/ml/agg_utils/src/validate_number.ts", "deprecated": false, diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index a2aca7b480702..ade856d4afd63 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index 3898279e816bc..408cc8b685390 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_cancellable_search.mdx b/api_docs/kbn_ml_cancellable_search.mdx index bca8c6b3645f3..7071638352fa8 100644 --- a/api_docs/kbn_ml_cancellable_search.mdx +++ b/api_docs/kbn_ml_cancellable_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-cancellable-search title: "@kbn/ml-cancellable-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-cancellable-search plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-cancellable-search'] --- import kbnMlCancellableSearchObj from './kbn_ml_cancellable_search.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index b96a35ea66014..14aa93bc79303 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index ea01902d92049..9f9df22217c01 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index 87eb1ec825dae..eed4ade9ca233 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index bf0fec7949987..fa160db0609bb 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 021d514eb3141..ec4c3e3aa0ab1 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 863e54fcb91fb..19171db9bafb7 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index ca2ee29c0455b..8125a9f3416c1 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_field_stats_flyout.devdocs.json b/api_docs/kbn_ml_field_stats_flyout.devdocs.json index 131c42348ee75..7f1b33a152d60 100644 --- a/api_docs/kbn_ml_field_stats_flyout.devdocs.json +++ b/api_docs/kbn_ml_field_stats_flyout.devdocs.json @@ -591,7 +591,7 @@ "signature": [ "Omit<", "_EuiComboBoxProps", - ", \"options\" | \"prepend\" | \"append\" | \"async\" | \"isClearable\" | \"compressed\" | \"fullWidth\" | \"selectedOptions\" | \"optionMatcher\" | \"singleSelection\" | \"sortMatchesBy\"> & Partial>" + ", \"options\" | \"async\" | \"prepend\" | \"append\" | \"isClearable\" | \"compressed\" | \"fullWidth\" | \"selectedOptions\" | \"optionMatcher\" | \"singleSelection\" | \"sortMatchesBy\"> & Partial>" ], "path": "x-pack/packages/ml/field_stats_flyout/eui_combo_box_with_field_stats.tsx", "deprecated": false, diff --git a/api_docs/kbn_ml_field_stats_flyout.mdx b/api_docs/kbn_ml_field_stats_flyout.mdx index 64823abf36b30..c41ce02d0d854 100644 --- a/api_docs/kbn_ml_field_stats_flyout.mdx +++ b/api_docs/kbn_ml_field_stats_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-field-stats-flyout title: "@kbn/ml-field-stats-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-field-stats-flyout plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-field-stats-flyout'] --- import kbnMlFieldStatsFlyoutObj from './kbn_ml_field_stats_flyout.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index 410ac9c5e3073..977cad40c394d 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index e1d3160eb23a8..b766037d44bdd 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 97f0c9dd92e0a..debccf6adf2eb 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index 10af486d5d30f..1f8bcc6512c65 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index aff232e826d1a..38d18902b95f2 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index 1186acb2e1cf0..fc3514afa0d99 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index 30a72fa8b906c..87c12e1b50e72 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_parse_interval.mdx b/api_docs/kbn_ml_parse_interval.mdx index efe4d8a3e5c42..fba4064be1fa6 100644 --- a/api_docs/kbn_ml_parse_interval.mdx +++ b/api_docs/kbn_ml_parse_interval.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-parse-interval title: "@kbn/ml-parse-interval" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-parse-interval plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-parse-interval'] --- import kbnMlParseIntervalObj from './kbn_ml_parse_interval.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index 9ff84d81a38e7..8e008d75bc389 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index 580be021eb99a..0667794f06841 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index 52a923da8f287..3c5c4eb0b61e1 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index d8d07c8604ca2..bcf4004a921ff 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index a010de32ddffc..165c52136ac86 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_time_buckets.mdx b/api_docs/kbn_ml_time_buckets.mdx index 2e4c2742c54e4..37c90ca8d7278 100644 --- a/api_docs/kbn_ml_time_buckets.mdx +++ b/api_docs/kbn_ml_time_buckets.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-time-buckets title: "@kbn/ml-time-buckets" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-time-buckets plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-time-buckets'] --- import kbnMlTimeBucketsObj from './kbn_ml_time_buckets.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 06fc28f82b447..ae1d53975be5e 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_ui_actions.mdx b/api_docs/kbn_ml_ui_actions.mdx index 476cc5dc40375..deda4a1b84fed 100644 --- a/api_docs/kbn_ml_ui_actions.mdx +++ b/api_docs/kbn_ml_ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-ui-actions title: "@kbn/ml-ui-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-ui-actions plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-ui-actions'] --- import kbnMlUiActionsObj from './kbn_ml_ui_actions.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index a4433aa421398..238cdf7da163a 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_ml_validators.mdx b/api_docs/kbn_ml_validators.mdx index 1ddc7deb9b69b..1249f99f8d804 100644 --- a/api_docs/kbn_ml_validators.mdx +++ b/api_docs/kbn_ml_validators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-validators title: "@kbn/ml-validators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-validators plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-validators'] --- import kbnMlValidatorsObj from './kbn_ml_validators.devdocs.json'; diff --git a/api_docs/kbn_mock_idp_utils.mdx b/api_docs/kbn_mock_idp_utils.mdx index fbb8946691b06..e782e7280af15 100644 --- a/api_docs/kbn_mock_idp_utils.mdx +++ b/api_docs/kbn_mock_idp_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mock-idp-utils title: "@kbn/mock-idp-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mock-idp-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mock-idp-utils'] --- import kbnMockIdpUtilsObj from './kbn_mock_idp_utils.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 52bcc0ddb8ed4..d2e69f3dc1d14 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index 81bcf8da9120a..f19f29a6113da 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_object_versioning_utils.mdx b/api_docs/kbn_object_versioning_utils.mdx index fd4358cbae95b..d672121c2c00d 100644 --- a/api_docs/kbn_object_versioning_utils.mdx +++ b/api_docs/kbn_object_versioning_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning-utils title: "@kbn/object-versioning-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning-utils'] --- import kbnObjectVersioningUtilsObj from './kbn_object_versioning_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index e929014e88b7a..592966e13ca2b 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_rule_utils.mdx b/api_docs/kbn_observability_alerting_rule_utils.mdx index dc63e29320d33..7e1eb498fb0e8 100644 --- a/api_docs/kbn_observability_alerting_rule_utils.mdx +++ b/api_docs/kbn_observability_alerting_rule_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-rule-utils title: "@kbn/observability-alerting-rule-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-rule-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-rule-utils'] --- import kbnObservabilityAlertingRuleUtilsObj from './kbn_observability_alerting_rule_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 968e592d7fd2e..f0a514b4af2cc 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx index fc6721033cb98..62f86d664eced 100644 --- a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-get-padded-alert-time-range-util title: "@kbn/observability-get-padded-alert-time-range-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-get-padded-alert-time-range-util plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-get-padded-alert-time-range-util'] --- import kbnObservabilityGetPaddedAlertTimeRangeUtilObj from './kbn_observability_get_padded_alert_time_range_util.devdocs.json'; diff --git a/api_docs/kbn_observability_synthetics_test_data.mdx b/api_docs/kbn_observability_synthetics_test_data.mdx index 07cfc1ec6a47d..828edac99b8fb 100644 --- a/api_docs/kbn_observability_synthetics_test_data.mdx +++ b/api_docs/kbn_observability_synthetics_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-synthetics-test-data title: "@kbn/observability-synthetics-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-synthetics-test-data plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-synthetics-test-data'] --- import kbnObservabilitySyntheticsTestDataObj from './kbn_observability_synthetics_test_data.devdocs.json'; diff --git a/api_docs/kbn_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx index 0ef5d50c9f477..37f1c1e81345d 100644 --- a/api_docs/kbn_openapi_bundler.mdx +++ b/api_docs/kbn_openapi_bundler.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-bundler title: "@kbn/openapi-bundler" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-bundler plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-bundler'] --- import kbnOpenapiBundlerObj from './kbn_openapi_bundler.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index 8bfa15ea2bf87..c8df15ea30421 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index a92195bca7a16..a164fe9ff99da 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index bdeb5c82efd84..fcaaa33c2e8ed 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_osquery_io_ts_types.mdx b/api_docs/kbn_osquery_io_ts_types.mdx index 045aa4c9cc388..3ef18fedfbfd1 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx index cd19794c01859..e9d3d9323cc47 100644 --- a/api_docs/kbn_panel_loader.mdx +++ b/api_docs/kbn_panel_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-panel-loader title: "@kbn/panel-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/panel-loader plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/panel-loader'] --- import kbnPanelLoaderObj from './kbn_panel_loader.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 48bcca1c92f1c..83d1b1ab5aaa5 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_check.mdx b/api_docs/kbn_plugin_check.mdx index ccd75cd033ad3..6a4d949ae3371 100644 --- a/api_docs/kbn_plugin_check.mdx +++ b/api_docs/kbn_plugin_check.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-check title: "@kbn/plugin-check" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-check plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-check'] --- import kbnPluginCheckObj from './kbn_plugin_check.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index c933980118ea5..218a31c2c8e6a 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index a546d47bd67ea..199b781f7001f 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_presentation_containers.mdx b/api_docs/kbn_presentation_containers.mdx index e255e73b868cc..0e70093279f5a 100644 --- a/api_docs/kbn_presentation_containers.mdx +++ b/api_docs/kbn_presentation_containers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-containers title: "@kbn/presentation-containers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-containers plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index a18754f8412de..682ee67a46f48 100644 --- a/api_docs/kbn_presentation_publishing.mdx +++ b/api_docs/kbn_presentation_publishing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-publishing title: "@kbn/presentation-publishing" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-publishing plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; diff --git a/api_docs/kbn_product_doc_artifact_builder.mdx b/api_docs/kbn_product_doc_artifact_builder.mdx index a44c254e63c7c..5db07210304ad 100644 --- a/api_docs/kbn_product_doc_artifact_builder.mdx +++ b/api_docs/kbn_product_doc_artifact_builder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-product-doc-artifact-builder title: "@kbn/product-doc-artifact-builder" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/product-doc-artifact-builder plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/product-doc-artifact-builder'] --- import kbnProductDocArtifactBuilderObj from './kbn_product_doc_artifact_builder.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 75adfc0b6c393..968caae8e9ca8 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 07435d529c9ab..3f0ab65e186bd 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index b972cda37a024..2efaadf4992a1 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_hooks.mdx b/api_docs/kbn_react_hooks.mdx index 5c471e1dc1b04..2a6d313e6aabe 100644 --- a/api_docs/kbn_react_hooks.mdx +++ b/api_docs/kbn_react_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-hooks title: "@kbn/react-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-hooks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-hooks'] --- import kbnReactHooksObj from './kbn_react_hooks.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index b4ac6fcee4c03..d1dd1e19bce08 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index e8098d6fd8cdb..da47b5db355e3 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index 9a39fb6ca9a61..1d9be93872499 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index ebbdeaeb1655d..aeb14fa369275 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index 466266b9ffe7b..779d31e44efdc 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index eaa97648ed72b..c0b21e3c1a85e 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_recently_accessed.mdx b/api_docs/kbn_recently_accessed.mdx index 6ad833de85471..3e559aad5d4de 100644 --- a/api_docs/kbn_recently_accessed.mdx +++ b/api_docs/kbn_recently_accessed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-recently-accessed title: "@kbn/recently-accessed" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/recently-accessed plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/recently-accessed'] --- import kbnRecentlyAccessedObj from './kbn_recently_accessed.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 73cb3631f5bc0..4026d67c2fece 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index 477a2c93b9710..b6c06b57271ed 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index 0e5303e48b54c..5e7ca480ce0fa 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 89374282553c0..36bd0669965d6 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 84b7b4e382dcf..1248577e24f2e 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_csv_share_panel.mdx b/api_docs/kbn_reporting_csv_share_panel.mdx index 49336e55c04fc..846aece4de830 100644 --- a/api_docs/kbn_reporting_csv_share_panel.mdx +++ b/api_docs/kbn_reporting_csv_share_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-csv-share-panel title: "@kbn/reporting-csv-share-panel" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-csv-share-panel plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-csv-share-panel'] --- import kbnReportingCsvSharePanelObj from './kbn_reporting_csv_share_panel.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index 2896c16a50b71..8646f515d9d6f 100644 --- a/api_docs/kbn_reporting_export_types_csv.mdx +++ b/api_docs/kbn_reporting_export_types_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv title: "@kbn/reporting-export-types-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index 53d2f5b74eb34..0b53eca7a0e44 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.mdx +++ b/api_docs/kbn_reporting_export_types_csv_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv-common title: "@kbn/reporting-export-types-csv-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index c6a0fdace71ce..c7dd02354a7ea 100644 --- a/api_docs/kbn_reporting_export_types_pdf.mdx +++ b/api_docs/kbn_reporting_export_types_pdf.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf title: "@kbn/reporting-export-types-pdf" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf'] --- import kbnReportingExportTypesPdfObj from './kbn_reporting_export_types_pdf.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf_common.mdx b/api_docs/kbn_reporting_export_types_pdf_common.mdx index 74a86fdf86770..e0af4316adec1 100644 --- a/api_docs/kbn_reporting_export_types_pdf_common.mdx +++ b/api_docs/kbn_reporting_export_types_pdf_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf-common title: "@kbn/reporting-export-types-pdf-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf-common'] --- import kbnReportingExportTypesPdfCommonObj from './kbn_reporting_export_types_pdf_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png.mdx b/api_docs/kbn_reporting_export_types_png.mdx index e97ac348eabe3..3aaa58e646b64 100644 --- a/api_docs/kbn_reporting_export_types_png.mdx +++ b/api_docs/kbn_reporting_export_types_png.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png title: "@kbn/reporting-export-types-png" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png'] --- import kbnReportingExportTypesPngObj from './kbn_reporting_export_types_png.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png_common.mdx b/api_docs/kbn_reporting_export_types_png_common.mdx index 0ce721efb9cb0..b620da4588d5a 100644 --- a/api_docs/kbn_reporting_export_types_png_common.mdx +++ b/api_docs/kbn_reporting_export_types_png_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png-common title: "@kbn/reporting-export-types-png-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png-common'] --- import kbnReportingExportTypesPngCommonObj from './kbn_reporting_export_types_png_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_mocks_server.mdx b/api_docs/kbn_reporting_mocks_server.mdx index 9c47025b8d273..f83b1aebc76eb 100644 --- a/api_docs/kbn_reporting_mocks_server.mdx +++ b/api_docs/kbn_reporting_mocks_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-mocks-server title: "@kbn/reporting-mocks-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-mocks-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index 770521c1e77d2..c0861e2c8c768 100644 --- a/api_docs/kbn_reporting_public.mdx +++ b/api_docs/kbn_reporting_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-public title: "@kbn/reporting-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-public plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index c681fc144f6f4..72bae1fb03ccc 100644 --- a/api_docs/kbn_reporting_server.mdx +++ b/api_docs/kbn_reporting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-server title: "@kbn/reporting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index ceef5a0b66d4f..0d6578bad70c3 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_response_ops_feature_flag_service.mdx b/api_docs/kbn_response_ops_feature_flag_service.mdx index 6672f29f92f43..4a30d3fe3221e 100644 --- a/api_docs/kbn_response_ops_feature_flag_service.mdx +++ b/api_docs/kbn_response_ops_feature_flag_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-feature-flag-service title: "@kbn/response-ops-feature-flag-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-feature-flag-service plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-feature-flag-service'] --- import kbnResponseOpsFeatureFlagServiceObj from './kbn_response_ops_feature_flag_service.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index eb05f818f70f6..3fbeb9aa4efb5 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rollup.mdx b/api_docs/kbn_rollup.mdx index 9e847935b874a..f73ddef315fe5 100644 --- a/api_docs/kbn_rollup.mdx +++ b/api_docs/kbn_rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rollup title: "@kbn/rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rollup plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rollup'] --- import kbnRollupObj from './kbn_rollup.devdocs.json'; diff --git a/api_docs/kbn_router_to_openapispec.mdx b/api_docs/kbn_router_to_openapispec.mdx index ac6467afeb59e..d1c864721603d 100644 --- a/api_docs/kbn_router_to_openapispec.mdx +++ b/api_docs/kbn_router_to_openapispec.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-to-openapispec title: "@kbn/router-to-openapispec" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-to-openapispec plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-to-openapispec'] --- import kbnRouterToOpenapispecObj from './kbn_router_to_openapispec.devdocs.json'; diff --git a/api_docs/kbn_router_utils.mdx b/api_docs/kbn_router_utils.mdx index 813a75f128acf..c8e9ba6bd7920 100644 --- a/api_docs/kbn_router_utils.mdx +++ b/api_docs/kbn_router_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-utils title: "@kbn/router-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-utils'] --- import kbnRouterUtilsObj from './kbn_router_utils.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index e3141ed0ab895..873698677d569 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index e1e2d4bfeda4b..f22959da85643 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index 98075853c7f05..5f1dda2797bc9 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_screenshotting_server.mdx b/api_docs/kbn_screenshotting_server.mdx index dff7e7db5a6e5..7d4d0aa528f0d 100644 --- a/api_docs/kbn_screenshotting_server.mdx +++ b/api_docs/kbn_screenshotting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-screenshotting-server title: "@kbn/screenshotting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/screenshotting-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/screenshotting-server'] --- import kbnScreenshottingServerObj from './kbn_screenshotting_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_keys_components.mdx b/api_docs/kbn_search_api_keys_components.mdx index ae667638d22bd..ede098e5c0d7e 100644 --- a/api_docs/kbn_search_api_keys_components.mdx +++ b/api_docs/kbn_search_api_keys_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-keys-components title: "@kbn/search-api-keys-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-keys-components plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-keys-components'] --- import kbnSearchApiKeysComponentsObj from './kbn_search_api_keys_components.devdocs.json'; diff --git a/api_docs/kbn_search_api_keys_server.mdx b/api_docs/kbn_search_api_keys_server.mdx index ae14ff3baf7a3..a364f9df583d1 100644 --- a/api_docs/kbn_search_api_keys_server.mdx +++ b/api_docs/kbn_search_api_keys_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-keys-server title: "@kbn/search-api-keys-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-keys-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-keys-server'] --- import kbnSearchApiKeysServerObj from './kbn_search_api_keys_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index 4448ca78cbd83..67cfdb9e9dd4e 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index ae53f15467f35..d60675ebeab3b 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index c6d5be00fc157..c81dd2089aab4 100644 --- a/api_docs/kbn_search_errors.mdx +++ b/api_docs/kbn_search_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-errors title: "@kbn/search-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-errors plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-errors'] --- import kbnSearchErrorsObj from './kbn_search_errors.devdocs.json'; diff --git a/api_docs/kbn_search_index_documents.devdocs.json b/api_docs/kbn_search_index_documents.devdocs.json index 898afd3c6a698..89638cae88f09 100644 --- a/api_docs/kbn_search_index_documents.devdocs.json +++ b/api_docs/kbn_search_index_documents.devdocs.json @@ -274,7 +274,7 @@ "label": "Result", "description": [], "signature": [ - "({ metaData, fields, defaultVisibleFields, compactCard, showScore, onDocumentClick, }: ", + "({ metaData, fields, defaultVisibleFields, compactCard, showScore, onDocumentClick, onDocumentDelete, }: ", "ResultProps", ") => React.JSX.Element" ], @@ -287,7 +287,7 @@ "id": "def-common.Result.$1", "type": "Object", "tags": [], - "label": "{\n metaData,\n fields,\n defaultVisibleFields = DEFAULT_VISIBLE_FIELDS,\n compactCard = true,\n showScore = false,\n onDocumentClick,\n}", + "label": "{\n metaData,\n fields,\n defaultVisibleFields = DEFAULT_VISIBLE_FIELDS,\n compactCard = true,\n showScore = false,\n onDocumentClick,\n onDocumentDelete,\n}", "description": [], "signature": [ "ResultProps" diff --git a/api_docs/kbn_search_index_documents.mdx b/api_docs/kbn_search_index_documents.mdx index d98a1f013fdd2..448f5f47f19ce 100644 --- a/api_docs/kbn_search_index_documents.mdx +++ b/api_docs/kbn_search_index_documents.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-index-documents title: "@kbn/search-index-documents" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-index-documents plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-index-documents'] --- import kbnSearchIndexDocumentsObj from './kbn_search_index_documents.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 9bc1eaf19d150..340e556ea2b17 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_search_shared_ui.mdx b/api_docs/kbn_search_shared_ui.mdx index cd0819492e755..eed566207285f 100644 --- a/api_docs/kbn_search_shared_ui.mdx +++ b/api_docs/kbn_search_shared_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-shared-ui title: "@kbn/search-shared-ui" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-shared-ui plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-shared-ui'] --- import kbnSearchSharedUiObj from './kbn_search_shared_ui.devdocs.json'; diff --git a/api_docs/kbn_search_types.mdx b/api_docs/kbn_search_types.mdx index ffb1dc74d62f2..15e78baad0e75 100644 --- a/api_docs/kbn_search_types.mdx +++ b/api_docs/kbn_search_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-types title: "@kbn/search-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_api_key_management.mdx b/api_docs/kbn_security_api_key_management.mdx index 0fa186e57857d..302e7fd2ae6fc 100644 --- a/api_docs/kbn_security_api_key_management.mdx +++ b/api_docs/kbn_security_api_key_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-api-key-management title: "@kbn/security-api-key-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-api-key-management plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-api-key-management'] --- import kbnSecurityApiKeyManagementObj from './kbn_security_api_key_management.devdocs.json'; diff --git a/api_docs/kbn_security_authorization_core.mdx b/api_docs/kbn_security_authorization_core.mdx index ee0486e8b1fde..916824d4c80fb 100644 --- a/api_docs/kbn_security_authorization_core.mdx +++ b/api_docs/kbn_security_authorization_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-authorization-core title: "@kbn/security-authorization-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-authorization-core plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-authorization-core'] --- import kbnSecurityAuthorizationCoreObj from './kbn_security_authorization_core.devdocs.json'; diff --git a/api_docs/kbn_security_form_components.mdx b/api_docs/kbn_security_form_components.mdx index 4bf26cb012826..3ef7c20ad615c 100644 --- a/api_docs/kbn_security_form_components.mdx +++ b/api_docs/kbn_security_form_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-form-components title: "@kbn/security-form-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-form-components plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-form-components'] --- import kbnSecurityFormComponentsObj from './kbn_security_form_components.devdocs.json'; diff --git a/api_docs/kbn_security_hardening.mdx b/api_docs/kbn_security_hardening.mdx index 845fd46276105..2189641935b26 100644 --- a/api_docs/kbn_security_hardening.mdx +++ b/api_docs/kbn_security_hardening.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-hardening title: "@kbn/security-hardening" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-hardening plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-hardening'] --- import kbnSecurityHardeningObj from './kbn_security_hardening.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx index c98dcb9ed8d7d..732d834db5f75 100644 --- a/api_docs/kbn_security_plugin_types_common.mdx +++ b/api_docs/kbn_security_plugin_types_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-common title: "@kbn/security-plugin-types-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-common'] --- import kbnSecurityPluginTypesCommonObj from './kbn_security_plugin_types_common.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_public.mdx b/api_docs/kbn_security_plugin_types_public.mdx index 6e315f3e60738..9f6fc6bb3a842 100644 --- a/api_docs/kbn_security_plugin_types_public.mdx +++ b/api_docs/kbn_security_plugin_types_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-public title: "@kbn/security-plugin-types-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-public plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index 72181bebdf510..c13dea0cf1d5c 100644 --- a/api_docs/kbn_security_plugin_types_server.mdx +++ b/api_docs/kbn_security_plugin_types_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-server title: "@kbn/security-plugin-types-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] --- import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; diff --git a/api_docs/kbn_security_role_management_model.mdx b/api_docs/kbn_security_role_management_model.mdx index 8d87403d03401..522ad94e7ea9d 100644 --- a/api_docs/kbn_security_role_management_model.mdx +++ b/api_docs/kbn_security_role_management_model.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-role-management-model title: "@kbn/security-role-management-model" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-role-management-model plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-role-management-model'] --- import kbnSecurityRoleManagementModelObj from './kbn_security_role_management_model.devdocs.json'; diff --git a/api_docs/kbn_security_solution_common.mdx b/api_docs/kbn_security_solution_common.mdx index f9d9aec848e01..e6413d43302e6 100644 --- a/api_docs/kbn_security_solution_common.mdx +++ b/api_docs/kbn_security_solution_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-common title: "@kbn/security-solution-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-common plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-common'] --- import kbnSecuritySolutionCommonObj from './kbn_security_solution_common.devdocs.json'; diff --git a/api_docs/kbn_security_solution_distribution_bar.mdx b/api_docs/kbn_security_solution_distribution_bar.mdx index b8e4b49dbd3be..e97493dadf6a7 100644 --- a/api_docs/kbn_security_solution_distribution_bar.mdx +++ b/api_docs/kbn_security_solution_distribution_bar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-distribution-bar title: "@kbn/security-solution-distribution-bar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-distribution-bar plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-distribution-bar'] --- import kbnSecuritySolutionDistributionBarObj from './kbn_security_solution_distribution_bar.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index d01d8c1eac3ec..01627073917dd 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index 9f5d1bab90eba..e1de23471bca5 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index 64386c40940e6..4e92aaebb9c88 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-side-nav'] --- import kbnSecuritySolutionSideNavObj from './kbn_security_solution_side_nav.devdocs.json'; diff --git a/api_docs/kbn_security_solution_storybook_config.mdx b/api_docs/kbn_security_solution_storybook_config.mdx index 62310d2fc5038..e9134129a76ab 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_security_ui_components.mdx b/api_docs/kbn_security_ui_components.mdx index 2b4458b7d6023..010756d7c268d 100644 --- a/api_docs/kbn_security_ui_components.mdx +++ b/api_docs/kbn_security_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-ui-components title: "@kbn/security-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-ui-components plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-ui-components'] --- import kbnSecurityUiComponentsObj from './kbn_security_ui_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 4b64072097118..6c6012e38a94d 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index e9dfc6cb3f130..c314132fb6c59 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index c3acc1902b0ae..9e44daeaa1f8d 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 0c12657f9adc8..55a0b60a721ad 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_exception_list_components.devdocs.json b/api_docs/kbn_securitysolution_exception_list_components.devdocs.json index e1106dd5c031d..23228311954f4 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.devdocs.json +++ b/api_docs/kbn_securitysolution_exception_list_components.devdocs.json @@ -868,7 +868,7 @@ "label": "formattedDateComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"path\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" + "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"path\" | \"code\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, @@ -882,7 +882,7 @@ "label": "securityLinkAnchorComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"path\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" + "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"path\" | \"code\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, @@ -1021,7 +1021,7 @@ "label": "securityLinkAnchorComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"path\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" + "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"path\" | \"code\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, @@ -1035,7 +1035,7 @@ "label": "formattedDateComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"path\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" + "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"path\" | \"code\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, @@ -1161,7 +1161,7 @@ "label": "showValueListModal", "description": [], "signature": [ - "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"path\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" + "\"symbol\" | \"object\" | \"source\" | \"meta\" | \"desc\" | \"filter\" | \"search\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"text\" | \"map\" | \"head\" | \"title\" | \"data\" | \"path\" | \"code\" | \"pattern\" | \"set\" | \"summary\" | \"template\" | \"span\" | \"q\" | \"body\" | \"html\" | \"stop\" | \"main\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"article\" | \"aside\" | \"audio\" | \"b\" | \"base\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"center\" | \"cite\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"form\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"img\" | \"input\" | \"ins\" | \"kbd\" | \"keygen\" | \"label\" | \"legend\" | \"li\" | \"mark\" | \"menu\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"output\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"progress\" | \"rp\" | \"rt\" | \"ruby\" | \"s\" | \"samp\" | \"slot\" | \"script\" | \"section\" | \"select\" | \"strong\" | \"style\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"time\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"svg\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"image\" | \"line\" | \"linearGradient\" | \"marker\" | \"mask\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\" | React.ComponentType" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index b1b80667adfe3..5436ea9c4050f 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index bfa0a021e959c..f41b923db1854 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 944dfac48d3da..419e90293ffcc 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 36a3073e0845c..e73e428abb8f5 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 7ef375bf391ca..73af640e0be1b 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index 74ba5ed4563aa..dc6cfdb53a2ac 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index b325959007c77..5cb544e9b7ba8 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index 1a2e1bfb43cdf..92af394435254 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index 92b82c496af29..9b3f664e9aea7 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 9fac0a1ec89cc..18107450e9ceb 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index b229c738a2e99..148bce950e7cf 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index 3d6fad7c7fc9e..94a9f78729db8 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 9733d00540ad1..f4b4706486e27 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index fd02abaafdf0a..6a45af618295e 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index cf28be4594df4..4780c577c3fc1 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_client.mdx b/api_docs/kbn_server_route_repository_client.mdx index 28406015f76e1..90ea560a4f40a 100644 --- a/api_docs/kbn_server_route_repository_client.mdx +++ b/api_docs/kbn_server_route_repository_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-client title: "@kbn/server-route-repository-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-client plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-client'] --- import kbnServerRouteRepositoryClientObj from './kbn_server_route_repository_client.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_utils.devdocs.json b/api_docs/kbn_server_route_repository_utils.devdocs.json index 20111453d650d..4f96f6bafd375 100644 --- a/api_docs/kbn_server_route_repository_utils.devdocs.json +++ b/api_docs/kbn_server_route_repository_utils.devdocs.json @@ -715,7 +715,7 @@ "label": "ZodParamsObject", "description": [], "signature": [ - "Zod.ZodObject<{ path?: Zod.ZodType | undefined; query?: Zod.ZodType | undefined; body?: Zod.ZodType | undefined; }, Zod.UnknownKeysParam, Zod.ZodTypeAny, { query?: unknown; body?: unknown; path?: unknown; }, { query?: unknown; body?: unknown; path?: unknown; }>" + "Zod.ZodObject<{ path?: Zod.ZodType | undefined; query?: Zod.ZodType | undefined; body?: Zod.ZodType | undefined; }, Zod.UnknownKeysParam, Zod.ZodTypeAny, { query?: unknown; path?: unknown; body?: unknown; }, { query?: unknown; path?: unknown; body?: unknown; }>" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, diff --git a/api_docs/kbn_server_route_repository_utils.mdx b/api_docs/kbn_server_route_repository_utils.mdx index 911007eeffdcd..829a33b532609 100644 --- a/api_docs/kbn_server_route_repository_utils.mdx +++ b/api_docs/kbn_server_route_repository_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-utils title: "@kbn/server-route-repository-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-utils'] --- import kbnServerRouteRepositoryUtilsObj from './kbn_server_route_repository_utils.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index 17272be250985..21150d4e8ba59 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index 83a2e2484a36e..a48cb235d6519 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index 270985e709e79..3ce9b6b6c0ab4 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index 2e437a4688a6a..25ed33ee1d1aa 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 20db3d87c472f..078b99916c339 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index 6133d4bf421aa..3f10231dcd8e7 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 48f4de40160ab..ce2439143826f 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index 5b04e6affa0fe..5aa6f80a996b9 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 3bead0496dcfe..a4836e049eb62 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 758a2da663998..5b9bf1354bd3d 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 17613423f562a..ad1fe3b5ebf82 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index 5e10bf99f5ef5..09b899b37eccf 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index f9a4b08a0a550..5981917cd15d8 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index f8d15d999e228..c687876caa9ed 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 4ba9b3b78facd..c3790a20d0702 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index 188aeb1c6df22..d1e301e9b1b52 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index c59acd5dcb50b..a7fe247951b57 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index 5b4fb0e8df3d9..8ee49e43c7d90 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index c85f044c28108..7837d6d8c1a04 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index 3150b5a72b41e..d57124e89d1cc 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index 2d500119a0a49..885037aa7eaa1 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index de3949727a1c5..1203426d8c125 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index af07b5e757c74..5855635877aa0 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index 5848da63b458f..3bda78b414aba 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index 7d908ed66cb6a..fff6a6e139a39 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index 97a86b88829e1..0b6965d4aad07 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 29090e9ca84fb..118990c48e728 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index 849408c441f74..51862ff6c6d8b 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index ad2e89199dea5..4e37308de2c53 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index 5ce40973a50ad..67272a526d153 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index 5cd5faefe272e..80120f99e0f1a 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index 505d1ad8cf557..4c95060b0a95d 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index 28ab40315e6d5..ae22e0d40e641 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index 18167ed7069a8..a0c1fd9e1816e 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index 65a1994fc31a6..caa614be53ec3 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index 4288831bdaf4b..87d6fad8a80ad 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index 93cb3191b9425..921c27e432dc8 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index 75e247db6a8f2..4701939eb52ef 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 8ab43d427f0dc..6bf20035960c8 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index b2b2678d6923c..0681eb8dcdeb0 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 5489924e3b2f9..960645ce3f4f5 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index e89f329c3171f..67b9e5bf59887 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index 4dff51dbb1262..7c99070d847c5 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 3e8fa1edcfa73..1102659ca2a4b 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_tabbed_modal.mdx b/api_docs/kbn_shared_ux_tabbed_modal.mdx index e10f7db713532..2b31fbf2c35f5 100644 --- a/api_docs/kbn_shared_ux_tabbed_modal.mdx +++ b/api_docs/kbn_shared_ux_tabbed_modal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-tabbed-modal title: "@kbn/shared-ux-tabbed-modal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-tabbed-modal plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-tabbed-modal'] --- import kbnSharedUxTabbedModalObj from './kbn_shared_ux_tabbed_modal.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_table_persist.mdx b/api_docs/kbn_shared_ux_table_persist.mdx index 58fa099f6615e..a4a62460233cc 100644 --- a/api_docs/kbn_shared_ux_table_persist.mdx +++ b/api_docs/kbn_shared_ux_table_persist.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-table-persist title: "@kbn/shared-ux-table-persist" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-table-persist plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-table-persist'] --- import kbnSharedUxTablePersistObj from './kbn_shared_ux_table_persist.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index e80d9af5ee3a6..9b8294e57388e 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 95ec735ca802a..1d55ab60f4256 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 4479322d08239..22bb0676dad9d 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_predicates.mdx b/api_docs/kbn_sort_predicates.mdx index 0f916e43b0d85..d7005fbc39763 100644 --- a/api_docs/kbn_sort_predicates.mdx +++ b/api_docs/kbn_sort_predicates.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-predicates title: "@kbn/sort-predicates" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-predicates plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-predicates'] --- import kbnSortPredicatesObj from './kbn_sort_predicates.devdocs.json'; diff --git a/api_docs/kbn_sse_utils.mdx b/api_docs/kbn_sse_utils.mdx index c2b3a0139c508..589fb3e729edb 100644 --- a/api_docs/kbn_sse_utils.mdx +++ b/api_docs/kbn_sse_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils title: "@kbn/sse-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils'] --- import kbnSseUtilsObj from './kbn_sse_utils.devdocs.json'; diff --git a/api_docs/kbn_sse_utils_client.mdx b/api_docs/kbn_sse_utils_client.mdx index 23815fba149a7..366a8e0c08995 100644 --- a/api_docs/kbn_sse_utils_client.mdx +++ b/api_docs/kbn_sse_utils_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils-client title: "@kbn/sse-utils-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils-client plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils-client'] --- import kbnSseUtilsClientObj from './kbn_sse_utils_client.devdocs.json'; diff --git a/api_docs/kbn_sse_utils_server.mdx b/api_docs/kbn_sse_utils_server.mdx index 72dc403f6a934..63b6db4fd88fc 100644 --- a/api_docs/kbn_sse_utils_server.mdx +++ b/api_docs/kbn_sse_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils-server title: "@kbn/sse-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils-server plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils-server'] --- import kbnSseUtilsServerObj from './kbn_sse_utils_server.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index b2d5d3e950f37..78385c9f54ea4 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index 5b0ba28ee5f81..cfa71aec7e5b6 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index 75cd35c44f6c1..ae29de0490843 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_synthetics_e2e.mdx b/api_docs/kbn_synthetics_e2e.mdx index 3e8ac83da3f90..e88ff817218de 100644 --- a/api_docs/kbn_synthetics_e2e.mdx +++ b/api_docs/kbn_synthetics_e2e.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-e2e title: "@kbn/synthetics-e2e" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-e2e plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-e2e'] --- import kbnSyntheticsE2eObj from './kbn_synthetics_e2e.devdocs.json'; diff --git a/api_docs/kbn_synthetics_private_location.mdx b/api_docs/kbn_synthetics_private_location.mdx index e38dc686a433a..0368ad9cbd328 100644 --- a/api_docs/kbn_synthetics_private_location.mdx +++ b/api_docs/kbn_synthetics_private_location.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-private-location title: "@kbn/synthetics-private-location" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-private-location plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-private-location'] --- import kbnSyntheticsPrivateLocationObj from './kbn_synthetics_private_location.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index f6b31fc779791..cc3d2d62067f6 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 300d665f8d6d4..cc01d66479bad 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index dd324cc93385c..2b0da779a976b 100644 --- a/api_docs/kbn_test_eui_helpers.mdx +++ b/api_docs/kbn_test_eui_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-eui-helpers title: "@kbn/test-eui-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-eui-helpers plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-eui-helpers'] --- import kbnTestEuiHelpersObj from './kbn_test_eui_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 7f8544181a1f0..30c22294eb7fb 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 0672811a83b63..0cdab0bf4590f 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_timerange.mdx b/api_docs/kbn_timerange.mdx index 3d0881e70b053..a7d4a23abca5e 100644 --- a/api_docs/kbn_timerange.mdx +++ b/api_docs/kbn_timerange.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-timerange title: "@kbn/timerange" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/timerange plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/timerange'] --- import kbnTimerangeObj from './kbn_timerange.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 6c60b9483307b..5504da2afbc7c 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index b34040d645362..c2e50631acbe2 100644 --- a/api_docs/kbn_triggers_actions_ui_types.mdx +++ b/api_docs/kbn_triggers_actions_ui_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-triggers-actions-ui-types title: "@kbn/triggers-actions-ui-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/triggers-actions-ui-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; diff --git a/api_docs/kbn_try_in_console.mdx b/api_docs/kbn_try_in_console.mdx index 3a0b69d39c577..8bf567afefcfa 100644 --- a/api_docs/kbn_try_in_console.mdx +++ b/api_docs/kbn_try_in_console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-try-in-console title: "@kbn/try-in-console" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/try-in-console plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/try-in-console'] --- import kbnTryInConsoleObj from './kbn_try_in_console.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index b0783002cedb6..d06c008f7ac38 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index a9143339807f4..92153743c3c7f 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index a8c0255e192a7..ca17eddb0a34d 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index 4a62baa99d5f4..f801e917526f4 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 88792da9bd53c..44e236a7dc40e 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index ed814cb915c0a..3f5d23da152b2 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index 2c29404487ec4..95641fb556ff9 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.devdocs.json b/api_docs/kbn_unified_field_list.devdocs.json index 2a95bf7a3e779..b62b99adafb76 100644 --- a/api_docs/kbn_unified_field_list.devdocs.json +++ b/api_docs/kbn_unified_field_list.devdocs.json @@ -277,7 +277,7 @@ "label": "FieldPopover", "description": [], "signature": [ - "({ isOpen, closePopover, renderHeader, renderContent, ...otherPopoverProps }: ", + "({ isOpen, closePopover, renderHeader, renderContent, renderFooter, ...otherPopoverProps }: ", { "pluginId": "@kbn/unified-field-list", "scope": "public", @@ -296,7 +296,7 @@ "id": "def-public.FieldPopover.$1", "type": "Object", "tags": [], - "label": "{\n isOpen,\n closePopover,\n renderHeader,\n renderContent,\n ...otherPopoverProps\n}", + "label": "{\n isOpen,\n closePopover,\n renderHeader,\n renderContent,\n renderFooter,\n ...otherPopoverProps\n}", "description": [], "signature": [ { @@ -3900,6 +3900,22 @@ "trackAdoption": false, "children": [], "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-field-list", + "id": "def-public.FieldPopoverProps.renderFooter", + "type": "Function", + "tags": [], + "label": "renderFooter", + "description": [], + "signature": [ + "(() => React.ReactNode) | undefined" + ], + "path": "packages/kbn-unified-field-list/src/components/field_popover/field_popover.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index aaca69648cf07..0924ae97750bb 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 314 | 0 | 285 | 8 | +| 315 | 0 | 286 | 8 | ## Client diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index e9958d9a72033..6703b96deee8c 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_prompt.mdx b/api_docs/kbn_unsaved_changes_prompt.mdx index 04ab51c7217a7..1fa20975576f1 100644 --- a/api_docs/kbn_unsaved_changes_prompt.mdx +++ b/api_docs/kbn_unsaved_changes_prompt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-prompt title: "@kbn/unsaved-changes-prompt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-prompt plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-prompt'] --- import kbnUnsavedChangesPromptObj from './kbn_unsaved_changes_prompt.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 4572330857bb7..e2b92b0dc845e 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 5421233d7f522..db3653c049c51 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index 5ec549c6d506d..7a715f8cb5aff 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index 779cd47bb2870..fc07731c58883 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index dfa1bebf06f6d..bb32a42169bb4 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 253e794b3df79..f37f0ff8053e9 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_visualization_utils.mdx b/api_docs/kbn_visualization_utils.mdx index f5ee891913ebd..7b202b9106faa 100644 --- a/api_docs/kbn_visualization_utils.mdx +++ b/api_docs/kbn_visualization_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-utils title: "@kbn/visualization-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-utils'] --- import kbnVisualizationUtilsObj from './kbn_visualization_utils.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index 76bb1a8510b18..542ff7becd0f3 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index e69a7d9ab8d55..4c5384be88db2 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod.devdocs.json b/api_docs/kbn_zod.devdocs.json index ef11fbf6e070c..d0a32cdaf8ff5 100644 --- a/api_docs/kbn_zod.devdocs.json +++ b/api_docs/kbn_zod.devdocs.json @@ -19062,7 +19062,7 @@ "label": "UnknownKeysParam", "description": [], "signature": [ - "\"strict\" | \"passthrough\" | \"strip\"" + "\"passthrough\" | \"strict\" | \"strip\"" ], "path": "node_modules/zod/lib/types.d.ts", "deprecated": false, diff --git a/api_docs/kbn_zod.mdx b/api_docs/kbn_zod.mdx index 4fbcb6c48176f..ce3b2778a9c1c 100644 --- a/api_docs/kbn_zod.mdx +++ b/api_docs/kbn_zod.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod title: "@kbn/zod" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod'] --- import kbnZodObj from './kbn_zod.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index 11a17b16a9e02..d6de2b8f55ced 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 7ccc543109ad3..2de0087162ed1 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index edf72ebfa8fbb..854c8abd5a013 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index 363eb26c68cdb..c053614fda621 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 170fc181004b4..bc1354e83940e 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index e4b6c27f664be..c9ecd355c2dcb 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index e3e8ff834eb29..ab7f7cd8033bb 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 0d3d2fbaaeedd..627de35ce3e17 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 30b7cd2497ec5..5ad4fb88ce2cd 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index 404f0dd7571fd..3612104474d7b 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 7225a4af9259a..a4bba76b31f2e 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/logs_data_access.mdx b/api_docs/logs_data_access.mdx index 826833aa8ae7c..96139450b4019 100644 --- a/api_docs/logs_data_access.mdx +++ b/api_docs/logs_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsDataAccess title: "logsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the logsDataAccess plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsDataAccess'] --- import logsDataAccessObj from './logs_data_access.devdocs.json'; diff --git a/api_docs/logs_explorer.mdx b/api_docs/logs_explorer.mdx index e38d66588cc43..b9fda44cd0373 100644 --- a/api_docs/logs_explorer.mdx +++ b/api_docs/logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsExplorer title: "logsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logsExplorer plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsExplorer'] --- import logsExplorerObj from './logs_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index a05143c7ea9e4..4ea568f345d4b 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index b7319cf76e33a..45304339da6f5 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index e3e5ba3b23e70..1c02395a6924d 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 77ae42c242a7e..ca3cbcd4384ea 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index 46e2ee266c29d..d9f3e4860b11c 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 4294cec7ee106..303ba2dba3953 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index 44146084bca4e..46de59b41e4c7 100644 --- a/api_docs/mock_idp_plugin.mdx +++ b/api_docs/mock_idp_plugin.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mockIdpPlugin title: "mockIdpPlugin" image: https://source.unsplash.com/400x175/?github description: API docs for the mockIdpPlugin plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] --- import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 7b1cd221f16c2..ea7a022d63db0 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 82786703cbed2..ef7875643dafa 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index cacc4e71c330b..46e2b6c2fea1b 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index 144fc8b828065..5148e448c4c32 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index 02901f45aba65..bb8b9e4022b76 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index f93fd5c7dbb48..dcf8c065e58db 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 0a6221db28d2f..e850f47f57433 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index 7d201a30d5b7a..fb6a4ea255577 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index f59aaf2044d28..ba09f242631fc 100644 --- a/api_docs/observability_a_i_assistant_app.mdx +++ b/api_docs/observability_a_i_assistant_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistantApp title: "observabilityAIAssistantApp" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistantApp plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistantApp'] --- import observabilityAIAssistantAppObj from './observability_a_i_assistant_app.devdocs.json'; diff --git a/api_docs/observability_ai_assistant_management.mdx b/api_docs/observability_ai_assistant_management.mdx index a70b9087f15bf..9123d544d9fe3 100644 --- a/api_docs/observability_ai_assistant_management.mdx +++ b/api_docs/observability_ai_assistant_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAiAssistantManagement title: "observabilityAiAssistantManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAiAssistantManagement plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAiAssistantManagement'] --- import observabilityAiAssistantManagementObj from './observability_ai_assistant_management.devdocs.json'; diff --git a/api_docs/observability_logs_explorer.mdx b/api_docs/observability_logs_explorer.mdx index 6d109911c0391..b6607be3a7600 100644 --- a/api_docs/observability_logs_explorer.mdx +++ b/api_docs/observability_logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogsExplorer title: "observabilityLogsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogsExplorer plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogsExplorer'] --- import observabilityLogsExplorerObj from './observability_logs_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 95bf6124957bd..fade1e8e4b3f9 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 977b805a2e7e7..52af32327b405 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; diff --git a/api_docs/osquery.devdocs.json b/api_docs/osquery.devdocs.json index 4cde122de5cd7..dc574c1d8c7d1 100644 --- a/api_docs/osquery.devdocs.json +++ b/api_docs/osquery.devdocs.json @@ -309,9 +309,7 @@ "section": "def-common.MultiField", "text": "MultiField" }, - "[]; }; readonly \"kibana.alert.rule.execution.timestamp\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.rule.parameters\": { readonly array: false; readonly type: \"flattened\"; readonly ignore_above: 4096; readonly required: false; }; readonly \"kibana.alert.rule.tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.severity_improving\": { readonly type: \"boolean\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.start\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.time_range\": { readonly type: \"date_range\"; readonly format: \"epoch_millis||strict_date_optional_time\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.url\": { readonly type: \"keyword\"; readonly array: false; readonly index: false; readonly required: false; readonly ignore_above: 2048; }; readonly \"kibana.alert.workflow_assignee_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.workflow_status\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.workflow_tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.version\": { readonly type: \"version\"; readonly array: false; readonly required: false; }; }>> & { _index: string; }) | undefined) => Promise<{ response: { action_id: string; '@timestamp': string; expiration: string; type: string; input_type: string; alert_ids: string[] | undefined; event_ids: string[] | undefined; case_ids: string[] | undefined; agent_ids: string[] | undefined; agent_all: boolean | undefined; agent_platforms: string[] | undefined; agent_policy_ids: string[] | undefined; agents: string[]; user_id: string | undefined; metadata: object | undefined; pack_id: string | undefined; pack_name: string | undefined; pack_prebuilt: boolean | undefined; queries: ", - "Dictionary", - "[]; }; fleetActionsCount: number; }>; stop: () => void; }" + "[]; }; readonly \"kibana.alert.rule.execution.timestamp\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.rule.parameters\": { readonly array: false; readonly type: \"flattened\"; readonly ignore_above: 4096; readonly required: false; }; readonly \"kibana.alert.rule.tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.severity_improving\": { readonly type: \"boolean\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.start\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.time_range\": { readonly type: \"date_range\"; readonly format: \"epoch_millis||strict_date_optional_time\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.url\": { readonly type: \"keyword\"; readonly array: false; readonly index: false; readonly required: false; readonly ignore_above: 2048; }; readonly \"kibana.alert.workflow_assignee_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.workflow_status\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.workflow_tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.version\": { readonly type: \"version\"; readonly array: false; readonly required: false; }; }>> & { _index: string; }) | undefined) => Promise<{ response: { action_id: string; '@timestamp': string; expiration: string; type: string; input_type: string; alert_ids: string[] | undefined; event_ids: string[] | undefined; case_ids: string[] | undefined; agent_ids: string[] | undefined; agent_all: boolean | undefined; agent_platforms: string[] | undefined; agent_policy_ids: string[] | undefined; agents: string[]; user_id: string | undefined; metadata: object | undefined; pack_id: string | undefined; pack_name: string | undefined; pack_prebuilt: boolean | undefined; queries: _.Dictionary[]; }; fleetActionsCount: number; }>; stop: () => void; }" ], "path": "x-pack/plugins/osquery/server/types.ts", "deprecated": false, diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 56279b82b35f1..c8e43c9ec7082 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index 831dad512d053..b5f175871aa93 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 518a352f79e8f..a5a2307c4d6db 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -21,7 +21,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 53576 | 244 | 40181 | 1987 | +| 53554 | 244 | 40184 | 1986 | ## Plugin Directory @@ -30,8 +30,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 314 | 0 | 308 | 33 | | | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 4 | 0 | 4 | 1 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 72 | 0 | 9 | 2 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 875 | 1 | 843 | 50 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 71 | 0 | 8 | 2 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 873 | 1 | 841 | 50 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | The user interface for Elastic APM | 29 | 0 | 29 | 118 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 93 | 0 | 93 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 9 | 0 | 9 | 0 | @@ -57,7 +57,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 54 | 0 | 51 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3209 | 31 | 2594 | 24 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 5 | 0 | 5 | 0 | -| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 6 | 0 | 6 | 0 | +| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 9 | 0 | 9 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 35 | 0 | 25 | 5 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Reusable data view field editor across Kibana | 72 | 0 | 33 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data view management app | 2 | 0 | 2 | 0 | @@ -103,7 +103,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 88 | 0 | 88 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 240 | 0 | 24 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Simple UI for managing files in Kibana | 3 | 0 | 3 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1410 | 5 | 1287 | 74 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1412 | 5 | 1289 | 74 | | ftrApis | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 72 | 0 | 14 | 5 | | globalSearchBar | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | @@ -114,7 +114,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 149 | 0 | 111 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Image embeddable | 1 | 0 | 1 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | -| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 246 | 0 | 241 | 1 | +| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 251 | 0 | 246 | 1 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 49 | 0 | 44 | 15 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions | 24 | 0 | 24 | 5 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | @@ -162,7 +162,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 23 | 0 | 23 | 7 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds a standardized Presentation panel which allows any forward ref component to interface with various Kibana systems. | 11 | 0 | 11 | 4 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 212 | 2 | 157 | 11 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 160 | 2 | 130 | 10 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 16 | 1 | 16 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 22 | 0 | 22 | 7 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 23 | 0 | 23 | 0 | @@ -181,8 +181,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | AI Assistant for Search | 6 | 0 | 6 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Plugin hosting shared features for connectors | 19 | 0 | 19 | 3 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 18 | 0 | 10 | 0 | -| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 11 | 0 | 11 | 0 | -| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 10 | 0 | 6 | 1 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 18 | 0 | 18 | 0 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 11 | 0 | 7 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Plugin to provide access to and rendering of python notebooks for use in the persistent developer console. | 10 | 0 | 10 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 21 | 0 | 15 | 1 | | searchprofiler | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 0 | 0 | 0 | 0 | @@ -250,10 +250,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 27 | 3 | 27 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 5 | 0 | 5 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 23 | 0 | 22 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 222 | 0 | 219 | 0 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 221 | 0 | 218 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 33 | 0 | 33 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 31 | 0 | 15 | 1 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 318 | 0 | 302 | 8 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 321 | 0 | 305 | 8 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 73 | 0 | 73 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 18 | 0 | 18 | 0 | @@ -519,8 +519,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 266 | 1 | 208 | 34 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 29 | 0 | 12 | 0 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 73 | 0 | 69 | 0 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 199 | 0 | 187 | 12 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 75 | 0 | 71 | 0 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 204 | 0 | 192 | 12 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 40 | 0 | 40 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 0 | 52 | 1 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 44 | 0 | 17 | 3 | @@ -544,7 +544,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 37 | 0 | 27 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 36 | 0 | 7 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 47 | 0 | 40 | 0 | -| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 114 | 3 | 114 | 0 | +| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 119 | 3 | 119 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 7 | 1 | 7 | 1 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 9 | 0 | 9 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 12 | 43 | 0 | @@ -783,7 +783,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 9 | 0 | 8 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 183 | 0 | 108 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 18 | 0 | 17 | 5 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 314 | 0 | 285 | 8 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 315 | 0 | 286 | 8 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 13 | 0 | 9 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 3 | 0 | 2 | 1 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index 9508d9e565099..6b89d43fe8042 100644 --- a/api_docs/presentation_panel.mdx +++ b/api_docs/presentation_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationPanel title: "presentationPanel" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationPanel plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationPanel'] --- import presentationPanelObj from './presentation_panel.devdocs.json'; diff --git a/api_docs/presentation_util.devdocs.json b/api_docs/presentation_util.devdocs.json index ef9bd848b0edb..a4a51e8198050 100644 --- a/api_docs/presentation_util.devdocs.json +++ b/api_docs/presentation_util.devdocs.json @@ -1,572 +1,7 @@ { "id": "presentationUtil", "client": { - "classes": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider", - "type": "Class", - "tags": [], - "label": "PluginServiceProvider", - "description": [ - "\nAn object which uses a given factory to start, stop or provide a service.\n\nThe `Service` generic determines the shape of the API being produced.\nThe `StartParameters` generic determines what parameters are expected to\nstart the service." - ], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PluginServiceProvider", - "text": "PluginServiceProvider" - }, - "" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.Provider", - "type": "Function", - "tags": [], - "label": "Provider", - "description": [], - "signature": [ - "({ children }: { children?: React.ReactNode; }) => React.JSX.Element" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.Provider.$1", - "type": "Object", - "tags": [], - "label": "{ children }", - "description": [], - "signature": [ - "{ children?: React.ReactNode; }" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.Unnamed", - "type": "Function", - "tags": [], - "label": "Constructor", - "description": [], - "signature": [ - "any" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.Unnamed.$1", - "type": "Function", - "tags": [], - "label": "factory", - "description": [], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PluginServiceFactory", - "text": "PluginServiceFactory" - }, - ">" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.Unnamed.$2", - "type": "Uncategorized", - "tags": [], - "label": "requiredServices", - "description": [], - "signature": [ - "RequiredServices | undefined" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.getService", - "type": "Function", - "tags": [], - "label": "getService", - "description": [ - "\nGetter that will enforce proper setup throughout the class." - ], - "signature": [ - "() => Service" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.start", - "type": "Function", - "tags": [], - "label": "start", - "description": [ - "\nStart the service.\n" - ], - "signature": [ - "(params: StartParameters, requiredServices: ", - "PluginServiceRequiredServices", - ") => void" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.start.$1", - "type": "Uncategorized", - "tags": [], - "label": "params", - "description": [ - "Parameters used to start the service." - ], - "signature": [ - "StartParameters" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.start.$2", - "type": "Object", - "tags": [], - "label": "requiredServices", - "description": [], - "signature": [ - "PluginServiceRequiredServices", - "" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.getServiceReactHook", - "type": "Function", - "tags": [], - "label": "getServiceReactHook", - "description": [ - "\nReturns a function for providing a Context hook for the service." - ], - "signature": [ - "() => () => Service" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.stop", - "type": "Function", - "tags": [], - "label": "stop", - "description": [ - "\nStop the service." - ], - "signature": [ - "() => void" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProvider.requiredServices", - "type": "CompoundType", - "tags": [], - "label": "requiredServices", - "description": [], - "signature": [ - "never[] | NonNullable" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceRegistry", - "type": "Class", - "tags": [], - "label": "PluginServiceRegistry", - "description": [ - "\nA `PluginServiceRegistry` maintains a set of service providers which can be collectively\nstarted, stopped or retreived.\n\nThe `Services` generic determines the shape of all service APIs being produced.\nThe `StartParameters` generic determines what parameters are expected to\nstart the service." - ], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PluginServiceRegistry", - "text": "PluginServiceRegistry" - }, - "" - ], - "path": "src/plugins/presentation_util/public/services/create/registry.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceRegistry.Unnamed", - "type": "Function", - "tags": [], - "label": "Constructor", - "description": [], - "signature": [ - "any" - ], - "path": "src/plugins/presentation_util/public/services/create/registry.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceRegistry.Unnamed.$1", - "type": "Object", - "tags": [], - "label": "providers", - "description": [], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PluginServiceProviders", - "text": "PluginServiceProviders" - }, - "" - ], - "path": "src/plugins/presentation_util/public/services/create/registry.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceRegistry.isStarted", - "type": "Function", - "tags": [], - "label": "isStarted", - "description": [ - "\nReturns true if the registry has been started, false otherwise." - ], - "signature": [ - "() => boolean" - ], - "path": "src/plugins/presentation_util/public/services/create/registry.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceRegistry.getServiceProviders", - "type": "Function", - "tags": [], - "label": "getServiceProviders", - "description": [ - "\nReturns a map of `PluginServiceProvider` objects." - ], - "signature": [ - "() => ", - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PluginServiceProviders", - "text": "PluginServiceProviders" - }, - "" - ], - "path": "src/plugins/presentation_util/public/services/create/registry.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceRegistry.getContextProvider", - "type": "Function", - "tags": [], - "label": "getContextProvider", - "description": [ - "\nReturns a React Context Provider for use in consuming applications." - ], - "signature": [ - "() => React.FC<{ children?: React.ReactNode; }>" - ], - "path": "src/plugins/presentation_util/public/services/create/registry.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceRegistry.start", - "type": "Function", - "tags": [], - "label": "start", - "description": [ - "\nStart the registry.\n" - ], - "signature": [ - "(params: StartParameters) => this" - ], - "path": "src/plugins/presentation_util/public/services/create/registry.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceRegistry.start.$1", - "type": "Uncategorized", - "tags": [], - "label": "params", - "description": [ - "Parameters used to start the registry." - ], - "signature": [ - "StartParameters" - ], - "path": "src/plugins/presentation_util/public/services/create/registry.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceRegistry.stop", - "type": "Function", - "tags": [], - "label": "stop", - "description": [ - "\nStop the registry." - ], - "signature": [ - "() => this" - ], - "path": "src/plugins/presentation_util/public/services/create/registry.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServices", - "type": "Class", - "tags": [], - "label": "PluginServices", - "description": [ - "\n`PluginServices` is a top-level class for specifying and accessing services within a plugin.\n\nA `PluginServices` object can be provided with a `PluginServiceRegistry` at any time, which will\nthen be used to provide services to any component that accesses it.\n\nThe `Services` generic determines the shape of all service APIs being produced." - ], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PluginServices", - "text": "PluginServices" - }, - "" - ], - "path": "src/plugins/presentation_util/public/services/create/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServices.setRegistry", - "type": "Function", - "tags": [], - "label": "setRegistry", - "description": [ - "\nSupply a `PluginServiceRegistry` for the class to use to provide services and context.\n" - ], - "signature": [ - "(registry: ", - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PluginServiceRegistry", - "text": "PluginServiceRegistry" - }, - " | null) => void" - ], - "path": "src/plugins/presentation_util/public/services/create/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServices.setRegistry.$1", - "type": "CompoundType", - "tags": [], - "label": "registry", - "description": [ - "A setup and started `PluginServiceRegistry`." - ], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PluginServiceRegistry", - "text": "PluginServiceRegistry" - }, - " | null" - ], - "path": "src/plugins/presentation_util/public/services/create/index.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServices.hasRegistry", - "type": "Function", - "tags": [], - "label": "hasRegistry", - "description": [ - "\nReturns true if a registry has been provided, false otherwise." - ], - "signature": [ - "() => boolean" - ], - "path": "src/plugins/presentation_util/public/services/create/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServices.getContextProvider", - "type": "Function", - "tags": [], - "label": "getContextProvider", - "description": [ - "\nReturn the React Context Provider that will supply services." - ], - "signature": [ - "() => React.FC<{ children?: React.ReactNode; }>" - ], - "path": "src/plugins/presentation_util/public/services/create/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServices.getHooks", - "type": "Function", - "tags": [], - "label": "getHooks", - "description": [ - "\nReturn a map of React Hooks that can be used in React components." - ], - "signature": [ - "() => ServiceHooks" - ], - "path": "src/plugins/presentation_util/public/services/create/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServices.getServices", - "type": "Function", - "tags": [], - "label": "getServices", - "description": [], - "signature": [ - "() => Services" - ], - "path": "src/plugins/presentation_util/public/services/create/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - } - ], - "initialIsOpen": false - } - ], + "classes": [], "functions": [ { "parentPluginId": "presentationUtil", @@ -693,23 +128,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.getContextProvider", - "type": "Function", - "tags": [], - "label": "getContextProvider", - "description": [], - "signature": [ - "() => React.FC<{ children?: React.ReactNode; }>" - ], - "path": "src/plugins/presentation_util/public/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "presentationUtil", "id": "def-public.LazyDashboardPicker", @@ -1049,30 +467,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.useLabs", - "type": "Function", - "tags": [], - "label": "useLabs", - "description": [], - "signature": [ - "() => ", - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PresentationLabsService", - "text": "PresentationLabsService" - } - ], - "path": "src/plugins/presentation_util/public/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "presentationUtil", "id": "def-public.withSuspense", @@ -1216,274 +610,92 @@ ], "path": "src/plugins/presentation_util/public/components/types.ts", "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.ExpressionInputProps.isCompact", - "type": "CompoundType", - "tags": [], - "label": "isCompact", - "description": [ - "In full screen mode or not" - ], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/presentation_util/public/components/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.ExpressionInputProps.height", - "type": "CompoundType", - "tags": [], - "label": "height", - "description": [ - "\nThe CodeEditor requires a set height, either on itself, or set to 100% with the parent\ncontainer controlling the height. This prop is required so consumers understand this\nlimitation and are intentional in using the component." - ], - "signature": [ - "Property", - ".Height | undefined" - ], - "path": "src/plugins/presentation_util/public/components/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.ExpressionInputProps.editorRef", - "type": "Object", - "tags": [], - "label": "editorRef", - "description": [ - "\nAn optional ref in order to access the Monaco editor instance from consuming components,\n(e.g. to determine if the editor is focused, etc)." - ], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.ExpressionInputEditorRef", - "text": "ExpressionInputEditorRef" - }, - " | undefined" - ], - "path": "src/plugins/presentation_util/public/components/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.ExpressionInputProps.onEditorDidMount", - "type": "Function", - "tags": [], - "label": "onEditorDidMount", - "description": [], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.OnExpressionInputEditorDidMount", - "text": "OnExpressionInputEditorDidMount" - }, - " | undefined" - ], - "path": "src/plugins/presentation_util/public/components/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.KibanaPluginServiceParams", - "type": "Interface", - "tags": [], - "label": "KibanaPluginServiceParams", - "description": [ - "\nParameters necessary to create a Kibana-based service, (e.g. during Plugin\nstartup or setup).\n\nThe `Start` generic refers to the specific Plugin `TPluginsStart`." - ], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.KibanaPluginServiceParams", - "text": "KibanaPluginServiceParams" + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] }, - "" - ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ { "parentPluginId": "presentationUtil", - "id": "def-public.KibanaPluginServiceParams.coreStart", - "type": "Object", + "id": "def-public.ExpressionInputProps.isCompact", + "type": "CompoundType", "tags": [], - "label": "coreStart", - "description": [], + "label": "isCompact", + "description": [ + "In full screen mode or not" + ], "signature": [ - { - "pluginId": "@kbn/core-lifecycle-browser", - "scope": "public", - "docId": "kibKbnCoreLifecycleBrowserPluginApi", - "section": "def-public.CoreStart", - "text": "CoreStart" - } + "boolean | undefined" ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", + "path": "src/plugins/presentation_util/public/components/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "presentationUtil", - "id": "def-public.KibanaPluginServiceParams.startPlugins", - "type": "Uncategorized", + "id": "def-public.ExpressionInputProps.height", + "type": "CompoundType", "tags": [], - "label": "startPlugins", - "description": [], + "label": "height", + "description": [ + "\nThe CodeEditor requires a set height, either on itself, or set to 100% with the parent\ncontainer controlling the height. This prop is required so consumers understand this\nlimitation and are intentional in using the component." + ], "signature": [ - "Start" + "Property", + ".Height | undefined" ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", + "path": "src/plugins/presentation_util/public/components/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "presentationUtil", - "id": "def-public.KibanaPluginServiceParams.appUpdater", + "id": "def-public.ExpressionInputProps.editorRef", "type": "Object", "tags": [], - "label": "appUpdater", - "description": [], + "label": "editorRef", + "description": [ + "\nAn optional ref in order to access the Monaco editor instance from consuming components,\n(e.g. to determine if the editor is focused, etc)." + ], "signature": [ - "BehaviorSubject", - "<", { - "pluginId": "@kbn/core-application-browser", + "pluginId": "presentationUtil", "scope": "public", - "docId": "kibKbnCoreApplicationBrowserPluginApi", - "section": "def-public.AppUpdater", - "text": "AppUpdater" + "docId": "kibPresentationUtilPluginApi", + "section": "def-public.ExpressionInputEditorRef", + "text": "ExpressionInputEditorRef" }, - "> | undefined" + " | undefined" ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", + "path": "src/plugins/presentation_util/public/components/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "presentationUtil", - "id": "def-public.KibanaPluginServiceParams.initContext", - "type": "Object", + "id": "def-public.ExpressionInputProps.onEditorDidMount", + "type": "Function", "tags": [], - "label": "initContext", + "label": "onEditorDidMount", "description": [], "signature": [ { - "pluginId": "@kbn/core-plugins-browser", + "pluginId": "presentationUtil", "scope": "public", - "docId": "kibKbnCorePluginsBrowserPluginApi", - "section": "def-public.PluginInitializerContext", - "text": "PluginInitializerContext" + "docId": "kibPresentationUtilPluginApi", + "section": "def-public.OnExpressionInputEditorDidMount", + "text": "OnExpressionInputEditorDidMount" }, - " | undefined" + " | undefined" ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", + "path": "src/plugins/presentation_util/public/components/types.ts", "deprecated": false, "trackAdoption": false } ], "initialIsOpen": false }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PresentationCapabilitiesService", - "type": "Interface", - "tags": [], - "label": "PresentationCapabilitiesService", - "description": [], - "path": "src/plugins/presentation_util/public/services/capabilities/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PresentationCapabilitiesService.canAccessDashboards", - "type": "Function", - "tags": [], - "label": "canAccessDashboards", - "description": [], - "signature": [ - "() => boolean" - ], - "path": "src/plugins/presentation_util/public/services/capabilities/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PresentationCapabilitiesService.canCreateNewDashboards", - "type": "Function", - "tags": [], - "label": "canCreateNewDashboards", - "description": [], - "signature": [ - "() => boolean" - ], - "path": "src/plugins/presentation_util/public/services/capabilities/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PresentationCapabilitiesService.canSaveVisualizations", - "type": "Function", - "tags": [], - "label": "canSaveVisualizations", - "description": [], - "signature": [ - "() => boolean" - ], - "path": "src/plugins/presentation_util/public/services/capabilities/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PresentationCapabilitiesService.canSetAdvancedSettings", - "type": "Function", - "tags": [], - "label": "canSetAdvancedSettings", - "description": [], - "signature": [ - "() => boolean" - ], - "path": "src/plugins/presentation_util/public/services/capabilities/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - } - ], - "initialIsOpen": false - }, { "parentPluginId": "presentationUtil", "id": "def-public.PresentationLabsService", @@ -1491,7 +703,7 @@ "tags": [], "label": "PresentationLabsService", "description": [], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1505,7 +717,7 @@ "signature": [ "(id: \"labs:dashboard:deferBelowFold\" | \"labs:canvas:byValueEmbeddable\") => boolean" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1519,7 +731,7 @@ "signature": [ "\"labs:dashboard:deferBelowFold\" | \"labs:canvas:byValueEmbeddable\"" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -1527,22 +739,6 @@ ], "returnComment": [] }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PresentationLabsService.getProjectIDs", - "type": "Function", - "tags": [], - "label": "getProjectIDs", - "description": [], - "signature": [ - "() => readonly [\"labs:dashboard:deferBelowFold\", \"labs:canvas:byValueEmbeddable\"]" - ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, { "parentPluginId": "presentationUtil", "id": "def-public.PresentationLabsService.getProject", @@ -1560,7 +756,7 @@ "text": "Project" } ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1574,7 +770,7 @@ "signature": [ "\"labs:dashboard:deferBelowFold\" | \"labs:canvas:byValueEmbeddable\"" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -1600,7 +796,7 @@ }, ">" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1614,7 +810,7 @@ "signature": [ "(\"canvas\" | \"presentation\" | \"dashboard\")[] | undefined" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": false @@ -1632,7 +828,7 @@ "signature": [ "(id: \"labs:dashboard:deferBelowFold\" | \"labs:canvas:byValueEmbeddable\", env: \"kibana\" | \"browser\" | \"session\", status: boolean) => void" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1646,7 +842,7 @@ "signature": [ "\"labs:dashboard:deferBelowFold\" | \"labs:canvas:byValueEmbeddable\"" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -1661,7 +857,7 @@ "signature": [ "\"kibana\" | \"browser\" | \"session\"" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -1676,7 +872,7 @@ "signature": [ "boolean" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -1694,7 +890,7 @@ "signature": [ "() => void" ], - "path": "src/plugins/presentation_util/public/services/labs/types.ts", + "path": "src/plugins/presentation_util/public/services/presentation_labs_service.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -2561,69 +1757,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.KibanaPluginServiceFactory", - "type": "Type", - "tags": [], - "label": "KibanaPluginServiceFactory", - "description": [ - "\nA factory function for creating a Kibana-based service.\n\nThe `Service` generic determines the shape of the API being produced.\nThe `Setup` generic refers to the specific Plugin `TPluginsSetup`.\nThe `Start` generic refers to the specific Plugin `TPluginsStart`." - ], - "signature": [ - "(params: ", - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.KibanaPluginServiceParams", - "text": "KibanaPluginServiceParams" - }, - ", requiredServices: RequiredServices) => Service" - ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.KibanaPluginServiceFactory.$1", - "type": "Object", - "tags": [], - "label": "params", - "description": [], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.KibanaPluginServiceParams", - "text": "KibanaPluginServiceParams" - }, - "" - ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.KibanaPluginServiceFactory.$2", - "type": "Uncategorized", - "tags": [], - "label": "requiredServices", - "description": [], - "signature": [ - "RequiredServices" - ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "presentationUtil", "id": "def-public.OnExpressionInputEditorDidMount", @@ -2658,79 +1791,6 @@ } ], "initialIsOpen": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceFactory", - "type": "Type", - "tags": [], - "label": "PluginServiceFactory", - "description": [ - "\nA factory function for creating a service.\n\nThe `Service` generic determines the shape of the API being produced.\nThe `StartParameters` generic determines what parameters are expected to\ncreate the service." - ], - "signature": [ - "(params: Parameters, requiredServices: RequiredServices) => Service" - ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceFactory.$1", - "type": "Uncategorized", - "tags": [], - "label": "params", - "description": [], - "signature": [ - "Parameters" - ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceFactory.$2", - "type": "Uncategorized", - "tags": [], - "label": "requiredServices", - "description": [], - "signature": [ - "RequiredServices" - ], - "path": "src/plugins/presentation_util/public/services/create/factory.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PluginServiceProviders", - "type": "Type", - "tags": [], - "label": "PluginServiceProviders", - "description": [ - "\nA collection of `PluginServiceProvider` objects, keyed by the `Services` API generic.\n\nThe `Services` generic determines the shape of all service APIs being produced.\nThe `StartParameters` generic determines what parameters are expected to\nstart the service." - ], - "signature": [ - "{ [K in keyof Services]: ", - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.PluginServiceProvider", - "text": "PluginServiceProvider" - }, - "; }" - ], - "path": "src/plugins/presentation_util/public/services/create/provider.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false } ], "objects": [ @@ -2816,51 +1876,6 @@ "deprecated": false, "trackAdoption": false, "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PresentationUtilPluginStart.ContextProvider", - "type": "Function", - "tags": [], - "label": "ContextProvider", - "description": [], - "signature": [ - "React.FunctionComponent<{ children?: React.ReactNode; }>" - ], - "path": "src/plugins/presentation_util/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "presentationUtil", - "id": "def-public.PresentationUtilPluginStart.ContextProvider.$1", - "type": "Uncategorized", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "P" - ], - "path": "node_modules/@types/react/ts5.0/index.d.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "presentationUtil", - "id": "def-public.PresentationUtilPluginStart.ContextProvider.$2", - "type": "Any", - "tags": [], - "label": "context", - "description": [], - "signature": [ - "any" - ], - "path": "node_modules/@types/react/ts5.0/index.d.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, { "parentPluginId": "presentationUtil", "id": "def-public.PresentationUtilPluginStart.labsService", diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 164366e4b1082..b5710e9015b07 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 212 | 2 | 157 | 11 | +| 160 | 2 | 130 | 10 | ## Client @@ -37,9 +37,6 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib ### Functions -### Classes - - ### Interfaces diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index a6f99e928133b..f7221d49c87c5 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index 7ade173bd0494..2bd676de91d96 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index e4250386d58cf..f376c60136b3b 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index 65e23bcdbe973..f91a4fd137dc3 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index 0c742e8e81b93..05835eb761106 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.devdocs.json b/api_docs/rule_registry.devdocs.json index e17e7cc999233..61bae2aa71eda 100644 --- a/api_docs/rule_registry.devdocs.json +++ b/api_docs/rule_registry.devdocs.json @@ -2221,7 +2221,7 @@ "section": "def-common.ActionGroup", "text": "ActionGroup" }, - "<\"default\">[]; schemas?: { params?: { type: \"zod\"; schema: any; } | { type: \"config-schema\"; schema: ", + "<\"default\">[]; schemas?: { params?: { type: \"zod\"; schema: Zod.ZodObject | Zod.ZodIntersection; } | { type: \"config-schema\"; schema: ", { "pluginId": "@kbn/config-schema", "scope": "common", diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index b9d31891d1af5..f47ad6f9556ae 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index b91c6ea7a88d2..c3ce95f6272d3 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.devdocs.json b/api_docs/saved_objects.devdocs.json index 340a56e3620f2..3b32f60e8c2c6 100644 --- a/api_docs/saved_objects.devdocs.json +++ b/api_docs/saved_objects.devdocs.json @@ -50,14 +50,6 @@ "plugin": "presentationUtil", "path": "src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard.tsx" }, - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/visualizations/xy/annotations/actions/save_action.tsx" - }, - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/visualizations/xy/annotations/actions/save_action.tsx" - }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx" @@ -66,6 +58,14 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx" }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/visualizations/xy/annotations/actions/save_action.tsx" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/visualizations/xy/annotations/actions/save_action.tsx" + }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx" diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 9519a8db27882..dab0ae24650bf 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index 819bdaf3f9062..f83904386ce23 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 3a6b0190b21fe..748a7aad378e9 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index dd26279c7166e..f4533ef04aeb4 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.devdocs.json b/api_docs/saved_objects_tagging_oss.devdocs.json index 19ce96d58b622..d8e7562f267b1 100644 --- a/api_docs/saved_objects_tagging_oss.devdocs.json +++ b/api_docs/saved_objects_tagging_oss.devdocs.json @@ -1297,7 +1297,7 @@ "section": "def-common.Tag", "text": "Tag" }, - " | { type: \"__create_option__\"; }>, \"options\" | \"prepend\" | \"append\" | \"async\" | \"isClearable\" | \"compressed\" | \"fullWidth\" | \"selectedOptions\" | \"optionMatcher\" | \"singleSelection\" | \"sortMatchesBy\"> & Partial, \"options\" | \"async\" | \"prepend\" | \"append\" | \"isClearable\" | \"compressed\" | \"fullWidth\" | \"selectedOptions\" | \"optionMatcher\" | \"singleSelection\" | \"sortMatchesBy\"> & Partial +### Consts, variables and types + + ## Server ### Setup diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index faeab048d9299..45f27df5ffb88 100644 --- a/api_docs/search_notebooks.mdx +++ b/api_docs/search_notebooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchNotebooks title: "searchNotebooks" image: https://source.unsplash.com/400x175/?github description: API docs for the searchNotebooks plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNotebooks'] --- import searchNotebooksObj from './search_notebooks.devdocs.json'; diff --git a/api_docs/search_playground.mdx b/api_docs/search_playground.mdx index 9bcfeb5f2b6b6..23a8f0b22a629 100644 --- a/api_docs/search_playground.mdx +++ b/api_docs/search_playground.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchPlayground title: "searchPlayground" image: https://source.unsplash.com/400x175/?github description: API docs for the searchPlayground plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index f927b198cac03..6c5beb6452251 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index 69fab0e918ea7..a9bcc310b662d 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -3283,4 +3283,4 @@ } ] } -} +} \ No newline at end of file diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 662e5826ec460..342bdeb742d47 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index d867a6c37e449..438572acd2daf 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index 1f45c79c19b59..12ded8e467bd0 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index a84f3deb50d89..2e67831e7d757 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index 772a29eb48ab1..9d35b793439d7 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index 35d6be13827e7..be69143a7af66 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 8635c30027402..6f27466917c00 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.devdocs.json b/api_docs/share.devdocs.json index a9a55efbbad4d..df10eee7ece27 100644 --- a/api_docs/share.devdocs.json +++ b/api_docs/share.devdocs.json @@ -899,13 +899,13 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx" - }, { "plugin": "@kbn/reporting-public", "path": "packages/kbn-reporting/public/share/share_context_menu/register_pdf_png_modal_reporting.tsx" + }, + { + "plugin": "discover", + "path": "src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx" } ] }, diff --git a/api_docs/share.mdx b/api_docs/share.mdx index 31a4885f200fe..e4abf26526814 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index 09890bf628d7b..a1fb752bcfabe 100644 --- a/api_docs/slo.mdx +++ b/api_docs/slo.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/slo title: "slo" image: https://source.unsplash.com/400x175/?github description: API docs for the slo plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'slo'] --- import sloObj from './slo.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index f3133c7d7ef71..64a4b78a144fa 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index f5ec11bcafa4f..2e11658638cad 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 7b4bf7efd3374..0f3bf0d300d69 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/stack_connectors.mdx b/api_docs/stack_connectors.mdx index ff9caaaab8a60..981fa7ede68e5 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 67f0ccf8d719b..324a3baefbb08 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 815982e9e8912..36aeed2701335 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 53fbb47fa2a48..6cf462ea5ea39 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index 7174d2c210ffc..67350cf46dd36 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index a245902dfeb71..fb5b59262d397 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index f35dda7d39758..9bd58c15698f1 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index d98823650d6c8..94d923a7ecaa4 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index e0c5f618f77d4..f3c8935afbe99 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.devdocs.json b/api_docs/triggers_actions_ui.devdocs.json index 6698f14b9f401..ef8b0982063d0 100644 --- a/api_docs/triggers_actions_ui.devdocs.json +++ b/api_docs/triggers_actions_ui.devdocs.json @@ -1784,7 +1784,7 @@ "label": "transformRule", "description": [], "signature": [ - "({ rule_type_id: ruleTypeId, created_by: createdBy, updated_by: updatedBy, created_at: createdAt, updated_at: updatedAt, api_key_owner: apiKeyOwner, api_key_created_by_user: apiKeyCreatedByUser, notify_when: notifyWhen, mute_all: muteAll, muted_alert_ids: mutedInstanceIds, scheduled_task_id: scheduledTaskId, execution_status: executionStatus, actions: actions, snooze_schedule: snoozeSchedule, is_snoozed_until: isSnoozedUntil, active_snoozes: activeSnoozes, last_run: lastRun, next_run: nextRun, alert_delay: alertDelay, ...rest }: any) => any" + "({ rule_type_id: ruleTypeId, created_by: createdBy, updated_by: updatedBy, created_at: createdAt, updated_at: updatedAt, api_key_owner: apiKeyOwner, api_key_created_by_user: apiKeyCreatedByUser, notify_when: notifyWhen, mute_all: muteAll, muted_alert_ids: mutedInstanceIds, scheduled_task_id: scheduledTaskId, execution_status: executionStatus, actions: actions, snooze_schedule: snoozeSchedule, is_snoozed_until: isSnoozedUntil, active_snoozes: activeSnoozes, last_run: lastRun, next_run: nextRun, alert_delay: alertDelay, flapping, ...rest }: any) => any" ], "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts", "deprecated": false, @@ -1795,7 +1795,7 @@ "id": "def-public.transformRule.$1", "type": "Any", "tags": [], - "label": "{\n rule_type_id: ruleTypeId,\n created_by: createdBy,\n updated_by: updatedBy,\n created_at: createdAt,\n updated_at: updatedAt,\n api_key_owner: apiKeyOwner,\n api_key_created_by_user: apiKeyCreatedByUser,\n notify_when: notifyWhen,\n mute_all: muteAll,\n muted_alert_ids: mutedInstanceIds,\n scheduled_task_id: scheduledTaskId,\n execution_status: executionStatus,\n actions: actions,\n snooze_schedule: snoozeSchedule,\n is_snoozed_until: isSnoozedUntil,\n active_snoozes: activeSnoozes,\n last_run: lastRun,\n next_run: nextRun,\n alert_delay: alertDelay,\n ...rest\n}", + "label": "{\n rule_type_id: ruleTypeId,\n created_by: createdBy,\n updated_by: updatedBy,\n created_at: createdAt,\n updated_at: updatedAt,\n api_key_owner: apiKeyOwner,\n api_key_created_by_user: apiKeyCreatedByUser,\n notify_when: notifyWhen,\n mute_all: muteAll,\n muted_alert_ids: mutedInstanceIds,\n scheduled_task_id: scheduledTaskId,\n execution_status: executionStatus,\n actions: actions,\n snooze_schedule: snoozeSchedule,\n is_snoozed_until: isSnoozedUntil,\n active_snoozes: activeSnoozes,\n last_run: lastRun,\n next_run: nextRun,\n alert_delay: alertDelay,\n flapping,\n ...rest\n}", "description": [], "signature": [ "any" diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index df76980642150..db60c4e5f9ded 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 79f0a470bd283..2868fd3d335a5 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 2fb6bb1c97bc3..aa74839dadc1d 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index 9ec954583a9a9..281a43893f0e5 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 16f33d3b8486b..7087715142138 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 75d5aa283cfea..8b9834adb2c1d 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 708f75787ab93..b577fee06abe9 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index a593864927a6e..9ad1fee6eb9dc 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index b234fa5c88bf4..5fcaf1b7cd565 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 7f975b574a7d5..18b5f81323f8e 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index 4f08c5c2eff94..014734c4b9670 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index a88fb3666bbb8..3d5062fa5aab1 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 7b72818208c60..29d240b89312d 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index bc3fa199577cf..0beb94049474d 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index 7ae189c720c2b..82773b0123f2b 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index 480107a7df6d3..5523b0013bebf 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 96ccf72ac1270..a89a658883c02 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index 325364ccc72f9..129d63727e034 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index c27a01fa25841..26263bb3995f4 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index fb4f6035709f0..a51765e81ea9b 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index e61d2fa435c46..c3053b94dc703 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 256c9279436bd..1747a6a960a72 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2024-10-08 +date: 2024-10-09 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From 40471aedb9816a81e9ae6fcc143a96162068358d Mon Sep 17 00:00:00 2001 From: Yara Tercero Date: Tue, 8 Oct 2024 22:51:55 -0700 Subject: [PATCH 040/110] [Detection Engine] Fix rule edit success toast (#190928) ## Summary Addresses https://github.com/elastic/kibana/issues/122070 --- .../rule_creation_ui/pages/rule_editing/index.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx index 6c139acbbdbff..f8db919ff9416 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx @@ -23,6 +23,7 @@ import { useParams } from 'react-router-dom'; import type { DataViewListItem } from '@kbn/data-views-plugin/common'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { isEsqlRule } from '../../../../../common/detection_engine/utils'; import { RulePreview } from '../../components/rule_preview'; import { getIsRulePreviewDisabled } from '../../components/rule_preview/helpers'; @@ -38,7 +39,6 @@ import { getRuleDetailsUrl, getDetectionEngineUrl, } from '../../../../common/components/link_to/redirect_to_detection_engine'; -import { displaySuccessToast, useStateToaster } from '../../../../common/components/toasters'; import { SpyRoute } from '../../../../common/utils/route/spy_routes'; import { useUserData } from '../../../../detections/components/user_info'; import { StepPanel } from '../../../rule_creation/components/step_panel'; @@ -73,7 +73,7 @@ import { CustomHeaderPageMemo } from '..'; import { SaveWithErrorsModal } from '../../components/save_with_errors_confirmation'; const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { - const [, dispatchToaster] = useStateToaster(); + const { addSuccess } = useAppToasts(); const [ { loading: userInfoLoading, @@ -394,7 +394,7 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { const saveChanges = useCallback(async () => { startTransaction({ name: SINGLE_RULE_ACTIONS.SAVE }); - await updateRule({ + const updatedRule = await updateRule({ ...formatRule( defineStepData, aboutStepData, @@ -406,7 +406,7 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { ...(ruleId ? { id: ruleId } : {}), }); - displaySuccessToast(i18n.SUCCESSFULLY_SAVED_RULE(rule?.name ?? ''), dispatchToaster); + addSuccess(i18n.SUCCESSFULLY_SAVED_RULE(updatedRule?.name ?? '')); navigateToApp(APP_UI_ID, { deepLinkId: SecurityPageName.rules, path: getRuleDetailsUrl(ruleId ?? ''), @@ -414,11 +414,10 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { }, [ aboutStepData, actionsStepData, + addSuccess, defineStepData, - dispatchToaster, navigateToApp, rule?.exceptions_list, - rule?.name, ruleId, scheduleStepData, startTransaction, From ab2d7aa5682bb18514a9fbdb2a539914d36b2c7b Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Wed, 9 Oct 2024 00:05:56 -0700 Subject: [PATCH 041/110] [UII] Adjust test based on ES version tested against (#195508) ## Summary Follow up to #194764. This test was also failing on 7.17 branch when they 8.x ES compatibility tests were run, so this PR adjusts the test based on the ES version it runs against. This will be backported to 8.x and 7.17. --- .../apis/epm/install_overrides.ts | 89 ++++++++++--------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_overrides.ts b/x-pack/test/fleet_api_integration/apis/epm/install_overrides.ts index 50aafabd56d6f..4e184edc38387 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_overrides.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_overrides.ts @@ -120,56 +120,63 @@ export default function (providerContext: FtrProviderContext) { // omit routings delete body.template.settings.index.routing; - expect(body).to.eql({ - template: { - settings: { - index: { - default_pipeline: 'logs-overrides.test-0.1.0', - lifecycle: { - name: 'overridden by user', - }, - mapping: { - total_fields: { - limit: '1000', - }, + expect(Object.keys(body)).to.eql(['template', 'overlapping']); + expect(body.template).to.eql({ + settings: { + index: { + default_pipeline: 'logs-overrides.test-0.1.0', + lifecycle: { + name: 'overridden by user', + }, + mapping: { + total_fields: { + limit: '1000', }, - number_of_shards: '3', }, + number_of_shards: '3', }, - mappings: { - dynamic: 'false', - properties: { - '@timestamp': { - type: 'date', - }, - data_stream: { - properties: { - dataset: { - type: 'constant_keyword', - }, - namespace: { - type: 'constant_keyword', - }, - type: { - type: 'constant_keyword', - }, + }, + mappings: { + dynamic: 'false', + properties: { + '@timestamp': { + type: 'date', + }, + data_stream: { + properties: { + dataset: { + type: 'constant_keyword', + }, + namespace: { + type: 'constant_keyword', + }, + type: { + type: 'constant_keyword', }, }, }, }, - aliases: {}, }, - overlapping: [ - { - name: 'logs', - index_patterns: ['logs-*-*'], - }, - { - index_patterns: ['logs-*.otel-*'], - name: 'logs-otel@template', - }, - ], + aliases: {}, }); + + // otel logs templates were added in 8.16 but these tests also run against + // previous versions, so we conditionally test based on the ES version + const esVersion = getService('esVersion'); + expect(body.overlapping).to.eql([ + { + name: 'logs', + index_patterns: ['logs-*-*'], + }, + ...(esVersion.matchRange('>=8.16.0') + ? [ + { + index_patterns: ['logs-*.otel-*'], + name: 'logs-otel@template', + }, + ] + : []), + ]); }); }); } From c3c587bc50816ce570d442b805fe63cb8faee8cc Mon Sep 17 00:00:00 2001 From: Cristina Amico Date: Wed, 9 Oct 2024 09:06:56 +0200 Subject: [PATCH 042/110] [Fleet] Add missing privilege callout in Integrations Policies table (#195429) Fixes https://github.com/elastic/kibana/issues/191800 ## Summary Add missing privilege callout in Integrations Policies table. Currently the route `app/integrations/detail/{pkgName}-{version}/policies` is available even though the policies tab is not visible with limited privileges. ### Testing - Install `osquery_manager` - Enable rbac feature flag - Create role with privileges ![Screenshot 2024-10-08 at 16 24 46](https://github.com/user-attachments/assets/774de651-ac91-4365-9151-2df18efc811c) - Log in with user with the above role - Navigate to `app/integrations/detail/osquery_manager-1.14.0/policies` - Verify that a limited privileges callout is displayed ![Screenshot 2024-10-08 at 16 12 23](https://github.com/user-attachments/assets/4498cbc1-243b-4fa9-a028-8899670f8e14) --- .../sections/epm/screens/detail/index.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx index 6a9b6c875e9dd..51f54fc26c9cb 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx @@ -67,6 +67,8 @@ import { import type { WithHeaderLayoutProps } from '../../../../layouts'; import { WithHeaderLayout } from '../../../../layouts'; +import { PermissionsError } from '../../../../../fleet/layouts'; + import { DeferredAssetsWarning } from './assets/deferred_assets_warning'; import { useIsFirstTimeAgentUserQuery } from './hooks'; import { getInstallPkgRouteOptions } from './utils'; @@ -826,7 +828,14 @@ export function Detail() { - + {canReadIntegrationPolicies ? ( + + ) : ( + + )} From 9975fd63d38a4a6baa27ec34c32d49dab53ec854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Wed, 9 Oct 2024 08:43:52 +0100 Subject: [PATCH 043/110] [Inventory][ECO] Return metadata values (#195204) https://github.com/elastic/kibana/issues/194131 Use `entity.identityFields` instead of host, container and service specific ones. Get the first environment available. --- .../inventory/common/entities.ts | 8 ++-- .../entities_grid/entity_name/index.tsx | 29 +++++++------- .../public/utils/parse_service_params.test.ts | 39 ------------------- .../public/utils/parse_service_params.ts | 30 -------------- .../common/field_names/elasticsearch.ts | 1 + .../observability_shared/common/index.ts | 1 + 6 files changed, 22 insertions(+), 86 deletions(-) delete mode 100644 x-pack/plugins/observability_solution/inventory/public/utils/parse_service_params.test.ts delete mode 100644 x-pack/plugins/observability_solution/inventory/public/utils/parse_service_params.ts diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts index 01f17807c3486..218e3d50905a9 100644 --- a/x-pack/plugins/observability_solution/inventory/common/entities.ts +++ b/x-pack/plugins/observability_solution/inventory/common/entities.ts @@ -6,15 +6,16 @@ */ import { ENTITY_LATEST, entitiesAliasPattern } from '@kbn/entities-schema'; import { - CONTAINER_ID, - HOST_NAME, AGENT_NAME, CLOUD_PROVIDER, + CONTAINER_ID, ENTITY_DEFINITION_ID, ENTITY_DISPLAY_NAME, ENTITY_ID, + ENTITY_IDENTITY_FIELDS, ENTITY_LAST_SEEN, ENTITY_TYPE, + HOST_NAME, SERVICE_ENVIRONMENT, SERVICE_NAME, } from '@kbn/observability-shared-plugin/common'; @@ -77,6 +78,7 @@ interface BaseEntity { [ENTITY_TYPE]: EntityType; [ENTITY_DISPLAY_NAME]: string; [ENTITY_DEFINITION_ID]: string; + [ENTITY_IDENTITY_FIELDS]: string[]; } /** @@ -85,7 +87,7 @@ interface BaseEntity { interface ServiceEntity extends BaseEntity { [ENTITY_TYPE]: 'service'; [SERVICE_NAME]: string; - [SERVICE_ENVIRONMENT]?: string | null; + [SERVICE_ENVIRONMENT]?: string | string[] | null; [AGENT_NAME]: string | string[] | null; } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx index 28fe38511fa9f..debe91d52dec1 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx @@ -5,19 +5,20 @@ * 2.0. */ -import { EuiLink, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React, { useCallback } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; import { - AssetDetailsLocatorParams, ASSET_DETAILS_LOCATOR_ID, - ServiceOverviewParams, - ENTITY_TYPE, + AssetDetailsLocatorParams, ENTITY_DISPLAY_NAME, + ENTITY_IDENTITY_FIELDS, + ENTITY_TYPE, + SERVICE_ENVIRONMENT, + ServiceOverviewParams, } from '@kbn/observability-shared-plugin/common'; +import React, { useCallback } from 'react'; +import { Entity } from '../../../../common/entities'; import { useKibana } from '../../../hooks/use_kibana'; import { EntityIcon } from '../../entity_icon'; -import { Entity } from '../../../../common/entities'; -import { parseServiceParams } from '../../../utils/parse_service_params'; interface EntityNameProps { entity: Entity; @@ -34,23 +35,23 @@ export function EntityName({ entity }: EntityNameProps) { const getEntityRedirectUrl = useCallback(() => { const type = entity[ENTITY_TYPE]; + // For service, host and container type there is only one identity field + const identityField = entity[ENTITY_IDENTITY_FIELDS][0]; // Any unrecognised types will always return undefined switch (type) { case 'host': case 'container': return assetDetailsLocator?.getRedirectUrl({ - assetId: entity[ENTITY_DISPLAY_NAME], + assetId: identityField, assetType: type, }); case 'service': - // For services, the format of the display name is `service.name:service.environment`. - // We just want the first part of the name for the locator. - // TODO: Replace this with a better approach for handling service names. See https://github.com/elastic/kibana/issues/194131 - return serviceOverviewLocator?.getRedirectUrl( - parseServiceParams(entity[ENTITY_DISPLAY_NAME]) - ); + return serviceOverviewLocator?.getRedirectUrl({ + serviceName: identityField, + environment: [entity[SERVICE_ENVIRONMENT] || undefined].flat()[0], + }); } }, [entity, assetDetailsLocator, serviceOverviewLocator]); diff --git a/x-pack/plugins/observability_solution/inventory/public/utils/parse_service_params.test.ts b/x-pack/plugins/observability_solution/inventory/public/utils/parse_service_params.test.ts deleted file mode 100644 index 217b28480feb1..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/utils/parse_service_params.test.ts +++ /dev/null @@ -1,39 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { parseServiceParams } from './parse_service_params'; - -describe('parseServiceParams', () => { - it('should return only serviceName with a simple name string', () => { - const params = parseServiceParams('service.name'); - - expect(params).toEqual({ serviceName: 'service.name' }); - }); - - it('should return both serviceName and environment with a full name string', () => { - const params = parseServiceParams('service.name:service.environment'); - - expect(params).toEqual({ serviceName: 'service.name', environment: 'service.environment' }); - }); - - it('should ignore multiple colons in the environment portion of the displayName', () => { - const params = parseServiceParams('service.name:synthtrace: service.environment'); - - expect(params).toEqual({ - serviceName: 'service.name', - environment: 'synthtrace: service.environment', - }); - }); - - it('should ignore empty environment names and return only the service.name', () => { - const params = parseServiceParams('service.name:'); - - expect(params).toEqual({ - serviceName: 'service.name', - }); - }); -}); diff --git a/x-pack/plugins/observability_solution/inventory/public/utils/parse_service_params.ts b/x-pack/plugins/observability_solution/inventory/public/utils/parse_service_params.ts deleted file mode 100644 index 637957c578272..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/utils/parse_service_params.ts +++ /dev/null @@ -1,30 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { ServiceOverviewParams } from '@kbn/observability-shared-plugin/common'; - -/** - * Parses a displayName string with the format `service.name:service.environment`, - * returning a valid `ServiceOverviewParams` object. - * @param displayName A string from a `entity.displayName` field. - * @returns - */ -export const parseServiceParams = (displayName: string): ServiceOverviewParams => { - const separatorIndex = displayName.indexOf(':'); - - const hasEnvironmentName = separatorIndex !== -1; - - const serviceName = hasEnvironmentName ? displayName.slice(0, separatorIndex) : displayName; - // Exclude the separator from the sliced string for the environment name. - // If the string is empty however, then we default to undefined. - const environment = (hasEnvironmentName && displayName.slice(separatorIndex + 1)) || undefined; - - return { - serviceName, - environment, - }; -}; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/field_names/elasticsearch.ts b/x-pack/plugins/observability_solution/observability_shared/common/field_names/elasticsearch.ts index 741e9b6b0e2d3..5652671a87281 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/field_names/elasticsearch.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/field_names/elasticsearch.ts @@ -153,4 +153,5 @@ export const ENTITY_LAST_SEEN = 'entity.lastSeenTimestamp'; export const ENTITY_FIRST_SEEN = 'entity.firstSeenTimestamp'; export const ENTITY_DISPLAY_NAME = 'entity.displayName'; export const ENTITY_DEFINITION_ID = 'entity.definitionId'; +export const ENTITY_IDENTITY_FIELDS = 'entity.identityFields'; export const SOURCE_DATA_STREAM_TYPE = 'source_data_stream.type'; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/index.ts b/x-pack/plugins/observability_solution/observability_shared/common/index.ts index a33c0aa99d1e2..a359a3d862ce9 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/index.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/index.ts @@ -136,6 +136,7 @@ export { ENTITY_LAST_SEEN, ENTITY_TYPE, SOURCE_DATA_STREAM_TYPE, + ENTITY_IDENTITY_FIELDS, } from './field_names/elasticsearch'; export { From 9907601dd148ba59420bffda45ff584686f47b43 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Wed, 9 Oct 2024 10:14:06 +0200 Subject: [PATCH 044/110] [LogsUI] Add UI setting to hide Logs Stream and dashboard panel option (#194519) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📓 Summary Closes #193319 Closes #193320 This work is part of the effort to progressively deprecate the existing Logs Stream feature. Changes taken on this PR consist of: - Create a new uiSettings `observability:enableLogsStream` which defaults to `false` on the stateful/cloud deployments and is not available in serverless ones (still, defaults to `false` behind the scene). - When `observability:enableLogsStream` is `false`, the Logs Stream page route is not registered, and neither is its deep link for global search. - When `observability:enableLogsStream` is `false`, the panels list on Dashboard won't show anymore the option `Logs Stream (Deprecated)` to prevent usage of this embeddable in new dashboards. The embeddable is still registered for retro-compatibility with active dashboards, and it has now a callout explaining the status of this embeddable (unmaintained/deprecated). - Rename logs ML to "Logs Anomalies" and "Logs Categories". Other minor improvements regard: - Remove duplicate Xstate utils and use the relative package instead. - Remove the duplicated `useBoolean` hook used in the deprecation callout. - Sync deep links registration with available routes through a single `getLogsRoutes` util. ## 🎥 Recordings ### Logs Stream app removed https://github.com/user-attachments/assets/f4173294-8789-4abd-9972-29c9b7c197ed ### Logs Stream dashboard panel entry removed https://github.com/user-attachments/assets/7f99ca2a-c030-4867-b976-8fdc1df09d29 ### Logs Stream app removed from project nav https://github.com/user-attachments/assets/de51bdd6-820a-4c03-8b64-fb1a6ced0a12 ### Embeddable deprecation callout Screenshot 2024-10-02 at 10 22 09 ### Unavailable setting in serverless https://github.com/user-attachments/assets/91bf6c37-0845-4918-a485-b6250bbd96bf --------- Co-authored-by: Marco Antonio Ghiani Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Mike Birnstiehl <114418652+mdbirnstiehl@users.noreply.github.com> --- .../settings/setting_ids/index.ts | 1 + .../server/collectors/management/schema.ts | 4 + .../server/collectors/management/types.ts | 1 + src/plugins/telemetry/schema/oss_plugins.json | 6 + .../group1/create_and_add_embeddables.ts | 12 +- test/tsconfig.json | 1 + .../infra/common/ui_settings.ts | 30 +++ .../log_stream_react_embeddable.tsx | 55 +++++- .../components/logs_deprecation_callout.tsx | 37 +++- .../infra/public/hooks/use_boolean.ts | 36 ---- .../log_stream_page/state/src/selectors.ts | 2 +- .../state/src/state_machine.ts | 2 +- .../src/state_machine.ts | 2 +- .../src/state_machine.ts | 2 +- .../xstate_helpers/src/index.ts | 3 - .../src/notification_channel.ts | 41 ---- .../xstate_helpers/src/send_actions.test.ts | 67 ------- .../xstate_helpers/src/send_actions.ts | 36 ---- .../xstate_helpers/src/types.ts | 43 ---- .../public/pages/logs/log_entry_rate/page.tsx | 4 +- .../logs/log_entry_rate/page_content.tsx | 8 +- .../infra/public/pages/logs/page_content.tsx | 103 +++++----- .../infra/public/pages/logs/routes.ts | 56 ++++++ .../source_configuration_settings.tsx | 2 + .../pages/logs/stream/page_logs_content.tsx | 4 +- .../pages/logs/stream/page_providers.tsx | 2 +- .../waffle/waffle_group_by_controls.tsx | 2 +- .../infra/public/plugin.ts | 183 ++++++++++-------- .../infra/public/translations.ts | 6 +- .../lib/adapters/framework/adapter_types.ts | 2 + .../infra/server/plugin.ts | 4 + .../infra/tsconfig.json | 3 + .../observability/public/navigation_tree.ts | 6 + .../observability/tsconfig.json | 2 +- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../functional/apps/infra/logs/log_stream.ts | 4 + .../apps/infra/logs/log_stream_date_nano.ts | 4 + .../infra/logs/logs_source_configuration.ts | 3 + .../functional/apps/infra/page_not_found.ts | 11 +- 41 files changed, 387 insertions(+), 406 deletions(-) create mode 100644 x-pack/plugins/observability_solution/infra/common/ui_settings.ts delete mode 100644 x-pack/plugins/observability_solution/infra/public/hooks/use_boolean.ts delete mode 100644 x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/notification_channel.ts delete mode 100644 x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/send_actions.test.ts delete mode 100644 x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/send_actions.ts delete mode 100644 x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/types.ts create mode 100644 x-pack/plugins/observability_solution/infra/public/pages/logs/routes.ts diff --git a/packages/kbn-management/settings/setting_ids/index.ts b/packages/kbn-management/settings/setting_ids/index.ts index cb32dbd4a4505..a7051804289bd 100644 --- a/packages/kbn-management/settings/setting_ids/index.ts +++ b/packages/kbn-management/settings/setting_ids/index.ts @@ -144,6 +144,7 @@ export const OBSERVABILITY_LOGS_EXPLORER_ALLOWED_DATA_VIEWS_ID = 'observability:logsExplorer:allowedDataViews'; export const OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE = 'observability:entityCentricExperience'; export const OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID = 'observability:logSources'; +export const OBSERVABILITY_ENABLE_LOGS_STREAM = 'observability:enableLogsStream'; export const OBSERVABILITY_AI_ASSISTANT_SIMULATED_FUNCTION_CALLING = 'observability:aiAssistantSimulatedFunctionCalling'; export const OBSERVABILITY_AI_ASSISTANT_SEARCH_CONNECTOR_INDEX_PATTERN = diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index 0ece5f004c23e..dc2d2ad2c5de2 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -510,6 +510,10 @@ export const stackManagementSchema: MakeSchemaFrom = { _meta: { description: 'Non-default value of setting.' }, }, }, + 'observability:enableLogsStream': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'banners:placement': { type: 'keyword', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index ca1df3c95e87a..ef20ab223dfb6 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -55,6 +55,7 @@ export interface UsageStats { 'observability:apmEnableServiceInventoryTableSearchBar': boolean; 'observability:logsExplorer:allowedDataViews': string[]; 'observability:logSources': string[]; + 'observability:enableLogsStream': boolean; 'observability:aiAssistantSimulatedFunctionCalling': boolean; 'observability:aiAssistantSearchConnectorIndexPattern': string; 'visualization:heatmap:maxBuckets': number; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index f25c29e5f6952..958280d9eba00 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -10486,6 +10486,12 @@ } } }, + "observability:enableLogsStream": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "banners:placement": { "type": "keyword", "_meta": { diff --git a/test/functional/apps/dashboard/group1/create_and_add_embeddables.ts b/test/functional/apps/dashboard/group1/create_and_add_embeddables.ts index 61929b19ff468..34e78f3e68632 100644 --- a/test/functional/apps/dashboard/group1/create_and_add_embeddables.ts +++ b/test/functional/apps/dashboard/group1/create_and_add_embeddables.ts @@ -8,7 +8,7 @@ */ import expect from '@kbn/expect'; - +import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; import { VisualizeConstants } from '@kbn/visualizations-plugin/common/constants'; import { FtrProviderContext } from '../../../ftr_provider_context'; @@ -28,6 +28,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.replace({ defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c', }); + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: true }); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: false }); }); it('ensure toolbar popover closes on add', async () => { @@ -39,10 +45,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardAddPanel.expectEditorMenuClosed(); }); - after(async () => { - await kibanaServer.savedObjects.cleanStandardList(); - }); - describe('add new visualization link', () => { before(async () => { await dashboard.navigateToApp(); diff --git a/test/tsconfig.json b/test/tsconfig.json index 8b0d946bded62..1d8c301c44a2b 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -76,5 +76,6 @@ "@kbn/default-nav-management", "@kbn/default-nav-devtools", "@kbn/core-saved-objects-import-export-server-internal", + "@kbn/management-settings-ids", ] } diff --git a/x-pack/plugins/observability_solution/infra/common/ui_settings.ts b/x-pack/plugins/observability_solution/infra/common/ui_settings.ts new file mode 100644 index 0000000000000..95f1ee0a44bae --- /dev/null +++ b/x-pack/plugins/observability_solution/infra/common/ui_settings.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * uiSettings definitions for the logs_data_access plugin. + */ +import { schema } from '@kbn/config-schema'; +import { UiSettingsParams } from '@kbn/core-ui-settings-common'; +import { i18n } from '@kbn/i18n'; +import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; + +export const uiSettings: Record = { + [OBSERVABILITY_ENABLE_LOGS_STREAM]: { + category: ['observability'], + name: i18n.translate('xpack.infra.enableLogsStream', { + defaultMessage: 'Logs Stream', + }), + value: false, + description: i18n.translate('xpack.infra.enableLogsStreamDescription', { + defaultMessage: 'Enables the legacy Logs Stream application and dashboard panel. ', + }), + type: 'boolean', + schema: schema.boolean(), + requiresPageReload: true, + }, +}; diff --git a/x-pack/plugins/observability_solution/infra/public/components/log_stream/log_stream_react_embeddable.tsx b/x-pack/plugins/observability_solution/infra/public/components/log_stream/log_stream_react_embeddable.tsx index bbb2e09d8660a..1193b81379219 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/log_stream/log_stream_react_embeddable.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/log_stream/log_stream_react_embeddable.tsx @@ -6,6 +6,8 @@ */ import React, { FC, PropsWithChildren, useEffect, useMemo, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiCallOut, EuiLink } from '@elastic/eui'; import { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { initializeTimeRange, @@ -17,6 +19,9 @@ import { AppMountParameters, CoreStart } from '@kbn/core/public'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { Query } from '@kbn/es-query'; import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; +import { euiThemeVars } from '@kbn/ui-theme'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; +import { FormattedMessage } from '@kbn/i18n-react'; import type { LogStreamApi, LogStreamSerializedState, Services } from './types'; import { datemathToEpochMillis } from '../../utils/datemath'; import { LOG_STREAM_EMBEDDABLE } from './constants'; @@ -81,7 +86,7 @@ export function getLogStreamEmbeddableFactory(services: Services) { theme$={services.coreStart.theme.theme$} > -
    +
    +
    @@ -101,6 +107,53 @@ export function getLogStreamEmbeddableFactory(services: Services) { return factory; } +const DISMISSAL_STORAGE_KEY = 'observability:logStreamEmbeddableDeprecationCalloutDismissed'; +const SAVED_SEARCH_DOCS_URL = + 'https://www.elastic.co/guide/en/kibana/current/save-open-search.html'; + +const DeprecationCallout = () => { + const [isDismissed, setDismissed] = useLocalStorage(DISMISSAL_STORAGE_KEY, false); + + if (isDismissed) { + return null; + } + + return ( + setDismissed(true)} + css={{ + position: 'absolute', + bottom: euiThemeVars.euiSizeM, + right: euiThemeVars.euiSizeM, + width: 'min(100%, 40ch)', + }} + > +

    + + {i18n.translate( + 'xpack.infra.logsStreamEmbeddable.deprecationWarningDescription.savedSearchesLinkLabel', + { defaultMessage: 'saved searches' } + )} + + ), + }} + /> +

    +
    + ); +}; + export interface LogStreamEmbeddableProvidersProps { core: CoreStart; pluginStart: InfraClientStartExports; diff --git a/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx b/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx index 71ae9698ea3b9..63107f4a4d031 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx @@ -18,14 +18,38 @@ import { css } from '@emotion/css'; import { SharePublicStart } from '@kbn/share-plugin/public/plugin'; import { useKibanaContextForPlugin } from '../hooks/use_kibana'; -const DISMISSAL_STORAGE_KEY = 'log_stream_deprecation_callout_dismissed'; +const pageConfigurations = { + stream: { + dismissalStorageKey: 'log_stream_deprecation_callout_dismissed', + message: i18n.translate('xpack.infra.logsDeprecationCallout.p.theNewLogsExplorerLabel', { + defaultMessage: + 'The new Logs Explorer makes viewing and inspecting your logs easier with more features, better performance, and more intuitive navigation. We recommend switching to Logs Explorer, as it will replace Logs Stream in a future version.', + }), + }, + settings: { + dismissalStorageKey: 'log_settings_deprecation_callout_dismissed', + message: i18n.translate( + 'xpack.infra.logsSettingsDeprecationCallout.p.theNewLogsExplorerLabel', + { + defaultMessage: + 'These settings only apply to the legacy Logs Stream app, and we do not recommend configuring them. Instead, use Logs Explorer which makes viewing and inspecting your logs easier with more features, better performance, and more intuitive navigation.', + } + ), + }, +}; + +interface LogsDeprecationCalloutProps { + page: keyof typeof pageConfigurations; +} -export const LogsDeprecationCallout = () => { +export const LogsDeprecationCallout = ({ page }: LogsDeprecationCalloutProps) => { const { services: { share }, } = useKibanaContextForPlugin(); - const [isDismissed, setDismissed] = useLocalStorage(DISMISSAL_STORAGE_KEY, false); + const { dismissalStorageKey, message } = pageConfigurations[page]; + + const [isDismissed, setDismissed] = useLocalStorage(dismissalStorageKey, false); if (isDismissed) { return null; @@ -42,12 +66,7 @@ export const LogsDeprecationCallout = () => { onDismiss={() => setDismissed(true)} className={calloutStyle} > -

    - {i18n.translate('xpack.infra.logsDeprecationCallout.p.theNewLogsExplorerLabel', { - defaultMessage: - 'The new Logs Explorer makes viewing and inspecting your logs easier with more features, better performance, and more intuitive navigation. We recommend switching to Logs Explorer, as it will replace Logs Stream in a future version.', - })} -

    +

    {message}

    void; - -export type DispatchWithOptionalAction = (_arg?: Type | unknown) => void; - -export interface UseBooleanHandlers { - on: VoidHandler; - off: VoidHandler; - toggle: DispatchWithOptionalAction; -} - -export type UseBooleanResult = [boolean, UseBooleanHandlers]; - -export const useBoolean = (initialValue: boolean = false): UseBooleanResult => { - const [value, toggle] = useToggle(initialValue); - - const handlers = useMemo( - () => ({ - toggle, - on: () => toggle(true), - off: () => toggle(false), - }), - [toggle] - ); - - return [value, handlers]; -}; diff --git a/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_page/state/src/selectors.ts b/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_page/state/src/selectors.ts index c6bfafd020ab2..6f00ce32097e9 100644 --- a/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_page/state/src/selectors.ts +++ b/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_page/state/src/selectors.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { MatchedStateFromActor } from '@kbn/xstate-utils'; import { LogStreamQueryActorRef } from '../../../log_stream_query_state'; -import { MatchedStateFromActor } from '../../../xstate_helpers'; import { LogStreamPageActorRef } from './state_machine'; type LogStreamPageStateWithLogViewIndices = diff --git a/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts b/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts index d2a71c65702eb..e2755b29d21e3 100644 --- a/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts +++ b/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts @@ -10,6 +10,7 @@ import { TimeRange } from '@kbn/es-query'; import { actions, ActorRefFrom, createMachine, EmittedFrom } from 'xstate'; import { DEFAULT_REFRESH_INTERVAL } from '@kbn/logs-shared-plugin/common'; import type { LogViewNotificationChannel } from '@kbn/logs-shared-plugin/public'; +import { OmitDeprecatedState } from '@kbn/xstate-utils'; import { datemathToEpochMillis } from '../../../../utils/datemath'; import { createLogStreamPositionStateMachine } from '../../../log_stream_position_state/src/state_machine'; import { @@ -17,7 +18,6 @@ import { DEFAULT_TIMERANGE, LogStreamQueryStateMachineDependencies, } from '../../../log_stream_query_state'; -import { OmitDeprecatedState } from '../../../xstate_helpers'; import { waitForInitialQueryParameters, waitForInitialPositionParameters, diff --git a/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts b/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts index 868f29a5c07e9..0cc26d3e6ed35 100644 --- a/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts +++ b/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts @@ -10,8 +10,8 @@ import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; import { convertISODateToNanoPrecision } from '@kbn/logs-shared-plugin/common'; import moment from 'moment'; import { actions, ActorRefFrom, createMachine, EmittedFrom, SpecialTargets } from 'xstate'; +import { OmitDeprecatedState, sendIfDefined } from '@kbn/xstate-utils'; import { isSameTimeKey } from '../../../../common/time'; -import { OmitDeprecatedState, sendIfDefined } from '../../xstate_helpers'; import { DESIRED_BUFFER_PAGES, RELATIVE_END_UPDATE_DELAY } from './defaults'; import { LogStreamPositionNotificationEventSelectors } from './notifications'; import type { diff --git a/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts b/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts index 1c0de464121c8..5570faf16f3f8 100644 --- a/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts +++ b/x-pack/plugins/observability_solution/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts @@ -15,7 +15,7 @@ import { EsQueryConfig } from '@kbn/es-query'; import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; import { actions, ActorRefFrom, createMachine, SpecialTargets, send } from 'xstate'; import { DEFAULT_REFRESH_INTERVAL } from '@kbn/logs-shared-plugin/common'; -import { OmitDeprecatedState, sendIfDefined } from '../../xstate_helpers'; +import { OmitDeprecatedState, sendIfDefined } from '@kbn/xstate-utils'; import { logStreamQueryNotificationEventSelectors } from './notifications'; import { subscribeToFilterSearchBarChanges, diff --git a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/index.ts b/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/index.ts index 8e6f993a9755e..67b23e66b78e8 100644 --- a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/index.ts +++ b/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/index.ts @@ -6,7 +6,4 @@ */ export * from './invalid_state_callout'; -export * from './notification_channel'; -export * from './send_actions'; -export * from './types'; export * from './state_machine_playground'; diff --git a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/notification_channel.ts b/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/notification_channel.ts deleted file mode 100644 index 0108ab0225176..0000000000000 --- a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/notification_channel.ts +++ /dev/null @@ -1,41 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReplaySubject } from 'rxjs'; -import { ActionFunction, EventObject, Expr, Subscribable } from 'xstate'; - -export interface NotificationChannel { - createService: () => Subscribable; - notify: ( - eventExpr: Expr - ) => ActionFunction; -} - -export const createNotificationChannel = < - TContext, - TEvent extends EventObject, - TSentEvent ->(): NotificationChannel => { - const eventsSubject = new ReplaySubject(1); - - const createService = () => eventsSubject.asObservable(); - - const notify = - (eventExpr: Expr) => - (context: TContext, event: TEvent) => { - const eventToSend = eventExpr(context, event); - - if (eventToSend != null) { - eventsSubject.next(eventToSend); - } - }; - - return { - createService, - notify, - }; -}; diff --git a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/send_actions.test.ts b/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/send_actions.test.ts deleted file mode 100644 index cf446fec63b3f..0000000000000 --- a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/send_actions.test.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { actions, ActorRef, EventObject } from 'xstate'; -import { sendIfDefined } from './send_actions'; - -describe('function sendIfDefined', () => { - it('sends the events to the specified target', () => { - const actor = createMockActor(); - const createEvent = (context: {}) => ({ - type: 'testEvent', - }); - - const action = sendIfDefined(actor)(createEvent).get({}, { type: 'triggeringEvent' }); - - expect(action).toEqual([ - actions.send('testEvent', { - to: actor, - }), - ]); - }); - - it('sends the events created by the event expression', () => { - const actor = createMockActor(); - const createEvent = (context: {}) => ({ - type: 'testEvent', - payload: 'payload', - }); - - const action = sendIfDefined(actor)(createEvent).get({}, { type: 'triggeringEvent' }); - - expect(action).toEqual([ - actions.send( - { - type: 'testEvent', - payload: 'payload', - }, - { - to: actor, - } - ), - ]); - }); - - it("doesn't send anything when the event expression returns undefined", () => { - const actor = createMockActor(); - const createEvent = (context: {}) => undefined; - - const action = sendIfDefined(actor)(createEvent).get({}, { type: 'triggeringEvent' }); - - expect(action).toEqual(undefined); - }); -}); - -const createMockActor = (): ActorRef => ({ - getSnapshot: jest.fn(), - id: 'mockActor', - send: jest.fn(), - subscribe: jest.fn(), - [Symbol.observable]() { - return this; - }, -}); diff --git a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/send_actions.ts b/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/send_actions.ts deleted file mode 100644 index 375fd831b030f..0000000000000 --- a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/send_actions.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - actions, - ActorRef, - AnyEventObject, - EventObject, - Expr, - PureAction, - SendActionOptions, -} from 'xstate'; - -export const sendIfDefined = - (target: string | ActorRef) => - ( - eventExpr: Expr, - options?: SendActionOptions - ): PureAction => { - return actions.pure((context, event) => { - const targetEvent = eventExpr(context, event); - - return targetEvent != null - ? [ - actions.send(targetEvent, { - ...options, - to: target, - }), - ] - : undefined; - }); - }; diff --git a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/types.ts b/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/types.ts deleted file mode 100644 index 05e75c5fe6e45..0000000000000 --- a/x-pack/plugins/observability_solution/infra/public/observability_logs/xstate_helpers/src/types.ts +++ /dev/null @@ -1,43 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { ActorRef, ActorRefWithDeprecatedState, EmittedFrom, State, StateValue } from 'xstate'; - -export type OmitDeprecatedState> = Omit< - T, - 'state' ->; - -export type MatchedState< - TState extends State, - TStateValue extends StateValue -> = TState extends State< - any, - infer TEvent, - infer TStateSchema, - infer TTypestate, - infer TResolvedTypesMeta -> - ? State< - (TTypestate extends any - ? { value: TStateValue; context: any } extends TTypestate - ? TTypestate - : never - : never)['context'], - TEvent, - TStateSchema, - TTypestate, - TResolvedTypesMeta - > & { - value: TStateValue; - } - : never; - -export type MatchedStateFromActor< - TActorRef extends ActorRef, - TStateValue extends StateValue -> = MatchedState, TStateValue>; diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/page.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/page.tsx index 50a4852c458c4..97841745ae13a 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/page.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/page.tsx @@ -10,13 +10,13 @@ import React from 'react'; import { LogEntryRatePageContent } from './page_content'; import { LogEntryRatePageProviders } from './page_providers'; import { useLogsBreadcrumbs } from '../../../hooks/use_logs_breadcrumbs'; -import { anomaliesTitle } from '../../../translations'; +import { logsAnomaliesTitle } from '../../../translations'; import { LogMlJobIdFormatsShimProvider } from '../shared/use_log_ml_job_id_formats_shim'; export const LogEntryRatePage = () => { useLogsBreadcrumbs([ { - text: anomaliesTitle, + text: logsAnomaliesTitle, }, ]); return ( diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/page_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/page_content.tsx index e4dc0694c3f75..3ac8d7d9137d1 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/page_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/page_content.tsx @@ -36,7 +36,7 @@ import { useLogMlJobIdFormatsShimContext } from '../shared/use_log_ml_job_id_for const JOB_STATUS_POLLING_INTERVAL = 30000; -const anomaliesTitle = i18n.translate('xpack.infra.logs.anomaliesPageTitle', { +const logsAnomaliesTitle = i18n.translate('xpack.infra.logs.anomaliesPageTitle', { defaultMessage: 'Anomalies', }); @@ -101,7 +101,7 @@ export const LogEntryRatePageContent = memo(() => { ); @@ -137,7 +137,7 @@ export const LogEntryRatePageContent = memo(() => { ) { return ( <> - + ); @@ -172,7 +172,7 @@ const AnomaliesPageTemplate: React.FC = ({ rest.isEmptyState ? undefined : { - pageTitle: anomaliesTitle, + pageTitle: logsAnomaliesTitle, } } {...rest} diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/page_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/page_content.tsx index 5b5965bb2d5ec..ecf5af5572b31 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/logs/page_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/page_content.tsx @@ -9,26 +9,36 @@ import { EuiFlexGroup, EuiFlexItem, EuiHeaderLink, EuiHeaderLinks } from '@elast import { i18n } from '@kbn/i18n'; import React, { useContext } from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { useKibana, useUiSetting } from '@kbn/kibana-react-plugin/public'; import { HeaderMenuPortal, useLinkProps } from '@kbn/observability-shared-plugin/public'; import { SharePublicStart } from '@kbn/share-plugin/public/plugin'; import { ObservabilityOnboardingLocatorParams, OBSERVABILITY_ONBOARDING_LOCATOR, + AllDatasetsLocatorParams, + ALL_DATASETS_LOCATOR_ID, } from '@kbn/deeplinks-observability'; import { dynamic } from '@kbn/shared-ux-utility'; +import { isDevMode } from '@kbn/xstate-utils'; +import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; import { LazyAlertDropdownWrapper } from '../../alerting/log_threshold'; import { HelpCenterContent } from '../../components/help_center_content'; import { useReadOnlyBadge } from '../../hooks/use_readonly_badge'; import { HeaderActionMenuContext } from '../../containers/header_action_menu_provider'; import { RedirectWithQueryParams } from '../../utils/redirect_with_query_params'; -import { LogEntryCategoriesPage } from './log_entry_categories'; -import { LogEntryRatePage } from './log_entry_rate'; -import { LogsSettingsPage } from './settings'; -import { StreamPage } from './stream'; -import { isDevMode } from '../../utils/dev_mode'; import { NotFoundPage } from '../404'; +import { getLogsAppRoutes } from './routes'; +const StreamPage = dynamic(() => import('./stream').then((mod) => ({ default: mod.StreamPage }))); +const LogEntryCategoriesPage = dynamic(() => + import('./log_entry_categories').then((mod) => ({ default: mod.LogEntryCategoriesPage })) +); +const LogEntryRatePage = dynamic(() => + import('./log_entry_rate').then((mod) => ({ default: mod.LogEntryRatePage })) +); +const LogsSettingsPage = dynamic(() => + import('./settings').then((mod) => ({ default: mod.LogsSettingsPage })) +); const StateMachinePlayground = dynamic(() => import('../../observability_logs/xstate_helpers').then((mod) => ({ default: mod.StateMachinePlayground, @@ -37,6 +47,9 @@ const StateMachinePlayground = dynamic(() => export const LogsPageContent: React.FunctionComponent = () => { const { application, share } = useKibana<{ share: SharePublicStart }>().services; + + const isLogsStreamEnabled: boolean = useUiSetting(OBSERVABILITY_ENABLE_LOGS_STREAM, false); + const uiCapabilities = application?.capabilities; const onboardingLocator = share?.url.locators.get( OBSERVABILITY_ONBOARDING_LOCATOR @@ -47,30 +60,7 @@ export const LogsPageContent: React.FunctionComponent = () => { useReadOnlyBadge(!uiCapabilities?.logs?.save); - // !! Need to be kept in sync with the deepLinks in x-pack/plugins/observability_solution/infra/public/plugin.ts - const streamTab = { - app: 'logs', - title: streamTabTitle, - pathname: '/stream', - }; - - const anomaliesTab = { - app: 'logs', - title: anomaliesTabTitle, - pathname: '/anomalies', - }; - - const logCategoriesTab = { - app: 'logs', - title: logCategoriesTabTitle, - pathname: '/log-categories', - }; - - const settingsTab = { - app: 'logs', - title: settingsTabTitle, - pathname: '/settings', - }; + const routes = getLogsAppRoutes({ isLogsStreamEnabled }); const settingsLinkProps = useLinkProps({ app: 'logs', @@ -104,25 +94,36 @@ export const LogsPageContent: React.FunctionComponent = () => { )} - - - - + {routes.stream ? ( + + ) : ( + { + share.url.locators + .get(ALL_DATASETS_LOCATOR_ID) + ?.navigate({}); + + return null; + }} + /> + )} + + + {enableDeveloperRoutes && ( )} - - - - ( - - )} + + + + + } /> ); @@ -132,18 +133,6 @@ const pageTitle = i18n.translate('xpack.infra.header.logsTitle', { defaultMessage: 'Logs', }); -const streamTabTitle = i18n.translate('xpack.infra.logs.index.streamTabTitle', { - defaultMessage: 'Stream', -}); - -const anomaliesTabTitle = i18n.translate('xpack.infra.logs.index.anomaliesTabTitle', { - defaultMessage: 'Anomalies', -}); - -const logCategoriesTabTitle = i18n.translate('xpack.infra.logs.index.logCategoriesBetaBadgeTitle', { - defaultMessage: 'Categories', -}); - const settingsTabTitle = i18n.translate('xpack.infra.logs.index.settingsTabTitle', { defaultMessage: 'Settings', }); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/routes.ts b/x-pack/plugins/observability_solution/infra/public/pages/logs/routes.ts new file mode 100644 index 0000000000000..a5c38672a8bed --- /dev/null +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/routes.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + logsAnomaliesTitle, + logCategoriesTitle, + settingsTitle, + streamTitle, +} from '../../translations'; + +export interface LogsRoute { + id: string; + title: string; + path: string; +} + +export interface LogsAppRoutes { + logsAnomalies: LogsRoute; + logsCategories: LogsRoute; + settings: LogsRoute; + stream?: LogsRoute; +} + +export const getLogsAppRoutes = ({ isLogsStreamEnabled }: { isLogsStreamEnabled: boolean }) => { + const routes: LogsAppRoutes = { + logsAnomalies: { + id: 'anomalies', + title: logsAnomaliesTitle, + path: '/anomalies', + }, + logsCategories: { + id: 'log-categories', + title: logCategoriesTitle, + path: '/log-categories', + }, + settings: { + id: 'settings', + title: settingsTitle, + path: '/settings', + }, + }; + + if (isLogsStreamEnabled) { + routes.stream = { + id: 'stream', + title: streamTitle, + path: '/stream', + }; + } + + return routes; +}; diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/source_configuration_settings.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/source_configuration_settings.tsx index 557fe1cfab314..d1df2a5820dd3 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/source_configuration_settings.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/source_configuration_settings.tsx @@ -20,6 +20,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import { Prompt } from '@kbn/observability-shared-plugin/public'; import { useTrackPageview } from '@kbn/observability-shared-plugin/public'; import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; +import { LogsDeprecationCallout } from '../../../components/logs_deprecation_callout'; import { SourceLoadingPage } from '../../../components/source_loading_page'; import { useLogsBreadcrumbs } from '../../../hooks/use_logs_breadcrumbs'; import { settingsTitle } from '../../../translations'; @@ -98,6 +99,7 @@ export const LogsSettingsPage = () => { data-test-subj="sourceConfigurationContent" restrictWidth > + diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page_logs_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page_logs_content.tsx index d40014ed4468b..f59d3c1f03fbf 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page_logs_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page_logs_content.tsx @@ -26,6 +26,7 @@ import { useSelector } from '@xstate/react'; import stringify from 'json-stable-stringify'; import React, { useCallback, useEffect, useMemo } from 'react'; import usePrevious from 'react-use/lib/usePrevious'; +import { MatchedStateFromActor } from '@kbn/xstate-utils'; import { LogsDeprecationCallout } from '../../../components/logs_deprecation_callout'; import { TimeKey } from '../../../../common/time'; import { AutoSizer } from '../../../components/auto_sizer'; @@ -45,7 +46,6 @@ import { useLogStreamPageStateContext, } from '../../../observability_logs/log_stream_page/state'; import { type ParsedQuery } from '../../../observability_logs/log_stream_query_state'; -import { MatchedStateFromActor } from '../../../observability_logs/xstate_helpers'; import { datemathToEpochMillis, isValidDatemath } from '../../../utils/datemath'; import { LogsToolbar } from './page_toolbar'; import { PageViewLogInContext } from './page_view_log_in_context'; @@ -234,7 +234,7 @@ export const StreamPageLogsContent = React.memo<{ return ( <> - + diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page_providers.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page_providers.tsx index a8fd0cecf448b..497329782d879 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page_providers.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page_providers.tsx @@ -15,6 +15,7 @@ import { useLogStreamContext, useLogViewContext, } from '@kbn/logs-shared-plugin/public'; +import { MatchedStateFromActor } from '@kbn/xstate-utils'; import { LogStreamPageActorRef, LogStreamPageCallbacks, @@ -22,7 +23,6 @@ import { import { LogEntryFlyoutProvider } from '../../../containers/logs/log_flyout'; import { LogViewConfigurationProvider } from '../../../containers/logs/log_view_configuration'; import { ViewLogInContextProvider } from '../../../containers/logs/view_log_in_context'; -import { MatchedStateFromActor } from '../../../observability_logs/xstate_helpers'; const ViewLogInContext: FC> = ({ children }) => { const { startTimestamp, endTimestamp } = useLogPositionStateContext(); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/waffle/waffle_group_by_controls.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/waffle/waffle_group_by_controls.tsx index 47e5f58a258df..bca1a3858f5c9 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/waffle/waffle_group_by_controls.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/waffle/waffle_group_by_controls.tsx @@ -17,7 +17,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; import { css } from '@emotion/react'; -import { useBoolean } from '../../../../../hooks/use_boolean'; +import { useBoolean } from '@kbn/react-hooks'; import { InfraGroupByOptions } from '../../../../../common/inventory/types'; import { CustomFieldPanel } from './custom_field_panel'; import { SnapshotGroupBy } from '../../../../../../common/http_api/snapshot_api'; diff --git a/x-pack/plugins/observability_solution/infra/public/plugin.ts b/x-pack/plugins/observability_solution/infra/public/plugin.ts index 843a23bdfccc5..daaa3510e1660 100644 --- a/x-pack/plugins/observability_solution/infra/public/plugin.ts +++ b/x-pack/plugins/observability_solution/infra/public/plugin.ts @@ -33,6 +33,8 @@ import { type AssetDetailsLocatorParams, type InventoryLocatorParams, } from '@kbn/observability-shared-plugin/common'; +import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; +import { NavigationEntry } from '@kbn/observability-shared-plugin/public'; import type { InfraPublicConfig } from '../common/plugin_config_types'; import { createInventoryMetricRuleType } from './alerting/inventory'; import { createLogThresholdRuleType } from './alerting/log_threshold'; @@ -53,7 +55,14 @@ import type { } from './types'; import { getLogsHasDataFetcher, getLogsOverviewDataFetcher } from './utils/logs_overview_fetchers'; import type { LogStreamSerializedState } from './components/log_stream/types'; -import { hostsTitle, inventoryTitle, metricsExplorerTitle, metricsTitle } from './translations'; +import { + hostsTitle, + inventoryTitle, + logsTitle, + metricsExplorerTitle, + metricsTitle, +} from './translations'; +import { LogsAppRoutes, LogsRoute, getLogsAppRoutes } from './pages/logs/routes'; export class Plugin implements InfraClientPluginClass { public config: InfraPublicConfig; @@ -77,6 +86,8 @@ export class Plugin implements InfraClientPluginClass { } setup(core: InfraClientCoreSetup, pluginsSetup: InfraClientSetupDeps) { + const isLogsStreamEnabled = core.uiSettings.get(OBSERVABILITY_ENABLE_LOGS_STREAM, false); + if (pluginsSetup.home) { registerFeatures(pluginsSetup.home); } @@ -125,6 +136,8 @@ export class Plugin implements InfraClientPluginClass { core.settings.client.get$(enableInfrastructureHostsView), ]); + const logRoutes = getLogsAppRoutes({ isLogsStreamEnabled }); + /** !! Need to be kept in sync with the deepLinks in x-pack/plugins/observability_solution/infra/public/plugin.ts */ pluginsSetup.observabilityShared.navigation.registerSections( startDep$AndHostViewFlag$.pipe( @@ -137,32 +150,18 @@ export class Plugin implements InfraClientPluginClass { ], isInfrastructureHostsViewEnabled, ]) => { - const { infrastructure, logs, discover, fleet } = capabilities; + const { infrastructure, logs } = capabilities; return [ ...(logs.show ? [ { - label: 'Logs', + label: logsTitle, sortKey: 200, - entries: [ - ...(discover?.show && fleet?.read - ? [ - { - label: 'Explorer', - app: 'observability-logs-explorer', - path: '/', - isBetaFeature: true, - }, - ] - : []), - ...(this.config.featureFlags.logsUIEnabled - ? [ - { label: 'Stream', app: 'logs', path: '/stream' }, - { label: 'Anomalies', app: 'logs', path: '/anomalies' }, - { label: 'Categories', app: 'logs', path: '/log-categories' }, - ] - : []), - ], + entries: getLogsNavigationEntries({ + capabilities, + config: this.config, + routes: logRoutes, + }), }, ] : []), @@ -230,37 +229,7 @@ export class Plugin implements InfraClientPluginClass { euiIconType: 'logoObservability', order: 8100, appRoute: '/app/logs', - // !! Need to be kept in sync with the routes in x-pack/plugins/observability_solution/infra/public/pages/logs/page_content.tsx - deepLinks: [ - { - id: 'stream', - title: i18n.translate('xpack.infra.logs.index.streamTabTitle', { - defaultMessage: 'Stream', - }), - path: '/stream', - }, - { - id: 'anomalies', - title: i18n.translate('xpack.infra.logs.index.anomaliesTabTitle', { - defaultMessage: 'Anomalies', - }), - path: '/anomalies', - }, - { - id: 'log-categories', - title: i18n.translate('xpack.infra.logs.index.logCategoriesBetaBadgeTitle', { - defaultMessage: 'Categories', - }), - path: '/log-categories', - }, - { - id: 'settings', - title: i18n.translate('xpack.infra.logs.index.settingsTabTitle', { - defaultMessage: 'Settings', - }), - path: '/settings', - }, - ], + deepLinks: Object.values(logRoutes), category: DEFAULT_APP_CATEGORIES.observability, mount: async (params: AppMountParameters) => { // mount callback should not use setup dependencies, get start dependencies instead @@ -384,44 +353,47 @@ export class Plugin implements InfraClientPluginClass { } start(core: InfraClientCoreStart, plugins: InfraClientStartDeps) { - const { http } = core; + const { http, uiSettings } = core; + const isLogsStreamEnabled = uiSettings.get(OBSERVABILITY_ENABLE_LOGS_STREAM, false); const inventoryViews = this.inventoryViews.start({ http }); const metricsExplorerViews = this.metricsExplorerViews?.start({ http }); const telemetry = this.telemetry.start(); - plugins.uiActions.registerAction({ - id: ADD_LOG_STREAM_ACTION_ID, - grouping: [COMMON_EMBEDDABLE_GROUPING.legacy], - order: 30, - getDisplayName: () => - i18n.translate('xpack.infra.logStreamEmbeddable.displayName', { - defaultMessage: 'Log stream (deprecated)', - }), - getDisplayNameTooltip: () => - i18n.translate('xpack.infra.logStreamEmbeddable.description', { - defaultMessage: - 'Add a table of live streaming logs. For a more efficient experience, we recommend using the Discover Page to create a saved search instead of using Log stream.', - }), - getIconType: () => 'logsApp', - isCompatible: async ({ embeddable }) => { - return apiCanAddNewPanel(embeddable); - }, - execute: async ({ embeddable }) => { - if (!apiCanAddNewPanel(embeddable)) throw new IncompatibleActionError(); - embeddable.addNewPanel( - { - panelType: LOG_STREAM_EMBEDDABLE, - initialState: { - title: i18n.translate('xpack.infra.logStreamEmbeddable.title', { - defaultMessage: 'Log stream', - }), + if (isLogsStreamEnabled) { + plugins.uiActions.registerAction({ + id: ADD_LOG_STREAM_ACTION_ID, + grouping: [COMMON_EMBEDDABLE_GROUPING.legacy], + order: 30, + getDisplayName: () => + i18n.translate('xpack.infra.logStreamEmbeddable.displayName', { + defaultMessage: 'Log stream (deprecated)', + }), + getDisplayNameTooltip: () => + i18n.translate('xpack.infra.logStreamEmbeddable.description', { + defaultMessage: + 'Add a table of live streaming logs. For a more efficient experience, we recommend using the Discover Page to create a saved search instead of using Log stream.', + }), + getIconType: () => 'logsApp', + isCompatible: async ({ embeddable }) => { + return apiCanAddNewPanel(embeddable); + }, + execute: async ({ embeddable }) => { + if (!apiCanAddNewPanel(embeddable)) throw new IncompatibleActionError(); + embeddable.addNewPanel( + { + panelType: LOG_STREAM_EMBEDDABLE, + initialState: { + title: i18n.translate('xpack.infra.logStreamEmbeddable.title', { + defaultMessage: 'Log stream', + }), + }, }, - }, - true - ); - }, - }); - plugins.uiActions.attachAction(ADD_PANEL_TRIGGER, ADD_LOG_STREAM_ACTION_ID); + true + ); + }, + }); + plugins.uiActions.attachAction(ADD_PANEL_TRIGGER, ADD_LOG_STREAM_ACTION_ID); + } const startContract: InfraClientStartExports = { inventoryViews, @@ -434,3 +406,42 @@ export class Plugin implements InfraClientPluginClass { stop() {} } + +const getLogsNavigationEntries = ({ + capabilities, + config, + routes, +}: { + capabilities: CoreStart['application']['capabilities']; + config: InfraPublicConfig; + routes: LogsAppRoutes; +}) => { + const entries: NavigationEntry[] = []; + + if (!config.featureFlags.logsUIEnabled) return entries; + + if (capabilities.discover?.show && capabilities.fleet?.read) { + entries.push({ + label: 'Explorer', + app: 'observability-logs-explorer', + path: '/', + isBetaFeature: true, + }); + } + + // Display Stream nav entry when Logs Stream is enabled + if (routes.stream) entries.push(createNavEntryFromRoute(routes.stream)); + // Display always Logs Anomalies and Logs Categories entries + entries.push(createNavEntryFromRoute(routes.logsAnomalies)); + entries.push(createNavEntryFromRoute(routes.logsCategories)); + // Display Logs Settings entry when Logs Stream is not enabled + if (!routes.stream) entries.push(createNavEntryFromRoute(routes.settings)); + + return entries; +}; + +const createNavEntryFromRoute = ({ path, title }: LogsRoute): NavigationEntry => ({ + app: 'logs', + label: title, + path, +}); diff --git a/x-pack/plugins/observability_solution/infra/public/translations.ts b/x-pack/plugins/observability_solution/infra/public/translations.ts index 2e9153ce171b9..ecb72b3df4b01 100644 --- a/x-pack/plugins/observability_solution/infra/public/translations.ts +++ b/x-pack/plugins/observability_solution/infra/public/translations.ts @@ -19,14 +19,14 @@ export const streamTitle = i18n.translate('xpack.infra.logs.index.streamTabTitle defaultMessage: 'Stream', }); -export const anomaliesTitle = i18n.translate('xpack.infra.logs.index.anomaliesTabTitle', { - defaultMessage: 'Anomalies', +export const logsAnomaliesTitle = i18n.translate('xpack.infra.logs.index.anomaliesTabTitle', { + defaultMessage: 'Logs Anomalies', }); export const logCategoriesTitle = i18n.translate( 'xpack.infra.logs.index.logCategoriesBetaBadgeTitle', { - defaultMessage: 'Categories', + defaultMessage: 'Logs Categories', } ); diff --git a/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts index 2cbf6b61623cf..b8dd11a17fb0b 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts @@ -39,6 +39,7 @@ import { ApmDataAccessPluginStart, } from '@kbn/apm-data-access-plugin/server'; import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/server'; +import { ServerlessPluginStart } from '@kbn/serverless/server'; import type { EntityManagerServerPluginStart, EntityManagerServerPluginSetup, @@ -60,6 +61,7 @@ export interface InfraServerPluginSetupDeps { metricsDataAccess: MetricsDataPluginSetup; profilingDataAccess?: ProfilingDataAccessPluginSetup; apmDataAccess: ApmDataAccessPluginSetup; + serverless?: ServerlessPluginStart; entityManager: EntityManagerServerPluginSetup; } diff --git a/x-pack/plugins/observability_solution/infra/server/plugin.ts b/x-pack/plugins/observability_solution/infra/server/plugin.ts index 73d49ed938546..b8becb916a4e3 100644 --- a/x-pack/plugins/observability_solution/infra/server/plugin.ts +++ b/x-pack/plugins/observability_solution/infra/server/plugin.ts @@ -59,6 +59,7 @@ import { } from './types'; import { UsageCollector } from './usage/usage_collector'; import { mapSourceToLogView } from './utils/map_source_to_log_view'; +import { uiSettings } from '../common/ui_settings'; export const config: PluginConfigDescriptor = { schema: schema.object({ @@ -211,6 +212,9 @@ export class InfraServerPlugin const inventoryViews = this.inventoryViews.setup(); const metricsExplorerViews = this.metricsExplorerViews?.setup(); + // Register uiSettings config + core.uiSettings.register(uiSettings); + // Register saved object types core.savedObjects.registerType(infraSourceConfigurationSavedObjectType); core.savedObjects.registerType(inventoryViewSavedObjectType); diff --git a/x-pack/plugins/observability_solution/infra/tsconfig.json b/x-pack/plugins/observability_solution/infra/tsconfig.json index e7aade296fa8a..fea285b3a794e 100644 --- a/x-pack/plugins/observability_solution/infra/tsconfig.json +++ b/x-pack/plugins/observability_solution/infra/tsconfig.json @@ -110,6 +110,9 @@ "@kbn/observability-alerting-rule-utils", "@kbn/core-application-browser", "@kbn/shared-ux-page-no-data-types", + "@kbn/xstate-utils", + "@kbn/management-settings-ids", + "@kbn/core-ui-settings-common", "@kbn/entityManager-plugin", "@kbn/observability-utils", "@kbn/entities-schema" diff --git a/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts b/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts index c661976fd0765..0c6ceede07561 100644 --- a/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts +++ b/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts @@ -366,6 +366,12 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { defaultMessage: 'Logs categories', }), }, + { + link: 'logs:settings', + title: i18n.translate('xpack.observability.obltNav.otherTools.logsSettings', { + defaultMessage: 'Logs settings', + }), + }, { link: 'maps' }, { link: 'canvas' }, { link: 'graph' }, diff --git a/x-pack/plugins/observability_solution/observability/tsconfig.json b/x-pack/plugins/observability_solution/observability/tsconfig.json index d7a33cb6492cb..cc8cef2a9716a 100644 --- a/x-pack/plugins/observability_solution/observability/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability/tsconfig.json @@ -113,7 +113,7 @@ "@kbn/io-ts-utils", "@kbn/core-ui-settings-server-mocks", "@kbn/es-types", - "@kbn/logging-mocks" + "@kbn/logging-mocks", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index d65dddae39479..e47a52ec5df58 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -23213,7 +23213,6 @@ "xpack.infra.logs.highlights.highlightTermsFieldLabel": "Termes à mettre en surbrillance", "xpack.infra.logs.index.anomaliesTabTitle": "Anomalies", "xpack.infra.logs.index.logCategoriesBetaBadgeTitle": "Catégories", - "xpack.infra.logs.index.logsLabel": "Logs", "xpack.infra.logs.index.settingsTabTitle": "Paramètres", "xpack.infra.logs.index.streamTabTitle": "Flux", "xpack.infra.logs.logCategoriesTitle": "Catégories", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 3883a41164835..8e2125deaf18c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -22963,7 +22963,6 @@ "xpack.infra.logs.highlights.highlightTermsFieldLabel": "ハイライトする用語", "xpack.infra.logs.index.anomaliesTabTitle": "異常", "xpack.infra.logs.index.logCategoriesBetaBadgeTitle": "カテゴリー", - "xpack.infra.logs.index.logsLabel": "ログ", "xpack.infra.logs.index.settingsTabTitle": "設定", "xpack.infra.logs.index.streamTabTitle": "ストリーム", "xpack.infra.logs.logCategoriesTitle": "カテゴリー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 823092906f7ba..3b7a338fab717 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -22994,7 +22994,6 @@ "xpack.infra.logs.highlights.highlightTermsFieldLabel": "要突出显示的词", "xpack.infra.logs.index.anomaliesTabTitle": "异常", "xpack.infra.logs.index.logCategoriesBetaBadgeTitle": "类别", - "xpack.infra.logs.index.logsLabel": "日志", "xpack.infra.logs.index.settingsTabTitle": "设置", "xpack.infra.logs.index.streamTabTitle": "流式传输", "xpack.infra.logs.logCategoriesTitle": "类别", diff --git a/x-pack/test/functional/apps/infra/logs/log_stream.ts b/x-pack/test/functional/apps/infra/logs/log_stream.ts index 8592287477826..16dcc038f7aab 100644 --- a/x-pack/test/functional/apps/infra/logs/log_stream.ts +++ b/x-pack/test/functional/apps/infra/logs/log_stream.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; import { URL } from 'url'; import { FtrProviderContext } from '../../../ftr_provider_context'; @@ -16,17 +17,20 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const retry = getService('retry'); const browser = getService('browser'); const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); describe('Log stream', function () { describe('Legacy URL handling', () => { describe('Correctly handles legacy versions of logFilter', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/logs_and_metrics'); + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: true }); }); after(async () => { await esArchiver.unload( 'x-pack/test/functional/es_archives/infra/8.0.0/logs_and_metrics' ); + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: false }); }); it('Expression and kind', async () => { const location = { diff --git a/x-pack/test/functional/apps/infra/logs/log_stream_date_nano.ts b/x-pack/test/functional/apps/infra/logs/log_stream_date_nano.ts index ed1f85248b303..141d1bc38c3d3 100644 --- a/x-pack/test/functional/apps/infra/logs/log_stream_date_nano.ts +++ b/x-pack/test/functional/apps/infra/logs/log_stream_date_nano.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { DATES } from '../constants'; @@ -14,6 +15,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); const logsUi = getService('logsUi'); const find = getService('find'); + const kibanaServer = getService('kibanaServer'); const logFilter = { timeRange: { from: DATES.metricsAndLogs.stream.startWithData, @@ -24,9 +26,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Log stream supports nano precision', function () { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/infra/logs_with_nano_date'); + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: true }); }); after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/infra/logs_with_nano_date'); + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: false }); }); it('should display logs entries containing date_nano timestamps properly ', async () => { diff --git a/x-pack/test/functional/apps/infra/logs/logs_source_configuration.ts b/x-pack/test/functional/apps/infra/logs/logs_source_configuration.ts index 4fdb4687faf6d..84158051021c3 100644 --- a/x-pack/test/functional/apps/infra/logs/logs_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/logs/logs_source_configuration.ts @@ -10,6 +10,7 @@ import { ELASTIC_HTTP_VERSION_HEADER, X_ELASTIC_INTERNAL_ORIGIN_REQUEST, } from '@kbn/core-http-common'; +import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; import { DATES } from '../constants'; import { FtrProviderContext } from '../../../ftr_provider_context'; @@ -31,9 +32,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Logs Source Configuration', function () { before(async () => { await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: true }); }); after(async () => { await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: false }); }); describe('Allows indices configuration', () => { diff --git a/x-pack/test/functional/apps/infra/page_not_found.ts b/x-pack/test/functional/apps/infra/page_not_found.ts index 479d9979b918a..eb1fc77b4f9f9 100644 --- a/x-pack/test/functional/apps/infra/page_not_found.ts +++ b/x-pack/test/functional/apps/infra/page_not_found.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; import { FtrProviderContext } from '../../ftr_provider_context'; const logsPages = ['logs/stream', 'logs/anomalies', 'logs/log-categories', 'logs/settings']; @@ -19,14 +20,22 @@ const metricsPages = [ ]; export default ({ getPageObjects, getService }: FtrProviderContext) => { - const find = getService('find'); const pageObjects = getPageObjects(['common', 'infraHome']); + const find = getService('find'); + const kibanaServer = getService('kibanaServer'); const testSubjects = getService('testSubjects'); describe('Infra Not Found page', function () { this.tags('includeFirefox'); describe('Logs', () => { + before(async () => { + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: true }); + }); + after(async () => { + await kibanaServer.uiSettings.update({ [OBSERVABILITY_ENABLE_LOGS_STREAM]: false }); + }); + it('should render the not found page when the route does not exist', async () => { await pageObjects.common.navigateToApp('logs/broken-link'); await testSubjects.existOrFail('infraNotFoundPage'); From 1b4ebaa85261074aec775d23165474863ddea45a Mon Sep 17 00:00:00 2001 From: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:14:50 +0200 Subject: [PATCH 045/110] [ML] Hide ES|QL based saved searches in ML & Transforms (#195084) ## Summary Fix for: [#187962](https://github.com/elastic/kibana/issues/187962) We were displaying ES|QL based searches in various areas of ML, not just in the places mentioned in the issue. Before: ![Screenshot 2024-10-04 at 16 16 26](https://github.com/user-attachments/assets/dff7e1d6-4c8e-4916-acec-c6b9931c2a39) Then, after selecting the ESQL based search: ![image](https://github.com/user-attachments/assets/9314cd0b-442a-4287-9d29-799e172f929a) After the fix: ![image](https://github.com/user-attachments/assets/e660ef24-c585-4d95-bcf1-2578ec9e663d) --- .../components/source_selection/source_selection.tsx | 9 +++++++-- .../datavisualizer/data_drift/index_patterns_picker.tsx | 7 +++++++ .../jobs/new_job/pages/index_or_search/page.tsx | 6 ++++++ .../components/search_selection/search_selection.tsx | 6 ++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx index ae03a0779edf1..5aa0ccc46a5cd 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx @@ -11,7 +11,7 @@ import { EuiCallOut, EuiPageBody, EuiPanel, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { getNestedProperty } from '@kbn/ml-nested-property'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; -import type { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; +import type { FinderAttributes, SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; import { CreateDataViewButton } from '../../../../../components/create_data_view_button'; import { useMlKibana, useNavigateToPath } from '../../../../../contexts/kibana'; import { useToastNotificationService } from '../../../../../services/toast_notification_service'; @@ -22,6 +22,8 @@ import { const fixedPageSize: number = 20; +type SavedObject = SavedObjectCommon; + export const SourceSelection: FC = () => { const { services: { @@ -41,7 +43,7 @@ export const SourceSelection: FC = () => { id: string, type: string, fullName?: string, - savedObject?: SavedObjectCommon + savedObject?: SavedObject ) => { // Kibana data views including `:` are cross-cluster search indices // and are not supported by Data Frame Analytics yet. For saved searches @@ -142,6 +144,9 @@ export const SourceSelection: FC = () => { defaultMessage: 'Saved search', } ), + showSavedObject: (savedObject: SavedObject) => + // ES|QL Based saved searches are not supported in DFA, filter them out + savedObject.attributes.isTextBasedQuery !== true, }, { type: 'index-pattern', diff --git a/x-pack/plugins/ml/public/application/datavisualizer/data_drift/index_patterns_picker.tsx b/x-pack/plugins/ml/public/application/datavisualizer/data_drift/index_patterns_picker.tsx index 04dd9ca764ab0..1f31ce934e442 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/data_drift/index_patterns_picker.tsx +++ b/x-pack/plugins/ml/public/application/datavisualizer/data_drift/index_patterns_picker.tsx @@ -14,12 +14,16 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; import { type DataViewEditorService as DataViewEditorServiceSpec } from '@kbn/data-view-editor-plugin/public'; import { INDEX_PATTERN_TYPE } from '@kbn/data-views-plugin/public'; +import type { FinderAttributes, SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; import { createPath } from '../../routing/router'; import { ML_PAGES } from '../../../../common/constants/locator'; import { DataDriftIndexPatternsEditor } from './data_drift_index_patterns_editor'; import { MlPageHeader } from '../../components/page_header'; import { useMlKibana, useNavigateToPath } from '../../contexts/kibana'; + +type SavedObject = SavedObjectCommon; + export const DataDriftIndexOrSearchRedirect: FC = () => { const navigateToPath = useNavigateToPath(); const { contentManagement, uiSettings } = useMlKibana().services; @@ -65,6 +69,9 @@ export const DataDriftIndexOrSearchRedirect: FC = () => { defaultMessage: 'Saved search', } ), + showSavedObject: (savedObject: SavedObject) => + // ES|QL Based saved searches are not supported in Data Drift, filter them out + savedObject.attributes.isTextBasedQuery !== true, }, { type: 'index-pattern', diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx index 972b8dc09e3ef..6e630ca61886f 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx @@ -11,6 +11,7 @@ import { EuiFlexGroup, EuiPageBody, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; +import type { FinderAttributes, SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; import { CreateDataViewButton } from '../../../../components/create_data_view_button'; import { useMlKibana, useNavigateToPath } from '../../../../contexts/kibana'; import { MlPageHeader } from '../../../../components/page_header'; @@ -21,6 +22,8 @@ export interface PageProps { const RESULTS_PER_PAGE = 20; +type SavedObject = SavedObjectCommon; + export const Page: FC = ({ nextStepPath, extraButtons, @@ -69,6 +72,9 @@ export const Page: FC = ({ defaultMessage: 'Saved search', } ), + showSavedObject: (savedObject: SavedObject) => + // ES|QL Based saved searches are not supported across ML, filter them out + savedObject.attributes.isTextBasedQuery !== true, }, { type: 'index-pattern', diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx index 3c6fcc67f0c7e..7c0b03f7b9856 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx @@ -11,6 +11,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React, { type FC, Fragment } from 'react'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; +import type { FinderAttributes, SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; import { useAppDependencies } from '../../../../app_dependencies'; interface SearchSelectionProps { @@ -19,6 +20,8 @@ interface SearchSelectionProps { canEditDataView: boolean; } +type SavedObject = SavedObjectCommon; + const fixedPageSize: number = 8; export const SearchSelection: FC = ({ @@ -64,6 +67,9 @@ export const SearchSelection: FC = ({ defaultMessage: 'Saved search', } ), + showSavedObject: (savedObject: SavedObject) => + // ES|QL Based saved searches are not supported in transforms, filter them out + savedObject.attributes.isTextBasedQuery !== true, }, { type: 'index-pattern', From 6df672421d6df47cb3e8f86ab9448f021dabc871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georgiana-Andreea=20Onolea=C8=9B=C4=83?= Date: Wed, 9 Oct 2024 11:22:57 +0300 Subject: [PATCH 046/110] [ResponseOps][Rules] Rule type selection modal content cut off on small screens due to lack of vertical scrolling (#195234) ## Summary Closes https://github.com/elastic/kibana/issues/184048 - the rule type selection modal is now scrollable on smaller windows https://github.com/user-attachments/assets/47082b35-02a7-4b67-9a88-ee4200908bef Co-authored-by: Antonio --- .../src/rule_type_modal/components/rule_type_list.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/kbn-alerts-ui-shared/src/rule_type_modal/components/rule_type_list.tsx b/packages/kbn-alerts-ui-shared/src/rule_type_modal/components/rule_type_list.tsx index 9b84bb83cf1fa..4e21e428f3c5c 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_type_modal/components/rule_type_list.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_type_modal/components/rule_type_list.tsx @@ -97,6 +97,8 @@ export const RuleTypeList: React.FC = ({ grow={1} style={{ paddingTop: euiTheme.size.base /* Match drop shadow padding in the right column */, + paddingRight: euiTheme.size.base, + overflowY: 'auto', }} > From 88cf632da91dbbfc7e119cdc6d930baed57de4e6 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Wed, 9 Oct 2024 10:34:05 +0200 Subject: [PATCH 047/110] [ML] Updates for Trained Models table layout and model states (#194614) ## Summary - Updates Trained Models table layout - Adds the E5 model disclaimer - Removes redundant success toasts about model download, deletion, and start of a deployment image ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --- .../src/constants/trained_models.ts | 9 + .../analytics_list/use_table_settings.ts | 47 ++- .../data_drift/data_view_editor.tsx | 3 +- .../model_management/delete_models_modal.tsx | 12 +- .../model_management/get_model_state.tsx | 62 ++- .../model_management/model_actions.tsx | 103 ++--- .../model_management/models_list.tsx | 358 ++++++++---------- .../model_management/model_provider.test.ts | 8 + .../translations/translations/fr-FR.json | 9 - .../translations/translations/ja-JP.json | 8 - .../translations/translations/zh-CN.json | 9 - .../apis/ml/trained_models/model_downloads.ts | 4 + .../services/ml/trained_models_table.ts | 18 +- 13 files changed, 335 insertions(+), 315 deletions(-) diff --git a/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts b/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts index 95337518361e9..9fd3483771a9f 100644 --- a/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts +++ b/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts @@ -120,6 +120,10 @@ export const ELASTIC_MODEL_DEFINITIONS: Record< license: 'MIT', licenseUrl: 'https://huggingface.co/elastic/multilingual-e5-small', type: ['pytorch', 'text_embedding'], + disclaimer: i18n.translate('xpack.ml.trainedModels.modelsList.e5v1Disclaimer', { + defaultMessage: + 'This E5 model, as defined, hosted, integrated and used in conjunction with our other Elastic Software is covered by our standard warranty.', + }), }, [E5_LINUX_OPTIMIZED_MODEL_ID]: { modelName: 'e5', @@ -138,6 +142,10 @@ export const ELASTIC_MODEL_DEFINITIONS: Record< license: 'MIT', licenseUrl: 'https://huggingface.co/elastic/multilingual-e5-small_linux-x86_64', type: ['pytorch', 'text_embedding'], + disclaimer: i18n.translate('xpack.ml.trainedModels.modelsList.e5v1Disclaimer', { + defaultMessage: + 'This E5 model, as defined, hosted, integrated and used in conjunction with our other Elastic Software is covered by our standard warranty.', + }), }, } as const); @@ -167,6 +175,7 @@ export interface ModelDefinition { /** Link to the external license/documentation page */ licenseUrl?: string; type?: readonly string[]; + disclaimer?: string; } export type ModelDefinitionResponse = ModelDefinition & { diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts index 670efb1627ef7..fa24a65c425bc 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts @@ -30,9 +30,11 @@ export interface CriteriaWithPagination extends Criteria { }; } -interface UseTableSettingsReturnValue { +interface UseTableSettingsReturnValue { onTableChange: EuiBasicTableProps['onChange']; - pagination: Required>; + pagination: HidePagination extends true + ? Required> | boolean + : Required>; sorting: { sort: { field: keyof T; @@ -44,8 +46,31 @@ interface UseTableSettingsReturnValue { export function useTableSettings( totalItemCount: number, pageState: ListingPageUrlState, - updatePageState: (update: Partial) => void -): UseTableSettingsReturnValue { + updatePageState: (update: Partial) => void, + hide: true +): UseTableSettingsReturnValue; + +export function useTableSettings( + totalItemCount: number, + pageState: ListingPageUrlState, + updatePageState: (update: Partial) => void, + hide?: false +): UseTableSettingsReturnValue; + +/** + * + * @param totalItemCount + * @param pageState + * @param updatePageState + * @param hide If true, hides pagination when total number of items is lower that the smallest per page option + * @returns + */ +export function useTableSettings( + totalItemCount: number, + pageState: ListingPageUrlState, + updatePageState: (update: Partial) => void, + hide: boolean = false +): UseTableSettingsReturnValue { const { pageIndex, pageSize, sortField, sortDirection } = pageState; const onTableChange: EuiBasicTableProps['onChange'] = useCallback( @@ -66,15 +91,19 @@ export function useTableSettings( [pageState, updatePageState] ); - const pagination = useMemo( - () => ({ + const pagination = useMemo(() => { + if (hide && totalItemCount <= Math.min(...PAGE_SIZE_OPTIONS)) { + // Hide pagination if total number of items is lower that the smallest per page option + return false; + } + + return { pageIndex, pageSize, totalItemCount, pageSizeOptions: PAGE_SIZE_OPTIONS, - }), - [totalItemCount, pageIndex, pageSize] - ); + }; + }, [totalItemCount, pageIndex, pageSize, hide]); const sorting = useMemo( () => ({ diff --git a/x-pack/plugins/ml/public/application/datavisualizer/data_drift/data_view_editor.tsx b/x-pack/plugins/ml/public/application/datavisualizer/data_drift/data_view_editor.tsx index 5f52ef1c928f8..eafe31cb0f355 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/data_drift/data_view_editor.tsx +++ b/x-pack/plugins/ml/public/application/datavisualizer/data_drift/data_view_editor.tsx @@ -80,8 +80,7 @@ export function DataViewEditor({ const { onTableChange, pagination } = useTableSettings( matchedReferenceIndices.length, pageState, - // @ts-expect-error callback will have all the 4 necessary params - updatePageState + updatePageState as Parameters['2'] ); const pageOfItems = useMemo(() => { diff --git a/x-pack/plugins/ml/public/application/model_management/delete_models_modal.tsx b/x-pack/plugins/ml/public/application/model_management/delete_models_modal.tsx index 1e08ae9874567..0f5c515c22776 100644 --- a/x-pack/plugins/ml/public/application/model_management/delete_models_modal.tsx +++ b/x-pack/plugins/ml/public/application/model_management/delete_models_modal.tsx @@ -35,7 +35,7 @@ interface DeleteModelsModalProps { export const DeleteModelsModal: FC = ({ models, onClose }) => { const trainedModelsApiService = useTrainedModelsApiService(); - const { displayErrorToast, displaySuccessToast } = useToastNotificationService(); + const { displayErrorToast } = useToastNotificationService(); const [canDeleteModel, setCanDeleteModel] = useState(false); const [deletePipelines, setDeletePipelines] = useState(false); @@ -66,16 +66,6 @@ export const DeleteModelsModal: FC = ({ models, onClose }) ) ); - displaySuccessToast( - i18n.translate('xpack.ml.trainedModels.modelsList.successfullyDeletedMessage', { - defaultMessage: - '{modelsCount, plural, one {Model {modelIds}} other {# models}} {modelsCount, plural, one {has} other {have}} been successfully deleted', - values: { - modelsCount: modelIds.length, - modelIds: modelIds.join(', '), - }, - }) - ); } catch (error) { displayErrorToast( error, diff --git a/x-pack/plugins/ml/public/application/model_management/get_model_state.tsx b/x-pack/plugins/ml/public/application/model_management/get_model_state.tsx index 8591a3b9e8dc9..d8bf2b8084a6a 100644 --- a/x-pack/plugins/ml/public/application/model_management/get_model_state.tsx +++ b/x-pack/plugins/ml/public/application/model_management/get_model_state.tsx @@ -5,8 +5,17 @@ * 2.0. */ +import React from 'react'; import { DEPLOYMENT_STATE, MODEL_STATE, type ModelState } from '@kbn/ml-trained-models-utils'; -import type { EuiHealthProps } from '@elastic/eui'; +import { + EuiBadge, + EuiHealth, + EuiLoadingSpinner, + type EuiHealthProps, + EuiFlexGroup, + EuiFlexItem, + EuiText, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import type { ModelItem } from './models_list'; @@ -33,11 +42,11 @@ export const getModelDeploymentState = (model: ModelItem): ModelState | undefine export const getModelStateColor = ( state: ModelState | undefined -): { color: EuiHealthProps['color']; name: string } | null => { +): { color: EuiHealthProps['color']; name: string; component?: React.ReactNode } | null => { switch (state) { case MODEL_STATE.DOWNLOADED: return { - color: 'subdued', + color: 'success', name: i18n.translate('xpack.ml.trainedModels.modelsList.modelState.downloadedName', { defaultMessage: 'Ready to deploy', }), @@ -46,37 +55,64 @@ export const getModelStateColor = ( return { color: 'primary', name: i18n.translate('xpack.ml.trainedModels.modelsList.modelState.downloadingName', { - defaultMessage: 'Downloading...', + defaultMessage: 'Downloading', }), }; case MODEL_STATE.STARTED: return { - color: 'success', + color: '#E6F9F7', name: i18n.translate('xpack.ml.trainedModels.modelsList.modelState.startedName', { defaultMessage: 'Deployed', }), + get component() { + return ( + + + {this.name} + + + ); + }, }; case MODEL_STATE.STARTING: return { color: 'success', name: i18n.translate('xpack.ml.trainedModels.modelsList.modelState.startingName', { - defaultMessage: 'Starting deployment...', + defaultMessage: 'Deploying', }), + get component() { + return ( + + + + + + {this.name} + + + ); + }, }; case MODEL_STATE.STOPPING: return { color: 'accent', name: i18n.translate('xpack.ml.trainedModels.modelsList.modelState.stoppingName', { - defaultMessage: 'Stopping deployment...', + defaultMessage: 'Stopping', }), + get component() { + return ( + + + + + + {this.name} + + + ); + }, }; case MODEL_STATE.NOT_DOWNLOADED: - return { - color: '#d4dae5', - name: i18n.translate('xpack.ml.trainedModels.modelsList.modelState.notDownloadedName', { - defaultMessage: 'Not downloaded', - }), - }; default: return null; } diff --git a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx index b9e0c39578349..b4ddff093933a 100644 --- a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx +++ b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx @@ -8,7 +8,7 @@ import type { Action } from '@elastic/eui/src/components/basic_table/action_types'; import { i18n } from '@kbn/i18n'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import { EuiToolTip } from '@elastic/eui'; +import { EuiToolTip, useIsWithinMaxBreakpoint } from '@elastic/eui'; import React, { useCallback, useMemo, useEffect, useState } from 'react'; import { BUILT_IN_MODEL_TAG, @@ -53,6 +53,8 @@ export function useModelActions({ fetchModels: () => Promise; modelAndDeploymentIds: string[]; }): Array> { + const isMobileLayout = useIsWithinMaxBreakpoint('l'); + const { services: { application: { navigateToUrl }, @@ -132,7 +134,7 @@ export function useModelActions({ [] ); - return useMemo( + return useMemo>>( () => [ { name: i18n.translate('xpack.ml.trainedModels.modelsList.viewTrainingDataNameActionLabel', { @@ -203,12 +205,18 @@ export function useModelActions({ ), 'data-test-subj': 'mlModelsTableRowStartDeploymentAction', icon: 'play', - type: 'icon', + // @ts-ignore + type: isMobileLayout ? 'icon' : 'button', isPrimary: true, + color: 'success', enabled: (item) => { - return canStartStopTrainedModels && !isLoading && item.state !== MODEL_STATE.DOWNLOADING; + return canStartStopTrainedModels && !isLoading; + }, + available: (item) => { + return ( + item.model_type === TRAINED_MODEL_TYPE.PYTORCH && item.state === MODEL_STATE.DOWNLOADED + ); }, - available: (item) => item.model_type === TRAINED_MODEL_TYPE.PYTORCH, onClick: async (item) => { const modelDeploymentParams = await getUserInputModelDeploymentParams( item, @@ -234,14 +242,6 @@ export function useModelActions({ : {}), } ); - displaySuccessToast( - i18n.translate('xpack.ml.trainedModels.modelsList.startSuccess', { - defaultMessage: 'Deployment for "{modelId}" has been started successfully.', - values: { - modelId: item.model_id, - }, - }) - ); await fetchModels(); } catch (e) { displayErrorToast( @@ -342,6 +342,7 @@ export function useModelActions({ available: (item) => item.model_type === TRAINED_MODEL_TYPE.PYTORCH && canStartStopTrainedModels && + // Deployment can be either started, starting, or exist in a failed state (item.state === MODEL_STATE.STARTED || item.state === MODEL_STATE.STARTING) && // Only show the action if there is at least one deployment that is not used by the inference service (!Array.isArray(item.inference_apis) || @@ -373,16 +374,6 @@ export function useModelActions({ force: requireForceStop, } ); - displaySuccessToast( - i18n.translate('xpack.ml.trainedModels.modelsList.stopSuccess', { - defaultMessage: - '{numberOfDeployments, plural, one {Deployment} other {Deployments}} for "{modelId}" has been stopped successfully.', - values: { - modelId: item.model_id, - numberOfDeployments: deploymentIds.length, - }, - }) - ); if (Object.values(results).some((r) => r.error !== undefined)) { Object.entries(results).forEach(([id, r]) => { if (r.error !== undefined) { @@ -423,7 +414,9 @@ export function useModelActions({ }), 'data-test-subj': 'mlModelsTableRowDownloadModelAction', icon: 'download', - type: 'icon', + color: 'text', + // @ts-ignore + type: isMobileLayout ? 'icon' : 'button', isPrimary: true, available: (item) => canCreateTrainedModels && item.state === MODEL_STATE.NOT_DOWNLOADED, enabled: (item) => !isLoading, @@ -480,10 +473,16 @@ export function useModelActions({ }, { name: (model) => { - return ( + return model.state === MODEL_STATE.DOWNLOADING ? ( + <> + {i18n.translate('xpack.ml.trainedModels.modelsList.deleteModelActionLabel', { + defaultMessage: 'Cancel', + })} + + ) : ( <> {i18n.translate('xpack.ml.trainedModels.modelsList.deleteModelActionLabel', { - defaultMessage: 'Delete model', + defaultMessage: 'Delete', })} ); @@ -491,27 +490,35 @@ export function useModelActions({ description: (model: ModelItem) => { const hasDeployments = model.deployment_ids.length > 0; const { hasInferenceServices } = model; - return hasInferenceServices - ? i18n.translate( - 'xpack.ml.trainedModels.modelsList.deleteDisabledWithInferenceServicesTooltip', - { - defaultMessage: 'Model is used by the _inference API', - } - ) - : hasDeployments - ? i18n.translate( - 'xpack.ml.trainedModels.modelsList.deleteDisabledWithDeploymentsTooltip', - { - defaultMessage: 'Model has started deployments', - } - ) - : i18n.translate('xpack.ml.trainedModels.modelsList.deleteModelActionLabel', { - defaultMessage: 'Delete model', - }); + + if (model.state === MODEL_STATE.DOWNLOADING) { + return i18n.translate('xpack.ml.trainedModels.modelsList.cancelDownloadActionLabel', { + defaultMessage: 'Cancel download', + }); + } else if (hasInferenceServices) { + return i18n.translate( + 'xpack.ml.trainedModels.modelsList.deleteDisabledWithInferenceServicesTooltip', + { + defaultMessage: 'Model is used by the _inference API', + } + ); + } else if (hasDeployments) { + return i18n.translate( + 'xpack.ml.trainedModels.modelsList.deleteDisabledWithDeploymentsTooltip', + { + defaultMessage: 'Model has started deployments', + } + ); + } else { + return i18n.translate('xpack.ml.trainedModels.modelsList.deleteModelActionLabel', { + defaultMessage: 'Delete model', + }); + } }, 'data-test-subj': 'mlModelsTableRowDeleteAction', icon: 'trash', - type: 'icon', + // @ts-ignore + type: isMobileLayout ? 'icon' : 'button', color: 'danger', isPrimary: false, onClick: (model) => { @@ -539,9 +546,10 @@ export function useModelActions({ }), 'data-test-subj': 'mlModelsTableRowTestAction', icon: 'inputOutput', - type: 'icon', + // @ts-ignore + type: isMobileLayout ? 'icon' : 'button', isPrimary: true, - available: isTestable, + available: (item) => isTestable(item, true), onClick: (item) => { if (isDfaTrainedModel(item) && !isBuiltInModel(item)) { onDfaTestAction(item); @@ -550,7 +558,7 @@ export function useModelActions({ } }, enabled: (item) => { - return canTestTrainedModels && isTestable(item, true) && !isLoading; + return canTestTrainedModels && !isLoading; }, }, { @@ -612,6 +620,7 @@ export function useModelActions({ trainedModelsApiService, urlLocator, onModelDownloadRequest, + isMobileLayout, ] ); } diff --git a/x-pack/plugins/ml/public/application/model_management/models_list.tsx b/x-pack/plugins/ml/public/application/model_management/models_list.tsx index 3aef951f1545e..f218030c65ad3 100644 --- a/x-pack/plugins/ml/public/application/model_management/models_list.tsx +++ b/x-pack/plugins/ml/public/application/model_management/models_list.tsx @@ -5,9 +5,6 @@ * 2.0. */ -import type { FC } from 'react'; -import { useRef } from 'react'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; import type { SearchFilterConfig } from '@elastic/eui'; import { EuiBadge, @@ -16,52 +13,43 @@ import { EuiCallOut, EuiFlexGroup, EuiFlexItem, - EuiHealth, EuiIcon, EuiInMemoryTable, EuiLink, EuiProgress, EuiSpacer, EuiSwitch, + EuiText, EuiTitle, EuiToolTip, type EuiSearchBarProps, } from '@elastic/eui'; -import { groupBy, isEmpty } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; import type { EuiBasicTableColumn } from '@elastic/eui/src/components/basic_table/basic_table'; import type { EuiTableSelectionType } from '@elastic/eui/src/components/basic_table/table_types'; -import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common'; -import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import { usePageUrlState } from '@kbn/ml-url-state'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useTimefilter } from '@kbn/ml-date-picker'; -import type { DeploymentState } from '@kbn/ml-trained-models-utils'; +import { isDefined } from '@kbn/ml-is-defined'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; +import { useStorage } from '@kbn/ml-local-storage'; import { BUILT_IN_MODEL_TAG, BUILT_IN_MODEL_TYPE, - DEPLOYMENT_STATE, - ELASTIC_MODEL_DEFINITIONS, ELASTIC_MODEL_TAG, ELASTIC_MODEL_TYPE, ELSER_ID_V1, MODEL_STATE, type ModelState, } from '@kbn/ml-trained-models-utils'; -import { isDefined } from '@kbn/ml-is-defined'; -import { useStorage } from '@kbn/ml-local-storage'; +import type { ListingPageUrlState } from '@kbn/ml-url-state'; +import { usePageUrlState } from '@kbn/ml-url-state'; import { dynamic } from '@kbn/shared-ux-utility'; +import { cloneDeep, groupBy, isEmpty, memoize } from 'lodash'; +import type { FC } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import useMountedState from 'react-use/lib/useMountedState'; -import type { ListingPageUrlState } from '@kbn/ml-url-state'; -import { getModelStateColor, getModelDeploymentState } from './get_model_state'; +import { ML_PAGES } from '../../../common/constants/locator'; import { ML_ELSER_CALLOUT_DISMISSED } from '../../../common/types/storage'; -import { TechnicalPreviewBadge } from '../components/technical_preview_badge'; -import { useModelActions } from './model_actions'; -import { ModelsTableToConfigMapping } from './config_mapping'; -import type { ModelsBarStats } from '../components/stats_bar'; -import { StatsBar } from '../components/stats_bar'; -import { useMlKibana } from '../contexts/kibana'; -import { useTrainedModelsApiService } from '../services/ml_api_service/trained_models'; import type { ModelDownloadState, ModelPipelines, @@ -69,17 +57,23 @@ import type { TrainedModelDeploymentStatsResponse, TrainedModelStat, } from '../../../common/types/trained_models'; -import { DeleteModelsModal } from './delete_models_modal'; -import { ML_PAGES } from '../../../common/constants/locator'; +import { AddInferencePipelineFlyout } from '../components/ml_inference'; +import { SavedObjectsWarning } from '../components/saved_objects_warning'; +import type { ModelsBarStats } from '../components/stats_bar'; +import { StatsBar } from '../components/stats_bar'; +import { TechnicalPreviewBadge } from '../components/technical_preview_badge'; +import { useMlKibana } from '../contexts/kibana'; +import { useEnabledFeatures } from '../contexts/ml'; import { useTableSettings } from '../data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings'; -import { useToastNotificationService } from '../services/toast_notification_service'; -import { useFieldFormatter } from '../contexts/kibana/use_field_formatter'; import { useRefresh } from '../routing/use_refresh'; -import { SavedObjectsWarning } from '../components/saved_objects_warning'; -import { TestModelAndPipelineCreationFlyout } from './test_models'; +import { useTrainedModelsApiService } from '../services/ml_api_service/trained_models'; +import { useToastNotificationService } from '../services/toast_notification_service'; +import { ModelsTableToConfigMapping } from './config_mapping'; +import { DeleteModelsModal } from './delete_models_modal'; +import { getModelDeploymentState, getModelStateColor } from './get_model_state'; +import { useModelActions } from './model_actions'; import { TestDfaModelsFlyout } from './test_dfa_models_flyout'; -import { AddInferencePipelineFlyout } from '../components/ml_inference'; -import { useEnabledFeatures } from '../contexts/ml'; +import { TestModelAndPipelineCreationFlyout } from './test_models'; type Stats = Omit; @@ -106,6 +100,7 @@ export type ModelItem = TrainedModelConfigResponse & { softwareLicense?: string; licenseUrl?: string; downloadState?: ModelDownloadState; + disclaimer?: string; }; export type ModelItemFull = Required; @@ -165,8 +160,6 @@ export const ModelsList: FC = ({ useTimefilter({ timeRangeSelector: false, autoRefreshSelector: true }); - const dateFormatter = useFieldFormatter(FIELD_FORMAT_IDS.DATE); - // allow for an internally controlled page state which stores the state in the URL // or an external page state, which is passed in as a prop. // external page state is used on the management page. @@ -188,7 +181,7 @@ export const ModelsList: FC = ({ const trainedModelsApiService = useTrainedModelsApiService(); - const { displayErrorToast, displaySuccessToast } = useToastNotificationService(); + const { displayErrorToast } = useToastNotificationService(); const [isInitialized, setIsInitialized] = useState(false); const [isLoading, setIsLoading] = useState(false); @@ -219,28 +212,9 @@ export const ModelsList: FC = ({ }, [items]); /** - * Checks if the model download complete. + * Fetch of model definitions available for download needs to happen only once */ - const isDownloadComplete = useCallback( - async (modelId: string): Promise => { - try { - const response = await trainedModelsApiService.getTrainedModels(modelId, { - include: 'definition_status', - }); - // @ts-ignore - return !!response[0]?.fully_defined; - } catch (error) { - displayErrorToast( - error, - i18n.translate('xpack.ml.trainedModels.modelsList.downloadStatusCheckErrorMessage', { - defaultMessage: 'Failed to check download status', - }) - ); - } - return false; - }, - [trainedModelsApiService, displayErrorToast] - ); + const getTrainedModelDownloads = memoize(trainedModelsApiService.getTrainedModelDownloads); /** * Fetches trained models. @@ -288,15 +262,20 @@ export const ModelsList: FC = ({ const idMap = new Map( resultItems.map((model) => [model.model_id, model]) ); - const forDownload = await trainedModelsApiService.getTrainedModelDownloads(); + /** + * Fetches model definitions available for download + */ + const forDownload = await getTrainedModelDownloads(); + const notDownloaded: ModelItem[] = forDownload - .filter(({ model_id: modelId, hidden, recommended, supported }) => { + .filter(({ model_id: modelId, hidden, recommended, supported, disclaimer }) => { if (idMap.has(modelId)) { const model = idMap.get(modelId)!; if (recommended) { model.recommended = true; } model.supported = supported; + model.disclaimer = disclaimer; } return !idMap.has(modelId) && !hidden; }) @@ -315,23 +294,28 @@ export const ModelsList: FC = ({ softwareLicense: modelDefinition.license, licenseUrl: modelDefinition.licenseUrl, supported: modelDefinition.supported, + disclaimer: modelDefinition.disclaimer, } as ModelItem; }); resultItems = [...resultItems, ...notDownloaded]; } - setItems(resultItems); - - if (expandedItemsToRefresh.length > 0) { - await fetchModelsStats(expandedItemsToRefresh); - - setItemIdToExpandedRowMap( - expandedItemsToRefresh.reduce((acc, item) => { - acc[item.model_id] = ; - return acc; - }, {} as Record) - ); - } + setItems((prevItems) => { + // Need to merge existing items with new items + // to preserve state and download status + return resultItems.map((item) => { + const prevItem = prevItems.find((i) => i.model_id === item.model_id); + return { + ...item, + ...(prevItem?.state === MODEL_STATE.DOWNLOADING + ? { + state: prevItem.state, + downloadState: prevItem.downloadState, + } + : {}), + }; + }); + }); } catch (error) { displayErrorToast( error, @@ -340,7 +324,9 @@ export const ModelsList: FC = ({ }) ); } + setIsInitialized(true); + setIsLoading(false); await fetchDownloadStatus(); @@ -399,20 +385,6 @@ export const ModelsList: FC = ({ return c.reason ?? ''; }, ''); }); - - const elasticModels = models.filter((model) => - Object.hasOwn(ELASTIC_MODEL_DEFINITIONS, model.model_id) - ); - if (elasticModels.length > 0) { - for (const model of elasticModels) { - if (Object.values(DEPLOYMENT_STATE).includes(model.state as DeploymentState)) { - // no need to check for the download status if the model has been deployed - continue; - } - const isDownloaded = await isDownloadComplete(model.model_id); - model.state = isDownloaded ? MODEL_STATE.DOWNLOADED : MODEL_STATE.DOWNLOADING; - } - } } return true; @@ -429,6 +401,8 @@ export const ModelsList: FC = ({ }, []); const downLoadStatusFetchInProgress = useRef(false); + const abortedDownload = useRef(new Set()); + /** * Updates model list with download status */ @@ -448,47 +422,43 @@ export const ModelsList: FC = ({ if (isMounted()) { setItems((prevItems) => { return prevItems.map((item) => { - const newItem = { ...item }; + if (!item.type?.includes('pytorch')) { + return item; + } + const newItem = cloneDeep(item); + if (downloadStatus[item.model_id]) { + newItem.state = MODEL_STATE.DOWNLOADING; newItem.downloadState = downloadStatus[item.model_id]; } else { - if (downloadInProgress.has(item.model_id)) { + /* Unfortunately, model download status does not report 100% download state, only from 1 to 99. Hence, there might be 3 cases + * 1. Model is not downloaded at all + * 2. Model download was in progress and finished + * 3. Model download was in progress and aborted + */ + delete newItem.downloadState; + + if (abortedDownload.current.has(item.model_id)) { + // Change downloading state to not downloaded + newItem.state = MODEL_STATE.NOT_DOWNLOADED; + abortedDownload.current.delete(item.model_id); + } else if (downloadInProgress.has(item.model_id) || !newItem.state) { // Change downloading state to downloaded - delete newItem.downloadState; newItem.state = MODEL_STATE.DOWNLOADED; } + + downloadInProgress.delete(item.model_id); } return newItem; }); }); } - const downloadedModelIds = Array.from(downloadInProgress).filter( - (v) => !downloadStatus[v] - ); - - if (downloadedModelIds.length > 0) { - // Show success toast - displaySuccessToast( - i18n.translate('xpack.ml.trainedModels.modelsList.downloadCompleteSuccess', { - defaultMessage: - '"{modelIds}" {modelIdsLength, plural, one {has} other {have}} been downloaded successfully.', - values: { - modelIds: downloadedModelIds.join(', '), - modelIdsLength: downloadedModelIds.length, - }, - }) - ); - } - Object.keys(downloadStatus).forEach((modelId) => { if (downloadStatus[modelId]) { downloadInProgress.add(modelId); } }); - downloadedModelIds.forEach((v) => { - downloadInProgress.delete(v); - }); if (isEmpty(downloadStatus)) { downLoadStatusFetchInProgress.current = false; @@ -501,7 +471,7 @@ export const ModelsList: FC = ({ downLoadStatusFetchInProgress.current = false; } }, - [trainedModelsApiService, displaySuccessToast, isMounted] + [trainedModelsApiService, isMounted] ); /** @@ -575,7 +545,6 @@ export const ModelsList: FC = ({ if (itemIdToExpandedRowMapValues[item.model_id]) { delete itemIdToExpandedRowMapValues[item.model_id]; } else { - await fetchModelsStats([item]); itemIdToExpandedRowMapValues[item.model_id] = ; } setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues); @@ -583,9 +552,8 @@ export const ModelsList: FC = ({ const columns: Array> = [ { - align: 'left', - width: '32px', isExpander: true, + align: 'center', render: (item: ModelItem) => { if (!item.stats) { return null; @@ -610,35 +578,25 @@ export const ModelsList: FC = ({ }, { name: modelIdColumnName, - width: '15%', sortable: ({ model_id: modelId }: ModelItem) => modelId, truncateText: false, textOnly: false, 'data-test-subj': 'mlModelsTableColumnId', - render: ({ description, model_id: modelId }: ModelItem) => { + render: ({ + description, + model_id: modelId, + recommended, + supported, + type, + disclaimer, + }: ModelItem) => { const isTechPreview = description?.includes('(Tech Preview)'); - return ( - - {modelId} - {isTechPreview ? ( - - - - ) : null} - - ); - }, - }, - { - name: i18n.translate('xpack.ml.trainedModels.modelsList.modelDescriptionHeader', { - defaultMessage: 'Description', - }), - truncateText: false, - 'data-test-subj': 'mlModelsTableColumnDescription', - render: ({ description, recommended, tags, supported }: ModelItem) => { - if (!description) return null; - const descriptionText = description.replace('(Tech Preview)', ''); + let descriptionText = description?.replace('(Tech Preview)', ''); + + if (disclaimer) { + descriptionText += '. ' + disclaimer; + } const tooltipContent = supported === false ? ( @@ -653,80 +611,98 @@ export const ModelsList: FC = ({ /> ) : null; - return tooltipContent ? ( - - <> - {descriptionText}  - - - - ) : ( - descriptionText + return ( + + + + {modelId} + + {isTechPreview ? ( + + + + ) : null} + + + {descriptionText ? ( + + {descriptionText} + {tooltipContent ? ( + <> +   + + + + + ) : null} + + ) : null} + + {Array.isArray(type) && type.length > 0 ? ( + + {type.map((t) => ( + + + + {t} + + + + ))} + + ) : null} + ); }, }, { - width: '15%', - field: ModelsTableToConfigMapping.type, - name: i18n.translate('xpack.ml.trainedModels.modelsList.typeHeader', { - defaultMessage: 'Type', - }), - sortable: true, - truncateText: true, - align: 'left', - render: (types: string[]) => ( - - {types.map((type) => ( - - - {type} - - - ))} - - ), - 'data-test-subj': 'mlModelsTableColumnType', - }, - { - width: '10%', name: i18n.translate('xpack.ml.trainedModels.modelsList.stateHeader', { defaultMessage: 'State', }), - align: 'left', truncateText: false, + width: '150px', render: ({ state, downloadState }: ModelItem) => { const config = getModelStateColor(state); if (!config) return null; - const isDownloadInProgress = state === MODEL_STATE.DOWNLOADING && downloadState; + const isProgressbarVisible = state === MODEL_STATE.DOWNLOADING && downloadState; const label = ( - + {config.name} - + ); return ( - {isDownloadInProgress ? ( + {isProgressbarVisible ? ( - {((downloadState.downloaded_parts / downloadState.total_parts) * 100).toFixed( - 0 - ) + '%'} + {downloadState + ? ( + (downloadState.downloaded_parts / downloadState.total_parts) * + 100 + ).toFixed(0) + '%' + : '100%'} } - value={downloadState?.downloaded_parts} - max={downloadState?.total_parts} + value={downloadState?.downloaded_parts ?? 1} + max={downloadState?.total_parts ?? 1} size="xs" color={config.color} /> ) : ( - {label} + + {config.component ?? label} + )} ); @@ -734,21 +710,10 @@ export const ModelsList: FC = ({ 'data-test-subj': 'mlModelsTableColumnDeploymentState', }, { - width: '20%', - field: ModelsTableToConfigMapping.createdAt, - name: i18n.translate('xpack.ml.trainedModels.modelsList.createdAtHeader', { - defaultMessage: 'Created at', - }), - dataType: 'date', - render: (v: number) => dateFormatter(v), - sortable: true, - 'data-test-subj': 'mlModelsTableColumnCreatedAt', - }, - { - width: '15%', name: i18n.translate('xpack.ml.trainedModels.modelsList.actionsHeader', { defaultMessage: 'Actions', }), + width: '200px', actions, 'data-test-subj': 'mlModelsTableColumnActions', }, @@ -836,7 +801,8 @@ export const ModelsList: FC = ({ const { onTableChange, pagination, sorting } = useTableSettings( items.length, pageState, - updatePageState + updatePageState, + true ); const search: EuiSearchBarProps = { @@ -921,6 +887,7 @@ export const ModelsList: FC = ({
    + tableLayout={'auto'} responsiveBreakpoint={'xl'} allowNeutralSort={false} columns={columns} @@ -974,7 +941,14 @@ export const ModelsList: FC = ({ {modelsToDelete.length > 0 && ( { + modelsToDelete.forEach((model) => { + if (model.state === MODEL_STATE.DOWNLOADING) { + abortedDownload.current.add(model.model_id); + } + }); + setModelsToDelete([]); + if (refreshList) { fetchModelsData(); } diff --git a/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts b/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts index 33530bade5fcf..0b9b93720234d 100644 --- a/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts +++ b/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts @@ -89,6 +89,8 @@ describe('modelsProvider', () => { { config: { input: { field_names: ['text_field'] } }, description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations)', + disclaimer: + 'This E5 model, as defined, hosted, integrated and used in conjunction with our other Elastic Software is covered by our standard warranty.', model_id: '.multilingual-e5-small', default: true, supported: true, @@ -103,6 +105,8 @@ describe('modelsProvider', () => { config: { input: { field_names: ['text_field'] } }, description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimized for linux-x86_64', + disclaimer: + 'This E5 model, as defined, hosted, integrated and used in conjunction with our other Elastic Software is covered by our standard warranty.', model_id: '.multilingual-e5-small_linux-x86_64', os: 'Linux', recommended: true, @@ -175,6 +179,8 @@ describe('modelsProvider', () => { { config: { input: { field_names: ['text_field'] } }, description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations)', + disclaimer: + 'This E5 model, as defined, hosted, integrated and used in conjunction with our other Elastic Software is covered by our standard warranty.', model_id: '.multilingual-e5-small', recommended: true, supported: true, @@ -189,6 +195,8 @@ describe('modelsProvider', () => { config: { input: { field_names: ['text_field'] } }, description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimized for linux-x86_64', + disclaimer: + 'This E5 model, as defined, hosted, integrated and used in conjunction with our other Elastic Software is covered by our standard warranty.', model_id: '.multilingual-e5-small_linux-x86_64', os: 'Linux', supported: false, diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index e47a52ec5df58..0ee9a547fc7f1 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -30070,7 +30070,6 @@ "xpack.ml.trainedModels.modelsList.builtInModelLabel": "intégré", "xpack.ml.trainedModels.modelsList.builtInModelMessage": "Modèle intégré", "xpack.ml.trainedModels.modelsList.collapseRow": "Réduire", - "xpack.ml.trainedModels.modelsList.createdAtHeader": "Créé à", "xpack.ml.trainedModels.modelsList.deleteDisabledWithDeploymentsTooltip": "Le modèle a commencé à être déployé", "xpack.ml.trainedModels.modelsList.deleteDisabledWithInferenceServicesTooltip": "Le modèle est utilisé par l'API _inference", "xpack.ml.trainedModels.modelsList.deleteModal.approvePipelinesDeletionLabel": "Supprimer {pipelinesCount, plural, one {le pipeline} other {les pipelines}}", @@ -30085,9 +30084,7 @@ "xpack.ml.trainedModels.modelsList.deleteModelsButtonLabel": "Supprimer", "xpack.ml.trainedModels.modelsList.deployModelActionLabel": "Déployer le modèle", "xpack.ml.trainedModels.modelsList.disableSelectableMessage": "Le modèle a des pipelines associés", - "xpack.ml.trainedModels.modelsList.downloadCompleteSuccess": "\"{modelIds}\" {modelIdsLength, plural, one {a été téléchargé} other {ont été téléchargés}} avec succès.", "xpack.ml.trainedModels.modelsList.downloadFailed": "Échec du téléchargement de \"{modelId}\"", - "xpack.ml.trainedModels.modelsList.downloadStatusCheckErrorMessage": "Échec de la vérification du statut du téléchargement", "xpack.ml.trainedModels.modelsList.e5Title": "E5 (EmbEddings from bidirEctional Encoder rEpresentations)", "xpack.ml.trainedModels.modelsList.e5v1Description": "E5 (EmbEddings from bidirEctional Encoder rEpresentations)", "xpack.ml.trainedModels.modelsList.e5v1x86Description": "E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimisé for linux-x86_64", @@ -30125,11 +30122,9 @@ "xpack.ml.trainedModels.modelsList.forceStopDialog.selectDeploymentsLegend": "Sélectionner les déploiements à arrêter", "xpack.ml.trainedModels.modelsList.forceStopDialog.title": "Arrêter {deploymentCount, plural, one {le déploiement} other {les déploiements}} du modèle {modelId} ?", "xpack.ml.trainedModels.modelsList.mitLicenseLabel": "Licence : MIT", - "xpack.ml.trainedModels.modelsList.modelDescriptionHeader": "Description", "xpack.ml.trainedModels.modelsList.modelIdHeader": "ID", "xpack.ml.trainedModels.modelsList.modelState.downloadedName": "Paré au déploiement", "xpack.ml.trainedModels.modelsList.modelState.downloadingName": "Téléchargement...", - "xpack.ml.trainedModels.modelsList.modelState.notDownloadedName": "Non téléchargé", "xpack.ml.trainedModels.modelsList.modelState.startedName": "Déployé", "xpack.ml.trainedModels.modelsList.modelState.startingName": "Déploiement lancé...", "xpack.ml.trainedModels.modelsList.modelState.stoppingName": "Déploiement en phase d'arrêt...", @@ -30156,14 +30151,10 @@ "xpack.ml.trainedModels.modelsList.startDeployment.updateButton": "Mettre à jour", "xpack.ml.trainedModels.modelsList.startDeployment.viewElserDocLink": "Afficher la documentation", "xpack.ml.trainedModels.modelsList.startFailed": "Impossible de démarrer \"{modelId}\"", - "xpack.ml.trainedModels.modelsList.startSuccess": "Le déploiement pour \"{modelId}\" a bien été démarré.", "xpack.ml.trainedModels.modelsList.stateHeader": "État", "xpack.ml.trainedModels.modelsList.stopDeploymentWarning": "Impossible d'arrêter \"{deploymentId}\"", "xpack.ml.trainedModels.modelsList.stopFailed": "Impossible d'arrêter \"{modelId}\"", - "xpack.ml.trainedModels.modelsList.stopSuccess": "{numberOfDeployments, plural, one {Le déploiement} other {Les déploiements}} pour \"{modelId}\" {numberOfDeployments, plural, one {a bien été arrêté} other {ont bien été arrêtés}}.", - "xpack.ml.trainedModels.modelsList.successfullyDeletedMessage": "{modelsCount, plural, one {Le modèle {modelIds}} other {# modèles}} {modelsCount, plural, one {a bien été supprimé} other {ont bien été supprimés}}.", "xpack.ml.trainedModels.modelsList.totalAmountLabel": "Total de modèles entraînés", - "xpack.ml.trainedModels.modelsList.typeHeader": "Type", "xpack.ml.trainedModels.modelsList.updateDeployment.modalTitle": "Mettre à jour le déploiement {modelId}", "xpack.ml.trainedModels.modelsList.updateFailed": "Impossible de mettre à jour \"{modelId}\"", "xpack.ml.trainedModels.modelsList.updateSuccess": "Le déploiement pour \"{modelId}\" a bien été mis à jour.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8e2125deaf18c..d7a24239bfec4 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -29817,7 +29817,6 @@ "xpack.ml.trainedModels.modelsList.builtInModelLabel": "ビルトイン", "xpack.ml.trainedModels.modelsList.builtInModelMessage": "ビルトインモデル", "xpack.ml.trainedModels.modelsList.collapseRow": "縮小", - "xpack.ml.trainedModels.modelsList.createdAtHeader": "作成日時:", "xpack.ml.trainedModels.modelsList.deleteDisabledWithDeploymentsTooltip": "モデルはデプロイを開始しました", "xpack.ml.trainedModels.modelsList.deleteDisabledWithInferenceServicesTooltip": "モデルは_inference APIによって使用されます。", "xpack.ml.trainedModels.modelsList.deleteModal.approvePipelinesDeletionLabel": "{pipelinesCount, plural, other {パイプライン}}を削除", @@ -29832,9 +29831,7 @@ "xpack.ml.trainedModels.modelsList.deleteModelsButtonLabel": "削除", "xpack.ml.trainedModels.modelsList.deployModelActionLabel": "モデルをデプロイ", "xpack.ml.trainedModels.modelsList.disableSelectableMessage": "モデルにはパイプラインが関連付けられています", - "xpack.ml.trainedModels.modelsList.downloadCompleteSuccess": "\"{modelIds}\" {modelIdsLength, plural, other {が}}正常にダウンロードされました。", "xpack.ml.trainedModels.modelsList.downloadFailed": "\"{modelId}\"をダウンロードできませんでした", - "xpack.ml.trainedModels.modelsList.downloadStatusCheckErrorMessage": "ダウンロードステータスを確認できませんでした", "xpack.ml.trainedModels.modelsList.e5Title": "E5(bidirEctional Encoder rEpresentationsからのEmbEddings)", "xpack.ml.trainedModels.modelsList.e5v1Description": "E5(bidirEctional Encoder rEpresentationsからのEmbEddings)", "xpack.ml.trainedModels.modelsList.e5v1x86Description": "E5(bidirEctional Encoder rEpresentationsからのEmbEddings)、inux-x86_64向けに最適化", @@ -29872,11 +29869,9 @@ "xpack.ml.trainedModels.modelsList.forceStopDialog.selectDeploymentsLegend": "停止するデプロイを選択", "xpack.ml.trainedModels.modelsList.forceStopDialog.title": "モデル{modelId}の{deploymentCount, plural, other {デプロイ}}を停止しますか?", "xpack.ml.trainedModels.modelsList.mitLicenseLabel": "ライセンス:MIT", - "xpack.ml.trainedModels.modelsList.modelDescriptionHeader": "説明", "xpack.ml.trainedModels.modelsList.modelIdHeader": "ID", "xpack.ml.trainedModels.modelsList.modelState.downloadedName": "デプロイできます", "xpack.ml.trainedModels.modelsList.modelState.downloadingName": "ダウンロード中...", - "xpack.ml.trainedModels.modelsList.modelState.notDownloadedName": "未ダウンロード", "xpack.ml.trainedModels.modelsList.modelState.startedName": "デプロイ済み", "xpack.ml.trainedModels.modelsList.modelState.startingName": "デプロイを開始中...", "xpack.ml.trainedModels.modelsList.modelState.stoppingName": "デプロイを停止中...", @@ -29903,13 +29898,10 @@ "xpack.ml.trainedModels.modelsList.startDeployment.updateButton": "更新", "xpack.ml.trainedModels.modelsList.startDeployment.viewElserDocLink": "ドキュメンテーションを表示", "xpack.ml.trainedModels.modelsList.startFailed": "\"{modelId}\"の開始に失敗しました", - "xpack.ml.trainedModels.modelsList.startSuccess": "\"{modelId}\"のデプロイが正常に開始しました。", "xpack.ml.trainedModels.modelsList.stateHeader": "ステータス", "xpack.ml.trainedModels.modelsList.stopDeploymentWarning": "\"{deploymentId}\"を停止できませんでした", "xpack.ml.trainedModels.modelsList.stopFailed": "\"{modelId}\"の停止に失敗しました", - "xpack.ml.trainedModels.modelsList.stopSuccess": "\"{modelId}\"の{numberOfDeployments, plural, other {デプロイ}}が正常に停止しました。", "xpack.ml.trainedModels.modelsList.totalAmountLabel": "学習済みモデルの合計数", - "xpack.ml.trainedModels.modelsList.typeHeader": "型", "xpack.ml.trainedModels.modelsList.updateDeployment.modalTitle": "{modelId}デプロイを更新", "xpack.ml.trainedModels.modelsList.updateFailed": "\"{modelId}\"を更新できませんでした", "xpack.ml.trainedModels.modelsList.updateSuccess": "\"{modelId}\"のデプロイが正常に更新されました。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 3b7a338fab717..8ad1766adf0f6 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -29857,7 +29857,6 @@ "xpack.ml.trainedModels.modelsList.builtInModelLabel": "内置", "xpack.ml.trainedModels.modelsList.builtInModelMessage": "内置模型", "xpack.ml.trainedModels.modelsList.collapseRow": "折叠", - "xpack.ml.trainedModels.modelsList.createdAtHeader": "创建于", "xpack.ml.trainedModels.modelsList.deleteDisabledWithDeploymentsTooltip": "模型已开始部署", "xpack.ml.trainedModels.modelsList.deleteDisabledWithInferenceServicesTooltip": "模型由 _inference API 使用", "xpack.ml.trainedModels.modelsList.deleteModal.approvePipelinesDeletionLabel": "删除{pipelinesCount, plural, other {管道}}", @@ -29872,9 +29871,7 @@ "xpack.ml.trainedModels.modelsList.deleteModelsButtonLabel": "删除", "xpack.ml.trainedModels.modelsList.deployModelActionLabel": "部署模型", "xpack.ml.trainedModels.modelsList.disableSelectableMessage": "模型有关联的管道", - "xpack.ml.trainedModels.modelsList.downloadCompleteSuccess": "“{modelIds}”{modelIdsLength, plural, other {已}}成功下载。", "xpack.ml.trainedModels.modelsList.downloadFailed": "无法下载“{modelId}”", - "xpack.ml.trainedModels.modelsList.downloadStatusCheckErrorMessage": "无法检查下载状态", "xpack.ml.trainedModels.modelsList.e5Title": "E5 (EmbEddings from bidirEctional Encoder rEpresentations)", "xpack.ml.trainedModels.modelsList.e5v1Description": "E5 (EmbEddings from bidirEctional Encoder rEpresentations)", "xpack.ml.trainedModels.modelsList.e5v1x86Description": "针对 linux-x86_64 进行了优化的 E5 (EmbEddings from bidirEctional Encoder rEpresentations)", @@ -29912,11 +29909,9 @@ "xpack.ml.trainedModels.modelsList.forceStopDialog.selectDeploymentsLegend": "选择要停止的部署", "xpack.ml.trainedModels.modelsList.forceStopDialog.title": "停止{deploymentCount, plural, other {部署}}模型 {modelId}?", "xpack.ml.trainedModels.modelsList.mitLicenseLabel": "许可证:MIT", - "xpack.ml.trainedModels.modelsList.modelDescriptionHeader": "描述", "xpack.ml.trainedModels.modelsList.modelIdHeader": "ID", "xpack.ml.trainedModels.modelsList.modelState.downloadedName": "准备部署", "xpack.ml.trainedModels.modelsList.modelState.downloadingName": "正在下载......", - "xpack.ml.trainedModels.modelsList.modelState.notDownloadedName": "未下载", "xpack.ml.trainedModels.modelsList.modelState.startedName": "已部署", "xpack.ml.trainedModels.modelsList.modelState.startingName": "开始部署......", "xpack.ml.trainedModels.modelsList.modelState.stoppingName": "停止部署......", @@ -29943,14 +29938,10 @@ "xpack.ml.trainedModels.modelsList.startDeployment.updateButton": "更新", "xpack.ml.trainedModels.modelsList.startDeployment.viewElserDocLink": "查看文档", "xpack.ml.trainedModels.modelsList.startFailed": "无法启动“{modelId}”", - "xpack.ml.trainedModels.modelsList.startSuccess": "已成功启动“{modelId}”的部署。", "xpack.ml.trainedModels.modelsList.stateHeader": "状态", "xpack.ml.trainedModels.modelsList.stopDeploymentWarning": "无法停止“{deploymentId}”", "xpack.ml.trainedModels.modelsList.stopFailed": "无法停止“{modelId}”", - "xpack.ml.trainedModels.modelsList.stopSuccess": "已成功停止“{modelId}”的{numberOfDeployments, plural, other {部署}}。", - "xpack.ml.trainedModels.modelsList.successfullyDeletedMessage": "{modelsCount, plural, one {模型 {modelIds}} other {# 个模型}}{modelsCount, plural, other {已}}成功删除", "xpack.ml.trainedModels.modelsList.totalAmountLabel": "已训练的模型总数", - "xpack.ml.trainedModels.modelsList.typeHeader": "类型", "xpack.ml.trainedModels.modelsList.updateDeployment.modalTitle": "更新 {modelId} 部署", "xpack.ml.trainedModels.modelsList.updateFailed": "无法更新“{modelId}”", "xpack.ml.trainedModels.modelsList.updateSuccess": "已成功更新“{modelId}”的部署。", diff --git a/x-pack/test/api_integration/apis/ml/trained_models/model_downloads.ts b/x-pack/test/api_integration/apis/ml/trained_models/model_downloads.ts index 4e229c133b4fd..4e5fd70314495 100644 --- a/x-pack/test/api_integration/apis/ml/trained_models/model_downloads.ts +++ b/x-pack/test/api_integration/apis/ml/trained_models/model_downloads.ts @@ -100,6 +100,8 @@ export default ({ getService }: FtrProviderContext) => { }, }, description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations)', + disclaimer: + 'This E5 model, as defined, hosted, integrated and used in conjunction with our other Elastic Software is covered by our standard warranty.', license: 'MIT', licenseUrl: 'https://huggingface.co/elastic/multilingual-e5-small', type: ['pytorch', 'text_embedding'], @@ -119,6 +121,8 @@ export default ({ getService }: FtrProviderContext) => { }, description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimized for linux-x86_64', + disclaimer: + 'This E5 model, as defined, hosted, integrated and used in conjunction with our other Elastic Software is covered by our standard warranty.', license: 'MIT', licenseUrl: 'https://huggingface.co/elastic/multilingual-e5-small_linux-x86_64', type: ['pytorch', 'text_embedding'], diff --git a/x-pack/test/functional/services/ml/trained_models_table.ts b/x-pack/test/functional/services/ml/trained_models_table.ts index 990ca6c1ed37a..941308b61c328 100644 --- a/x-pack/test/functional/services/ml/trained_models_table.ts +++ b/x-pack/test/functional/services/ml/trained_models_table.ts @@ -52,17 +52,16 @@ export function TrainedModelsTableProvider( id: string; description: string; modelTypes: string[]; - createdAt: string; state: string; } = { id: $tr .findTestSubject('mlModelsTableColumnId') - .find('.euiTableCellContent') + .findTestSubject('mlModelsTableColumnIdValueId') .text() .trim(), description: $tr - .findTestSubject('mlModelsTableColumnDescription') - .find('.euiTableCellContent') + .findTestSubject('mlModelsTableColumnId') + .findTestSubject('mlModelsTableColumnIdValueDescription') .text() .trim(), modelTypes, @@ -71,11 +70,6 @@ export function TrainedModelsTableProvider( .find('.euiTableCellContent') .text() .trim(), - createdAt: $tr - .findTestSubject('mlModelsTableColumnCreatedAt') - .find('.euiTableCellContent') - .text() - .trim(), }; rows.push(rowObject); @@ -161,12 +155,6 @@ export function TrainedModelsTableProvider( expectedRow.modelTypes )}' (got '${JSON.stringify(modelRow.modelTypes)}')` ); - // 'Created at' will be different on each run, - // so we will just assert that the value is in the expected timestamp format. - expect(modelRow.createdAt).to.match( - /^\w{3}\s\d+,\s\d{4}\s@\s\d{2}:\d{2}:\d{2}\.\d{3}$/, - `Expected trained model row created at time to have same format as 'Dec 5, 2019 @ 12:28:34.594' (got '${modelRow.createdAt}')` - ); } public async assertTableIsPopulated() { From f4a4a681f58c1c64eb8a05070b44f0605c625458 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Wed, 9 Oct 2024 02:40:45 -0600 Subject: [PATCH 048/110] [ML] Anomaly Detection: adds ability to delete forecasts from job (#194896) ## Summary Related issues: - https://github.com/elastic/kibana/issues/18511 - https://github.com/elastic/kibana/issues/192301 In this PR, in Job management > expanded row > Forecasts tab - a delete action has been added to each row in the forecasts table. A confirmation modal allows the user to confirm the delete action. In the SMV view, the forecast being currently viewed is now highlighted in the Forecast modal to make it easier to identify. ![image](https://github.com/user-attachments/assets/87814889-d41d-4780-98ab-695c6f12a023) image image Dark mode: image ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: Elastic Machine Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../plugins/ml/common/types/capabilities.ts | 2 + .../capabilities/check_capabilities.ts | 4 + .../forecasts_table/forecasts_table.js | 168 ++++++++++++++---- .../timeseriesexplorer/state_manager.tsx | 7 +- .../services/ml_api_service/index.ts | 12 ++ .../forecasting_modal/forecasting_modal.js | 17 +- .../forecasting_modal/forecasts_list.js | 44 +++-- .../components/forecasting_modal/modal.js | 7 +- .../timeseriesexplorer/timeseriesexplorer.js | 1 + .../timeseriesexplorer_embeddable_chart.js | 1 + .../capabilities/check_capabilities.test.ts | 8 +- .../ml/server/routes/anomaly_detectors.ts | 36 ++++ .../schemas/anomaly_detectors_schema.ts | 5 + .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../anomaly_detectors/forecast_with_spaces.ts | 32 +++- .../apis/ml/system/capabilities.ts | 4 +- .../apis/ml/system/space_capabilities.ts | 6 +- 19 files changed, 283 insertions(+), 74 deletions(-) diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index 7dc841a5cb4d7..e7a097fae7dc4 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -58,6 +58,7 @@ export const adminMlCapabilities = { canResetJob: false, canUpdateJob: false, canForecastJob: false, + canDeleteForecast: false, canCreateDatafeed: false, canDeleteDatafeed: false, canStartStopDatafeed: false, @@ -222,6 +223,7 @@ export const featureCapabilities: FeatureCapabilities = { 'canResetJob', 'canUpdateJob', 'canForecastJob', + 'canDeleteForecast', 'canCreateDatafeed', 'canDeleteDatafeed', 'canStartStopDatafeed', diff --git a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts index ed930b857473d..734993a4e4a6e 100644 --- a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts +++ b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts @@ -269,6 +269,10 @@ export function createPermissionFailureMessage(privilegeType: keyof MlCapabiliti message = i18n.translate('xpack.ml.privilege.noPermission.runForecastsTooltip', { defaultMessage: 'You do not have permission to run forecasts.', }); + } else if (privilegeType === 'canDeleteForecast') { + message = i18n.translate('xpack.ml.privilege.noPermission.deleteForecastsTooltip', { + defaultMessage: 'You do not have permission to delete forecasts.', + }); } return i18n.translate('xpack.ml.privilege.pleaseContactAdministratorTooltip', { defaultMessage: '{message} Please contact your administrator.', diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js index 5f1cbb1c76ca0..bfed613b9ad5d 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js @@ -9,8 +9,8 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { - EuiButtonIcon, EuiCallOut, + EuiConfirmModal, EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, @@ -32,9 +32,43 @@ import { isTimeSeriesViewJob, } from '../../../../../../../common/util/job_utils'; import { ML_APP_LOCATOR, ML_PAGES } from '../../../../../../../common/constants/locator'; +import { checkPermission } from '../../../../../capabilities/check_capabilities'; const MAX_FORECASTS = 500; +const DeleteForecastConfirm = ({ onCancel, onConfirm }) => ( + +

    + +

    +
    +); + /** * Table component for rendering the lists of forecasts run on an ML job. */ @@ -44,6 +78,7 @@ export class ForecastsTable extends Component { this.state = { isLoading: props.job.data_counts.processed_record_count !== 0, forecasts: [], + forecastIdToDelete: undefined, }; this.mlForecastService = forecastServiceFactory(constructorContext.services.mlServices.mlApi); } @@ -54,6 +89,11 @@ export class ForecastsTable extends Component { static contextType = context; componentDidMount() { + this.loadForecasts(); + this.canDeleteJobForecast = checkPermission('canDeleteForecast'); + } + + async loadForecasts() { const dataCounts = this.props.job.data_counts; if (dataCounts.processed_record_count > 0) { // Get the list of all the forecasts with results at or later than the specified 'from' time. @@ -163,6 +203,36 @@ export class ForecastsTable extends Component { await navigateToUrl(singleMetricViewerForecastLink); } + async deleteForecast(forecastId) { + const { + services: { + mlServices: { mlApi }, + }, + } = this.context; + + this.setState({ + isLoading: true, + forecastIdToDelete: undefined, + }); + + try { + await mlApi.deleteForecast({ jobId: this.props.job.job_id, forecastId }); + } catch (error) { + this.setState({ + forecastIdToDelete: undefined, + isLoading: false, + errorMessage: i18n.translate( + 'xpack.ml.jobsList.jobDetails.forecastsTable.deleteForecastErrorMessage', + { + defaultMessage: 'An error occurred when deleting the forecast.', + } + ), + }); + } + + this.loadForecasts(); + } + render() { if (this.state.isLoading === true) { return ( @@ -302,48 +372,74 @@ export class ForecastsTable extends Component { textOnly: true, }, { - name: i18n.translate('xpack.ml.jobsList.jobDetails.forecastsTable.viewLabel', { - defaultMessage: 'View', + width: '75px', + name: i18n.translate('xpack.ml.jobsList.jobDetails.forecastsTable.actionsLabel', { + defaultMessage: 'Actions', }), - width: '60px', - render: (forecast) => { - const viewForecastAriaLabel = i18n.translate( - 'xpack.ml.jobsList.jobDetails.forecastsTable.viewAriaLabel', - { - defaultMessage: 'View forecast created at {createdDate}', - values: { - createdDate: timeFormatter(forecast.forecast_create_timestamp), - }, - } - ); - - return ( - this.openSingleMetricView(forecast)} - isDisabled={ + actions: [ + { + description: i18n.translate('xpack.ml.jobsList.jobDetails.forecastsTable.viewLabel', { + defaultMessage: 'View', + }), + type: 'icon', + icon: 'eye', + enabled: (forecast) => + !( this.props.job.blocked !== undefined || forecast.forecast_status !== FORECAST_REQUEST_STATE.FINISHED - } - iconType="singleMetricViewer" - aria-label={viewForecastAriaLabel} - data-test-subj="mlJobListForecastTabOpenSingleMetricViewButton" - /> - ); - }, + ), + onClick: (forecast) => this.openSingleMetricView(forecast), + 'data-test-subj': 'mlJobListForecastTabOpenSingleMetricViewButton', + }, + ...(this.canDeleteJobForecast + ? [ + { + description: i18n.translate( + 'xpack.ml.jobsList.jobDetails.forecastsTable.deleteForecastDescription', + { + defaultMessage: 'Delete forecast', + } + ), + type: 'icon', + icon: 'trash', + color: 'danger', + enabled: () => this.state.isLoading === false, + onClick: (item) => { + this.setState({ + forecastIdToDelete: item.forecast_id, + }); + }, + 'data-test-subj': 'mlJobListForecastTabDeleteForecastButton', + }, + ] + : []), + ], }, ]; return ( - + <> + + {this.state.forecastIdToDelete !== undefined ? ( + + this.setState({ + forecastIdToDelete: undefined, + }) + } + onConfirm={() => this.deleteForecast(this.state.forecastIdToDelete)} + /> + ) : null} + ); } } diff --git a/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer/state_manager.tsx b/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer/state_manager.tsx index fa1753a4342fc..309f24dd1c62b 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer/state_manager.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer/state_manager.tsx @@ -216,6 +216,10 @@ export const TimeSeriesExplorerUrlStateManager: FC { + if (selectedForecastIdProp !== selectedForecastId) { + setSelectedForecastIdProp(undefined); + } + if ( autoZoomDuration !== undefined && boundsMinMs !== undefined && @@ -223,9 +227,6 @@ export const TimeSeriesExplorerUrlStateManager: FC { diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts index fa6d179059eec..868ca0d5baa0f 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts @@ -103,6 +103,10 @@ export interface GetModelSnapshotsResponse { model_snapshots: ModelSnapshot[]; } +export interface DeleteForecastResponse { + acknowledged: boolean; +} + export function mlApiProvider(httpService: HttpService) { return { getJobs(obj?: { jobId?: string }) { @@ -368,6 +372,14 @@ export function mlApiProvider(httpService: HttpService) { }); }, + deleteForecast({ jobId, forecastId }: { jobId: string; forecastId: string }) { + return httpService.http({ + path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/_forecast/${forecastId}`, + method: 'DELETE', + version: '1', + }); + }, + overallBuckets({ jobId, topN, diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasting_modal.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasting_modal.js index 5ac0dd68700d6..1bd47ff69ebc6 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasting_modal.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasting_modal.js @@ -30,9 +30,13 @@ import { forecastServiceFactory } from '../../../services/forecast_service'; import { ForecastButton } from './forecast_button'; export const FORECAST_DURATION_MAX_DAYS = 3650; // Max forecast duration allowed by analytics. - -const FORECAST_JOB_MIN_VERSION = '6.1.0'; // Forecasting only allowed for jobs created >= 6.1.0. +const STATUS_FINISHED_QUERY = { + term: { + forecast_status: FORECAST_REQUEST_STATE.FINISHED, + }, +}; const FORECASTS_VIEW_MAX = 5; // Display links to a maximum of 5 forecasts. +const FORECAST_JOB_MIN_VERSION = '6.1.0'; // Forecasting only allowed for jobs created >= 6.1.0. const FORECAST_DURATION_MAX_MS = FORECAST_DURATION_MAX_DAYS * 86400000; const WARN_NUM_PARTITIONS = 100; // Warn about running a forecast with this number of field values. const FORECAST_STATS_POLL_FREQUENCY = 250; // Frequency in ms at which to poll for forecast request stats. @@ -64,6 +68,7 @@ export class ForecastingModal extends Component { latestRecordTimestamp: PropTypes.number, entities: PropTypes.array, setForecastId: PropTypes.func, + selectedForecastId: PropTypes.string, }; constructor(props) { @@ -405,13 +410,8 @@ export class ForecastingModal extends Component { // Get the list of all the finished forecasts for this job with results at or later than the dashboard 'from' time. const { timefilter } = this.context.services.data.query.timefilter; const bounds = timefilter.getActiveBounds(); - const statusFinishedQuery = { - term: { - forecast_status: FORECAST_REQUEST_STATE.FINISHED, - }, - }; this.mlForecastService - .getForecastsSummary(job, statusFinishedQuery, bounds.min.valueOf(), FORECASTS_VIEW_MAX) + .getForecastsSummary(job, STATUS_FINISHED_QUERY, bounds.min.valueOf(), FORECASTS_VIEW_MAX) .then((resp) => { this.setState({ previousForecasts: resp.forecasts, @@ -558,6 +558,7 @@ export class ForecastingModal extends Component { jobOpeningState={this.state.jobOpeningState} jobClosingState={this.state.jobClosingState} messages={this.state.messages} + selectedForecastId={this.props.selectedForecastId} /> )}
    diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasts_list.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasts_list.js index 9e01f06094451..52ce2b201dd8d 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasts_list.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasts_list.js @@ -12,11 +12,12 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { EuiButtonIcon, EuiIcon, EuiInMemoryTable, EuiText, EuiToolTip } from '@elastic/eui'; +import { EuiButtonIcon, EuiIconTip, EuiInMemoryTable, EuiText } from '@elastic/eui'; import { formatHumanReadableDateTimeSeconds } from '@kbn/ml-date-utils'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useCurrentThemeVars } from '../../../contexts/kibana'; function getColumns(viewForecast) { return [ @@ -75,37 +76,41 @@ function getColumns(viewForecast) { ]; } -// TODO - add in ml-info-icon to the h3 element, -// then remove tooltip and inline style. -export function ForecastsList({ forecasts, viewForecast }) { +export function ForecastsList({ forecasts, viewForecast, selectedForecastId }) { + const { euiTheme } = useCurrentThemeVars(); + const getRowProps = (item) => { return { 'data-test-subj': `mlForecastsListRow row-${item.rowId}`, + ...(item.forecast_id === selectedForecastId + ? { + style: { + backgroundColor: `${euiTheme.euiPanelBackgroundColorModifiers.primary}`, + }, + } + : {}), }; }; return ( -

    +

    +   + + } + />

    - - } - > - - 0 && ( - + )} @@ -104,4 +108,5 @@ Modal.propType = { jobOpeningState: PropTypes.number, jobClosingState: PropTypes.number, messages: PropTypes.array, + selectedForecastId: PropTypes.string, }; diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index 601bbf058868f..57ded98fc8374 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -1081,6 +1081,7 @@ export class TimeSeriesExplorer extends React.Component { latestRecordTimestamp={selectedJob.data_counts.latest_record_timestamp} setForecastId={this.setForecastId} className="forecast-controls" + selectedForecastId={this.props.selectedForecastId} /> diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_embeddable_chart/timeseriesexplorer_embeddable_chart.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_embeddable_chart/timeseriesexplorer_embeddable_chart.js index 90b0e76167517..48ef63c2eae37 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_embeddable_chart/timeseriesexplorer_embeddable_chart.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_embeddable_chart/timeseriesexplorer_embeddable_chart.js @@ -1051,6 +1051,7 @@ export class TimeSeriesExplorerEmbeddableChart extends React.Component { setForecastId={this.setForecastId} className="forecast-controls" onForecastComplete={onForecastComplete} + selectedForecastId={this.props.selectedForecastId} /> )} diff --git a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts index d19ff7f723d0a..e82371c358152 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts @@ -47,7 +47,7 @@ describe('check_capabilities', () => { ); const { capabilities } = await getCapabilities(); const count = Object.keys(capabilities).length; - expect(count).toBe(43); + expect(count).toBe(44); }); }); @@ -86,6 +86,7 @@ describe('check_capabilities', () => { expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canResetJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); + expect(capabilities.canDeleteForecast).toBe(false); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); expect(capabilities.canCreateDatafeed).toBe(false); @@ -146,6 +147,7 @@ describe('check_capabilities', () => { expect(capabilities.canCloseJob).toBe(true); expect(capabilities.canResetJob).toBe(true); expect(capabilities.canForecastJob).toBe(true); + expect(capabilities.canDeleteForecast).toBe(true); expect(capabilities.canStartStopDatafeed).toBe(true); expect(capabilities.canUpdateJob).toBe(true); expect(capabilities.canCreateDatafeed).toBe(true); @@ -206,6 +208,7 @@ describe('check_capabilities', () => { expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canResetJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); + expect(capabilities.canDeleteForecast).toBe(false); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); expect(capabilities.canCreateDatafeed).toBe(false); @@ -266,6 +269,7 @@ describe('check_capabilities', () => { expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canResetJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); + expect(capabilities.canDeleteForecast).toBe(false); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); expect(capabilities.canCreateDatafeed).toBe(false); @@ -326,6 +330,7 @@ describe('check_capabilities', () => { expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canResetJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); + expect(capabilities.canDeleteForecast).toBe(false); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); expect(capabilities.canCreateDatafeed).toBe(false); @@ -387,6 +392,7 @@ describe('check_capabilities', () => { expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canResetJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); + expect(capabilities.canDeleteForecast).toBe(false); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); expect(capabilities.canCreateDatafeed).toBe(false); diff --git a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts index 1fafd467595e9..4f843620003ba 100644 --- a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts +++ b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts @@ -13,6 +13,7 @@ import type { RouteInitialization } from '../types'; import { anomalyDetectionJobSchema, anomalyDetectionUpdateJobSchema, + deleteForecastSchema, jobIdSchema, getBucketsSchema, getOverallBucketsSchema, @@ -379,6 +380,41 @@ export function jobRoutes({ router, routeGuard }: RouteInitialization) { }) ); + router.versioned + .delete({ + path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/{jobId}/_forecast/{forecastId}`, + access: 'internal', + options: { + tags: ['access:ml:canDeleteForecast'], + }, + summary: 'Deletes specified forecast for specified job', + description: 'Deletes a specified forecast for the specified anomaly detection job.', + }) + .addVersion( + { + version: '1', + validate: { + request: { + params: deleteForecastSchema, + }, + }, + }, + routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => { + try { + const { jobId, forecastId } = request.params; + const body = await mlClient.deleteForecast({ + job_id: jobId, + forecast_id: forecastId, + }); + return response.ok({ + body, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + router.versioned .post({ path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/{jobId}/_forecast`, diff --git a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts index 370b5d657e7c1..3b1eb0b481e46 100644 --- a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts +++ b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts @@ -154,6 +154,11 @@ export const jobIdSchema = schema.object({ ...jobIdSchemaBasic, }); +export const deleteForecastSchema = schema.object({ + ...jobIdSchemaBasic, + forecastId: schema.string(), +}); + export const getBucketsSchema = schema.object({ anomaly_score: schema.maybe(schema.number()), desc: schema.maybe(schema.boolean()), diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 0ee9a547fc7f1..ea995a275449d 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -28641,7 +28641,6 @@ "xpack.ml.jobsList.jobDetails.forecastsTable.processingTimeLabel": "Temps de traitement", "xpack.ml.jobsList.jobDetails.forecastsTable.statusLabel": "Statut", "xpack.ml.jobsList.jobDetails.forecastsTable.toLabel": "À", - "xpack.ml.jobsList.jobDetails.forecastsTable.viewAriaLabel": "Afficher la prévision créée le {createdDate}", "xpack.ml.jobsList.jobDetails.forecastsTable.viewLabel": "Afficher", "xpack.ml.jobsList.jobDetails.generalTitle": "Général", "xpack.ml.jobsList.jobDetails.influencersTitle": "Influenceurs", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d7a24239bfec4..2ec8bc11bc0c8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -28390,7 +28390,6 @@ "xpack.ml.jobsList.jobDetails.forecastsTable.processingTimeLabel": "処理時間", "xpack.ml.jobsList.jobDetails.forecastsTable.statusLabel": "ステータス", "xpack.ml.jobsList.jobDetails.forecastsTable.toLabel": "終了:", - "xpack.ml.jobsList.jobDetails.forecastsTable.viewAriaLabel": "{createdDate} に作成された予測を表示", "xpack.ml.jobsList.jobDetails.forecastsTable.viewLabel": "表示", "xpack.ml.jobsList.jobDetails.generalTitle": "一般", "xpack.ml.jobsList.jobDetails.influencersTitle": "影響", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8ad1766adf0f6..12ee59bb6fc9c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -28427,7 +28427,6 @@ "xpack.ml.jobsList.jobDetails.forecastsTable.processingTimeLabel": "处理时间", "xpack.ml.jobsList.jobDetails.forecastsTable.statusLabel": "状态", "xpack.ml.jobsList.jobDetails.forecastsTable.toLabel": "至", - "xpack.ml.jobsList.jobDetails.forecastsTable.viewAriaLabel": "查看在 {createdDate} 创建的预测", "xpack.ml.jobsList.jobDetails.forecastsTable.viewLabel": "查看", "xpack.ml.jobsList.jobDetails.generalTitle": "常规", "xpack.ml.jobsList.jobDetails.influencersTitle": "影响因素", diff --git a/x-pack/test/api_integration/apis/ml/anomaly_detectors/forecast_with_spaces.ts b/x-pack/test/api_integration/apis/ml/anomaly_detectors/forecast_with_spaces.ts index 1176452408762..a330edd9a41d7 100644 --- a/x-pack/test/api_integration/apis/ml/anomaly_detectors/forecast_with_spaces.ts +++ b/x-pack/test/api_integration/apis/ml/anomaly_detectors/forecast_with_spaces.ts @@ -38,7 +38,28 @@ export default ({ getService }: FtrProviderContext) => { return body; } + async function deleteForecast( + jobId: string, + forecastId: string, + space: string, + user: USER, + expectedStatusCode: number + ) { + const { body, status } = await supertest + .delete( + `${ + space ? `/s/${space}` : '' + }/internal/ml/anomaly_detectors/${jobId}/_forecast/${forecastId}` + ) + .auth(user, ml.securityCommon.getPasswordForUser(user)) + .set(getCommonRequestHeader('1')); + ml.api.assertResponseStatusCode(expectedStatusCode, status, body); + + return body; + } + describe('POST anomaly_detectors _forecast with spaces', function () { + let forecastId: string; before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -79,13 +100,22 @@ export default ({ getService }: FtrProviderContext) => { await ml.api.waitForDatafeedState(forecastJobDatafeedId, DATAFEED_STATE.STOPPED); await ml.api.waitForJobState(forecastJobId, JOB_STATE.CLOSED); await ml.api.openAnomalyDetectionJob(forecastJobId); - await runForecast(forecastJobId, idSpace1, '1d', USER.ML_POWERUSER, 200); + const resp = await runForecast(forecastJobId, idSpace1, '1d', USER.ML_POWERUSER, 200); + forecastId = resp.forecast_id; await ml.testExecution.logTestStep( `forecast results should exist for job '${forecastJobId}'` ); await ml.api.assertForecastResultsExist(forecastJobId); }); + it('should not delete forecast for user without permissions', async () => { + await await deleteForecast(forecastJobId, forecastId, idSpace1, USER.ML_VIEWER, 403); + }); + + it('should delete forecast for user with permissions', async () => { + await await deleteForecast(forecastJobId, forecastId, idSpace1, USER.ML_POWERUSER, 200); + }); + it('should not run forecast for open job with invalid duration', async () => { await runForecast(forecastJobId, idSpace1, 3600000, USER.ML_POWERUSER, 400); }); diff --git a/x-pack/test/api_integration/apis/ml/system/capabilities.ts b/x-pack/test/api_integration/apis/ml/system/capabilities.ts index b653632432310..c4775cacdfa66 100644 --- a/x-pack/test/api_integration/apis/ml/system/capabilities.ts +++ b/x-pack/test/api_integration/apis/ml/system/capabilities.ts @@ -12,7 +12,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api'; import { USER } from '../../../../functional/services/ml/security_common'; -const NUMBER_OF_CAPABILITIES = 43; +const NUMBER_OF_CAPABILITIES = 44; export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertestWithoutAuth'); @@ -61,6 +61,7 @@ export default ({ getService }: FtrProviderContext) => { canResetJob: false, canUpdateJob: false, canForecastJob: false, + canDeleteForecast: false, canCreateDatafeed: false, canDeleteDatafeed: false, canStartStopDatafeed: false, @@ -111,6 +112,7 @@ export default ({ getService }: FtrProviderContext) => { canResetJob: true, canUpdateJob: true, canForecastJob: true, + canDeleteForecast: true, canCreateDatafeed: true, canDeleteDatafeed: true, canStartStopDatafeed: true, diff --git a/x-pack/test/api_integration/apis/ml/system/space_capabilities.ts b/x-pack/test/api_integration/apis/ml/system/space_capabilities.ts index f45d54a741da3..1832e5d096e34 100644 --- a/x-pack/test/api_integration/apis/ml/system/space_capabilities.ts +++ b/x-pack/test/api_integration/apis/ml/system/space_capabilities.ts @@ -15,7 +15,7 @@ import { USER } from '../../../../functional/services/ml/security_common'; const idSpaceWithMl = 'space_with_ml'; const idSpaceNoMl = 'space_no_ml'; -const NUMBER_OF_CAPABILITIES = 43; +const NUMBER_OF_CAPABILITIES = 44; export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertestWithoutAuth'); @@ -90,6 +90,7 @@ export default ({ getService }: FtrProviderContext) => { canResetJob: false, canUpdateJob: false, canForecastJob: false, + canDeleteForecast: false, canCreateDatafeed: false, canDeleteDatafeed: false, canStartStopDatafeed: false, @@ -139,6 +140,7 @@ export default ({ getService }: FtrProviderContext) => { canResetJob: false, canUpdateJob: false, canForecastJob: false, + canDeleteForecast: false, canCreateDatafeed: false, canDeleteDatafeed: false, canStartStopDatafeed: false, @@ -188,6 +190,7 @@ export default ({ getService }: FtrProviderContext) => { canResetJob: true, canUpdateJob: true, canForecastJob: true, + canDeleteForecast: true, canCreateDatafeed: true, canDeleteDatafeed: true, canStartStopDatafeed: true, @@ -237,6 +240,7 @@ export default ({ getService }: FtrProviderContext) => { canResetJob: false, canUpdateJob: false, canForecastJob: false, + canDeleteForecast: false, canCreateDatafeed: false, canDeleteDatafeed: false, canStartStopDatafeed: false, From 7fdd90d148660256d822c45f5a4594d82d21af38 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:14:16 +0100 Subject: [PATCH 049/110] [Security Solution][Detection Engine] fix cypress MKI flaky test (#194866) ## Summary This an attempt to fix flaky Cypress test: https://buildkite.com/organizations/elastic/analytics/suites/serverless-mki-cypress-detection-engine/tests/9cd134bd-fa8b-8ff3-858e-ba1733d30e2c?branch=main I was not able to reproduce it locally. Also, old version of test was very stable on flaky test runner too: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7078 I changed test a bit by re-arranging order of form filling. So, suppression fields will be last. Maybe it can reduce possibility of race condition when form is just rendered and fields being interacted with by Cypress. Also, added assertion if threshold checkbox changed it status to enabled before interacting with other suppression inputs. If this won't help, next step can be using default suppression configuration instead. New version of test: 200 runs w/o failures https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7084 --------- Co-authored-by: Ryland Herrick --- .../detection_engine/rule_creation/threshold_rule.cy.ts | 8 ++++++-- .../cypress/tasks/create_new_rule.ts | 9 +++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/threshold_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/threshold_rule.cy.ts index 11740c1f795f8..8af755c6ed328 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/threshold_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/threshold_rule.cy.ts @@ -58,6 +58,8 @@ import { fillScheduleRuleAndContinue, selectThresholdRuleType, waitForAlertsToPopulate, + fillDefineThresholdRule, + continueFromDefineStep, } from '../../../../tasks/create_new_rule'; import { login } from '../../../../tasks/login'; import { visit } from '../../../../tasks/navigation'; @@ -68,7 +70,7 @@ import { CREATE_RULE_URL } from '../../../../urls/navigation'; describe( 'Threshold rules', { - tags: ['@ess', '@serverless', '@skipInServerlessMKI'], + tags: ['@ess', '@serverless'], }, () => { const rule = getNewThresholdRule(); @@ -152,8 +154,10 @@ describe( it('Creates a new threshold rule with suppression enabled', () => { selectThresholdRuleType(); + fillDefineThresholdRule(rule); enablesAndPopulatesThresholdSuppression(5, 'h'); - fillDefineThresholdRuleAndContinue(rule); + continueFromDefineStep(); + // ensures duration displayed on define step in preview mode cy.get(DEFINITION_DETAILS).within(() => { getDetails(SUPPRESS_FOR_DETAILS).should('have.text', '5h'); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts index 68dc2cfffd908..501dd0461dd44 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts @@ -557,7 +557,7 @@ export const fillRuleActionFilters = (alertsFilter: AlertsFilter) => { .type(`{selectall}${alertsFilter.timeframe.timezone}{enter}`); }; -export const fillDefineThresholdRuleAndContinue = (rule: ThresholdRuleCreateProps) => { +export const fillDefineThresholdRule = (rule: ThresholdRuleCreateProps) => { const thresholdField = 0; const threshold = 1; @@ -578,7 +578,11 @@ export const fillDefineThresholdRuleAndContinue = (rule: ThresholdRuleCreateProp cy.wrap(inputs[threshold]).clear(); cy.wrap(inputs[threshold]).type(`${rule.threshold.value}`); }); - cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true }); +}; + +export const fillDefineThresholdRuleAndContinue = (rule: ThresholdRuleCreateProps) => { + fillDefineThresholdRule(rule); + continueFromDefineStep(); }; export const fillDefineEqlRule = (rule: EqlRuleCreateProps) => { @@ -908,6 +912,7 @@ export const enablesAndPopulatesThresholdSuppression = ( // enables suppression for threshold rule cy.get(THRESHOLD_ENABLE_SUPPRESSION_CHECKBOX).should('not.be.checked'); cy.get(THRESHOLD_ENABLE_SUPPRESSION_CHECKBOX).click(); + cy.get(THRESHOLD_ENABLE_SUPPRESSION_CHECKBOX).should('be.checked'); setAlertSuppressionDuration(interval, timeUnit); From 94934505eb3673db64dd429bf25386bdc9fe9bc5 Mon Sep 17 00:00:00 2001 From: Alex Szabo Date: Wed, 9 Oct 2024 11:26:46 +0200 Subject: [PATCH 050/110] [CI] Add tags for kibana pipelines (#195388) ## Summary Kibana-related pipelines are hard to find on Buildkite, due to other, ingest-related pipelines having 'kibana' in their names. This pipeline adds tags to pipelines serving `kibana` CI duties, so they can be easily found using Buildkite's tags/labels. The tags added are mostly `kibana` but some pipelines also got the `security-solution` label, as these pipelines can be easily associated with the served solution. --- .../_templates/_new_pipeline.yml | 2 ++ .../pipeline-resource-definitions/kibana-api-docs.yml | 2 ++ .../kibana-apis-capacity-testing-daily.yml | 2 ++ .../kibana-artifacts-container-image.yml | 2 ++ .../kibana-artifacts-snapshot.yml | 2 ++ .../kibana-artifacts-staging.yml | 2 ++ .../kibana-artifacts-trigger.yml | 2 ++ .../kibana-chrome-forward-testing.yml | 2 ++ .buildkite/pipeline-resource-definitions/kibana-codeql.yml | 2 ++ .../pipeline-resource-definitions/kibana-coverage-daily.yml | 2 ++ .../kibana-es-forward-testing.yml | 2 ++ .../kibana-es-serverless-snapshots.yml | 2 ++ .../pipeline-resource-definitions/kibana-es-snapshots.yml | 6 ++++++ .../kibana-esql-grammar-sync.yml | 2 ++ .../pipeline-resource-definitions/kibana-fips-daily.yml | 2 ++ .buildkite/pipeline-resource-definitions/kibana-flaky.yml | 2 ++ .../kibana-fleet-packages-daily.yml | 2 ++ .../kibana-migration-staging.yml | 2 ++ .../kibana-on-merge-unsupported-ftrs.yml | 2 ++ .../pipeline-resource-definitions/kibana-on-merge.yml | 2 ++ .../kibana-performance-daily.yml | 2 ++ .../kibana-performance-data-set-extraction-daily.yml | 2 ++ .../kibana-pointer-compression.yml | 2 ++ .buildkite/pipeline-resource-definitions/kibana-pr.yml | 2 ++ .../kibana-purge-cloud-deployments.yml | 2 ++ .../kibana-serverless-emergency-release.yml | 2 ++ .../kibana-serverless-quality-gates-emergency.yml | 2 ++ .../kibana-serverless-quality-gates.yml | 2 ++ .../kibana-serverless-release-testing.yml | 2 ++ .../kibana-serverless-release.yml | 2 ++ .../scalability_testing-daily.yml | 2 ++ .../security-solution-ess/security-solution-ess.yml | 3 +++ ...less-security-solution-quality-gate-defend-workflows.yml | 3 +++ ...less-security-solution-quality-gate-detection-engine.yml | 3 +++ ...less-security-solution-quality-gate-entity-analytics.yml | 3 +++ ...na-serverless-security-solution-quality-gate-explore.yml | 3 +++ ...ana-serverless-security-solution-quality-gate-gen-ai.yml | 3 +++ ...erless-security-solution-quality-gate-investigations.yml | 3 +++ ...rless-security-solution-quality-gate-rule-management.yml | 3 +++ .../trigger-version-dependent-jobs.yml | 2 ++ 40 files changed, 92 insertions(+) diff --git a/.buildkite/pipeline-resource-definitions/_templates/_new_pipeline.yml b/.buildkite/pipeline-resource-definitions/_templates/_new_pipeline.yml index f33e738882693..6ef0d7652b964 100644 --- a/.buildkite/pipeline-resource-definitions/_templates/_new_pipeline.yml +++ b/.buildkite/pipeline-resource-definitions/_templates/_new_pipeline.yml @@ -70,3 +70,5 @@ spec: # Optionally, set schedule-specific env-vars here env: SCHEDULED: 'true' + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-api-docs.yml b/.buildkite/pipeline-resource-definitions/kibana-api-docs.yml index 5368b60314e47..26ff7242dac65 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-api-docs.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-api-docs.yml @@ -49,3 +49,5 @@ spec: cronline: 0 0 * * * America/New_York message: Daily build branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-apis-capacity-testing-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-apis-capacity-testing-daily.yml index c52e6203485f4..244a0351de0be 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-apis-capacity-testing-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-apis-capacity-testing-daily.yml @@ -47,3 +47,5 @@ spec: cronline: 0 1/3 * * * Europe/Berlin message: Capacity every 3h testing branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-container-image.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-container-image.yml index eff970c69af6b..37bc5ee59ff0b 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-container-image.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-container-image.yml @@ -42,3 +42,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml index e1c40f690f4ec..f994f0cba33c3 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml @@ -43,3 +43,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml index 71bcc4079c50d..1d7b0488c7b3f 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml @@ -43,3 +43,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml index 8a9585762de83..f08e505b9aabb 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml @@ -44,3 +44,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-chrome-forward-testing.yml b/.buildkite/pipeline-resource-definitions/kibana-chrome-forward-testing.yml index beeb6152509b6..15265da35f390 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-chrome-forward-testing.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-chrome-forward-testing.yml @@ -47,3 +47,5 @@ spec: cronline: 0 12 * * * message: Daily Chrome Forward Testing branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-codeql.yml b/.buildkite/pipeline-resource-definitions/kibana-codeql.yml index 3da2c9137c4e0..68a41a547a64a 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-codeql.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-codeql.yml @@ -32,3 +32,5 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: READ_ONLY + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-coverage-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-coverage-daily.yml index c73a276a6d786..4192bb9186589 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-coverage-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-coverage-daily.yml @@ -48,3 +48,5 @@ spec: cronline: 0 5 * * * message: Daily 6 am UTC branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-es-forward-testing.yml b/.buildkite/pipeline-resource-definitions/kibana-es-forward-testing.yml index 2d87415841df6..fa4ee2d263873 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-es-forward-testing.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-es-forward-testing.yml @@ -40,3 +40,5 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml b/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml index 60bedaafba586..684e2e07fb187 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml @@ -53,3 +53,5 @@ spec: env: PUBLISH_DOCKER_TAG: 'true' branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml b/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml index 1c041d7016f44..851862a613111 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml @@ -61,6 +61,8 @@ spec: cronline: 0 9 * * * America/New_York message: Daily build branch: '7.17' + tags: + - kibana --- # yaml-language-server: $schema=https://gist.githubusercontent.com/elasticmachine/988b80dae436cafea07d9a4a460a011d/raw/rre.schema.json apiVersion: backstage.io/v1alpha1 @@ -108,6 +110,8 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana --- # yaml-language-server: $schema=https://gist.githubusercontent.com/elasticmachine/988b80dae436cafea07d9a4a460a011d/raw/rre.schema.json apiVersion: backstage.io/v1alpha1 @@ -156,3 +160,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-esql-grammar-sync.yml b/.buildkite/pipeline-resource-definitions/kibana-esql-grammar-sync.yml index 952babf7d580d..8cc4b54a5ce0c 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-esql-grammar-sync.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-esql-grammar-sync.yml @@ -51,3 +51,5 @@ spec: cronline: 0 0 * * 1 America/New_York message: Weekly build branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml index b64521858c1f6..bedb81cccc5a4 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml @@ -38,3 +38,5 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: READ_ONLY + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-flaky.yml b/.buildkite/pipeline-resource-definitions/kibana-flaky.yml index 82797c03f2378..f1c348e059209 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-flaky.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-flaky.yml @@ -39,3 +39,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-fleet-packages-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-fleet-packages-daily.yml index 8805fef47f914..d948460513c8e 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-fleet-packages-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-fleet-packages-daily.yml @@ -47,3 +47,5 @@ spec: message: Single user daily test env: {} branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-migration-staging.yml b/.buildkite/pipeline-resource-definitions/kibana-migration-staging.yml index b999babc24fc8..980fee4db5671 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-migration-staging.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-migration-staging.yml @@ -30,3 +30,5 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-on-merge-unsupported-ftrs.yml b/.buildkite/pipeline-resource-definitions/kibana-on-merge-unsupported-ftrs.yml index b9c6cb8970271..a6ddb28309987 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-on-merge-unsupported-ftrs.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-on-merge-unsupported-ftrs.yml @@ -44,3 +44,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml b/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml index 6fe305979652e..5e6622e6da513 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml @@ -47,3 +47,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-performance-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-performance-daily.yml index 9ed561c9cfdbe..915cce93a2481 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-performance-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-performance-daily.yml @@ -48,3 +48,5 @@ spec: cronline: 0 */3 * * * Europe/Berlin message: Single user daily test branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-performance-data-set-extraction-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-performance-data-set-extraction-daily.yml index aa38564fd963b..3fe79832d35fd 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-performance-data-set-extraction-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-performance-data-set-extraction-daily.yml @@ -47,3 +47,5 @@ spec: cronline: 0 3/8 * * * Europe/Berlin message: Extract APM traces branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-pointer-compression.yml b/.buildkite/pipeline-resource-definitions/kibana-pointer-compression.yml index 5a23fc95d9971..bcc94453b14e2 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-pointer-compression.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-pointer-compression.yml @@ -36,3 +36,5 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: READ_ONLY + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-pr.yml b/.buildkite/pipeline-resource-definitions/kibana-pr.yml index 4d6275843327e..2ce36f6799b5a 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-pr.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-pr.yml @@ -47,3 +47,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml b/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml index 3b5d3fd84fad5..9124d001d6f70 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml @@ -49,3 +49,5 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-emergency-release.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-emergency-release.yml index 5911095262ac1..c51e44432596d 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-emergency-release.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-emergency-release.yml @@ -28,3 +28,5 @@ spec: access_level: BUILD_AND_READ everyone: access_level: READ_ONLY + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates-emergency.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates-emergency.yml index ba053d7c44da6..267db48ba6d90 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates-emergency.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates-emergency.yml @@ -31,3 +31,5 @@ spec: access_level: BUILD_AND_READ everyone: access_level: READ_ONLY + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates.yml index 1f57f2ca83250..8d4e7f35cd6fe 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates.yml @@ -31,3 +31,5 @@ spec: access_level: BUILD_AND_READ everyone: access_level: READ_ONLY + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml index fe3fdaf49c748..0a033e72d53b8 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml @@ -44,3 +44,5 @@ spec: access_level: MANAGE_BUILD_AND_READ kibana-tech-leads: access_level: MANAGE_BUILD_AND_READ + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml index 057a31c47190a..7a35ea3ad1ec8 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml @@ -46,3 +46,5 @@ spec: env: AUTO_SELECT_COMMIT: 'true' branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/scalability_testing-daily.yml b/.buildkite/pipeline-resource-definitions/scalability_testing-daily.yml index 06f2f2dd6634b..162bb6220ea1c 100644 --- a/.buildkite/pipeline-resource-definitions/scalability_testing-daily.yml +++ b/.buildkite/pipeline-resource-definitions/scalability_testing-daily.yml @@ -47,3 +47,5 @@ spec: cronline: 0 6 * * * Europe/Berlin message: Scalability daily benchmarking branch: main + tags: + - kibana diff --git a/.buildkite/pipeline-resource-definitions/security-solution-ess/security-solution-ess.yml b/.buildkite/pipeline-resource-definitions/security-solution-ess/security-solution-ess.yml index b22891cbe9d2d..239bd74c66922 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-ess/security-solution-ess.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-ess/security-solution-ess.yml @@ -35,3 +35,6 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana + - security-solution diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml index d5e32ca55172c..d4d2541f1c4ad 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml @@ -36,3 +36,6 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana + - security-solution diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml index 8dc4265b3e6f4..77361eed441e6 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml @@ -36,3 +36,6 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana + - security-solution diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml index 9d5bba5f40d1d..49338bf7b6d32 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml @@ -36,3 +36,6 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana + - security-solution diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml index cd2739fe4a6fb..ee8cf00a755f9 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml @@ -36,3 +36,6 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana + - security-solution diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml index 1aeeefe2a0ad8..f22e321176eb0 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml @@ -36,3 +36,6 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana + - security-solution diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml index 955bcf24b1e63..7de3b5f8cc282 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml @@ -36,3 +36,6 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana + - security-solution diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml index af0386076dd4d..4f095294f4422 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml @@ -36,3 +36,6 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: BUILD_AND_READ + tags: + - kibana + - security-solution diff --git a/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml b/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml index ea474356b137d..8dd486c3176ce 100644 --- a/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml +++ b/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml @@ -69,3 +69,5 @@ spec: env: TRIGGER_PIPELINE_SET: artifacts-trigger MESSAGE: Daily build + tags: + - kibana From ee4815a570e4ac1151deec1eb28437ec585411b6 Mon Sep 17 00:00:00 2001 From: Sandra G Date: Wed, 9 Oct 2024 05:47:16 -0400 Subject: [PATCH 051/110] [Data Usage] add locator to link to data stream management (#195433) ## Summary add locator to link to data stream management recently made available https://github.com/elastic/kibana/pull/195299 --- .../public/app/components/legend_action.tsx | 12 ++++++------ x-pack/plugins/data_usage/tsconfig.json | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/data_usage/public/app/components/legend_action.tsx b/x-pack/plugins/data_usage/public/app/components/legend_action.tsx index a816d1f8eadda..c9059037c4445 100644 --- a/x-pack/plugins/data_usage/public/app/components/legend_action.tsx +++ b/x-pack/plugins/data_usage/public/app/components/legend_action.tsx @@ -14,6 +14,7 @@ import { EuiListGroupItem, EuiSpacer, } from '@elastic/eui'; +import { IndexManagementLocatorParams } from '@kbn/index-management-shared-types'; import { DatasetQualityLink } from './dataset_quality_link'; import { useKibanaContextForPlugin } from '../../utils/use_kibana'; @@ -39,12 +40,11 @@ export const LegendAction: React.FC = React.memo( const hasIndexManagementFeature = !!capabilities?.index_management; const onClickIndexManagement = useCallback(async () => { - // TODO: use proper index management locator https://github.com/elastic/kibana/issues/195083 - const dataQualityLocator = locators.get('MANAGEMENT_APP_LOCATOR'); - if (dataQualityLocator) { - await dataQualityLocator.navigate({ - sectionId: 'data', - appId: `index_management/data_streams/${label}`, + const locator = locators.get('INDEX_MANAGEMENT_LOCATOR_ID'); + if (locator) { + await locator.navigate({ + page: 'data_streams_details', + dataStreamName: label, }); } togglePopover(null); // Close the popover after action diff --git a/x-pack/plugins/data_usage/tsconfig.json b/x-pack/plugins/data_usage/tsconfig.json index cecbeb654db30..d3754906475e9 100644 --- a/x-pack/plugins/data_usage/tsconfig.json +++ b/x-pack/plugins/data_usage/tsconfig.json @@ -28,6 +28,7 @@ "@kbn/core-http-browser", "@kbn/core-chrome-browser", "@kbn/features-plugin", + "@kbn/index-management-shared-types", ], "exclude": ["target/**/*"] } From 15abb859920fc2132eaf7c519c18ca39577acaf1 Mon Sep 17 00:00:00 2001 From: Konrad Szwarc Date: Wed, 9 Oct 2024 12:21:55 +0200 Subject: [PATCH 052/110] [EDR Workflows] Deprecate public metadata/transforms api endpoint in favour of an internal one (#194829) New internal GET `/api/endpoint/metadata/transforms` route. Current public GET `/api/endpoint/metadata/transforms` route is set to deprecated. All usages across the project have been updated to consume the new internal route. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../output/kibana.serverless.staging.yaml | 1 + oas_docs/output/kibana.serverless.yaml | 1 + oas_docs/output/kibana.staging.yaml | 1 + oas_docs/output/kibana.yaml | 1 + .../metadata/get_metadata.schema.yaml | 1 + .../common/endpoint/constants.ts | 4 +++ ...agement_api_2023_10_31.bundled.schema.yaml | 1 + ...agement_api_2023_10_31.bundled.schema.yaml | 1 + .../management/pages/endpoint_hosts/mocks.ts | 4 +-- .../pages/endpoint_hosts/store/middleware.ts | 6 ++--- .../store/mock_endpoint_result_list.ts | 4 +-- .../server/endpoint/routes/metadata/index.ts | 20 ++++++++++++++ .../endpoint/routes/metadata/metadata.test.ts | 10 +++---- .../endpoint_authz.ts | 26 +++++++++++++++++-- .../trial_license_complete_tier/metadata.ts | 14 +++++----- 15 files changed, 74 insertions(+), 21 deletions(-) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index 67e2f6844a6df..18ce5022cdf02 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -8080,6 +8080,7 @@ paths: - Security Endpoint Management API /api/endpoint/metadata/transforms: get: + deprecated: true operationId: GetEndpointMetadataTransform responses: '200': diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index 67e2f6844a6df..18ce5022cdf02 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -8080,6 +8080,7 @@ paths: - Security Endpoint Management API /api/endpoint/metadata/transforms: get: + deprecated: true operationId: GetEndpointMetadataTransform responses: '200': diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index 372569024e114..bafecfccde407 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -11452,6 +11452,7 @@ paths: - Security Endpoint Management API /api/endpoint/metadata/transforms: get: + deprecated: true operationId: GetEndpointMetadataTransform responses: '200': diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index 372569024e114..bafecfccde407 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -11452,6 +11452,7 @@ paths: - Security Endpoint Management API /api/endpoint/metadata/transforms: get: + deprecated: true operationId: GetEndpointMetadataTransform responses: '200': diff --git a/x-pack/plugins/security_solution/common/api/endpoint/metadata/get_metadata.schema.yaml b/x-pack/plugins/security_solution/common/api/endpoint/metadata/get_metadata.schema.yaml index 680eb1b3be7ed..9bbcd11716513 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/metadata/get_metadata.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/endpoint/metadata/get_metadata.schema.yaml @@ -25,6 +25,7 @@ paths: /api/endpoint/metadata/transforms: get: + deprecated: true summary: Get metadata transforms operationId: GetEndpointMetadataTransform x-codegen-enabled: false diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts index 0e7218f0d7d41..2a11d047dd865 100644 --- a/x-pack/plugins/security_solution/common/endpoint/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -65,8 +65,12 @@ export const BASE_INTERNAL_ENDPOINT_ROUTE = `/internal${BASE_ENDPOINT_ROUTE}`; // Endpoint API routes export const HOST_METADATA_LIST_ROUTE = `${BASE_ENDPOINT_ROUTE}/metadata`; export const HOST_METADATA_GET_ROUTE = `${HOST_METADATA_LIST_ROUTE}/{id}`; + +/** @deprecated public route, use {@link METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE} internal route */ export const METADATA_TRANSFORMS_STATUS_ROUTE = `${BASE_ENDPOINT_ROUTE}/metadata/transforms`; +export const METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE = `${BASE_INTERNAL_ENDPOINT_ROUTE}/metadata/transforms`; + export const BASE_POLICY_RESPONSE_ROUTE = `${BASE_ENDPOINT_ROUTE}/policy_response`; export const BASE_POLICY_ROUTE = `${BASE_ENDPOINT_ROUTE}/policy`; export const AGENT_POLICY_SUMMARY_ROUTE = `${BASE_POLICY_ROUTE}/summaries`; diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml index 5d03e10969e14..60ac76e240fa4 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml @@ -438,6 +438,7 @@ paths: - Security Endpoint Management API /api/endpoint/metadata/transforms: get: + deprecated: true operationId: GetEndpointMetadataTransform responses: '200': diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml index f5c2d290af33c..7bd94b9c8227c 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml @@ -388,6 +388,7 @@ paths: - Security Endpoint Management API /api/endpoint/metadata/transforms: get: + deprecated: true operationId: GetEndpointMetadataTransform responses: '200': diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts index c3cc8adc3b4fe..45ee954caa466 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts @@ -21,7 +21,7 @@ import { BASE_POLICY_RESPONSE_ROUTE, HOST_METADATA_GET_ROUTE, HOST_METADATA_LIST_ROUTE, - METADATA_TRANSFORMS_STATUS_ROUTE, + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, } from '../../../../common/endpoint/constants'; import type { PendingActionsHttpMockInterface } from '../../../common/lib/endpoint/endpoint_pending_actions/mocks'; import { pendingActionsHttpMock } from '../../../common/lib/endpoint/endpoint_pending_actions/mocks'; @@ -120,7 +120,7 @@ export const failedTransformStateMock = { export const transformsHttpMocks = httpHandlerMockFactory([ { id: 'metadataTransformStats', - path: METADATA_TRANSFORMS_STATUS_ROUTE, + path: METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, method: 'get', handler: () => failedTransformStateMock, }, diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index 61a049d2dd99e..f91e74983e5a2 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -21,7 +21,7 @@ import type { import { ENDPOINT_FIELDS_SEARCH_STRATEGY, HOST_METADATA_LIST_ROUTE, - METADATA_TRANSFORMS_STATUS_ROUTE, + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, METADATA_UNITED_INDEX, metadataCurrentIndexPattern, } from '../../../../../common/endpoint/constants'; @@ -421,8 +421,8 @@ export async function handleLoadMetadataTransformStats(http: HttpStart, store: E try { const transformStatsResponse: TransformStatsResponse = await http.get( - METADATA_TRANSFORMS_STATUS_ROUTE, - { version: '2023-10-31' } + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, + { version: '1' } ); dispatch({ diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts index a851d2273907d..c29e8e25ac4d0 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts @@ -35,7 +35,7 @@ import { ENDPOINT_DEFAULT_SORT_DIRECTION, ENDPOINT_DEFAULT_SORT_FIELD, HOST_METADATA_LIST_ROUTE, - METADATA_TRANSFORMS_STATUS_ROUTE, + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, } from '../../../../../common/endpoint/constants'; import type { TransformStats, TransformStatsResponse } from '../types'; @@ -178,7 +178,7 @@ const endpointListApiPathHandlerMocks = ({ return pendingActionsResponseMock(); }, - [METADATA_TRANSFORMS_STATUS_ROUTE]: (): TransformStatsResponse => ({ + [METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE]: (): TransformStatsResponse => ({ count: transforms.length, transforms, }), diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts index 75d0fb2135fc8..9603e9e9a6d48 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts @@ -23,6 +23,7 @@ import type { SecuritySolutionPluginRouter } from '../../../types'; import { HOST_METADATA_GET_ROUTE, HOST_METADATA_LIST_ROUTE, + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, METADATA_TRANSFORMS_STATUS_ROUTE, } from '../../../../common/endpoint/constants'; import { withEndpointAuthz } from '../with_endpoint_authz'; @@ -94,6 +95,7 @@ export function registerEndpointRoutes( access: 'public', path: METADATA_TRANSFORMS_STATUS_ROUTE, options: { authRequired: true, tags: ['access:securitySolution'] }, + deprecated: true, }) .addVersion( { @@ -106,4 +108,22 @@ export function registerEndpointRoutes( getMetadataTransformStatsHandler(endpointAppContext, logger) ) ); + + router.versioned + .get({ + access: 'internal', + path: METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, + options: { authRequired: true, tags: ['access:securitySolution'] }, + }) + .addVersion( + { + version: '1', + validate: false, + }, + withEndpointAuthz( + { all: ['canReadSecuritySolution'] }, + logger, + getMetadataTransformStatsHandler(endpointAppContext, logger) + ) + ); } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts index 63d3c466dd2b6..dbf60ef127c22 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts @@ -47,7 +47,7 @@ import { ENDPOINT_DEFAULT_SORT_FIELD, HOST_METADATA_GET_ROUTE, HOST_METADATA_LIST_ROUTE, - METADATA_TRANSFORMS_STATUS_ROUTE, + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, METADATA_UNITED_INDEX, } from '../../../../common/endpoint/constants'; import { TRANSFORM_STATES } from '../../../../common/constants'; @@ -506,8 +506,8 @@ describe('test endpoint routes', () => { ({ routeConfig, routeHandler } = getRegisteredVersionedRouteMock( routerMock, 'get', - METADATA_TRANSFORMS_STATUS_ROUTE, - '2023-10-31' + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, + '1' )); const contextOverrides = { @@ -539,8 +539,8 @@ describe('test endpoint routes', () => { ({ routeConfig, routeHandler } = getRegisteredVersionedRouteMock( routerMock, 'get', - METADATA_TRANSFORMS_STATUS_ROUTE, - '2023-10-31' + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, + '1' )); await routeHandler( createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), diff --git a/x-pack/test/security_solution_api_integration/test_suites/edr_workflows/authentication/trial_license_complete_tier/endpoint_authz.ts b/x-pack/test/security_solution_api_integration/test_suites/edr_workflows/authentication/trial_license_complete_tier/endpoint_authz.ts index 5805dbef73e2e..c8dd877849b35 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/edr_workflows/authentication/trial_license_complete_tier/endpoint_authz.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/edr_workflows/authentication/trial_license_complete_tier/endpoint_authz.ts @@ -19,7 +19,7 @@ import { HOST_METADATA_LIST_ROUTE, ISOLATE_HOST_ROUTE_V2, KILL_PROCESS_ROUTE, - METADATA_TRANSFORMS_STATUS_ROUTE, + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, SUSPEND_PROCESS_ROUTE, UNISOLATE_HOST_ROUTE_V2, } from '@kbn/security-solution-plugin/common/endpoint/constants'; @@ -31,6 +31,7 @@ import { ROLE } from '../../../../config/services/security_solution_edr_workflow export default function ({ getService }: FtrProviderContext) { const endpointTestResources = getService('endpointTestResources'); const utils = getService('securitySolutionUtils'); + const samlAuth = getService('samlAuth'); interface ApiCallsInterface { method: keyof Pick; @@ -70,7 +71,8 @@ export default function ({ getService }: FtrProviderContext) { }, { method: 'get', - path: METADATA_TRANSFORMS_STATUS_ROUTE, + path: METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, + version: '1', body: undefined, }, { @@ -210,6 +212,11 @@ export default function ({ getService }: FtrProviderContext) { }]`, async () => { await t1AnalystSupertest[apiListItem.method](replacePathIds(apiListItem.path)) .set('kbn-xsrf', 'xxx') + .set( + apiListItem.version ? 'Elastic-Api-Version' : 'foo', + apiListItem.version || '2023-10-31' + ) + .set(samlAuth.getInternalRequestHeader()) .send(getBodyPayload(apiListItem)) .expect(200); }); @@ -246,6 +253,11 @@ export default function ({ getService }: FtrProviderContext) { }]`, async () => { await platformEnginnerSupertest[apiListItem.method](replacePathIds(apiListItem.path)) .set('kbn-xsrf', 'xxx') + .set( + apiListItem.version ? 'Elastic-Api-Version' : 'foo', + apiListItem.version || '2023-10-31' + ) + .set(samlAuth.getInternalRequestHeader()) .send(getBodyPayload(apiListItem)) .expect(200); }); @@ -283,6 +295,11 @@ export default function ({ getService }: FtrProviderContext) { await endpointOperationsAnalystSupertest[apiListItem.method]( replacePathIds(apiListItem.path) ) + .set( + apiListItem.version ? 'Elastic-Api-Version' : 'foo', + apiListItem.version || '2023-10-31' + ) + .set(samlAuth.getInternalRequestHeader()) .set('kbn-xsrf', 'xxx') .send(getBodyPayload(apiListItem)) .expect(200); @@ -304,6 +321,11 @@ export default function ({ getService }: FtrProviderContext) { }]`, async () => { await adminSupertest[apiListItem.method](replacePathIds(apiListItem.path)) .set('kbn-xsrf', 'xxx') + .set( + apiListItem.version ? 'Elastic-Api-Version' : 'foo', + apiListItem.version || '2023-10-31' + ) + .set(samlAuth.getInternalRequestHeader()) .send(getBodyPayload(apiListItem)) .expect(200); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/edr_workflows/metadata/trial_license_complete_tier/metadata.ts b/x-pack/test/security_solution_api_integration/test_suites/edr_workflows/metadata/trial_license_complete_tier/metadata.ts index 8dac3bfe66784..ee4ee09bbdad6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/edr_workflows/metadata/trial_license_complete_tier/metadata.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/edr_workflows/metadata/trial_license_complete_tier/metadata.ts @@ -13,12 +13,12 @@ import { ENDPOINT_DEFAULT_SORT_FIELD, HOST_METADATA_LIST_ROUTE, METADATA_DATASTREAM, - METADATA_TRANSFORMS_STATUS_ROUTE, METADATA_UNITED_INDEX, METADATA_UNITED_TRANSFORM, METADATA_UNITED_TRANSFORM_V2, metadataTransformPrefix, METADATA_CURRENT_TRANSFORM_V2, + METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, } from '@kbn/security-solution-plugin/common/endpoint/constants'; import { AGENTS_INDEX } from '@kbn/fleet-plugin/common'; import { indexFleetEndpointPolicy } from '@kbn/security-solution-plugin/common/endpoint/data_loaders/index_fleet_endpoint_policy'; @@ -426,9 +426,9 @@ export default function ({ getService }: FtrProviderContext) { const ca = config.get('servers.kibana').certificateAuthorities; await t1AnalystSupertest - .get(METADATA_TRANSFORMS_STATUS_ROUTE) + .get(METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE) .set('kbn-xsrf', 'xxx') - .set('Elastic-Api-Version', '2023-10-31') + .set('Elastic-Api-Version', '1') .ca(ca) .expect(401); }); @@ -438,9 +438,9 @@ export default function ({ getService }: FtrProviderContext) { await endpointDataStreamHelpers.stopTransform(getService, `${unitedTransformName}*`); const { body } = await adminSupertest - .get(METADATA_TRANSFORMS_STATUS_ROUTE) + .get(METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE) .set('kbn-xsrf', 'xxx') - .set('Elastic-Api-Version', '2023-10-31') + .set('Elastic-Api-Version', '1') .expect(200); const transforms = (body.transforms as TransformGetTransformStatsTransformStats[]).filter( @@ -466,9 +466,9 @@ export default function ({ getService }: FtrProviderContext) { it('correctly returns started transform stats', async () => { const { body } = await adminSupertest - .get(METADATA_TRANSFORMS_STATUS_ROUTE) + .get(METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE) .set('kbn-xsrf', 'xxx') - .set('Elastic-Api-Version', '2023-10-31') + .set('Elastic-Api-Version', '1') .expect(200); const transforms = (body.transforms as TransformGetTransformStatsTransformStats[]).filter( From 32c1bb2e094806c34ef8b7a21e6520c2792aef77 Mon Sep 17 00:00:00 2001 From: "elastic-renovate-prod[bot]" <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 12:35:09 +0200 Subject: [PATCH 053/110] Update dependency elastic-apm-node to ^4.8.0 (main) (#195446) Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 02b7f61924abb..f699668ca55b5 100644 --- a/package.json +++ b/package.json @@ -1099,7 +1099,7 @@ "del": "^6.1.0", "diff": "^5.1.0", "dotenv": "^16.4.5", - "elastic-apm-node": "^4.7.3", + "elastic-apm-node": "^4.8.0", "email-addresses": "^5.0.0", "eventsource-parser": "^1.1.1", "execa": "^5.1.1", diff --git a/yarn.lock b/yarn.lock index c3ec4698df7d2..455ed178b85b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14869,7 +14869,7 @@ cookie-signature@1.0.6: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= -cookie@0.6.0, cookie@^0.6.0: +cookie@0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== @@ -14879,6 +14879,11 @@ cookie@^0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== + cookiejar@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" @@ -16668,10 +16673,10 @@ elastic-apm-node@3.46.0: traverse "^0.6.6" unicode-byte-truncate "^1.0.0" -elastic-apm-node@^4.7.3: - version "4.7.3" - resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-4.7.3.tgz#d819a9030f7321cc858c788f60b383de85461f24" - integrity sha512-x+cQKrXSCz6JgoTFAiBpLlC85ruqZ7sAl+jAS3+DeSmc6ZXLRTwTa2ay2PCGv3DxGLZjVZ+ItzGdHTj5B7PYKg== +elastic-apm-node@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-4.8.0.tgz#10d17c3bbd127b8bab9cb264750936a81b4339ad" + integrity sha512-XEfkWWQlIyv72QTCgScFzXWYM2znm/mA+6I8e2DMmr3lBdwemOTxBZw9jExu4OQ2uMc+Ld8wc5bbikkAYp4nng== dependencies: "@elastic/ecs-pino-format" "^1.5.0" "@opentelemetry/api" "^1.4.1" @@ -16682,7 +16687,7 @@ elastic-apm-node@^4.7.3: async-value-promise "^1.1.1" basic-auth "^2.0.1" breadth-filter "^2.0.0" - cookie "^0.6.0" + cookie "^0.7.1" core-util-is "^1.0.2" end-of-stream "^1.4.4" error-callsites "^2.0.4" @@ -16691,7 +16696,7 @@ elastic-apm-node@^4.7.3: fast-safe-stringify "^2.0.7" fast-stream-to-buffer "^1.0.0" http-headers "^3.0.2" - import-in-the-middle "1.11.0" + import-in-the-middle "1.11.2" json-bigint "^1.0.0" lru-cache "10.2.0" measured-reporting "^1.51.1" @@ -20113,10 +20118,10 @@ import-fresh@^3.1.0, import-fresh@^3.2.1, import-fresh@^3.3.0: parent-module "^1.0.0" resolve-from "^4.0.0" -import-in-the-middle@1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.11.0.tgz#a94c4925b8da18256cde3b3b7b38253e6ca5e708" - integrity sha512-5DimNQGoe0pLUHbR9qK84iWaWjjbsxiqXnw6Qz64+azRgleqv9k2kTt5fw7QsOpmaGYtuxxursnPPsnTKEx10Q== +import-in-the-middle@1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.11.2.tgz#dd848e72b63ca6cd7c34df8b8d97fc9baee6174f" + integrity sha512-gK6Rr6EykBcc6cVWRSBR5TWf8nn6hZMYSRYqCcHa0l0d1fPK7JSYo6+Mlmck76jIX9aL/IZ71c06U2VpFwl1zA== dependencies: acorn "^8.8.2" acorn-import-attributes "^1.9.5" From 637d796071f067f8cab37165dd8f80111251ae81 Mon Sep 17 00:00:00 2001 From: Ilya Nikokoshev Date: Wed, 9 Oct 2024 15:24:00 +0300 Subject: [PATCH 054/110] [Auto Import] Improve the ECS mapping extraction logic (#195167) ## Release Notes Automatic Import is more forgiving if an LLM returns an ECS mapping in a slightly unexpected format. ## Summary When implementing https://github.com/elastic/kibana/pull/194386 an issue has been encountered where Claude returns the field name `date_format` instead of expected `date_formats` and the ECS chain breaks down. We add this case as a test to `x-pack/plugins/integration_assistant/server/graphs/ecs/validate.test`. Without the changes in this PR the list returned by `findInvalidEcsFields` is ``` [ 'Reserved ECS field mapping identified for event.created : ai_postgres_202410050058.logs.column1.target', 'Invalid ECS field mapping identified for 0.9 : ai_postgres_202410050058.logs.column1.confidence, ai_postgres_202410050058.logs.column5.confidence', 'Invalid ECS field mapping identified for date : ai_postgres_202410050058.logs.column1.type, ai_postgres_202410050058.logs.column9.type', 'Invalid ECS field mapping identified for 0.95 : ai_postgres_202410050058.logs.column12.confidence', 'Invalid ECS field mapping identified for string : ai_postgres_202410050058.logs.column12.type, ai_postgres_202410050058.logs.column14.type, ai_postgres_202410050058.logs.column24.type, ai_postgres_202410050058.logs.column5.type, ai_postgres_202410050058.logs.column3.type, ai_postgres_202410050058.logs.column2.type', 'Invalid ECS field mapping identified for 0.8 : ai_postgres_202410050058.logs.column9.confidence, ai_postgres_202410050058.logs.column3.confidence', 'Invalid ECS field mapping identified for 0.7 : ai_postgres_202410050058.logs.column14.confidence, ai_postgres_202410050058.logs.column2.confidence', 'Invalid ECS field mapping identified for 0.85 : ai_postgres_202410050058.logs.column24.confidence' ] ``` while with these changes the result does not contain any `Invalid ECS field` messages. The key changes are in the `processMapping` function: 1. We made function more forgiving in regards to the input, accepting `date_format` in lieu of `date_formats`. 2. We have removed the collection of "other paths", that is, the reverse index for simple values like `0.8`. The latter change generally limits the impact of any other format issues in the ECS mapping in the future. Additionally, the function has been renamed to `extractECSMapping`, its output type validated, and documentation has been added. --------- Co-authored-by: Elastic Machine --- .../server/graphs/ecs/validate.test.ts | 110 +++++++++++++++- .../server/graphs/ecs/validate.ts | 119 +++++++++++++----- 2 files changed, 193 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.test.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.test.ts index a7fb5962b5558..39c4e3ac4bab3 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.test.ts @@ -8,14 +8,14 @@ import { ECS_RESERVED } from './constants'; import { + extractECSMapping, findDuplicateFields, findInvalidEcsFields, - processMapping, removeReservedFields, } from './validate'; describe('Testing ecs handler', () => { - it('processMapping()', async () => { + it('extractECSMapping()', async () => { const path: string[] = []; const value = { checkpoint: { @@ -50,7 +50,7 @@ describe('Testing ecs handler', () => { }, }; const output: Record = {}; - await processMapping(path, value, output); + await extractECSMapping(path, value, output); expect(output).toEqual({ 'source.address': [['checkpoint', 'firewall', 'origin']], 'user.name': [['checkpoint', 'firewall', 'administrator']], @@ -96,6 +96,110 @@ describe('findInvalidEcsFields', () => { const invalid = findInvalidEcsFields(ecsMappingReserved); expect(invalid.length).toBe(1); }); + + it('invalid: date_format fields (natural example)', async () => { + const misspelledDateFormatMapping = { + ai_postgres_202410050058: { + logs: { + column1: { + target: 'event.created', + confidence: 0.9, + type: 'date', + date_format: ['yyyy-MM-dd HH:mm:ss.SSS z'], + }, + column12: { + target: 'log.level', + confidence: 0.95, + type: 'string', + date_format: [], + }, + column11: null, + column4: null, + column9: { + target: 'event.start', + confidence: 0.8, + type: 'date', + date_format: ['yyyy-MM-dd HH:mm:ss z'], + }, + column7: null, + column6: null, + column14: { + target: 'event.reason', + confidence: 0.7, + type: 'string', + date_format: [], + }, + column13: null, + column24: { + target: 'process.name', + confidence: 0.85, + type: 'string', + date_format: [], + }, + column23: null, + column10: null, + column5: { + target: 'source.address', + confidence: 0.9, + type: 'string', + date_format: [], + }, + column3: { + target: 'user.name', + confidence: 0.8, + type: 'string', + date_format: [], + }, + column2: { + target: 'destination.user.name', + confidence: 0.7, + type: 'string', + date_format: [], + }, + column8: null, + }, + }, + }; + + const invalid = findInvalidEcsFields(misspelledDateFormatMapping); + expect(invalid.length).toBe(1); + }); + + it('invalid: date_format fields (handcrafted example)', async () => { + const mixedMapping = { + some_title: { + logs: { + column1: { + target: 'event.created', + confidence: 0.9, + type: 'date', + date_format: ['yyyy-MM-dd HH:mm:ss.SSS z'], + }, + column12: { + target: 'log.level', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + column11: null, + column4: null, + column9: { + target: 'event.start', + confidence: 0.8, + type: 'date', + date_format: 'yyyy-MM-dd HH:mm:ss z', + }, + column2: { + target: 'destination.user.name', + type: 'string', + date_format: [], + }, + }, + }, + }; + const invalid = findInvalidEcsFields(mixedMapping); + expect(invalid.length).toBe(1); + }); }); describe('findDuplicateFields', () => { diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts index 62f88f2d234f2..033c6651982ea 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts @@ -10,7 +10,6 @@ import { mergeSamples } from '../../util/samples'; import { ECS_RESERVED } from './constants'; import type { EcsBaseNodeParams } from './types'; -const valueFieldKeys = new Set(['target', 'confidence', 'date_formats', 'type']); type AnyObject = Record; function extractKeys(data: AnyObject, prefix: string = ''): Set { @@ -46,43 +45,97 @@ function findMissingFields(combinedSamples: string, ecsMapping: AnyObject): stri return missingKeys; } -export function processMapping( +// Describes an LLM-generated ECS mapping candidate. +interface ECSFieldTarget { + target: string; + type: string; + confidence: number; + date_formats: string[]; +} + +/** + * Parses a given object as an ECSFieldTarget object if it meets the required structure. + * + * @param value - The value to be converted to an ECSMapping object. It should be an object + * with properties `target` and `type`. It should have `confidence` field and + * either `date_formats` or `date_format`, though we also fill in these otherwise. + * @returns An ECSFieldTarget object if the conversion succeeded, otherwise null. + */ +function asECSFieldTarget(value: any): ECSFieldTarget | null { + if (value === null || typeof value !== 'object' || Array.isArray(value)) { + return null; + } + + if ( + value.target && + typeof value.target === 'string' && + value.type && + typeof value.type === 'string' + ) { + let confidence = 0.5; + if (value.confidence && typeof value.confidence === 'number') { + confidence = value.confidence; + } + let dateFormats: string[] = []; + if (value.date_formats && Array.isArray(value.date_formats)) { + dateFormats = value.date_formats; + } else if (value.date_format && Array.isArray(value.date_format)) { + dateFormats = value.date_format; + } else if (value.date_format && typeof value.date_format === 'string') { + dateFormats = [value.date_format]; + } + return { + target: value.target, + type: value.type, + confidence, + date_formats: dateFormats, + }; + } + + return null; +} + +/** + * Extracts ECS (Elastic Common Schema) field mapping dictionary from the LLM output. + * + * @param path - The current path in the object being traversed (an array of strings). + * @param value - The value to be processed, which can be an array, object, or other types. + * @param output - A record where the extracted ECS mappings will be stored. The keys are ECS targets, and the values are arrays of paths. + * + * This function recursively traverses the provided value. If the value is an array, it processes each item in the array. + * If the value can be interpreted as an ECS mapping, it adds the path to the output record under the appropriate ECS target. + * If the value is a regular object, it continues traversing its properties. + */ +export function extractECSMapping( path: string[], value: any, output: Record ): void { - if (typeof value === 'object' && value !== null) { - if (!Array.isArray(value)) { - // If the value is a dict with all the keys returned for each source field, this is the full path of the field. - const valueKeys = new Set(Object.keys(value)); - - if ([...valueFieldKeys].every((k) => valueKeys.has(k))) { - if (value?.target !== null) { - if (!output[value?.target]) { - output[value.target] = []; - } - output[value.target].push(path); - } - } else { - // Regular dictionary, continue traversing - for (const [k, v] of Object.entries(value)) { - processMapping([...path, k], v, output); - } - } - } else { - // If the value is an array, iterate through items and process them - for (const item of value) { - if (typeof item === 'object' && item !== null) { - processMapping(path, item, output); - } + if (Array.isArray(value)) { + // If the value is an array, iterate through items and process them. + for (const item of value) { + if (typeof item === 'object' && item !== null) { + extractECSMapping(path, item, output); } } - } else if (value !== null) { - // Direct value, accumulate path - if (!output[value]) { - output[value] = []; + return; + } + + const ecsFieldTarget = asECSFieldTarget(value); + if (ecsFieldTarget) { + // If we can interpret the value as an ECSFieldTarget. + if (!output[ecsFieldTarget.target]) { + output[ecsFieldTarget.target] = []; + } + output[ecsFieldTarget.target].push(path); + return; + } + + if (typeof value === 'object' && value !== null) { + // Regular dictionary, continue traversing. + for (const [k, v] of Object.entries(value)) { + extractECSMapping([...path, k], v, output); } - output[value].push(path); } } @@ -96,7 +149,7 @@ export function findDuplicateFields(prefixedSamples: string[], ecsMapping: AnyOb const output: Record = {}; // Get all keys for each target ECS mapping field - processMapping([], ecsMapping, output); + extractECSMapping([], ecsMapping, output); // Filter out any ECS field that does not have multiple source fields mapped to it const filteredOutput = Object.fromEntries( @@ -138,7 +191,7 @@ export function findInvalidEcsFields(currentMapping: AnyObject): string[] { const ecsDict = ECS_FULL; const ecsReserved = ECS_RESERVED; - processMapping([], currentMapping, output); + extractECSMapping([], currentMapping, output); const filteredOutput = Object.fromEntries( Object.entries(output).filter(([key, _]) => key !== null) ); From a406acba31ed05588ae21eed5d380722e32fbbb0 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Wed, 9 Oct 2024 14:24:31 +0200 Subject: [PATCH 055/110] [ML] Fix assertion in the Trained Model UI tests (#195566) ## Summary Removes assertions for success toast messages that were deleted in https://github.com/elastic/kibana/pull/194614 ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- x-pack/test/functional/services/ml/trained_models_table.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/x-pack/test/functional/services/ml/trained_models_table.ts b/x-pack/test/functional/services/ml/trained_models_table.ts index 941308b61c328..8818df749ccd4 100644 --- a/x-pack/test/functional/services/ml/trained_models_table.ts +++ b/x-pack/test/functional/services/ml/trained_models_table.ts @@ -572,9 +572,6 @@ export function TrainedModelsTableProvider( await mlCommonUI.waitForRefreshButtonEnabled(); - await mlCommonUI.assertLastToastHeader( - `Deployment for "${modelId}" has been started successfully.` - ); await this.waitForModelsToLoad(); await retry.tryForTime( @@ -600,10 +597,6 @@ export function TrainedModelsTableProvider( public async stopDeployment(modelId: string) { await this.clickStopDeploymentAction(modelId); await mlCommonUI.waitForRefreshButtonEnabled(); - await mlCommonUI.assertLastToastHeader( - `Deployment for "${modelId}" has been stopped successfully.` - ); - await mlCommonUI.waitForRefreshButtonEnabled(); } public async openStartDeploymentModal(modelId: string) { From d0fb00439948f40d31145deb2e00dcc933c75381 Mon Sep 17 00:00:00 2001 From: Jill Guyonnet Date: Wed, 9 Oct 2024 13:51:25 +0100 Subject: [PATCH 056/110] [Fleet] Update tooltip for disabled add integration button (#195552) ## Summary Closes https://github.com/elastic/kibana/issues/191569 With the introduction of Fleet sub-feature privileges, the user needs at least `Agent policies: all` and `Integrations: All` privileges to add integrations. This PR updates the tooltip for when the button is disabled accordingly. ### Steps to reproduce 1. Create a role with `None` privilege on all Fleet sub-features (or any combination without `All` on Agent policies) and `All` on Integrations. Screenshot 2024-10-09 at 11 32 56 2. Assign the role to a test user and log in with it. 3. Attempt to add an integration. The button should be disabled and the tooltip should say that `Agent policies: all` and `Integrations: All` privileges are needed. Screenshot 2024-10-09 at 11 30 40 --- .../components/package_policies/package_policies_table.tsx | 2 +- .../epm/screens/detail/components/add_integration_button.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx index ed9805fb5f75a..83e18d77f2a06 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx @@ -426,7 +426,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ ) : ( ), } diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/components/add_integration_button.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/components/add_integration_button.tsx index f2ec544922b47..8ff7f3e7d5ec3 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/components/add_integration_button.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/components/add_integration_button.tsx @@ -32,7 +32,7 @@ export function AddIntegrationButton(props: AddIntegrationButtonProps) { ) : ( ), } From 2609a533fa950b9e7974d704fa0c3f9986816dbe Mon Sep 17 00:00:00 2001 From: seanrathier Date: Wed, 9 Oct 2024 08:52:03 -0400 Subject: [PATCH 057/110] [Cloud Security] Render Setup Technology Selector based on deployment mode (#194347) --- .../common/constants.ts | 2 +- .../fleet_extensions/policy_template_form.tsx | 7 ++ .../policy_template_selectors.tsx | 6 +- .../use_setup_technology.ts | 3 +- .../single_page_layout/index.tsx | 4 +- .../edit_package_policy_page/index.tsx | 7 +- .../agentless/index.ts | 16 ++++ .../agentless/security_posture.ts | 87 +++++++++++++++++++ .../config.agentless.ts | 5 +- .../add_cis_integration_form_page.ts | 22 +++++ .../agentless/cis_integration_aws.ts | 28 ------ .../agentless/cis_integration_gcp.ts | 24 ----- 12 files changed, 150 insertions(+), 61 deletions(-) create mode 100644 x-pack/test/cloud_security_posture_functional/agentless/index.ts create mode 100644 x-pack/test/cloud_security_posture_functional/agentless/security_posture.ts diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts index d415d4cfcfc69..474f29b859305 100644 --- a/x-pack/plugins/cloud_security_posture/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/common/constants.ts @@ -171,4 +171,4 @@ export const SINGLE_ACCOUNT = 'single-account'; export const CLOUD_SECURITY_PLUGIN_VERSION = '1.9.0'; // Cloud Credentials Template url was implemented in 1.10.0-preview01. See PR - https://github.com/elastic/integrations/pull/9828 -export const CLOUD_CREDENTIALS_PACKAGE_VERSION = '1.10.0-preview01'; +export const CLOUD_CREDENTIALS_PACKAGE_VERSION = '1.11.0-preview10'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 721c4ca147aee..73d8ed22011dc 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -674,6 +674,7 @@ export const CspPolicyTemplateForm = memo ({ id: v, label: getPolicyTemplateLabel(v) }))} + options={Array.from(policyTemplates, (v) => ({ + id: v, + label: getPolicyTemplateLabel(v), + testId: `policy-template-radio-button-${v}`, + }))} idSelected={selectedTemplate} onChange={(id: CloudSecurityPolicyTemplate) => setPolicyTemplate(id)} disabled={disabled} diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts index 8b6a190827f2e..e18119c3a39de 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts @@ -27,7 +27,8 @@ export const useSetupTechnology = ({ const isAgentlessSupportedForCloudProvider = isCspmAws || isCspmGcp || isCspmAzure; const isAgentlessAvailable = isAgentlessSupportedForCloudProvider && isAgentlessEnabled; const defaultSetupTechnology = - isEditPage && isAgentlessEnabled ? SetupTechnology.AGENTLESS : SetupTechnology.AGENT_BASED; + isEditPage && isAgentlessAvailable ? SetupTechnology.AGENTLESS : SetupTechnology.AGENT_BASED; + const [setupTechnology, setSetupTechnology] = useState(defaultSetupTechnology); const updateSetupTechnology = (value: SetupTechnology) => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index 3070b0961ab6d..24f8fa8a04fe5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -350,7 +350,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ "'package-policy-create' and 'package-policy-replace-define-step' cannot both be registered as UI extensions" ); } - const { isAgentlessEnabled, isAgentlessIntegration } = useAgentless(); + const { isAgentlessIntegration } = useAgentless(); const { handleSetupTechnologyChange, selectedSetupTechnology } = useSetupTechnology({ newAgentPolicy, setNewAgentPolicy, @@ -374,7 +374,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ validationResults={validationResults} isEditPage={false} handleSetupTechnologyChange={handleSetupTechnologyChange} - isAgentlessEnabled={isAgentlessEnabled} + isAgentlessEnabled={isAgentlessIntegration(packageInfo)} /> ) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index e448d1376b2fe..6157f09968680 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -103,7 +103,7 @@ export const EditPackagePolicyForm = memo<{ } = useConfig(); const { getHref } = useLink(); const { canUseMultipleAgentPolicies } = useMultipleAgentPolicies(); - const { isAgentlessAgentPolicy } = useAgentless(); + const { isAgentlessAgentPolicy, isAgentlessIntegration } = useAgentless(); const { // data agentPolicies: existingAgentPolicies, @@ -130,9 +130,10 @@ export const EditPackagePolicyForm = memo<{ const hasAgentlessAgentPolicy = useMemo( () => existingAgentPolicies.length === 1 - ? existingAgentPolicies.some((policy) => isAgentlessAgentPolicy(policy)) + ? existingAgentPolicies.some((policy) => isAgentlessAgentPolicy(policy)) && + isAgentlessIntegration(packageInfo) : false, - [existingAgentPolicies, isAgentlessAgentPolicy] + [existingAgentPolicies, isAgentlessAgentPolicy, packageInfo, isAgentlessIntegration] ); const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies; diff --git a/x-pack/test/cloud_security_posture_functional/agentless/index.ts b/x-pack/test/cloud_security_posture_functional/agentless/index.ts new file mode 100644 index 0000000000000..02f10dc5cc348 --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/agentless/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Cloud Security Posture', function () { + loadTestFile(require.resolve('./create_agent')); + loadTestFile(require.resolve('./security_posture')); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/agentless/security_posture.ts b/x-pack/test/cloud_security_posture_functional/agentless/security_posture.ts new file mode 100644 index 0000000000000..c7ee5ff8400e6 --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/agentless/security_posture.ts @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../ftr_provider_context'; +// eslint-disable-next-line import/no-default-export +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects([ + 'common', + 'cspSecurity', + 'security', + 'header', + 'cisAddIntegration', + ]); + + const KSPM_RADIO_OPTION = 'policy-template-radio-button-kspm'; + const CSPM_RADIO_OPTION = 'policy-template-radio-button-cspm'; + const CNVM_RADIO_OPTION = 'policy-template-radio-button-vuln_mgmt'; + + const POLICY_NAME_FIELD = 'createAgentPolicyNameField'; + const SETUP_TECHNOLOGY_SELECTOR = 'setup-technology-selector-accordion'; + + describe('Agentless Security Posture Integration Options', function () { + let cisIntegration: typeof pageObjects.cisAddIntegration; + + before(async () => { + cisIntegration = pageObjects.cisAddIntegration; + }); + + after(async () => { + await pageObjects.cspSecurity.logout(); + }); + + it(`should show kspm without agentless option`, async () => { + await cisIntegration.navigateToAddIntegrationWithVersionPage( + CLOUD_CREDENTIALS_PACKAGE_VERSION + ); + + await cisIntegration.clickOptionButton(KSPM_RADIO_OPTION); + await pageObjects.header.waitUntilLoadingHasFinished(); + + const hasSetupTechnologySelector = await testSubjects.exists(SETUP_TECHNOLOGY_SELECTOR); + const hasAgentBased = await testSubjects.exists(POLICY_NAME_FIELD); + + expect(hasSetupTechnologySelector).to.be(false); + expect(hasAgentBased).to.be(true); + }); + + it(`should show cnvm without agentless option`, async () => { + // const integrationPolicyName = `cloud_security_posture-${new Date().toISOString()}`; + await cisIntegration.navigateToAddIntegrationWithVersionPage( + CLOUD_CREDENTIALS_PACKAGE_VERSION + ); + + await cisIntegration.clickOptionButton(CNVM_RADIO_OPTION); + await pageObjects.header.waitUntilLoadingHasFinished(); + + const hasSetupTechnologySelector = await testSubjects.exists(SETUP_TECHNOLOGY_SELECTOR); + const hasAgentBased = await testSubjects.exists(POLICY_NAME_FIELD); + + expect(hasSetupTechnologySelector).to.be(false); + expect(hasAgentBased).to.be(true); + }); + + it(`should show cspm with agentless option`, async () => { + // const integrationPolicyName = `cloud_security_posture-${new Date().toISOString()}`; + await cisIntegration.navigateToAddIntegrationWithVersionPage( + CLOUD_CREDENTIALS_PACKAGE_VERSION + ); + + await cisIntegration.clickOptionButton(CSPM_RADIO_OPTION); + await pageObjects.header.waitUntilLoadingHasFinished(); + + const hasSetupTechnologySelector = await testSubjects.exists(SETUP_TECHNOLOGY_SELECTOR); + const hasAgentBased = await testSubjects.exists(POLICY_NAME_FIELD); + + expect(hasSetupTechnologySelector).to.be(true); + expect(hasAgentBased).to.be(true); + }); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/config.agentless.ts b/x-pack/test/cloud_security_posture_functional/config.agentless.ts index 341ef6a9905b7..498de6d888223 100644 --- a/x-pack/test/cloud_security_posture_functional/config.agentless.ts +++ b/x-pack/test/cloud_security_posture_functional/config.agentless.ts @@ -7,6 +7,7 @@ import type { FtrConfigProviderContext } from '@kbn/test'; import { CA_CERT_PATH, KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils'; +import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; import { pageObjects } from './page_objects'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { @@ -30,9 +31,11 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--xpack.fleet.agentless.api.tls.key=${KBN_KEY_PATH}`, `--xpack.fleet.agentless.api.tls.ca=${CA_CERT_PATH}`, `--xpack.cloud.id=something-anything`, + `--xpack.fleet.packages.0.name=cloud_security_posture`, + `--xpack.fleet.packages.0.version=${CLOUD_CREDENTIALS_PACKAGE_VERSION}`, ], }, // load tests in the index file - testFiles: [require.resolve('./agentless/create_agent.ts')], + testFiles: [require.resolve('./agentless')], }; } diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts index e3ef420055196..563507d705583 100644 --- a/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts +++ b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts @@ -154,6 +154,27 @@ export function AddCisIntegrationFormPageProvider({ await PageObjects.header.waitUntilLoadingHasFinished(); }; + const navigateToAddIntegrationWithVersionPage = async ( + packageVersion: string, + space?: string + ) => { + const options = space + ? { + basePath: `/s/${space}`, + shouldUseHashForSubUrl: false, + } + : { + shouldUseHashForSubUrl: false, + }; + + await PageObjects.common.navigateToUrl( + 'fleet', + `integrations/cloud_security_posture-${packageVersion}/add-integration`, + options + ); + await PageObjects.header.waitUntilLoadingHasFinished(); + }; + const navigateToAddIntegrationCspmWithVersionPage = async ( packageVersion: string, space?: string @@ -505,6 +526,7 @@ export function AddCisIntegrationFormPageProvider({ cisAzure, cisAws, cisGcp, + navigateToAddIntegrationWithVersionPage, navigateToAddIntegrationCspmPage, navigateToAddIntegrationCspmWithVersionPage, navigateToAddIntegrationCnvmPage, diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts index 90991304936ea..e669545d135f9 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts @@ -27,7 +27,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { let cisIntegrationAws: typeof pageObjects.cisAddIntegration.cisAws; let testSubjectIds: typeof pageObjects.cisAddIntegration.testSubjectIds; let mockApiServer: http.Server; - const previousPackageVersion = '1.9.0'; before(async () => { mockApiServer = mockAgentlessApiService.listen(8089); @@ -66,20 +65,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { (await cisIntegrationAws.showLaunchCloudFormationAgentlessButton()) !== undefined ).to.be(true); }); - - it(`should hide CIS_AWS Launch Cloud formation button when credentials selector is temporary keys and package version is less than ${previousPackageVersion}`, async () => { - await cisIntegration.navigateToAddIntegrationCspmWithVersionPage(previousPackageVersion); - - await cisIntegration.clickOptionButton(testSubjectIds.CIS_AWS_OPTION_TEST_ID); - await cisIntegration.clickOptionButton(testSubjectIds.AWS_SINGLE_ACCOUNT_TEST_ID); - await cisIntegration.selectSetupTechnology('agentless'); - - await cisIntegration.selectAwsCredentials('temporary'); - - await pageObjects.header.waitUntilLoadingHasFinished(); - - expect(await cisIntegrationAws.showLaunchCloudFormationAgentlessButton()).to.be(false); - }); }); describe('Serverless - Agentless CIS_AWS ORG Account Launch Cloud formation', () => { @@ -100,19 +85,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(await cisIntegrationAws.showLaunchCloudFormationAgentlessButton()).to.be(true); }); - - it(`should hide CIS_AWS Launch Cloud formation button when credentials selector is temporary keys and package version is less than ${previousPackageVersion}`, async () => { - await cisIntegration.navigateToAddIntegrationCspmWithVersionPage(previousPackageVersion); - - await cisIntegration.clickOptionButton(testSubjectIds.CIS_AWS_OPTION_TEST_ID); - await cisIntegration.selectSetupTechnology('agentless'); - - await cisIntegration.selectAwsCredentials('temporary'); - - await pageObjects.header.waitUntilLoadingHasFinished(); - - expect(await cisIntegrationAws.showLaunchCloudFormationAgentlessButton()).to.be(false); - }); }); // TODO: Migrate test after Serverless default agentless policy is deleted. diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts index 85a45f67bf9cc..95f855697c5bd 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts @@ -14,7 +14,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const pageObjects = getPageObjects(['common', 'svlCommonPage', 'cisAddIntegration', 'header']); const supertest = getService('supertest'); - const previousPackageVersion = '1.9.0'; describe('Agentless CIS Integration Page', function () { // TODO: we need to check if the tests are running on MKI. There is a suspicion that installing csp package via Kibana server args is not working on MKI. @@ -60,18 +59,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(await cisIntegrationGcp.showLaunchCloudShellAgentlessButton()).to.be(true); }); - - it(`should hide CIS_GCP Launch Cloud Shell button when package version is less than ${CLOUD_CREDENTIALS_PACKAGE_VERSION}`, async () => { - await cisIntegration.navigateToAddIntegrationCspmWithVersionPage(previousPackageVersion); - - await cisIntegration.clickOptionButton(testSubjectIds.CIS_GCP_OPTION_TEST_ID); - await cisIntegration.clickOptionButton(testSubjectIds.GCP_SINGLE_ACCOUNT_TEST_ID); - await cisIntegration.selectSetupTechnology('agentless'); - - await pageObjects.header.waitUntilLoadingHasFinished(); - - expect(await cisIntegrationGcp.showLaunchCloudShellAgentlessButton()).to.be(false); - }); }); describe('Agentless CIS_GCP ORG Account Launch Cloud Shell', () => { @@ -87,17 +74,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(await cisIntegrationGcp.showLaunchCloudShellAgentlessButton()).to.be(true); }); - - it(`should hide CIS_GCP Launch Cloud shell button when package version is ${previousPackageVersion}`, async () => { - await cisIntegration.navigateToAddIntegrationCspmWithVersionPage(previousPackageVersion); - - await cisIntegration.clickOptionButton(testSubjectIds.CIS_GCP_OPTION_TEST_ID); - await cisIntegration.selectSetupTechnology('agentless'); - - await pageObjects.header.waitUntilLoadingHasFinished(); - - expect(await cisIntegrationGcp.showLaunchCloudShellAgentlessButton()).to.be(false); - }); }); describe.skip('Serverless - Agentless CIS_GCP edit flow', () => { From fbf3f8b8b24575bd9fdc10e05ed0e5032a1a4340 Mon Sep 17 00:00:00 2001 From: Jordan <51442161+JordanSh@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:18:33 +0300 Subject: [PATCH 058/110] [Cloud Security] Fix vulnerability detection rule creation logic (#195291) --- .../index.ts | 5 +- .../latest_vulnerabilities_table.tsx | 6 +- ..._detection_rule_from_vulnerability.test.ts | 98 +++++++++++++++++++ ...reate_detection_rule_from_vulnerability.ts | 42 +++++--- .../vulnerability_detection_rule_counter.tsx | 33 ++----- .../vulnerability_finding_flyout.tsx | 2 +- 6 files changed, 142 insertions(+), 44 deletions(-) create mode 100644 x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts diff --git a/x-pack/packages/kbn-cloud-security-posture-common/index.ts b/x-pack/packages/kbn-cloud-security-posture-common/index.ts index e01401f37ef23..d5ee781c39b20 100644 --- a/x-pack/packages/kbn-cloud-security-posture-common/index.ts +++ b/x-pack/packages/kbn-cloud-security-posture-common/index.ts @@ -18,7 +18,10 @@ export type { CspSetupStatus, } from './types/status'; export type { CspFinding, CspFindingResult } from './types/findings'; -export type { CspVulnerabilityFinding } from './schema/vulnerabilities/csp_vulnerability_finding'; +export type { + CspVulnerabilityFinding, + Vulnerability, +} from './schema/vulnerabilities/csp_vulnerability_finding'; export type { BenchmarksCisId } from './types/benchmark'; export type { VulnSeverity } from './types/vulnerabilities'; export * from './constants'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx index 09c2989c1eb23..e8dde902a9f46 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx @@ -108,11 +108,11 @@ export const LatestVulnerabilitiesTable = ({ }); const createVulnerabilityRuleFn = (rowIndex: number) => { - const finding = getCspVulnerabilityFinding(rows[rowIndex].raw._source); - if (!finding) return; + const vulnerabilityFinding = getCspVulnerabilityFinding(rows[rowIndex].raw._source); + if (!vulnerabilityFinding) return; return async (http: HttpSetup) => - createDetectionRuleFromVulnerabilityFinding(http, finding.vulnerability); + createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityFinding); }; return ( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts new file mode 100644 index 0000000000000..209ec81168271 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + getVulnerabilityTags, + getVulnerabilityRuleName, + generateVulnerabilitiesRuleQuery, +} from './create_detection_rule_from_vulnerability'; +import { CspVulnerabilityFinding, Vulnerability } from '@kbn/cloud-security-posture-common'; +import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding'; + +// Mocking the isNativeCspFinding function +jest.mock('../../../common/utils/is_native_csp_finding', () => ({ + isNativeCspFinding: jest.fn(), +})); + +describe('CreateDetectionRuleFromVulnerability', () => { + describe('getVulnerabilityTags', () => { + it('should return tags with CSP_RULE_TAG and vulnerability id', () => { + const mockVulnerability = { + vulnerability: { id: 'CVE-2024-00001' }, + observer: undefined, + data_stream: undefined, + } as unknown as CspVulnerabilityFinding; + + (isNativeCspFinding as jest.Mock).mockReturnValue(false); + + const tags = getVulnerabilityTags(mockVulnerability); + expect(tags).toEqual(['Cloud Security', 'CVE-2024-00001']); + }); + + it('should include vendor tag if available', () => { + const mockVulnerability = { + vulnerability: { id: 'CVE-2024-00002' }, + observer: { vendor: 'Wiz' }, + data_stream: undefined, + } as unknown as CspVulnerabilityFinding; + + (isNativeCspFinding as jest.Mock).mockReturnValue(false); + + const tags = getVulnerabilityTags(mockVulnerability); + expect(tags).toEqual(['Cloud Security', 'CVE-2024-00002', 'Wiz']); + }); + + it('should include CNVM tags for native findings', () => { + const mockVulnerability = { + vulnerability: { id: 'CVE-2024-00003' }, + observer: undefined, + data_stream: undefined, + } as unknown as CspVulnerabilityFinding; + + (isNativeCspFinding as jest.Mock).mockReturnValue(true); + + const tags = getVulnerabilityTags(mockVulnerability); + expect(tags).toEqual([ + 'Cloud Security', + 'CNVM', + 'Data Source: Cloud Native Vulnerability Management', + 'Use Case: Vulnerability', + 'OS: Linux', + 'CVE-2024-00003', + ]); + }); + }); + + describe('getVulnerabilityRuleName', () => { + it('should return correct rule name for a vulnerability', () => { + const mockVulnerability = { + id: 'CVE-2024-00004', + description: '', + reference: '', + } as Vulnerability; + + const ruleName = getVulnerabilityRuleName(mockVulnerability); + expect(ruleName).toEqual('Vulnerability: CVE-2024-00004'); + }); + }); + + describe('generateVulnerabilitiesRuleQuery', () => { + it('should generate correct query for a vulnerability', () => { + const mockVulnerability = { + id: 'CVE-2024-00005', + description: '', + reference: '', + } as Vulnerability; + const currentTimestamp = new Date().toISOString(); + + const query = generateVulnerabilitiesRuleQuery(mockVulnerability); + expect(query).toEqual( + `vulnerability.id: "CVE-2024-00005" AND event.ingested >= "${currentTimestamp}"` + ); + }); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts index a09f9130836b2..b723c60f9ee3d 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts @@ -8,10 +8,12 @@ import { HttpSetup } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { + CspVulnerabilityFinding, LATEST_VULNERABILITIES_RETENTION_POLICY, VULNERABILITIES_SEVERITY, } from '@kbn/cloud-security-posture-common'; import type { Vulnerability } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; +import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding'; import { VULNERABILITIES_INDEX_PATTERN } from '../../../../common/constants'; import { createDetectionRule } from '../../../common/api/create_detection_rule'; @@ -42,15 +44,7 @@ enum AlertSuppressionMissingFieldsStrategy { Suppress = 'suppress', } -const CSP_RULE_TAG = 'Cloud Security'; - -const STATIC_RULE_TAGS = [CSP_RULE_TAG]; - -const generateVulnerabilitiesTags = (tags?: string[]) => { - return [...STATIC_RULE_TAGS, ...(!!tags?.length ? tags : [])]; -}; - -const getVulnerabilityRuleName = (vulnerability: Vulnerability) => { +export const getVulnerabilityRuleName = (vulnerability: Vulnerability) => { return i18n.translate('xpack.csp.vulnerabilities.detectionRuleNamePrefix', { defaultMessage: 'Vulnerability: {vulnerabilityId}', values: { @@ -59,20 +53,42 @@ const getVulnerabilityRuleName = (vulnerability: Vulnerability) => { }); }; -const generateVulnerabilitiesRuleQuery = (vulnerability: Vulnerability) => { +export const generateVulnerabilitiesRuleQuery = (vulnerability: Vulnerability) => { const currentTimestamp = new Date().toISOString(); return `vulnerability.id: "${vulnerability.id}" AND event.ingested >= "${currentTimestamp}"`; }; +const CSP_RULE_TAG = 'Cloud Security'; +const CNVM_TAG = 'CNVM'; +const CNVM_RULE_TAG_DATA_SOURCE = 'Data Source: Cloud Native Vulnerability Management'; +const CNVM_RULE_TAG_USE_CASE = 'Use Case: Vulnerability'; +const CNVM_RULE_TAG_OS = 'OS: Linux'; + +export const getVulnerabilityTags = (vulnerabilityFinding: CspVulnerabilityFinding) => { + let tags = [vulnerabilityFinding.vulnerability.id]; + const vendor = + vulnerabilityFinding.observer?.vendor || vulnerabilityFinding?.data_stream?.dataset; + + if (isNativeCspFinding(vulnerabilityFinding)) { + tags = [CNVM_TAG, CNVM_RULE_TAG_DATA_SOURCE, CNVM_RULE_TAG_USE_CASE, CNVM_RULE_TAG_OS, ...tags]; + } else if (!!vendor) { + tags.push(vendor); + } + + return [CSP_RULE_TAG, ...tags]; +}; + /* * Creates a detection rule from a Vulnerability */ export const createDetectionRuleFromVulnerabilityFinding = async ( http: HttpSetup, - vulnerability: Vulnerability, - tags?: string[] + vulnerabilityFinding: CspVulnerabilityFinding ) => { + const tags = getVulnerabilityTags(vulnerabilityFinding); + const vulnerability = vulnerabilityFinding.vulnerability; + return await createDetectionRule({ http, rule: { @@ -135,7 +151,7 @@ export const createDetectionRuleFromVulnerabilityFinding = async ( references: vulnerability.reference ? [vulnerability.reference] : [], name: getVulnerabilityRuleName(vulnerability), description: vulnerability.description, - tags: generateVulnerabilitiesTags(tags), + tags, investigation_fields: DEFAULT_INVESTIGATION_FIELDS, }, }); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx index 1c726a450655b..c4680177f72c0 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx @@ -8,40 +8,21 @@ import React from 'react'; import type { HttpSetup } from '@kbn/core/public'; import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; -import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding'; import { DetectionRuleCounter } from '../../../components/detection_rule_counter'; -import { createDetectionRuleFromVulnerabilityFinding } from '../utils/create_detection_rule_from_vulnerability'; - -const CNVM_TAG = 'CNVM'; -const CNVM_RULE_TAG_DATA_SOURCE = 'Data Source: Cloud Native Vulnerability Management'; -const CNVM_RULE_TAG_USE_CASE = 'Use Case: Vulnerability'; -const CNVM_RULE_TAG_OS = 'OS: Linux'; - -const getTags = (vulnerabilityRecord: CspVulnerabilityFinding) => { - let tags = [vulnerabilityRecord.vulnerability.id]; - const vendor = vulnerabilityRecord.observer?.vendor || vulnerabilityRecord?.data_stream?.dataset; - - if (isNativeCspFinding(vulnerabilityRecord)) { - tags = [CNVM_TAG, CNVM_RULE_TAG_DATA_SOURCE, CNVM_RULE_TAG_USE_CASE, CNVM_RULE_TAG_OS, ...tags]; - } else if (!!vendor) { - tags.push(vendor); - } - - return tags; -}; +import { + createDetectionRuleFromVulnerabilityFinding, + getVulnerabilityTags, +} from '../utils/create_detection_rule_from_vulnerability'; export const VulnerabilityDetectionRuleCounter = ({ vulnerabilityRecord, }: { vulnerabilityRecord: CspVulnerabilityFinding; }) => { - const tags = getTags(vulnerabilityRecord); + const tags = getVulnerabilityTags(vulnerabilityRecord); + const createVulnerabilityRuleFn = async (http: HttpSetup) => - await createDetectionRuleFromVulnerabilityFinding( - http, - vulnerabilityRecord.vulnerability, - tags - ); + await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord); return ; }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx index 8c7e3341424d9..1fe61e97506ef 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx @@ -162,7 +162,7 @@ export const VulnerabilityFindingFlyout = ({ const vulnerabilityReference = vulnerability?.reference; const createVulnerabilityRuleFn = async (http: HttpSetup) => - await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord.vulnerability); + await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord); return ( From 59f2f85b8a18cc23c7f0c168830fbc304a9346b6 Mon Sep 17 00:00:00 2001 From: Rickyanto Ang Date: Wed, 9 Oct 2024 20:25:28 +0700 Subject: [PATCH 059/110] [Cloud Security]Vulnerabilities table in Contextual flyout (#195143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary This PR is for Vulnerabilities data table in contextual flyout It also addresses the ticket to remove Empty State for Preview Component [ticket](https://github.com/elastic/security-team/issues/10746) Screenshot 2024-10-07 at 2 14 52 AM --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Maxim Kholod --- .../utils/ui_metrics.ts | 2 + .../kbn-cloud-security-posture/index.ts | 4 +- .../src}/components/vulnerability_badges.tsx | 6 +- .../src/hooks/use_misconfiguration_preview.ts | 2 +- .../src/hooks/use_vulnerabilities_findings.ts | 68 ++++++ .../src/hooks/use_vulnerabilities_preview.ts | 35 +-- .../utils/get_vulnerabilitiy_colors.test.ts | 24 +- .../src/utils/get_vulnerability_colors.ts | 12 + .../src/utils/hooks_utils.ts | 30 +++ .../src/utils/vulnerability_helpers.test.ts | 74 ++++++ .../src/utils/vulnerability_helpers.ts | 101 ++++++++ .../kbn-cloud-security-posture/tsconfig.json | 3 +- .../common/utils/get_vulnerability_colors.ts | 20 -- .../utils/get_vulnerabiltity_colors.test.ts | 31 --- .../public/components/test_subjects.ts | 2 - .../components/vulnerability_severity_map.tsx | 2 +- .../latest_vulnerabilities_table.tsx | 2 +- .../vulnerability_finding_flyout.tsx | 2 +- .../vulnerability_overview_tab.tsx | 2 +- .../vulnerability_table_panel_section.tsx | 2 +- .../csp_details/insights_tab_csp.tsx | 121 +++++++++- ...isconfiguration_findings_details_table.tsx | 2 + ...vulnerabilities_findings_details_table.tsx | 224 ++++++++++++++++++ .../{index.tsx => entity_insight.tsx} | 45 +++- .../misconfiguration_preview.test.tsx | 42 +++- .../misconfiguration_preview.tsx | 95 ++++---- .../vulnerabilities_preview.test.tsx | 41 +++- .../vulnerabilities_preview.tsx | 220 ++++++++--------- .../entity_details_flyout/index.tsx | 7 - .../host_details_left/index.tsx | 13 +- .../entity_details/host_right/content.tsx | 2 +- .../entity_details/host_right/index.tsx | 25 +- .../left_panel/left_panel_header.tsx | 5 + .../entity_details/user_right/content.tsx | 2 +- .../entity_details/user_right/index.tsx | 14 +- .../vulnerabilities_contextual_flyout.cy.ts | 55 +++-- 36 files changed, 1007 insertions(+), 330 deletions(-) rename x-pack/{plugins/cloud_security_posture/public => packages/kbn-cloud-security-posture/src}/components/vulnerability_badges.tsx (90%) create mode 100644 x-pack/packages/kbn-cloud-security-posture/src/hooks/use_vulnerabilities_findings.ts create mode 100644 x-pack/packages/kbn-cloud-security-posture/src/utils/vulnerability_helpers.test.ts create mode 100644 x-pack/packages/kbn-cloud-security-posture/src/utils/vulnerability_helpers.ts delete mode 100644 x-pack/plugins/cloud_security_posture/public/common/utils/get_vulnerability_colors.ts delete mode 100644 x-pack/plugins/cloud_security_posture/public/common/utils/get_vulnerabiltity_colors.test.ts create mode 100644 x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx rename x-pack/plugins/security_solution/public/cloud_security_posture/components/{index.tsx => entity_insight.tsx} (60%) diff --git a/x-pack/packages/kbn-cloud-security-posture-common/utils/ui_metrics.ts b/x-pack/packages/kbn-cloud-security-posture-common/utils/ui_metrics.ts index 9ea12ef7ed45f..8ecedd744efef 100644 --- a/x-pack/packages/kbn-cloud-security-posture-common/utils/ui_metrics.ts +++ b/x-pack/packages/kbn-cloud-security-posture-common/utils/ui_metrics.ts @@ -22,6 +22,7 @@ export const VULNERABILITIES_FLYOUT_VISITS = 'vulnerabilities-flyout-visits'; export const OPEN_FINDINGS_FLYOUT = 'open-findings-flyout'; export const GROUP_BY_CLICK = 'group-by-click'; export const CHANGE_RULE_STATE = 'change-rule-state'; +export const ENTITY_FLYOUT_VULNERABILITY_VIEW_VISITS = 'entity-flyout-vulnerability-view-visits'; type CloudSecurityUiCounters = | typeof ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS @@ -32,6 +33,7 @@ type CloudSecurityUiCounters = | typeof CREATE_DETECTION_RULE_FROM_FLYOUT | typeof CREATE_DETECTION_FROM_TABLE_ROW_ACTION | typeof GROUP_BY_CLICK + | typeof ENTITY_FLYOUT_VULNERABILITY_VIEW_VISITS | typeof CHANGE_RULE_STATE; export class UiMetricService { diff --git a/x-pack/packages/kbn-cloud-security-posture/index.ts b/x-pack/packages/kbn-cloud-security-posture/index.ts index 73b77376db46c..b7e45a546f3d5 100644 --- a/x-pack/packages/kbn-cloud-security-posture/index.ts +++ b/x-pack/packages/kbn-cloud-security-posture/index.ts @@ -12,5 +12,7 @@ export type { NavFilter } from './src/hooks/use_navigate_findings'; export { showErrorToast } from './src/utils/show_error_toast'; export { encodeQuery, decodeQuery } from './src/utils/query_utils'; export { CspEvaluationBadge } from './src/components/csp_evaluation_badge'; -export { getSeverityStatusColor } from './src/utils/get_vulnerability_colors'; +export { getSeverityStatusColor, getCvsScoreColor } from './src/utils/get_vulnerability_colors'; export { getSeverityText } from './src/utils/get_vulnerability_text'; +export { getVulnerabilityStats, hasVulnerabilitiesData } from './src/utils/vulnerability_helpers'; +export { CVSScoreBadge, SeverityStatusBadge } from './src/components/vulnerability_badges'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx b/x-pack/packages/kbn-cloud-security-posture/src/components/vulnerability_badges.tsx similarity index 90% rename from x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx rename to x-pack/packages/kbn-cloud-security-posture/src/components/vulnerability_badges.tsx index 7d4095b4bd662..e13d33c0e11cb 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx +++ b/x-pack/packages/kbn-cloud-security-posture/src/components/vulnerability_badges.tsx @@ -10,9 +10,9 @@ import React from 'react'; import { css } from '@emotion/react'; import { float } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { VulnSeverity } from '@kbn/cloud-security-posture-common'; -import { getSeverityStatusColor } from '@kbn/cloud-security-posture'; -import { getCvsScoreColor } from '../common/utils/get_vulnerability_colors'; -import { VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ } from './test_subjects'; +import { getCvsScoreColor, getSeverityStatusColor } from '../utils/get_vulnerability_colors'; + +const VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ = 'vulnerabilities_cvss_score_badge'; interface CVSScoreBadgeProps { score?: float; diff --git a/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_misconfiguration_preview.ts b/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_misconfiguration_preview.ts index 4711cd752ee5f..75bd0d3952bd7 100644 --- a/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_misconfiguration_preview.ts +++ b/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_misconfiguration_preview.ts @@ -38,7 +38,7 @@ export const useMisconfigurationPreview = (options: UseCspOptions) => { params: buildMisconfigurationsFindingsQuery(options, rulesStates!), }) ); - if (!aggregations && !options.ignore_unavailable) + if (!aggregations && options.ignore_unavailable === false) throw new Error('expected aggregations to be defined'); return { count: getMisconfigurationAggregationCount(aggregations?.count?.buckets), diff --git a/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_vulnerabilities_findings.ts b/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_vulnerabilities_findings.ts new file mode 100644 index 0000000000000..ba13ec983893f --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_vulnerabilities_findings.ts @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { useQuery } from '@tanstack/react-query'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { lastValueFrom } from 'rxjs'; +import type { IKibanaSearchResponse, IKibanaSearchRequest } from '@kbn/search-types'; +import { + SearchRequest, + SearchResponse, + AggregationsMultiBucketAggregateBase, + AggregationsStringRareTermsBucketKeys, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; +import type { CoreStart } from '@kbn/core/public'; +import type { CspClientPluginStartDeps, UseCspOptions } from '../../type'; +import { showErrorToast } from '../..'; +import { getVulnerabilitiesAggregationCount, getVulnerabilitiesQuery } from '../utils/hooks_utils'; + +type LatestFindingsRequest = IKibanaSearchRequest; +type LatestFindingsResponse = IKibanaSearchResponse< + SearchResponse +>; + +interface FindingsAggs { + count: AggregationsMultiBucketAggregateBase; +} + +export const useVulnerabilitiesFindings = (options: UseCspOptions) => { + const { + data, + notifications: { toasts }, + } = useKibana().services; + /** + * We're using useInfiniteQuery in this case to allow the user to fetch more data (if available and up to 10k) + * useInfiniteQuery differs from useQuery because it accumulates and caches a chunk of data from the previous fetches into an array + * it uses the getNextPageParam to know if there are more pages to load and retrieve the position of + * the last loaded record to be used as a from parameter to fetch the next chunk of data. + */ + return useQuery( + ['csp_vulnerabilities_findings', { params: options }], + async ({ pageParam }) => { + const { + rawResponse: { aggregations, hits }, + } = await lastValueFrom( + data.search.search({ + params: getVulnerabilitiesQuery(options, pageParam), + }) + ); + + return { + count: getVulnerabilitiesAggregationCount(aggregations?.count?.buckets), + rows: hits.hits.map((finding) => ({ + vulnerability: finding._source?.vulnerability, + resource: finding._source?.resource, + })) as Array>, + }; + }, + { + keepPreviousData: true, + enabled: options.enabled, + onError: (err: Error) => showErrorToast(toasts, err), + } + ); +}; diff --git a/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_vulnerabilities_preview.ts b/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_vulnerabilities_preview.ts index 00ca9691b013f..82b3f41d26819 100644 --- a/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_vulnerabilities_preview.ts +++ b/x-pack/packages/kbn-cloud-security-posture/src/hooks/use_vulnerabilities_preview.ts @@ -14,18 +14,11 @@ import { AggregationsMultiBucketAggregateBase, AggregationsStringRareTermsBucketKeys, } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { - CDR_VULNERABILITIES_INDEX_PATTERN, - LATEST_VULNERABILITIES_RETENTION_POLICY, -} from '@kbn/cloud-security-posture-common'; import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; import type { CoreStart } from '@kbn/core/public'; import type { CspClientPluginStartDeps, UseCspOptions } from '../../type'; import { showErrorToast } from '../..'; -import { - getFindingsCountAggQueryVulnerabilities, - getVulnerabilitiesAggregationCount, -} from '../utils/hooks_utils'; +import { getVulnerabilitiesAggregationCount, getVulnerabilitiesQuery } from '../utils/hooks_utils'; type LatestFindingsRequest = IKibanaSearchRequest; type LatestFindingsResponse = IKibanaSearchResponse< @@ -36,30 +29,6 @@ interface FindingsAggs { count: AggregationsMultiBucketAggregateBase; } -const getVulnerabilitiesQuery = ({ query }: UseCspOptions, isPreview = false) => ({ - index: CDR_VULNERABILITIES_INDEX_PATTERN, - size: 0, - aggs: getFindingsCountAggQueryVulnerabilities(), - ignore_unavailable: true, - query: { - ...query, - bool: { - ...query?.bool, - filter: [ - ...(query?.bool?.filter ?? []), - { - range: { - '@timestamp': { - gte: `now-${LATEST_VULNERABILITIES_RETENTION_POLICY}`, - lte: 'now', - }, - }, - }, - ], - }, - }, -}); - export const useVulnerabilitiesPreview = (options: UseCspOptions) => { const { data, @@ -73,7 +42,7 @@ export const useVulnerabilitiesPreview = (options: UseCspOptions) => { rawResponse: { aggregations }, } = await lastValueFrom( data.search.search({ - params: getVulnerabilitiesQuery(options), + params: getVulnerabilitiesQuery(options, true), }) ); diff --git a/x-pack/packages/kbn-cloud-security-posture/src/utils/get_vulnerabilitiy_colors.test.ts b/x-pack/packages/kbn-cloud-security-posture/src/utils/get_vulnerabilitiy_colors.test.ts index 0516faa7e83f7..dcc506fd6b27d 100644 --- a/x-pack/packages/kbn-cloud-security-posture/src/utils/get_vulnerabilitiy_colors.test.ts +++ b/x-pack/packages/kbn-cloud-security-posture/src/utils/get_vulnerabilitiy_colors.test.ts @@ -6,7 +6,7 @@ */ import { euiThemeVars } from '@kbn/ui-theme'; -import { getSeverityStatusColor } from './get_vulnerability_colors'; +import { getCvsScoreColor, getSeverityStatusColor } from './get_vulnerability_colors'; describe('getSeverityStatusColor', () => { it('should return the correct color for LOW severity', () => { expect(getSeverityStatusColor('LOW')).toBe(euiThemeVars.euiColorVis0); @@ -28,3 +28,25 @@ describe('getSeverityStatusColor', () => { expect(getSeverityStatusColor('UNKNOWN')).toBe('#aaa'); }); }); + +describe('getCvsScoreColor', () => { + it('returns correct color for low severity score', () => { + expect(getCvsScoreColor(1.5)).toBe(euiThemeVars.euiColorVis0); + }); + + it('returns correct color for medium severity score', () => { + expect(getCvsScoreColor(5.5)).toBe(euiThemeVars.euiColorVis7); + }); + + it('returns correct color for high severity score', () => { + expect(getCvsScoreColor(7.9)).toBe(euiThemeVars.euiColorVis9); + }); + + it('returns correct color for critical severity score', () => { + expect(getCvsScoreColor(10.0)).toBe(euiThemeVars.euiColorDanger); + }); + + it('returns correct color for low severity score for undefined value', () => { + expect(getCvsScoreColor(-0.2)).toBe(euiThemeVars.euiColorVis0); + }); +}); diff --git a/x-pack/packages/kbn-cloud-security-posture/src/utils/get_vulnerability_colors.ts b/x-pack/packages/kbn-cloud-security-posture/src/utils/get_vulnerability_colors.ts index 7e651f790fd80..54bcb357137b7 100644 --- a/x-pack/packages/kbn-cloud-security-posture/src/utils/get_vulnerability_colors.ts +++ b/x-pack/packages/kbn-cloud-security-posture/src/utils/get_vulnerability_colors.ts @@ -9,6 +9,18 @@ import { euiThemeVars } from '@kbn/ui-theme'; import type { VulnSeverity } from '@kbn/cloud-security-posture-common'; import { VULNERABILITIES_SEVERITY } from '@kbn/cloud-security-posture-common'; +export const getCvsScoreColor = (score: number): string | undefined => { + if (score <= 4) { + return euiThemeVars.euiColorVis0; // low severity + } else if (score >= 4 && score <= 7) { + return euiThemeVars.euiColorVis7; // medium severity + } else if (score >= 7 && score <= 9) { + return euiThemeVars.euiColorVis9; // high severity + } else if (score >= 9) { + return euiThemeVars.euiColorDanger; // critical severity + } +}; + export const getSeverityStatusColor = (severity: VulnSeverity): string => { switch (severity) { case VULNERABILITIES_SEVERITY.LOW: diff --git a/x-pack/packages/kbn-cloud-security-posture/src/utils/hooks_utils.ts b/x-pack/packages/kbn-cloud-security-posture/src/utils/hooks_utils.ts index d99fac8d6d96e..c7585adba9ce4 100644 --- a/x-pack/packages/kbn-cloud-security-posture/src/utils/hooks_utils.ts +++ b/x-pack/packages/kbn-cloud-security-posture/src/utils/hooks_utils.ts @@ -8,7 +8,9 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { CDR_MISCONFIGURATIONS_INDEX_PATTERN, + CDR_VULNERABILITIES_INDEX_PATTERN, LATEST_FINDINGS_RETENTION_POLICY, + LATEST_VULNERABILITIES_RETENTION_POLICY, } from '@kbn/cloud-security-posture-common'; import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common/schema/rules/latest'; import { buildMutedRulesFilter } from '@kbn/cloud-security-posture-common'; @@ -161,3 +163,31 @@ export const getFindingsCountAggQueryVulnerabilities = () => ({ }, }, }); + +export const getVulnerabilitiesQuery = ({ query }: UseCspOptions, isPreview = false) => ({ + index: CDR_VULNERABILITIES_INDEX_PATTERN, + size: isPreview ? 0 : 500, + aggs: getFindingsCountAggQueryVulnerabilities(), + ignore_unavailable: true, + query: buildVulnerabilityFindingsQueryWithFilters(query), +}); + +const buildVulnerabilityFindingsQueryWithFilters = (query: UseCspOptions['query']) => { + return { + ...query, + bool: { + ...query?.bool, + filter: [ + ...(query?.bool?.filter ?? []), + { + range: { + '@timestamp': { + gte: `now-${LATEST_VULNERABILITIES_RETENTION_POLICY}`, + lte: 'now', + }, + }, + }, + ], + }, + }; +}; diff --git a/x-pack/packages/kbn-cloud-security-posture/src/utils/vulnerability_helpers.test.ts b/x-pack/packages/kbn-cloud-security-posture/src/utils/vulnerability_helpers.test.ts new file mode 100644 index 0000000000000..898f9990a1a96 --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture/src/utils/vulnerability_helpers.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { euiThemeVars } from '@kbn/ui-theme'; +import { getVulnerabilityStats } from './vulnerability_helpers'; +import { i18n } from '@kbn/i18n'; + +describe('getVulnerabilitiesAggregationCount', () => { + it('should return empty array when all severity count is 0', () => { + const result = getVulnerabilityStats({ critical: 0, high: 0, medium: 0, low: 0, none: 0 }); + expect(result).toEqual([]); + }); + + it('should return stats for low, medium, high, and critical vulnerabilities', () => { + const result = getVulnerabilityStats({ critical: 1, high: 2, medium: 3, low: 4, none: 5 }); + + expect(result).toEqual([ + { + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.noneVulnerabilitiesText', + { + defaultMessage: 'None', + } + ), + count: 5, + color: '#aaa', + }, + { + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.lowVulnerabilitiesText', + { + defaultMessage: 'Low', + } + ), + count: 4, + color: euiThemeVars.euiColorVis0, + }, + { + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.mediumVulnerabilitiesText', + { + defaultMessage: 'Medium', + } + ), + count: 3, + color: euiThemeVars.euiColorVis5_behindText, + }, + { + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.highVulnerabilitiesText', + { + defaultMessage: 'High', + } + ), + count: 2, + color: euiThemeVars.euiColorVis9_behindText, + }, + { + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.CriticalVulnerabilitiesText', + { + defaultMessage: 'Critical', + } + ), + count: 1, + color: euiThemeVars.euiColorDanger, + }, + ]); + }); +}); diff --git a/x-pack/packages/kbn-cloud-security-posture/src/utils/vulnerability_helpers.ts b/x-pack/packages/kbn-cloud-security-posture/src/utils/vulnerability_helpers.ts new file mode 100644 index 0000000000000..c8782daf35308 --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture/src/utils/vulnerability_helpers.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { VULNERABILITIES_SEVERITY } from '@kbn/cloud-security-posture-common'; +import { i18n } from '@kbn/i18n'; +import { getSeverityStatusColor } from './get_vulnerability_colors'; +import { getSeverityText } from './get_vulnerability_text'; + +interface VulnerabilitiesDistributionBarProps { + key: string; + count: number; + color: string; +} + +interface VulnerabilityCounts { + critical: number; + high: number; + medium: number; + low: number; + none: number; +} + +export const hasVulnerabilitiesData = (counts: VulnerabilityCounts): boolean => { + if (Object.values(counts).reduce((acc, value) => acc + value, 0) > 0) return true; + return false; +}; + +export const getVulnerabilityStats = ( + counts: VulnerabilityCounts +): VulnerabilitiesDistributionBarProps[] => { + const vulnerabilityStats: VulnerabilitiesDistributionBarProps[] = []; + + const levels = Object.values(counts); + + if (levels.every((level) => level === 0)) { + return vulnerabilityStats; + } + + if (counts.none > 0) + vulnerabilityStats.push({ + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.noneVulnerabilitiesText', + { + defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.UNKNOWN), + } + ), + count: counts.none, + color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.UNKNOWN), + }); + if (counts.low > 0) + vulnerabilityStats.push({ + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.lowVulnerabilitiesText', + { + defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.LOW), + } + ), + count: counts.low, + color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.LOW), + }); + + if (counts.medium > 0) + vulnerabilityStats.push({ + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.mediumVulnerabilitiesText', + { + defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.MEDIUM), + } + ), + count: counts.medium, + color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.MEDIUM), + }); + if (counts.high > 0) + vulnerabilityStats.push({ + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.highVulnerabilitiesText', + { + defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.HIGH), + } + ), + count: counts.high, + color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.HIGH), + }); + if (counts.critical > 0) + vulnerabilityStats.push({ + key: i18n.translate( + 'xpack.securitySolution.flyout.right.insights.vulnerabilities.CriticalVulnerabilitiesText', + { + defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.CRITICAL), + } + ), + count: counts.critical, + color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.CRITICAL), + }); + + return vulnerabilityStats; +}; diff --git a/x-pack/packages/kbn-cloud-security-posture/tsconfig.json b/x-pack/packages/kbn-cloud-security-posture/tsconfig.json index 633ef28bf2074..a4a5376009d9a 100644 --- a/x-pack/packages/kbn-cloud-security-posture/tsconfig.json +++ b/x-pack/packages/kbn-cloud-security-posture/tsconfig.json @@ -5,7 +5,8 @@ "types": [ "jest", "node", - "react" + "react", + "@emotion/react/types/css-prop" ] }, "include": [ diff --git a/x-pack/plugins/cloud_security_posture/public/common/utils/get_vulnerability_colors.ts b/x-pack/plugins/cloud_security_posture/public/common/utils/get_vulnerability_colors.ts deleted file mode 100644 index cba51677dd58a..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/common/utils/get_vulnerability_colors.ts +++ /dev/null @@ -1,20 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { euiThemeVars } from '@kbn/ui-theme'; - -export const getCvsScoreColor = (score: number): string | undefined => { - if (score <= 4) { - return euiThemeVars.euiColorVis0; // low severity - } else if (score >= 4 && score <= 7) { - return euiThemeVars.euiColorVis7; // medium severity - } else if (score >= 7 && score <= 9) { - return euiThemeVars.euiColorVis9; // high severity - } else if (score >= 9) { - return euiThemeVars.euiColorDanger; // critical severity - } -}; diff --git a/x-pack/plugins/cloud_security_posture/public/common/utils/get_vulnerabiltity_colors.test.ts b/x-pack/plugins/cloud_security_posture/public/common/utils/get_vulnerabiltity_colors.test.ts deleted file mode 100644 index 5000e14a5afc6..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/common/utils/get_vulnerabiltity_colors.test.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { euiThemeVars } from '@kbn/ui-theme'; -import { getCvsScoreColor } from './get_vulnerability_colors'; - -describe('getCvsScoreColor', () => { - it('returns correct color for low severity score', () => { - expect(getCvsScoreColor(1.5)).toBe(euiThemeVars.euiColorVis0); - }); - - it('returns correct color for medium severity score', () => { - expect(getCvsScoreColor(5.5)).toBe(euiThemeVars.euiColorVis7); - }); - - it('returns correct color for high severity score', () => { - expect(getCvsScoreColor(7.9)).toBe(euiThemeVars.euiColorVis9); - }); - - it('returns correct color for critical severity score', () => { - expect(getCvsScoreColor(10.0)).toBe(euiThemeVars.euiColorDanger); - }); - - it('returns correct color for low severity score for undefined value', () => { - expect(getCvsScoreColor(-0.2)).toBe(euiThemeVars.euiColorVis0); - }); -}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts index 6e17a59b3ba08..d29971d3352e3 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts @@ -42,8 +42,6 @@ export const THIRD_PARTY_NO_VULNERABILITIES_FINDINGS_PROMPT_WIZ_INTEGRATION_BUTT '3p-no-vulnerabilities-findings-prompt-wiz-integration-button'; export const VULNERABILITIES_CONTAINER_TEST_SUBJ = 'vulnerabilities_container'; -export const VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ = 'vulnerabilities_cvss_score_badge'; - export const TAKE_ACTION_SUBJ = 'csp:take_action'; export const CREATE_RULE_ACTION_SUBJ = 'csp:create_rule'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/vulnerability_severity_map.tsx b/x-pack/plugins/cloud_security_posture/public/components/vulnerability_severity_map.tsx index 9046fcb265a86..4773f5378fb3e 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/vulnerability_severity_map.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/vulnerability_severity_map.tsx @@ -18,7 +18,7 @@ import { PaletteColorStop } from '@elastic/eui/src/components/color_picker/color import type { VulnSeverity } from '@kbn/cloud-security-posture-common'; import { i18n } from '@kbn/i18n'; import { getSeverityStatusColor } from '@kbn/cloud-security-posture'; -import { SeverityStatusBadge } from './vulnerability_badges'; +import { SeverityStatusBadge } from '@kbn/cloud-security-posture'; interface Props { total: number; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx index e8dde902a9f46..8b485d0b7e042 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx @@ -12,6 +12,7 @@ import { EuiDataGridCellValueElementProps, EuiSpacer } from '@elastic/eui'; import { Filter } from '@kbn/es-query'; import { HttpSetup } from '@kbn/core-http-browser'; import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; +import { CVSScoreBadge, SeverityStatusBadge } from '@kbn/cloud-security-posture'; import { getVendorName } from '../../common/utils/get_vendor_name'; import { CloudSecurityDataTable } from '../../components/cloud_security_data_table'; import { useLatestVulnerabilitiesTable } from './hooks/use_latest_vulnerabilities_table'; @@ -19,7 +20,6 @@ import { LATEST_VULNERABILITIES_TABLE } from './test_subjects'; import { getDefaultQuery, defaultColumns } from './constants'; import { VulnerabilityFindingFlyout } from './vulnerabilities_finding_flyout/vulnerability_finding_flyout'; import { ErrorCallout } from '../configurations/layout/error_callout'; -import { CVSScoreBadge, SeverityStatusBadge } from '../../components/vulnerability_badges'; import { createDetectionRuleFromVulnerabilityFinding } from './utils/create_detection_rule_from_vulnerability'; import { vulnerabilitiesTableFieldLabels } from './vulnerabilities_table_field_labels'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx index 1fe61e97506ef..392059c8cc0f4 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx @@ -28,13 +28,13 @@ import { euiThemeVars } from '@kbn/ui-theme'; import { css } from '@emotion/react'; import { HttpSetup } from '@kbn/core-http-browser'; import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; +import { SeverityStatusBadge } from '@kbn/cloud-security-posture'; import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding'; import { TakeAction } from '../../../components/take_action'; import { truthy } from '../../../../common/utils/helpers'; import { CspInlineDescriptionList } from '../../../components/csp_inline_description_list'; import { VulnerabilityOverviewTab } from './vulnerability_overview_tab'; import { VulnerabilityJsonTab } from './vulnerability_json_tab'; -import { SeverityStatusBadge } from '../../../components/vulnerability_badges'; import { FINDINGS_VULNERABILITY_FLYOUT_DESCRIPTION_LIST, TAB_ID_VULNERABILITY_FLYOUT, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_overview_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_overview_tab.tsx index d67649c508c13..ed9d7f985f357 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_overview_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_overview_tab.tsx @@ -28,10 +28,10 @@ import { VULNERABILITIES_FLYOUT_VISITS, uiMetricService, } from '@kbn/cloud-security-posture-common/utils/ui_metrics'; +import { CVSScoreBadge } from '@kbn/cloud-security-posture'; import { getVendorName } from '../../../common/utils/get_vendor_name'; import { CspFlyoutMarkdown } from '../../configurations/findings_flyout/findings_flyout'; import { NvdLogo } from '../../../assets/icons/nvd_logo_svg'; -import { CVSScoreBadge } from '../../../components/vulnerability_badges'; import { CVSScoreProps, Vendor } from '../types'; import { getVectorScoreList } from '../utils/get_vector_score_list'; import { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx index 42794e91d2036..28012e3e8e438 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx @@ -19,6 +19,7 @@ import { i18n } from '@kbn/i18n'; import type { NavFilter } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; import { useNavigateVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; import type { VulnSeverity } from '@kbn/cloud-security-posture-common'; +import { CVSScoreBadge, SeverityStatusBadge } from '@kbn/cloud-security-posture'; import { PatchableVulnerabilityStat, VulnerabilityStat, @@ -26,7 +27,6 @@ import { } from '../../../common/types_old'; import { DASHBOARD_TABLE_TYPES } from './vulnerability_table_panel.config'; import { VulnerabilityTablePanel } from './vulnerability_table_panel'; -import { CVSScoreBadge, SeverityStatusBadge } from '../../components/vulnerability_badges'; import { useVulnerabilityDashboardApi } from '../../common/api/use_vulnerability_dashboard_api'; import { VULNERABILITY_GROUPING_OPTIONS, VULNERABILITY_FIELDS } from '../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/insights_tab_csp.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/insights_tab_csp.tsx index 595aaf5127ca3..05421cfa7a208 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/insights_tab_csp.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/insights_tab_csp.tsx @@ -5,19 +5,134 @@ * 2.0. */ -import React, { memo } from 'react'; -import { EuiSpacer } from '@elastic/eui'; +import React, { memo, useMemo, useState } from 'react'; +import type { EuiButtonGroupOptionProps } from '@elastic/eui'; +import { EuiButtonGroup, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import type { FlyoutPanelProps, PanelPath } from '@kbn/expandable-flyout'; +import { useExpandableFlyoutState } from '@kbn/expandable-flyout'; +import { i18n } from '@kbn/i18n'; +// import type { FlyoutPanels } from '@kbn/expandable-flyout/src/store/state'; +import { CspInsightLeftPanelSubTab } from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header'; import { MisconfigurationFindingsDetailsTable } from './misconfiguration_findings_details_table'; +import { VulnerabilitiesFindingsDetailsTable } from './vulnerabilities_findings_details_table'; /** * Insights view displayed in the document details expandable flyout left section */ + +interface CspFlyoutPanelProps extends FlyoutPanelProps { + params: { + path: PanelPath; + hasMisconfigurationFindings: boolean; + hasVulnerabilitiesFindings: boolean; + }; +} + +// Type guard to check if the panel is a CspFlyoutPanelProps +function isCspFlyoutPanelProps( + panelLeft: FlyoutPanelProps | undefined +): panelLeft is CspFlyoutPanelProps { + return ( + !!panelLeft?.params?.hasMisconfigurationFindings || + !!panelLeft?.params?.hasVulnerabilitiesFindings + ); +} + export const InsightsTabCsp = memo( ({ name, fieldName }: { name: string; fieldName: 'host.name' | 'user.name' }) => { + const panels = useExpandableFlyoutState(); + + let hasMisconfigurationFindings = false; + let hasVulnerabilitiesFindings = false; + let subTab: string | undefined; + + // Check if panels.left is of type CspFlyoutPanelProps and extract values + if (isCspFlyoutPanelProps(panels.left)) { + hasMisconfigurationFindings = panels.left.params.hasMisconfigurationFindings; + hasVulnerabilitiesFindings = panels.left.params.hasVulnerabilitiesFindings; + subTab = panels.left.params.path?.subTab; + } + + const getDefaultTab = () => { + if (subTab) { + return subTab; + } + + return hasMisconfigurationFindings + ? CspInsightLeftPanelSubTab.MISCONFIGURATIONS + : hasVulnerabilitiesFindings + ? CspInsightLeftPanelSubTab.VULNERABILITIES + : ''; + }; + + const [activeInsightsId, setActiveInsightsId] = useState(getDefaultTab()); + + const insightsButtons: EuiButtonGroupOptionProps[] = useMemo(() => { + const buttons: EuiButtonGroupOptionProps[] = []; + + if (panels.left?.params?.hasMisconfigurationFindings) { + buttons.push({ + id: CspInsightLeftPanelSubTab.MISCONFIGURATIONS, + label: ( + + ), + 'data-test-subj': 'misconfigurationTabDataTestId', + }); + } + + if (panels.left?.params?.hasVulnerabilitiesFindings) { + buttons.push({ + id: CspInsightLeftPanelSubTab.VULNERABILITIES, + label: ( + + ), + 'data-test-subj': 'vulnerabilitiesTabDataTestId', + }); + } + return buttons; + }, [ + panels.left?.params?.hasMisconfigurationFindings, + panels.left?.params?.hasVulnerabilitiesFindings, + ]); + + const onTabChange = (id: string) => { + setActiveInsightsId(id); + }; + + if (insightsButtons.length === 0) { + return null; + } + return ( <> + - + {activeInsightsId === CspInsightLeftPanelSubTab.MISCONFIGURATIONS ? ( + + ) : ( + + )} ); } diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx index a27f92407fbdd..2cf99abdf4833 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx @@ -18,6 +18,7 @@ import { useNavigateFindings } from '@kbn/cloud-security-posture/src/hooks/use_n import type { CspBenchmarkRuleMetadata } from '@kbn/cloud-security-posture-common/schema/rules/latest'; import { CspEvaluationBadge } from '@kbn/cloud-security-posture'; import { + ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS, NAV_TO_FINDINGS_BY_HOST_NAME_FRPOM_ENTITY_FLYOUT, NAV_TO_FINDINGS_BY_RULE_NAME_FRPOM_ENTITY_FLYOUT, uiMetricService, @@ -57,6 +58,7 @@ const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: numb */ export const MisconfigurationFindingsDetailsTable = memo( ({ fieldName, queryName }: { fieldName: 'host.name' | 'user.name'; queryName: string }) => { + uiMetricService.trackUiMetric(METRIC_TYPE.COUNT, ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS); const { data } = useMisconfigurationFindings({ query: buildEntityFlyoutPreviewQuery(fieldName, queryName), sort: [], diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx new file mode 100644 index 0000000000000..9e3e4b140a9ba --- /dev/null +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx @@ -0,0 +1,224 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo, useState } from 'react'; +import type { Criteria, EuiBasicTableColumn } from '@elastic/eui'; +import { EuiSpacer, EuiIcon, EuiPanel, EuiLink, EuiText, EuiBasicTable } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import type { VulnSeverity } from '@kbn/cloud-security-posture-common'; +import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { DistributionBar } from '@kbn/security-solution-distribution-bar'; +import { useNavigateVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings'; +import { useVulnerabilitiesFindings } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_findings'; +import type { + CspVulnerabilityFinding, + Vulnerability, +} from '@kbn/cloud-security-posture-common/schema/vulnerabilities/csp_vulnerability_finding'; +import { + getVulnerabilityStats, + CVSScoreBadge, + SeverityStatusBadge, +} from '@kbn/cloud-security-posture'; +import { + ENTITY_FLYOUT_VULNERABILITY_VIEW_VISITS, + NAV_TO_FINDINGS_BY_HOST_NAME_FRPOM_ENTITY_FLYOUT, + uiMetricService, +} from '@kbn/cloud-security-posture-common/utils/ui_metrics'; +import { METRIC_TYPE } from '@kbn/analytics'; + +type VulnerabilitiesFindingDetailFields = Pick< + CspVulnerabilityFinding, + 'vulnerability' | 'resource' +>; + +interface VulnerabilitiesPackage extends Vulnerability { + package: { + name: string; + }; +} + +export const VulnerabilitiesFindingsDetailsTable = memo(({ queryName }: { queryName: string }) => { + uiMetricService.trackUiMetric(METRIC_TYPE.COUNT, ENTITY_FLYOUT_VULNERABILITY_VIEW_VISITS); + const { data } = useVulnerabilitiesFindings({ + query: buildEntityFlyoutPreviewQuery('host.name', queryName), + sort: [], + enabled: true, + pageSize: 1, + }); + + const { CRITICAL = 0, HIGH = 0, MEDIUM = 0, LOW = 0, NONE = 0 } = data?.count || {}; + + const [pageIndex, setPageIndex] = useState(0); + const [pageSize, setPageSize] = useState(10); + + const findingsPagination = (findings: VulnerabilitiesFindingDetailFields[]) => { + let pageOfItems; + + if (!pageIndex && !pageSize) { + pageOfItems = findings; + } else { + const startIndex = pageIndex * pageSize; + pageOfItems = findings?.slice(startIndex, Math.min(startIndex + pageSize, findings?.length)); + } + + return { + pageOfItems, + totalItemCount: findings?.length, + }; + }; + + const { pageOfItems, totalItemCount } = findingsPagination(data?.rows || []); + + const pagination = { + pageIndex, + pageSize, + totalItemCount, + pageSizeOptions: [10, 25, 100], + }; + + const onTableChange = ({ page }: Criteria) => { + if (page) { + const { index, size } = page; + setPageIndex(index); + setPageSize(size); + } + }; + + const navToVulnerabilities = useNavigateVulnerabilities(); + + const navToVulnerabilitiesByName = (name: string, queryField: 'host.name' | 'user.name') => { + navToVulnerabilities({ [queryField]: name }); + }; + + const navToVulnerabilityByVulnerabilityAndResourceId = ( + vulnerabilityId: string, + resourceId: string + ) => { + navToVulnerabilities({ + 'vulnerability.id': vulnerabilityId, + 'resource.id': resourceId, + }); + }; + + const columns: Array> = [ + { + field: 'vulnerability', + name: '', + width: '5%', + render: ( + vulnerability: VulnerabilitiesPackage, + finding: VulnerabilitiesFindingDetailFields + ) => ( + { + navToVulnerabilityByVulnerabilityAndResourceId( + vulnerability?.id, + finding?.resource?.id || '' + ); + }} + > + + + ), + }, + { + field: 'vulnerability', + render: (vulnerability: Vulnerability) => {vulnerability?.id}, + name: i18n.translate( + 'xpack.securitySolution.flyout.left.insights.vulnerability.table.resultColumnName', + { defaultMessage: 'Vulnerability' } + ), + width: '20%', + }, + { + field: 'vulnerability', + render: (vulnerability: Vulnerability) => ( + + + + ), + name: i18n.translate( + 'xpack.securitySolution.flyout.left.insights.vulnerability.table.ruleColumnName', + { defaultMessage: 'CVSS' } + ), + width: '12.5%', + }, + { + field: 'vulnerability', + render: (vulnerability: Vulnerability) => ( + <> + + + + + ), + name: i18n.translate( + 'xpack.securitySolution.flyout.left.insights.vulnerability.table.ruleColumnName', + { defaultMessage: 'Severity' } + ), + width: '12.5%', + }, + { + field: 'vulnerability', + render: (vulnerability: VulnerabilitiesPackage) => ( + {vulnerability?.package?.name} + ), + name: i18n.translate( + 'xpack.securitySolution.flyout.left.insights.vulnerability.table.ruleColumnName', + { defaultMessage: 'Package' } + ), + width: '50%', + }, + ]; + + return ( + <> + + { + uiMetricService.trackUiMetric( + METRIC_TYPE.CLICK, + NAV_TO_FINDINGS_BY_HOST_NAME_FRPOM_ENTITY_FLYOUT + ); + navToVulnerabilitiesByName(queryName, 'host.name'); + }} + > + {i18n.translate('xpack.securitySolution.flyout.left.insights.vulnerability.tableTitle', { + defaultMessage: 'Vulnerability ', + })} + + + + + + + + + ); +}); + +VulnerabilitiesFindingsDetailsTable.displayName = 'VulnerabilitiesFindingsDetailsTable'; diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/index.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/entity_insight.tsx similarity index 60% rename from x-pack/plugins/security_solution/public/cloud_security_posture/components/index.tsx rename to x-pack/plugins/security_solution/public/cloud_security_posture/components/entity_insight.tsx index b4ec54a29a073..7d9027c25a9e0 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/index.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/entity_insight.tsx @@ -10,7 +10,10 @@ import { EuiAccordion, EuiHorizontalRule, EuiSpacer, EuiTitle, useEuiTheme } fro import React from 'react'; import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useCspSetupStatusApi } from '@kbn/cloud-security-posture/src/hooks/use_csp_setup_status_api'; +import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'; +import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'; +import { hasVulnerabilitiesData } from '@kbn/cloud-security-posture'; import { MisconfigurationsPreview } from './misconfiguration/misconfiguration_preview'; import { VulnerabilitiesPreview } from './vulnerabilities/vulnerabilities_preview'; @@ -24,10 +27,37 @@ export const EntityInsight = ({ isPreviewMode?: boolean; }) => { const { euiTheme } = useEuiTheme(); - const getSetupStatus = useCspSetupStatusApi(); - const hasMisconfigurationFindings = getSetupStatus.data?.hasMisconfigurationsFindings; - const hasVulnerabilitiesFindings = getSetupStatus.data?.hasVulnerabilitiesFindings; const insightContent: React.ReactElement[] = []; + + const { data: dataMisconfiguration } = useMisconfigurationPreview({ + query: buildEntityFlyoutPreviewQuery(fieldName, name), + sort: [], + enabled: true, + pageSize: 1, + }); + + const passedFindings = dataMisconfiguration?.count.passed || 0; + const failedFindings = dataMisconfiguration?.count.failed || 0; + + const hasMisconfigurationFindings = passedFindings > 0 || failedFindings > 0; + + const { data } = useVulnerabilitiesPreview({ + query: buildEntityFlyoutPreviewQuery(fieldName, name), + sort: [], + enabled: true, + pageSize: 1, + }); + + const { CRITICAL = 0, HIGH = 0, MEDIUM = 0, LOW = 0, NONE = 0 } = data?.count || {}; + + const hasVulnerabilitiesFindings = hasVulnerabilitiesData({ + critical: CRITICAL, + high: HIGH, + medium: MEDIUM, + low: LOW, + none: NONE, + }); + const isVulnerabilitiesFindingForHost = hasVulnerabilitiesFindings && fieldName === 'host.name'; if (hasMisconfigurationFindings) @@ -37,16 +67,17 @@ export const EntityInsight = ({ ); - if (isVulnerabilitiesFindingForHost) + if (isVulnerabilitiesFindingForHost && hasVulnerabilitiesFindings) insightContent.push( <> - + ); return ( <> - {(hasMisconfigurationFindings || isVulnerabilitiesFindingForHost) && ( + {(hasMisconfigurationFindings || + (isVulnerabilitiesFindingForHost && hasVulnerabilitiesFindings)) && ( <> { - it('renders', () => { - const { queryByTestId } = render(, { - wrapper: TestProviders, + const mockOpenLeftPanel = jest.fn(); + + beforeEach(() => { + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + (useVulnerabilitiesPreview as jest.Mock).mockReturnValue({ + data: { count: { CRITICAL: 0, HIGH: 1, MEDIUM: 1, LOW: 0, UNKNOWN: 0 } }, + }); + (useRiskScore as jest.Mock).mockReturnValue({ data: [{ host: { risk: 75 } }] }); + (useMisconfigurationPreview as jest.Mock).mockReturnValue({ + data: { count: { passed: 1, failed: 1 } }, }); + }); + + it('renders', () => { + const { getByTestId } = render( + + + + ); + expect( - queryByTestId('securitySolutionFlyoutInsightsMisconfigurationsContent') + getByTestId('securitySolutionFlyoutInsightsMisconfigurationsTitleLink') ).toBeInTheDocument(); - expect(queryByTestId('noFindingsDataTestSubj')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/misconfiguration/misconfiguration_preview.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/misconfiguration/misconfiguration_preview.tsx index e6c3950e81583..a13a77a3562ff 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/misconfiguration/misconfiguration_preview.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/misconfiguration/misconfiguration_preview.tsx @@ -17,6 +17,12 @@ import { i18n } from '@kbn/i18n'; import { ExpandablePanel } from '@kbn/security-solution-common'; import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'; +import { hasVulnerabilitiesData } from '@kbn/cloud-security-posture'; +import { + CspInsightLeftPanelSubTab, + EntityDetailsLeftPanelTab, +} from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header'; import { UserDetailsPanelKey } from '../../../flyout/entity_details/user_details_left'; import { HostDetailsPanelKey } from '../../../flyout/entity_details/host_details_left'; import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score'; @@ -55,34 +61,6 @@ const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: numb ]; }; -const MisconfigurationEmptyState = ({ euiTheme }: { euiTheme: EuiThemeComputed<{}> }) => { - return ( - - - - -

    {'-'}

    -
    -
    - - - - - -
    -
    - ); -}; - const MisconfigurationPreviewScore = ({ passedFindings, failedFindings, @@ -136,6 +114,7 @@ export const MisconfigurationsPreview = ({ sort: [], enabled: true, pageSize: 1, + ignore_unavailable: true, }); const isUsingHostName = fieldName === 'host.name'; const passedFindings = data?.count.passed || 0; @@ -144,6 +123,29 @@ export const MisconfigurationsPreview = ({ const { euiTheme } = useEuiTheme(); const hasMisconfigurationFindings = passedFindings > 0 || failedFindings > 0; + const { data: vulnerabilitiesData } = useVulnerabilitiesPreview({ + query: buildEntityFlyoutPreviewQuery('host.name', name), + sort: [], + enabled: true, + pageSize: 1, + }); + + const { + CRITICAL = 0, + HIGH = 0, + MEDIUM = 0, + LOW = 0, + NONE = 0, + } = vulnerabilitiesData?.count || {}; + + const hasVulnerabilitiesFindings = hasVulnerabilitiesData({ + critical: CRITICAL, + high: HIGH, + medium: MEDIUM, + low: LOW, + none: NONE, + }); + const buildFilterQuery = useMemo( () => (isUsingHostName ? buildHostNamesFilter([name]) : buildUserNamesFilter([name])), [isUsingHostName, name] @@ -155,12 +157,17 @@ export const MisconfigurationsPreview = ({ onlyLatest: false, pagination: FIRST_RECORD_PAGINATION, }); + const { data: hostRisk } = riskScoreState; + const riskData = hostRisk?.[0]; + const isRiskScoreExist = isUsingHostName ? !!(riskData as HostRiskScore)?.host.risk : !!(riskData as UserRiskScore)?.user.risk; + const { openLeftPanel } = useExpandableFlyoutApi(); + const goToEntityInsightTab = useCallback(() => { openLeftPanel({ id: isUsingHostName ? HostDetailsPanelKey : UserDetailsPanelKey, @@ -169,16 +176,27 @@ export const MisconfigurationsPreview = ({ name, isRiskScoreExist, hasMisconfigurationFindings, - path: { tab: 'csp_insights' }, + hasVulnerabilitiesFindings, + path: { + tab: EntityDetailsLeftPanelTab.CSP_INSIGHTS, + subTab: CspInsightLeftPanelSubTab.MISCONFIGURATIONS, + }, } : { user: { name }, isRiskScoreExist, hasMisconfigurationFindings, - path: { tab: 'csp_insights' }, + path: { tab: EntityDetailsLeftPanelTab.CSP_INSIGHTS }, }, }); - }, [hasMisconfigurationFindings, isRiskScoreExist, isUsingHostName, name, openLeftPanel]); + }, [ + hasMisconfigurationFindings, + hasVulnerabilitiesFindings, + isRiskScoreExist, + isUsingHostName, + name, + openLeftPanel, + ]); const link = useMemo( () => !isPreviewMode @@ -216,15 +234,12 @@ export const MisconfigurationsPreview = ({ data-test-subj={'securitySolutionFlyoutInsightsMisconfigurations'} > - {hasMisconfigurationFindings ? ( - - ) : ( - - )} + + diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.test.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.test.tsx index 0436da3e192b3..cc71d1be2158d 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.test.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.test.tsx @@ -5,23 +5,44 @@ * 2.0. */ -import { TestProviders } from '../../../common/mock'; -import { render } from '@testing-library/react'; import React from 'react'; +import { render } from '@testing-library/react'; import { VulnerabilitiesPreview } from './vulnerabilities_preview'; +import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'; +import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'; +import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { TestProviders } from '../../../common/mock/test_providers'; -const mockProps: { hostName: string } = { - hostName: 'testContextID', -}; +// Mock hooks +jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'); +jest.mock('@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'); +jest.mock('../../../entity_analytics/api/hooks/use_risk_score'); +jest.mock('@kbn/expandable-flyout'); describe('VulnerabilitiesPreview', () => { - it('renders', () => { - const { queryByTestId } = render(, { - wrapper: TestProviders, + const mockOpenLeftPanel = jest.fn(); + + beforeEach(() => { + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + (useVulnerabilitiesPreview as jest.Mock).mockReturnValue({ + data: { count: { CRITICAL: 0, HIGH: 1, MEDIUM: 1, LOW: 0, UNKNOWN: 0 } }, + }); + (useRiskScore as jest.Mock).mockReturnValue({ data: [{ host: { risk: 75 } }] }); + (useMisconfigurationPreview as jest.Mock).mockReturnValue({ + data: { count: { passed: 1, failed: 1 } }, }); + }); + + it('renders', () => { + const { getByTestId } = render( + + + + ); + expect( - queryByTestId('securitySolutionFlyoutInsightsVulnerabilitiesContent') + getByTestId('securitySolutionFlyoutInsightsVulnerabilitiesTitleLink') ).toBeInTheDocument(); - expect(queryByTestId('noVulnerabilitiesDataTestSubj')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.tsx index 6e30d39fc98a6..eef778b1e6f0c 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.tsx @@ -5,125 +5,30 @@ * 2.0. */ -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { css } from '@emotion/react'; import type { EuiThemeComputed } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, useEuiTheme, EuiTitle } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { DistributionBar } from '@kbn/security-solution-distribution-bar'; import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'; -import { i18n } from '@kbn/i18n'; import { ExpandablePanel } from '@kbn/security-solution-common'; import { buildEntityFlyoutPreviewQuery, - VULNERABILITIES_SEVERITY, getAbbreviatedNumber, } from '@kbn/cloud-security-posture-common'; -import { getSeverityStatusColor, getSeverityText } from '@kbn/cloud-security-posture'; +import { getVulnerabilityStats, hasVulnerabilitiesData } from '@kbn/cloud-security-posture'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'; +import { EntityDetailsLeftPanelTab } from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header'; +import { HostDetailsPanelKey } from '../../../flyout/entity_details/host_details_left'; +import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score'; +import { RiskScoreEntity } from '../../../../common/entity_analytics/risk_engine'; +import { buildHostNamesFilter } from '../../../../common/search_strategy'; -interface VulnerabilitiesDistributionBarProps { - key: string; - count: number; - color: string; -} - -const getVulnerabilityStats = ( - critical: number, - high: number, - medium: number, - low: number, - none: number -): VulnerabilitiesDistributionBarProps[] => { - const vulnerabilityStats: VulnerabilitiesDistributionBarProps[] = []; - if (critical === 0 && high === 0 && medium === 0 && low === 0 && none === 0) - return vulnerabilityStats; - - if (none > 0) - vulnerabilityStats.push({ - key: i18n.translate( - 'xpack.securitySolution.flyout.right.insights.vulnerabilities.noneVulnerabilitiesText', - { - defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.UNKNOWN), - } - ), - count: none, - color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.UNKNOWN), - }); - if (low > 0) - vulnerabilityStats.push({ - key: i18n.translate( - 'xpack.securitySolution.flyout.right.insights.vulnerabilities.lowVulnerabilitiesText', - { - defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.LOW), - } - ), - count: low, - color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.LOW), - }); - - if (medium > 0) - vulnerabilityStats.push({ - key: i18n.translate( - 'xpack.securitySolution.flyout.right.insights.vulnerabilities.mediumVulnerabilitiesText', - { - defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.MEDIUM), - } - ), - count: medium, - color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.MEDIUM), - }); - if (high > 0) - vulnerabilityStats.push({ - key: i18n.translate( - 'xpack.securitySolution.flyout.right.insights.vulnerabilities.highVulnerabilitiesText', - { - defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.HIGH), - } - ), - count: high, - color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.HIGH), - }); - if (critical > 0) - vulnerabilityStats.push({ - key: i18n.translate( - 'xpack.securitySolution.flyout.right.insights.vulnerabilities.CriticalVulnerabilitiesText', - { - defaultMessage: getSeverityText(VULNERABILITIES_SEVERITY.CRITICAL), - } - ), - count: critical, - color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.CRITICAL), - }); - - return vulnerabilityStats; -}; - -const VulnerabilitiesEmptyState = ({ euiTheme }: { euiTheme: EuiThemeComputed<{}> }) => { - return ( - - - - -

    {'-'}

    -
    -
    - - - - - -
    -
    - ); +const FIRST_RECORD_PAGINATION = { + cursorStart: 0, + querySize: 1, }; const VulnerabilitiesCount = ({ @@ -159,9 +64,15 @@ const VulnerabilitiesCount = ({ ); }; -export const VulnerabilitiesPreview = ({ hostName }: { hostName: string }) => { +export const VulnerabilitiesPreview = ({ + name, + isPreviewMode, +}: { + name: string; + isPreviewMode?: boolean; +}) => { const { data } = useVulnerabilitiesPreview({ - query: buildEntityFlyoutPreviewQuery('host.name', hostName), + query: buildEntityFlyoutPreviewQuery('host.name', name), sort: [], enabled: true, pageSize: 1, @@ -170,11 +81,77 @@ export const VulnerabilitiesPreview = ({ hostName }: { hostName: string }) => { const { CRITICAL = 0, HIGH = 0, MEDIUM = 0, LOW = 0, NONE = 0 } = data?.count || {}; const totalVulnerabilities = CRITICAL + HIGH + MEDIUM + LOW + NONE; + + const hasVulnerabilitiesFindings = hasVulnerabilitiesData({ + critical: CRITICAL, + high: HIGH, + medium: MEDIUM, + low: LOW, + none: NONE, + }); + const { euiTheme } = useEuiTheme(); - const hasVulnerabilities = totalVulnerabilities > 0; + + const { data: dataMisconfiguration } = useMisconfigurationPreview({ + query: buildEntityFlyoutPreviewQuery('host.name', name), + sort: [], + enabled: true, + pageSize: 1, + }); + + const passedFindings = dataMisconfiguration?.count.passed || 0; + const failedFindings = dataMisconfiguration?.count.failed || 0; + + const hasMisconfigurationFindings = passedFindings > 0 || failedFindings > 0; + + const buildFilterQuery = useMemo(() => buildHostNamesFilter([name]), [name]); + const riskScoreState = useRiskScore({ + riskEntity: RiskScoreEntity.host, + filterQuery: buildFilterQuery, + onlyLatest: false, + pagination: FIRST_RECORD_PAGINATION, + }); + const { data: hostRisk } = riskScoreState; + const riskData = hostRisk?.[0]; + const isRiskScoreExist = riskData?.host.risk; + const { openLeftPanel } = useExpandableFlyoutApi(); + const goToEntityInsightTab = useCallback(() => { + openLeftPanel({ + id: HostDetailsPanelKey, + params: { + name, + isRiskScoreExist, + hasMisconfigurationFindings, + hasVulnerabilitiesFindings, + path: { tab: EntityDetailsLeftPanelTab.CSP_INSIGHTS, subTab: 'vulnerabilitiesTabId' }, + }, + }); + }, [ + hasMisconfigurationFindings, + hasVulnerabilitiesFindings, + isRiskScoreExist, + name, + openLeftPanel, + ]); + const link = useMemo( + () => + !isPreviewMode + ? { + callback: goToEntityInsightTab, + tooltip: ( + + ), + } + : undefined, + [isPreviewMode, goToEntityInsightTab] + ); return ( { />
    ), + link, }} data-test-subj={'securitySolutionFlyoutInsightsVulnerabilities'} > - {hasVulnerabilities ? ( - - ) : ( - - )} + - + diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/index.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/index.tsx index ddcdc252bff76..6f728d7653783 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/index.tsx @@ -7,11 +7,6 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { - ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS, - uiMetricService, -} from '@kbn/cloud-security-posture-common/utils/ui_metrics'; -import { METRIC_TYPE } from '@kbn/analytics'; import { EntityDetailsLeftPanelTab } from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header'; import { PREFIX } from '../../../flyout/shared/test_ids'; import type { RiskInputsTabProps } from './tabs/risk_inputs/risk_inputs_tab'; @@ -40,8 +35,6 @@ export const getInsightsInputTab = ({ name: string; fieldName: 'host.name' | 'user.name'; }) => { - uiMetricService.trackUiMetric(METRIC_TYPE.COUNT, ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS); - return { id: EntityDetailsLeftPanelTab.CSP_INSIGHTS, 'data-test-subj': INSIGHTS_TAB_TEST_ID, diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.tsx index 4d7ffc641ffc7..6e5774ba1756e 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_details_left/index.tsx @@ -12,6 +12,7 @@ import { getInsightsInputTab, } from '../../../entity_analytics/components/entity_details_flyout'; import { LeftPanelContent } from '../shared/components/left_panel/left_panel_content'; +import type { CspInsightLeftPanelSubTab } from '../shared/components/left_panel/left_panel_header'; import { EntityDetailsLeftPanelTab, LeftPanelHeader, @@ -23,8 +24,10 @@ export interface HostDetailsPanelProps extends Record { name: string; scopeId: string; hasMisconfigurationFindings?: boolean; + hasVulnerabilitiesFindings?: boolean; path?: { tab?: EntityDetailsLeftPanelTab; + subTab?: CspInsightLeftPanelSubTab; }; } export interface HostDetailsExpandableFlyoutProps extends FlyoutPanelProps { @@ -39,6 +42,7 @@ export const HostDetailsPanel = ({ scopeId, path, hasMisconfigurationFindings, + hasVulnerabilitiesFindings, }: HostDetailsPanelProps) => { const [selectedTabId, setSelectedTabId] = useState( path?.tab === EntityDetailsLeftPanelTab.CSP_INSIGHTS @@ -53,11 +57,12 @@ export const HostDetailsPanel = ({ : []; // Determine if the Insights tab should be included - const insightsTab = hasMisconfigurationFindings - ? [getInsightsInputTab({ name, fieldName: 'host.name' })] - : []; + const insightsTab = + hasMisconfigurationFindings || hasVulnerabilitiesFindings + ? [getInsightsInputTab({ name, fieldName: 'host.name' })] + : []; return [[...riskScoreTab, ...insightsTab], EntityDetailsLeftPanelTab.RISK_INPUTS, () => {}]; - }, [isRiskScoreExist, name, scopeId, hasMisconfigurationFindings]); + }, [isRiskScoreExist, name, scopeId, hasMisconfigurationFindings, hasVulnerabilitiesFindings]); return ( <> diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx index 8ea65a7f3096b..4538f53f0bd81 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiHorizontalRule } from '@elastic/eui'; import { FlyoutBody } from '@kbn/security-solution-common'; -import { EntityInsight } from '../../../cloud_security_posture/components'; +import { EntityInsight } from '../../../cloud_security_posture/components/entity_insight'; import { AssetCriticalityAccordion } from '../../../entity_analytics/components/asset_criticality/asset_criticality_selector'; import { FlyoutRiskSummary } from '../../../entity_analytics/components/risk_summary_flyout/risk_summary'; import type { RiskScoreState } from '../../../entity_analytics/api/hooks/use_risk_score'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx index 42280e60ef46e..9c75287ed0657 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx @@ -12,6 +12,8 @@ import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { FlyoutLoading, FlyoutNavigation } from '@kbn/security-solution-common'; import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'; +import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'; +import { sum } from 'lodash'; import { useRefetchQueryById } from '../../../entity_analytics/api/hooks/use_refetch_query_by_id'; import { RISK_INPUTS_TAB_QUERY_ID } from '../../../entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs_tab'; import type { Refetch } from '../../../common/types'; @@ -107,6 +109,15 @@ export const HostPanel = ({ const hasMisconfigurationFindings = passedFindings > 0 || failedFindings > 0; + const { data: vulnerabilitiesData } = useVulnerabilitiesPreview({ + query: buildEntityFlyoutPreviewQuery('host.name', hostName), + sort: [], + enabled: true, + pageSize: 1, + }); + + const hasVulnerabilitiesFindings = sum(Object.values(vulnerabilitiesData?.count || {})) > 0; + useQueryInspector({ deleteQuery, inspect: inspectRiskScore, @@ -130,10 +141,19 @@ export const HostPanel = ({ isRiskScoreExist, path: tab ? { tab } : undefined, hasMisconfigurationFindings, + hasVulnerabilitiesFindings, }, }); }, - [telemetry, openLeftPanel, hostName, scopeId, isRiskScoreExist, hasMisconfigurationFindings] + [ + telemetry, + openLeftPanel, + hostName, + scopeId, + isRiskScoreExist, + hasMisconfigurationFindings, + hasVulnerabilitiesFindings, + ] ); const openDefaultPanel = useCallback( @@ -173,7 +193,8 @@ export const HostPanel = ({ <> diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx index a33911c928aaf..438f75e7a4ccb 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx @@ -25,6 +25,11 @@ export enum EntityDetailsLeftPanelTab { CSP_INSIGHTS = 'csp_insights', } +export enum CspInsightLeftPanelSubTab { + MISCONFIGURATIONS = 'misconfigurationTabId', + VULNERABILITIES = 'vulnerabilitiesTabId', +} + export interface PanelHeaderProps { /** * Id of the tab selected in the parent component to display its content diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx index 42b281d0c8d2b..8bcf5dd690200 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx @@ -23,7 +23,7 @@ import { ObservedEntity } from '../shared/components/observed_entity'; import type { ObservedEntityData } from '../shared/components/observed_entity/types'; import { useObservedUserItems } from './hooks/use_observed_user_items'; import type { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; -import { EntityInsight } from '../../../cloud_security_posture/components'; +import { EntityInsight } from '../../../cloud_security_posture/components/entity_insight'; interface UserPanelContentProps { userName: string; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx index ee1ec526c2840..ec55fb292abfd 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx @@ -30,7 +30,7 @@ import { UserPanelContent } from './content'; import { UserPanelHeader } from './header'; import { UserDetailsPanelKey } from '../user_details_left'; import { useObservedUser } from './hooks/use_observed_user'; -import type { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; +import { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; import { UserPreviewPanelFooter } from '../user_preview/footer'; export interface UserPanelProps extends Record { @@ -83,6 +83,7 @@ export const UserPanel = ({ const { data: userRisk } = riskScoreState; const userRiskData = userRisk && userRisk.length > 0 ? userRisk[0] : undefined; + const isRiskScoreExist = !!userRiskData?.user.risk; const refetchRiskInputsTab = useRefetchQueryById(RISK_INPUTS_TAB_QUERY_ID); const refetchRiskScore = useCallback(() => { @@ -149,8 +150,15 @@ export const UserPanel = ({ hasMisconfigurationFindings, ] ); - - const openPanelFirstTab = useCallback(() => openPanelTab(), [openPanelTab]); + const openPanelFirstTab = useCallback( + () => + openPanelTab( + isRiskScoreExist + ? EntityDetailsLeftPanelTab.RISK_INPUTS + : EntityDetailsLeftPanelTab.CSP_INSIGHTS + ), + [isRiskScoreExist, openPanelTab] + ); const hasUserDetailsData = !!userRiskData?.user.risk || diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/vulnerabilities_contextual_flyout.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/vulnerabilities_contextual_flyout.cy.ts index 04ba10c908df7..591d458af56c1 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/vulnerabilities_contextual_flyout.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/vulnerabilities_contextual_flyout.cy.ts @@ -18,10 +18,12 @@ import { ALERTS_URL } from '../../../../urls/navigation'; import { visit } from '../../../../tasks/navigation'; const CSP_INSIGHT_VULNERABILITIES_TITLE = getDataTestSubjectSelector( - 'securitySolutionFlyoutInsightsVulnerabilitiesTitleText' + 'securitySolutionFlyoutInsightsVulnerabilitiesTitleLink' ); -const NO_VULNERABILITIES_TEXT = getDataTestSubjectSelector('noVulnerabilitiesDataTestSubj'); +const CSP_INSIGHT_VULNERABILITIES_TABLE = getDataTestSubjectSelector( + 'securitySolutionFlyoutVulnerabilitiesFindingsTable' +); const timestamp = Date.now(); @@ -154,6 +156,28 @@ describe('Alert Host details expandable flyout', { tags: ['@ess', '@serverless'] }); }); + context( + 'Host name - Has Vulnerabilities findings but with different host name than the alerts', + () => { + beforeEach(() => { + createMockVulnerability(false); + cy.reload(); + expandFirstAlertHostFlyout(); + }); + + afterEach(() => { + deleteDataStream(); + }); + + it('should display Vulnerabilities preview under Insights Entities when it has Vulnerabilities Findings', () => { + expandFirstAlertHostFlyout(); + + cy.log('check if Vulnerabilities preview title is not shown'); + cy.get(CSP_INSIGHT_VULNERABILITIES_TITLE).should('not.exist'); + }); + } + ); + context('Host name - Has Vulnerabilities findings', () => { beforeEach(() => { createMockVulnerability(true); @@ -169,27 +193,10 @@ describe('Alert Host details expandable flyout', { tags: ['@ess', '@serverless'] cy.log('check if Vulnerabilities preview title shown'); cy.get(CSP_INSIGHT_VULNERABILITIES_TITLE).should('be.visible'); }); - }); - - context( - 'Host name - Has Vulnerabilities findings but host name is not the same as alert host name', - () => { - beforeEach(() => { - createMockVulnerability(false); - cy.reload(); - expandFirstAlertHostFlyout(); - }); - afterEach(() => { - deleteDataStream(); - }); - - it('should display Vulnerabilities preview under Insights Entities when it has Vulnerabilities Findings but it should show no vulnerabilities title', () => { - cy.log('check if Vulnerabilities preview title shown'); - cy.get(CSP_INSIGHT_VULNERABILITIES_TITLE).should('be.visible'); - cy.log('check if no vulnerabilities text is shown'); - cy.get(NO_VULNERABILITIES_TEXT).should('be.visible'); - }); - } - ); + it('should display insight tabs and findings table upon clicking on misconfiguration accordion', () => { + cy.get(CSP_INSIGHT_VULNERABILITIES_TITLE).click(); + cy.get(CSP_INSIGHT_VULNERABILITIES_TABLE).should('be.visible'); + }); + }); }); From 02cc5a83b860713bc61868b766deda2c4e114bda Mon Sep 17 00:00:00 2001 From: Antonio Date: Wed, 9 Oct 2024 15:41:20 +0200 Subject: [PATCH 060/110] [ResponseOps][Cases] Fix case actions bug in serverless security (#195281) Fixes #186270 ## Summary This PR ensures that cases created by the case action in stack management rules in serverless security projects are assigned the correct owner. ### How to test 1. Add the following line to `serverless.yml` - `xpack.cloud.serverless.project_id: test-123` 2. Start elastic search in serverless security mode - `yarn es serverless --projectType security` 3. Start Kibana in serverless security mode - `yarn start --serverless=security` 4. Go to stack and create a rule with the cases action. 5. When an alert is triggered confirm you can view the case in `Security > Cases` --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../plugins/cases/common/utils/owner.test.ts | 26 +++++--- x-pack/plugins/cases/common/utils/owner.ts | 16 ++++- x-pack/plugins/cases/kibana.jsonc | 1 + .../system_actions/cases/cases_params.tsx | 2 +- .../server/connectors/cases/index.test.ts | 64 +++++++++++++++---- .../cases/server/connectors/cases/index.ts | 33 +++++++--- .../plugins/cases/server/connectors/index.ts | 11 +++- x-pack/plugins/cases/server/plugin.ts | 4 ++ x-pack/plugins/cases/server/types.ts | 2 + x-pack/plugins/cases/tsconfig.json | 1 + 10 files changed, 124 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/cases/common/utils/owner.test.ts b/x-pack/plugins/cases/common/utils/owner.test.ts index d3de319754725..a6f7c99f540bb 100644 --- a/x-pack/plugins/cases/common/utils/owner.test.ts +++ b/x-pack/plugins/cases/common/utils/owner.test.ts @@ -42,7 +42,7 @@ describe('owner utils', () => { it.each(owners)('returns owner %s correctly for consumer', (owner) => { for (const consumer of owner.validRuleConsumers ?? []) { - const result = getOwnerFromRuleConsumerProducer(consumer); + const result = getOwnerFromRuleConsumerProducer({ consumer }); expect(result).toBe(owner.id); } @@ -50,23 +50,33 @@ describe('owner utils', () => { it.each(owners)('returns owner %s correctly for producer', (owner) => { for (const producer of owner.validRuleConsumers ?? []) { - const result = getOwnerFromRuleConsumerProducer(undefined, producer); + const result = getOwnerFromRuleConsumerProducer({ producer }); expect(result).toBe(owner.id); } }); it('returns cases as a default owner', () => { - const owner = getOwnerFromRuleConsumerProducer(); + const owner = getOwnerFromRuleConsumerProducer({}); expect(owner).toBe(OWNER_INFO.cases.id); }); - it('returns owner as per consumer when both values are passed ', () => { - const owner = getOwnerFromRuleConsumerProducer( - AlertConsumers.SIEM, - AlertConsumers.OBSERVABILITY - ); + it('returns owner as per consumer when both values are passed', () => { + const owner = getOwnerFromRuleConsumerProducer({ + consumer: AlertConsumers.SIEM, + producer: AlertConsumers.OBSERVABILITY, + }); + + expect(owner).toBe(OWNER_INFO.securitySolution.id); + }); + + it('returns securitySolution owner if project isServerlessSecurity', () => { + const owner = getOwnerFromRuleConsumerProducer({ + consumer: AlertConsumers.OBSERVABILITY, + producer: AlertConsumers.OBSERVABILITY, + isServerlessSecurity: true, + }); expect(owner).toBe(OWNER_INFO.securitySolution.id); }); diff --git a/x-pack/plugins/cases/common/utils/owner.ts b/x-pack/plugins/cases/common/utils/owner.ts index d3650f0995b86..7bde7220233db 100644 --- a/x-pack/plugins/cases/common/utils/owner.ts +++ b/x-pack/plugins/cases/common/utils/owner.ts @@ -14,7 +14,21 @@ export const isValidOwner = (owner: string): owner is keyof typeof OWNER_INFO => export const getCaseOwnerByAppId = (currentAppId?: string) => Object.values(OWNER_INFO).find((info) => info.appId === currentAppId)?.id; -export const getOwnerFromRuleConsumerProducer = (consumer?: string, producer?: string): Owner => { +export const getOwnerFromRuleConsumerProducer = ({ + consumer, + producer, + isServerlessSecurity, +}: { + consumer?: string; + producer?: string; + isServerlessSecurity?: boolean; +}): Owner => { + // This is a workaround for a very specific bug with the cases action in serverless security + // More info here: https://github.com/elastic/kibana/issues/186270 + if (isServerlessSecurity) { + return OWNER_INFO.securitySolution.id; + } + for (const value of Object.values(OWNER_INFO)) { const foundConsumer = value.validRuleConsumers?.find( (validConsumer) => validConsumer === consumer || validConsumer === producer diff --git a/x-pack/plugins/cases/kibana.jsonc b/x-pack/plugins/cases/kibana.jsonc index 84c04da1fe0f6..300b1ee4c2c12 100644 --- a/x-pack/plugins/cases/kibana.jsonc +++ b/x-pack/plugins/cases/kibana.jsonc @@ -30,6 +30,7 @@ "uiActions", ], "optionalPlugins": [ + "cloud", "home", "taskManager", "usageCollection", diff --git a/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx b/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx index 6b6f85e53045f..6c93b2435af8e 100644 --- a/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx +++ b/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx @@ -43,7 +43,7 @@ export const CasesParamsFieldsComponent: React.FunctionComponent< notifications: { toasts }, data: { dataViews: dataViewsService }, } = useKibana().services; - const owner = getOwnerFromRuleConsumerProducer(featureId, producerId); + const owner = getOwnerFromRuleConsumerProducer({ consumer: featureId, producer: producerId }); const { dataView, isLoading: loadingAlertDataViews } = useAlertsDataView({ http, diff --git a/x-pack/plugins/cases/server/connectors/cases/index.test.ts b/x-pack/plugins/cases/server/connectors/cases/index.test.ts index cca7092fde368..5c7b29ef4e704 100644 --- a/x-pack/plugins/cases/server/connectors/cases/index.test.ts +++ b/x-pack/plugins/cases/server/connectors/cases/index.test.ts @@ -80,26 +80,26 @@ describe('getCasesConnectorType', () => { }); it('sets the correct connectorTypeId', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect(adapter.connectorTypeId).toEqual('.cases'); }); describe('ruleActionParamsSchema', () => { it('validates getParams() correctly', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect(adapter.ruleActionParamsSchema.validate(getParams())).toEqual(getParams()); }); it('throws if missing getParams()', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect(() => adapter.ruleActionParamsSchema.validate({})).toThrow(); }); it('does not accept more than one groupingBy key', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect(() => adapter.ruleActionParamsSchema.validate( @@ -109,7 +109,7 @@ describe('getCasesConnectorType', () => { }); it('should fail with not valid time window', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect(() => adapter.ruleActionParamsSchema.validate(getParams({ timeWindow: '10d+3d' })) @@ -119,7 +119,7 @@ describe('getCasesConnectorType', () => { describe('buildActionParams', () => { it('builds the action getParams() correctly', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect( adapter.buildActionParams({ @@ -164,7 +164,7 @@ describe('getCasesConnectorType', () => { }); it('builds the action getParams() and templateId correctly', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect( adapter.buildActionParams({ @@ -209,7 +209,7 @@ describe('getCasesConnectorType', () => { }); it('builds the action getParams() correctly without ruleUrl', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect( adapter.buildActionParams({ // @ts-expect-error: not all fields are needed @@ -252,7 +252,7 @@ describe('getCasesConnectorType', () => { }); it('maps observability consumers to the correct owner', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); for (const consumer of [ AlertConsumers.OBSERVABILITY, @@ -276,7 +276,7 @@ describe('getCasesConnectorType', () => { }); it('maps security solution consumers to the correct owner', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); for (const consumer of [AlertConsumers.SIEM]) { const connectorParams = adapter.buildActionParams({ @@ -292,7 +292,7 @@ describe('getCasesConnectorType', () => { }); it('maps stack consumers to the correct owner', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); for (const consumer of [AlertConsumers.ML, AlertConsumers.STACK_ALERTS]) { const connectorParams = adapter.buildActionParams({ @@ -308,7 +308,7 @@ describe('getCasesConnectorType', () => { }); it('fallback to the cases owner if the consumer is not in the mapping', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); const connectorParams = adapter.buildActionParams({ // @ts-expect-error: not all fields are needed @@ -320,11 +320,27 @@ describe('getCasesConnectorType', () => { expect(connectorParams.subActionParams.owner).toBe('cases'); }); + + it('correctly fallsback to security owner if the project is serverless security', () => { + const adapter = getCasesConnectorAdapter({ isServerlessSecurity: true }); + + for (const consumer of [AlertConsumers.ML, AlertConsumers.STACK_ALERTS]) { + const connectorParams = adapter.buildActionParams({ + // @ts-expect-error: not all fields are needed + alerts, + rule: { ...rule, consumer }, + params: getParams(), + spaceId: 'default', + }); + + expect(connectorParams.subActionParams.owner).toBe('securitySolution'); + } + }); }); describe('getKibanaPrivileges', () => { it('constructs the correct privileges from the consumer', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect( adapter.getKibanaPrivileges?.({ @@ -344,7 +360,7 @@ describe('getCasesConnectorType', () => { }); it('constructs the correct privileges from the producer if the consumer is not found', () => { - const adapter = getCasesConnectorAdapter(); + const adapter = getCasesConnectorAdapter({}); expect( adapter.getKibanaPrivileges?.({ @@ -362,6 +378,26 @@ describe('getCasesConnectorType', () => { 'cases:observability/findConfigurations', ]); }); + + it('correctly overrides the consumer and producer if the project is serverless security', () => { + const adapter = getCasesConnectorAdapter({ isServerlessSecurity: true }); + + expect( + adapter.getKibanaPrivileges?.({ + consumer: 'alerting', + producer: AlertConsumers.LOGS, + }) + ).toEqual([ + 'cases:securitySolution/createCase', + 'cases:securitySolution/updateCase', + 'cases:securitySolution/deleteCase', + 'cases:securitySolution/pushCase', + 'cases:securitySolution/createComment', + 'cases:securitySolution/updateComment', + 'cases:securitySolution/deleteComment', + 'cases:securitySolution/findConfigurations', + ]); + }); }); }); }); diff --git a/x-pack/plugins/cases/server/connectors/cases/index.ts b/x-pack/plugins/cases/server/connectors/cases/index.ts index 8be0b645cbfb3..07b4ab5e29551 100644 --- a/x-pack/plugins/cases/server/connectors/cases/index.ts +++ b/x-pack/plugins/cases/server/connectors/cases/index.ts @@ -16,7 +16,11 @@ import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { ConnectorAdapter } from '@kbn/alerting-plugin/server'; import { CasesConnector } from './cases_connector'; import { DEFAULT_MAX_OPEN_CASES } from './constants'; -import { CASES_CONNECTOR_ID, CASES_CONNECTOR_TITLE } from '../../../common/constants'; +import { + CASES_CONNECTOR_ID, + CASES_CONNECTOR_TITLE, + SECURITY_SOLUTION_OWNER, +} from '../../../common/constants'; import { getOwnerFromRuleConsumerProducer } from '../../../common/utils/owner'; import type { @@ -40,12 +44,14 @@ interface GetCasesConnectorTypeArgs { savedObjectTypes: string[] ) => Promise; getSpaceId: (request?: KibanaRequest) => string; + isServerlessSecurity?: boolean; } export const getCasesConnectorType = ({ getCasesClient, getSpaceId, getUnsecuredSavedObjectsClient, + isServerlessSecurity, }: GetCasesConnectorTypeArgs): SubActionConnectorType< CasesConnectorConfig, CasesConnectorSecrets @@ -69,27 +75,34 @@ export const getCasesConnectorType = ({ minimumLicenseRequired: 'platinum' as const, isSystemActionType: true, getKibanaPrivileges: ({ params } = { params: { subAction: 'run', subActionParams: {} } }) => { - const owner = params?.subActionParams?.owner as string; - - if (!owner) { + if (!params?.subActionParams?.owner) { throw new Error('Cannot authorize cases. Owner is not defined in the subActionParams.'); } + const owner = isServerlessSecurity + ? SECURITY_SOLUTION_OWNER + : (params?.subActionParams?.owner as string); + return constructRequiredKibanaPrivileges(owner); }, }); -export const getCasesConnectorAdapter = (): ConnectorAdapter< - CasesConnectorRuleActionParams, - CasesConnectorParams -> => { +export const getCasesConnectorAdapter = ({ + isServerlessSecurity, +}: { + isServerlessSecurity?: boolean; +}): ConnectorAdapter => { return { connectorTypeId: CASES_CONNECTOR_ID, ruleActionParamsSchema: CasesConnectorRuleActionParamsSchema, buildActionParams: ({ alerts, rule, params, spaceId, ruleUrl }) => { const caseAlerts = [...alerts.new.data, ...alerts.ongoing.data]; - const owner = getOwnerFromRuleConsumerProducer(rule.consumer, rule.producer); + const owner = getOwnerFromRuleConsumerProducer({ + consumer: rule.consumer, + producer: rule.producer, + isServerlessSecurity, + }); const subActionParams = { alerts: caseAlerts, @@ -105,7 +118,7 @@ export const getCasesConnectorAdapter = (): ConnectorAdapter< return { subAction: 'run', subActionParams }; }, getKibanaPrivileges: ({ consumer, producer }) => { - const owner = getOwnerFromRuleConsumerProducer(consumer, producer); + const owner = getOwnerFromRuleConsumerProducer({ consumer, producer, isServerlessSecurity }); return constructRequiredKibanaPrivileges(owner); }, }; diff --git a/x-pack/plugins/cases/server/connectors/index.ts b/x-pack/plugins/cases/server/connectors/index.ts index 2d680163dde28..0b0f201b46d42 100644 --- a/x-pack/plugins/cases/server/connectors/index.ts +++ b/x-pack/plugins/cases/server/connectors/index.ts @@ -22,12 +22,14 @@ export function registerConnectorTypes({ core, getCasesClient, getSpaceId, + isServerlessSecurity, }: { actions: ActionsPluginSetupContract; alerting: AlertingPluginSetup; core: CoreSetup; getCasesClient: (request: KibanaRequest) => Promise; getSpaceId: (request?: KibanaRequest) => string; + isServerlessSecurity?: boolean; }) { const getUnsecuredSavedObjectsClient = async ( request: KibanaRequest, @@ -53,8 +55,13 @@ export function registerConnectorTypes({ }; actions.registerSubActionConnectorType( - getCasesConnectorType({ getCasesClient, getSpaceId, getUnsecuredSavedObjectsClient }) + getCasesConnectorType({ + getCasesClient, + getSpaceId, + getUnsecuredSavedObjectsClient, + isServerlessSecurity, + }) ); - alerting.registerConnectorAdapter(getCasesConnectorAdapter()); + alerting.registerConnectorAdapter(getCasesConnectorAdapter({ isServerlessSecurity })); } diff --git a/x-pack/plugins/cases/server/plugin.ts b/x-pack/plugins/cases/server/plugin.ts index 262289bc6a24c..fa172b48520a7 100644 --- a/x-pack/plugins/cases/server/plugin.ts +++ b/x-pack/plugins/cases/server/plugin.ts @@ -145,12 +145,16 @@ export class CasePlugin return plugins.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; }; + const isServerlessSecurity = + plugins.cloud?.isServerlessEnabled && plugins.cloud?.serverless.projectType === 'security'; + registerConnectorTypes({ actions: plugins.actions, alerting: plugins.alerting, core, getCasesClient, getSpaceId, + isServerlessSecurity, }); return { diff --git a/x-pack/plugins/cases/server/types.ts b/x-pack/plugins/cases/server/types.ts index 0153083337cfa..a51817c9d7e58 100644 --- a/x-pack/plugins/cases/server/types.ts +++ b/x-pack/plugins/cases/server/types.ts @@ -30,6 +30,7 @@ import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing- import type { NotificationsPluginStart } from '@kbn/notifications-plugin/server'; import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server'; import type { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; +import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { CasesClient } from './client'; import type { AttachmentFramework } from './attachment_framework/types'; import type { ExternalReferenceAttachmentTypeRegistry } from './attachment_framework/external_reference_registry'; @@ -46,6 +47,7 @@ export interface CasesServerSetupDependencies { taskManager?: TaskManagerSetupContract; usageCollection?: UsageCollectionSetup; spaces?: SpacesPluginSetup; + cloud?: CloudSetup; } export interface CasesServerStartDependencies { diff --git a/x-pack/plugins/cases/tsconfig.json b/x-pack/plugins/cases/tsconfig.json index fbe05134b5bfd..1d126d78f9543 100644 --- a/x-pack/plugins/cases/tsconfig.json +++ b/x-pack/plugins/cases/tsconfig.json @@ -76,6 +76,7 @@ "@kbn/core-http-router-server-internal", "@kbn/presentation-publishing", "@kbn/alerts-ui-shared", + "@kbn/cloud-plugin", ], "exclude": [ "target/**/*", From cc7fdba1422f2717984b958509be13abc820b15b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:44:12 +0100 Subject: [PATCH 061/110] [Inventory] Add k8s fields to Service entity type (#195407) closes https://github.com/elastic/kibana/issues/195244 - Removed metrics definition from service, host and container - Removed `metrics-apm` index patterns from the service definition because k8s fields are not available on that scope. - Added `traces-apm*` index pattern on the service definition https://github.com/user-attachments/assets/6c6b4fd6-817a-494e-8649-e2d76a8e98e3 --- .../built_in/containers_from_ecs_data.ts | 92 +------ .../entities/built_in/hosts_from_ecs_data.ts | 113 +-------- .../built_in/services_from_ecs_data.ts | 90 +------ .../apm/common/entities/types.ts | 13 - .../server/routes/entities/get_entities.ts | 28 +-- .../get_entity_history_services_metrics.ts | 84 ------- .../get_entity_history_services_timeseries.ts | 116 --------- .../entities/services/get_service_entities.ts | 3 +- .../services/get_service_entity_summary.ts | 3 +- .../server/routes/entities/services/routes.ts | 44 ---- .../apm/server/routes/entities/types.ts | 2 - .../utils/calculate_avg_metrics.test.ts | 236 ------------------ .../entities/utils/calculate_avg_metrics.ts | 45 ---- .../entities/utils/merge_entities.test.ts | 233 ----------------- .../routes/entities/utils/merge_entities.ts | 13 +- ...vices_entities_detailed_statistics.spec.ts | 58 ----- 16 files changed, 12 insertions(+), 1161 deletions(-) delete mode 100644 x-pack/plugins/observability_solution/apm/server/routes/entities/get_entity_history_services_metrics.ts delete mode 100644 x-pack/plugins/observability_solution/apm/server/routes/entities/get_entity_history_services_timeseries.ts delete mode 100644 x-pack/plugins/observability_solution/apm/server/routes/entities/utils/calculate_avg_metrics.test.ts delete mode 100644 x-pack/plugins/observability_solution/apm/server/routes/entities/utils/calculate_avg_metrics.ts delete mode 100644 x-pack/test/apm_api_integration/tests/entities/services/services_entities_detailed_statistics.spec.ts diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/containers_from_ecs_data.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/containers_from_ecs_data.ts index b9119143ec37e..6ce76e127c8e8 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/containers_from_ecs_data.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/containers_from_ecs_data.ts @@ -12,7 +12,7 @@ export const builtInContainersFromEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ id: `${BUILT_IN_ID_PREFIX}containers_from_ecs_data`, managed: true, - version: '1.0.0', + version: '0.1.0', name: 'Containers from ECS data', description: 'This definition extracts container entities from common data streams by looking for the ECS field container.id', @@ -65,94 +65,4 @@ export const builtInContainersFromEcsEntityDefinition: EntityDefinition = 'agent.type', 'agent.ephemeral_id', ], - metrics: [ - { - name: 'log_rate', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'doc_count', - filter: 'log.level: * OR error.log.level: *', - }, - ], - }, - { - name: 'error_log_rate', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'doc_count', - filter: '(log.level: "error" OR "ERROR") OR (error.log.level: "error" OR "ERROR")', - }, - ], - }, - { - name: 'cpu_usage_avg', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'avg', - field: 'docker.cpu.total.pct', - }, - ], - }, - { - name: 'memory_usage_avg', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'avg', - field: 'docker.memory.usage.pct', - }, - ], - }, - { - name: 'network_in_avg', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'avg', - field: 'docker.network.in.bytes', - }, - ], - }, - { - name: 'network_out_avg', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'avg', - field: 'docker.network.out.bytes', - }, - ], - }, - { - name: 'disk_read_avg', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'avg', - field: 'docker.diskio.read.ops', - }, - ], - }, - { - name: 'disk_write_avg', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'avg', - field: 'docker.diskio.write.ops', - }, - ], - }, - ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/hosts_from_ecs_data.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/hosts_from_ecs_data.ts index 5fead32f5c0e8..56f83d5fbaed6 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/hosts_from_ecs_data.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/hosts_from_ecs_data.ts @@ -11,7 +11,7 @@ import { BUILT_IN_ID_PREFIX } from './constants'; export const builtInHostsFromEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ id: `${BUILT_IN_ID_PREFIX}hosts_from_ecs_data`, managed: true, - version: '1.0.0', + version: '0.1.0', name: 'Hosts from ECS data', description: 'This definition extracts host entities from common data streams by looking for the ECS field host.name', @@ -65,115 +65,4 @@ export const builtInHostsFromEcsEntityDefinition: EntityDefinition = entityDefin 'agent.type', 'agent.version', ], - metrics: [ - { - name: 'log_rate', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'doc_count', - filter: 'log.level: * OR error.log.level: *', - }, - ], - }, - { - name: 'error_log_rate', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'doc_count', - filter: '(log.level: "error" OR "ERROR") OR (error.log.level: "error" OR "ERROR")', - }, - ], - }, - { - name: 'cpu_usage_avg', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'avg', - field: 'system.cpu.total.norm.pct', - }, - ], - }, - { - name: 'normalized_load_avg', - equation: 'A / B', - metrics: [ - { - name: 'A', - aggregation: 'avg', - field: 'system.load.1', - }, - { - name: 'B', - aggregation: 'max', - field: 'system.load.cores', - }, - ], - }, - { - name: 'memory_usage_avg', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'avg', - field: 'system.memory.actual.used.pct', - }, - ], - }, - { - name: 'memory_free_avg', - equation: 'A - B', - metrics: [ - { - name: 'A', - aggregation: 'max', - field: 'system.memory.total', - }, - { - name: 'B', - aggregation: 'avg', - field: 'system.memory.actual.used.bytes', - }, - ], - }, - { - name: 'disk_usage_max', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'max', - field: 'system.filesystem.used.pct', - }, - ], - }, - { - name: 'rx_avg', - equation: 'A * 8', - metrics: [ - { - name: 'A', - aggregation: 'sum', - field: 'host.network.ingress.bytes', - }, - ], - }, - { - name: 'tx_avg', - equation: 'A * 8', - metrics: [ - { - name: 'A', - aggregation: 'sum', - field: 'host.network.egress.bytes', - }, - ], - }, - ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/services_from_ecs_data.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/services_from_ecs_data.ts index c1496f424d393..6caa209da02ca 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/services_from_ecs_data.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/services_from_ecs_data.ts @@ -8,31 +8,16 @@ import { EntityDefinition, entityDefinitionSchema } from '@kbn/entities-schema'; import { BUILT_IN_ID_PREFIX } from './constants'; -const serviceTransactionFilter = (additionalFilters: string[] = []) => { - const baseFilters = [ - 'processor.event: "metric"', - 'metricset.name: "service_transaction"', - 'metricset.interval: "1m"', - ]; - - return [...baseFilters, ...additionalFilters].join(' AND '); -}; - export const builtInServicesFromEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ - version: '0.3.0', + version: '0.4.0', id: `${BUILT_IN_ID_PREFIX}services_from_ecs_data`, name: 'Services from ECS data', description: 'This definition extracts service entities from common data streams by looking for the ECS field service.name', type: 'service', managed: true, - indexPatterns: [ - 'logs-*', - 'filebeat*', - 'metrics-apm.service_transaction.1m*', - 'metrics-apm.service_summary.1m*', - ], + indexPatterns: ['logs-*', 'filebeat*', 'traces-apm*'], history: { timestampField: '@timestamp', interval: '1m', @@ -65,72 +50,9 @@ export const builtInServicesFromEcsEntityDefinition: EntityDefinition = 'cloud.provider', 'cloud.availability_zone', 'cloud.machine.type', - ], - metrics: [ - { - name: 'latency', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'avg', - filter: serviceTransactionFilter(), - field: 'transaction.duration.histogram', - }, - ], - }, - { - name: 'throughput', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'value_count', - filter: serviceTransactionFilter(), - field: 'transaction.duration.summary', - }, - ], - }, - { - name: 'failedTransactionRate', - equation: '1 - (A / B)', - metrics: [ - { - name: 'A', - aggregation: 'sum', - filter: serviceTransactionFilter(), - field: 'event.success_count', - }, - { - name: 'B', - aggregation: 'value_count', - filter: serviceTransactionFilter(), - field: 'event.success_count', - }, - ], - }, - { - name: 'logErrorRate', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'doc_count', - filter: - 'log.level: "error" OR log.level: "ERROR" OR error.log.level: "error" OR error.log.level: "ERROR"', - }, - ], - }, - { - name: 'logRate', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'doc_count', - filter: 'data_stream.type: logs', - }, - ], - }, + 'kubernetes.namespace', + 'orchestrator.cluster.name', + 'k8s.namespace.name', + 'k8s.cluster.name', ], }); diff --git a/x-pack/plugins/observability_solution/apm/common/entities/types.ts b/x-pack/plugins/observability_solution/apm/common/entities/types.ts index 1e13d7c1d3634..9775b1e32eae6 100644 --- a/x-pack/plugins/observability_solution/apm/common/entities/types.ts +++ b/x-pack/plugins/observability_solution/apm/common/entities/types.ts @@ -10,16 +10,3 @@ export enum EntityDataStreamType { TRACES = 'traces', LOGS = 'logs', } - -interface TraceMetrics { - latency?: number | null; - throughput?: number | null; - failedTransactionRate?: number | null; -} - -interface LogsMetrics { - logRate?: number | null; - logErrorRate?: number | null; -} - -export type EntityMetrics = TraceMetrics & LogsMetrics; diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entities.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entities.ts index 7395f639bb6e9..6cedb09efa7c2 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entities.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entities.ts @@ -12,7 +12,6 @@ import { import type { EntitiesESClient } from '../../lib/helpers/create_es_client/create_entities_es_client/create_entities_es_client'; import { getEntityLatestServices } from './get_entity_latest_services'; import type { EntityLatestServiceRaw } from './types'; -import { getEntityHistoryServicesMetrics } from './get_entity_history_services_metrics'; export function entitiesRangeQuery(start?: number, end?: number): QueryDslQueryContainer[] { if (!start || !end) { @@ -64,30 +63,5 @@ export async function getEntities({ serviceName, }); - const serviceEntitiesHistoryMetricsMap = entityLatestServices.length - ? await getEntityHistoryServicesMetrics({ - start, - end, - entitiesESClient, - entityIds: entityLatestServices.map((latestEntity) => latestEntity.entity.id), - size, - }) - : undefined; - - return entityLatestServices.map((latestEntity) => { - const historyEntityMetrics = serviceEntitiesHistoryMetricsMap?.[latestEntity.entity.id]; - return { - ...latestEntity, - entity: { - ...latestEntity.entity, - metrics: historyEntityMetrics || { - latency: undefined, - logErrorRate: undefined, - failedTransactionRate: undefined, - logRate: undefined, - throughput: undefined, - }, - }, - }; - }); + return entityLatestServices; } diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entity_history_services_metrics.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entity_history_services_metrics.ts deleted file mode 100644 index 009f384af901b..0000000000000 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entity_history_services_metrics.ts +++ /dev/null @@ -1,84 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { rangeQuery, termsQuery } from '@kbn/observability-plugin/server'; -import { - ENTITY_ID, - ENTITY_LAST_SEEN, -} from '@kbn/observability-shared-plugin/common/field_names/elasticsearch'; -import { EntityMetrics } from '../../../common/entities/types'; -import { - ENTITY_METRICS_FAILED_TRANSACTION_RATE, - ENTITY_METRICS_LATENCY, - ENTITY_METRICS_LOG_ERROR_RATE, - ENTITY_METRICS_LOG_RATE, - ENTITY_METRICS_THROUGHPUT, -} from '../../../common/es_fields/entities'; -import { EntitiesESClient } from '../../lib/helpers/create_es_client/create_entities_es_client/create_entities_es_client'; - -interface Params { - entitiesESClient: EntitiesESClient; - start: number; - end: number; - entityIds: string[]; - size: number; -} - -export async function getEntityHistoryServicesMetrics({ - end, - entityIds, - start, - entitiesESClient, - size, -}: Params) { - const response = await entitiesESClient.searchHistory('get_entities_history', { - body: { - size: 0, - track_total_hits: false, - query: { - bool: { - filter: [ - ...rangeQuery(start, end, ENTITY_LAST_SEEN), - ...termsQuery(ENTITY_ID, ...entityIds), - ], - }, - }, - aggs: { - entityIds: { - terms: { field: ENTITY_ID, size }, - aggs: { - latency: { avg: { field: ENTITY_METRICS_LATENCY } }, - logErrorRate: { avg: { field: ENTITY_METRICS_LOG_ERROR_RATE } }, - logRate: { avg: { field: ENTITY_METRICS_LOG_RATE } }, - throughput: { avg: { field: ENTITY_METRICS_THROUGHPUT } }, - failedTransactionRate: { avg: { field: ENTITY_METRICS_FAILED_TRANSACTION_RATE } }, - }, - }, - }, - }, - }); - - if (!response.aggregations) { - return {}; - } - - return response.aggregations.entityIds.buckets.reduce>( - (acc, currBucket) => { - return { - ...acc, - [currBucket.key]: { - latency: currBucket.latency.value, - logErrorRate: currBucket.logErrorRate.value, - logRate: currBucket.logRate.value, - throughput: currBucket.throughput.value, - failedTransactionRate: currBucket.failedTransactionRate.value, - }, - }; - }, - {} - ); -} diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entity_history_services_timeseries.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entity_history_services_timeseries.ts deleted file mode 100644 index 4ee23966f282c..0000000000000 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/get_entity_history_services_timeseries.ts +++ /dev/null @@ -1,116 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getBucketSize } from '@kbn/apm-data-access-plugin/common'; -import { rangeQuery, termsQuery } from '@kbn/observability-plugin/server'; -import { ENTITY_LAST_SEEN } from '@kbn/observability-shared-plugin/common/field_names/elasticsearch'; -import { keyBy } from 'lodash'; -import { SERVICE_NAME } from '../../../common/es_fields/apm'; -import { - ENTITY_METRICS_FAILED_TRANSACTION_RATE, - ENTITY_METRICS_LATENCY, - ENTITY_METRICS_LOG_ERROR_RATE, - ENTITY_METRICS_LOG_RATE, - ENTITY_METRICS_THROUGHPUT, -} from '../../../common/es_fields/entities'; -import { environmentQuery } from '../../../common/utils/environment_query'; -import { EntitiesESClient } from '../../lib/helpers/create_es_client/create_entities_es_client/create_entities_es_client'; - -interface Params { - entitiesESClient: EntitiesESClient; - start: number; - end: number; - serviceNames: string[]; - environment: string; -} - -export async function getEntityHistoryServicesTimeseries({ - start, - end, - serviceNames, - entitiesESClient, - environment, -}: Params) { - const { intervalString } = getBucketSize({ - start, - end, - minBucketSize: 60, - }); - - const response = await entitiesESClient.searchHistory('get_entities_history_timeseries', { - body: { - size: 0, - track_total_hits: false, - query: { - bool: { - filter: [ - ...rangeQuery(start, end, ENTITY_LAST_SEEN), - ...termsQuery(SERVICE_NAME, ...serviceNames), - ...environmentQuery(environment), - ], - }, - }, - aggs: { - serviceNames: { - terms: { field: SERVICE_NAME, size: serviceNames.length }, - aggs: { - timeseries: { - date_histogram: { - field: '@timestamp', - fixed_interval: intervalString, - min_doc_count: 0, - extended_bounds: { min: start, max: end }, - }, - aggs: { - latency: { avg: { field: ENTITY_METRICS_LATENCY } }, - logErrorRate: { avg: { field: ENTITY_METRICS_LOG_ERROR_RATE } }, - logRate: { avg: { field: ENTITY_METRICS_LOG_RATE } }, - throughput: { avg: { field: ENTITY_METRICS_THROUGHPUT } }, - failedTransactionRate: { avg: { field: ENTITY_METRICS_FAILED_TRANSACTION_RATE } }, - }, - }, - }, - }, - }, - }, - }); - - if (!response.aggregations) { - return {}; - } - - return keyBy( - response.aggregations.serviceNames.buckets.map((serviceBucket) => { - const serviceName = serviceBucket.key as string; - - return { - serviceName, - latency: serviceBucket.timeseries.buckets.map((bucket) => ({ - x: bucket.key, - y: bucket.latency.value ?? null, - })), - logErrorRate: serviceBucket.timeseries.buckets.map((bucket) => ({ - x: bucket.key, - y: bucket.logErrorRate.value ?? null, - })), - logRate: serviceBucket.timeseries.buckets.map((bucket) => ({ - x: bucket.key, - y: bucket.logRate.value ?? null, - })), - throughput: serviceBucket.timeseries.buckets.map((bucket) => ({ - x: bucket.key, - y: bucket.throughput.value ?? null, - })), - failedTransactionRate: serviceBucket.timeseries.buckets.map((bucket) => ({ - x: bucket.key, - y: bucket.failedTransactionRate.value ?? null, - })), - }; - }), - 'serviceName' - ); -} diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/services/get_service_entities.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/services/get_service_entities.ts index 084fbbe438952..9e6bb34bceafe 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/services/get_service_entities.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/entities/services/get_service_entities.ts @@ -10,7 +10,6 @@ import { WrappedElasticsearchClientError } from '@kbn/observability-plugin/serve import { EntitiesESClient } from '../../../lib/helpers/create_es_client/create_entities_es_client/create_entities_es_client'; import { withApmSpan } from '../../../utils/with_apm_span'; import { getEntities } from '../get_entities'; -import { calculateAvgMetrics } from '../utils/calculate_avg_metrics'; import { mergeEntities } from '../utils/merge_entities'; export const MAX_NUMBER_OF_SERVICES = 1_000; @@ -41,7 +40,7 @@ export async function getServiceEntities({ size: MAX_NUMBER_OF_SERVICES, }); - return calculateAvgMetrics(mergeEntities({ entities })); + return mergeEntities({ entities }); } catch (error) { // If the index does not exist, handle it gracefully if ( diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/services/get_service_entity_summary.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/services/get_service_entity_summary.ts index e99ecc0217ed9..3ab3b907f5be2 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/services/get_service_entity_summary.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/entities/services/get_service_entity_summary.ts @@ -8,7 +8,6 @@ import type { EntitiesESClient } from '../../../lib/helpers/create_es_client/create_entities_es_client/create_entities_es_client'; import { withApmSpan } from '../../../utils/with_apm_span'; import { getEntityLatestServices } from '../get_entity_latest_services'; -import { calculateAvgMetrics } from '../utils/calculate_avg_metrics'; import { mergeEntities } from '../utils/merge_entities'; import { MAX_NUMBER_OF_SERVICES } from './get_service_entities'; @@ -27,7 +26,7 @@ export function getServiceEntitySummary({ entitiesESClient, environment, service serviceName, }); - const serviceEntity = calculateAvgMetrics(mergeEntities({ entities: entityLatestServices })); + const serviceEntity = mergeEntities({ entities: entityLatestServices }); return serviceEntity[0]; }); } diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/services/routes.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/services/routes.ts index c3f36a6d86c52..218de180cbc00 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/services/routes.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/entities/services/routes.ts @@ -4,8 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import Boom from '@hapi/boom'; -import { jsonRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { createEntitiesESClient } from '../../../lib/helpers/create_es_client/create_entities_es_client/create_entities_es_client'; @@ -13,7 +11,6 @@ import { createApmServerRoute } from '../../apm_routes/create_apm_server_route'; import { environmentRt, kueryRt, rangeRt } from '../../default_api_types'; import { getServiceEntities } from './get_service_entities'; import { getServiceEntitySummary } from './get_service_entity_summary'; -import { getEntityHistoryServicesTimeseries } from '../get_entity_history_services_timeseries'; const serviceEntitiesSummaryRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/entities/services/{serviceName}/summary', @@ -72,46 +69,6 @@ const servicesEntitiesRoute = createApmServerRoute({ }, }); -const servicesEntitiesDetailedStatisticsRoute = createApmServerRoute({ - endpoint: 'POST /internal/apm/entities/services/detailed_statistics', - params: t.type({ - query: t.intersection([environmentRt, kueryRt, rangeRt]), - body: t.type({ serviceNames: jsonRt.pipe(t.array(t.string)) }), - }), - options: { tags: ['access:apm'] }, - handler: async (resources) => { - const { context, params, request } = resources; - const coreContext = await context.core; - - const entitiesESClient = await createEntitiesESClient({ - request, - esClient: coreContext.elasticsearch.client.asCurrentUser, - }); - - const { environment, start, end } = params.query; - - const { serviceNames } = params.body; - - if (!serviceNames.length) { - throw Boom.badRequest(`serviceNames cannot be empty`); - } - - const serviceEntitiesTimeseries = await getEntityHistoryServicesTimeseries({ - start, - end, - serviceNames, - environment, - entitiesESClient, - }); - - return { - currentPeriod: { - ...serviceEntitiesTimeseries, - }, - }; - }, -}); - const serviceLogRateTimeseriesRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/entities/services/{serviceName}/logs_rate_timeseries', params: t.type({ @@ -183,6 +140,5 @@ export const servicesEntitiesRoutesRepository = { ...servicesEntitiesRoute, ...serviceLogRateTimeseriesRoute, ...serviceLogErrorRateTimeseriesRoute, - ...servicesEntitiesDetailedStatisticsRoute, ...serviceEntitiesSummaryRoute, }; diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/types.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/types.ts index 00f1b0580a669..5713c0a2b67fb 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/types.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/entities/types.ts @@ -5,7 +5,6 @@ * 2.0. */ import { AgentName } from '../../../typings/es_schemas/ui/fields/agent'; -import { EntityMetrics } from '../../../common/entities/types'; export enum EntityType { SERVICE = 'service', @@ -30,5 +29,4 @@ interface Entity { lastSeenTimestamp: string; firstSeenTimestamp: string; identityFields: string[]; - metrics: EntityMetrics; } diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/calculate_avg_metrics.test.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/calculate_avg_metrics.test.ts deleted file mode 100644 index 4d0a562295224..0000000000000 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/calculate_avg_metrics.test.ts +++ /dev/null @@ -1,236 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EntityMetrics, EntityDataStreamType } from '../../../../common/entities/types'; -import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; -import { calculateAvgMetrics, mergeMetrics } from './calculate_avg_metrics'; - -describe('calculateAverageMetrics', () => { - it('calculates average metrics', () => { - const entities = [ - { - agentName: 'nodejs' as AgentName, - dataStreamTypes: [EntityDataStreamType.METRICS, EntityDataStreamType.LOGS], - environments: [], - latestTimestamp: '2024-03-05T10:34:40.810Z', - metrics: [ - { - failedTransactionRate: 5, - latency: 5, - logErrorRate: 5, - logRate: 5, - throughput: 5, - }, - { - failedTransactionRate: 10, - latency: 10, - logErrorRate: 10, - logRate: 10, - throughput: 10, - }, - ], - serviceName: 'service-1', - hasLogMetrics: true, - }, - { - agentName: 'java' as AgentName, - dataStreamTypes: [EntityDataStreamType.METRICS], - environments: [], - latestTimestamp: '2024-06-05T10:34:40.810Z', - metrics: [ - { - failedTransactionRate: 15, - latency: 15, - logErrorRate: 15, - logRate: 15, - throughput: 15, - }, - { - failedTransactionRate: 5, - latency: 5, - logErrorRate: 5, - logRate: 5, - throughput: 5, - }, - ], - serviceName: 'service-2', - hasLogMetrics: true, - }, - ]; - - const result = calculateAvgMetrics(entities); - - expect(result).toEqual([ - { - agentName: 'nodejs', - dataStreamTypes: [EntityDataStreamType.METRICS, EntityDataStreamType.LOGS], - environments: [], - latestTimestamp: '2024-03-05T10:34:40.810Z', - metrics: { - failedTransactionRate: 7.5, - latency: 7.5, - logErrorRate: 7.5, - logRate: 7.5, - throughput: 7.5, - }, - serviceName: 'service-1', - hasLogMetrics: true, - }, - { - agentName: 'java' as AgentName, - dataStreamTypes: [EntityDataStreamType.METRICS], - environments: [], - latestTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - failedTransactionRate: 10, - latency: 10, - logErrorRate: 10, - logRate: 10, - throughput: 10, - }, - serviceName: 'service-2', - hasLogMetrics: true, - }, - ]); - }); - it('calculates average metrics with null', () => { - const entities = [ - { - agentName: 'nodejs' as AgentName, - dataStreamTypes: [EntityDataStreamType.METRICS], - environments: ['env-service-1', 'env-service-2'], - latestTimestamp: '2024-03-05T10:34:40.810Z', - metrics: [ - { - failedTransactionRate: 5, - latency: null, - logErrorRate: 5, - logRate: 5, - throughput: 5, - }, - { - failedTransactionRate: 10, - latency: null, - logErrorRate: 10, - logRate: 10, - throughput: 10, - }, - ], - serviceName: 'service-1', - hasLogMetrics: true, - }, - ]; - - const result = calculateAvgMetrics(entities); - - expect(result).toEqual([ - { - agentName: 'nodejs', - dataStreamTypes: [EntityDataStreamType.METRICS], - environments: ['env-service-1', 'env-service-2'], - latestTimestamp: '2024-03-05T10:34:40.810Z', - metrics: { - failedTransactionRate: 7.5, - logErrorRate: 7.5, - logRate: 7.5, - throughput: 7.5, - }, - serviceName: 'service-1', - hasLogMetrics: true, - }, - ]); - }); -}); - -describe('mergeMetrics', () => { - it('merges metrics correctly', () => { - const metrics = [ - { - failedTransactionRate: 5, - latency: 5, - logErrorRate: 5, - logRate: 5, - throughput: 5, - }, - { - failedTransactionRate: 10, - latency: 10, - logErrorRate: 10, - logRate: 10, - throughput: 10, - }, - ]; - - const result = mergeMetrics(metrics); - - expect(result).toEqual({ - failedTransactionRate: [5, 10], - latency: [5, 10], - logErrorRate: [5, 10], - logRate: [5, 10], - throughput: [5, 10], - }); - }); - - it('handles empty metrics array', () => { - const metrics: EntityMetrics[] = []; - - const result = mergeMetrics(metrics); - - expect(result).toEqual({}); - }); - - it('returns metrics with zero value', () => { - const metrics = [ - { - failedTransactionRate: 0, - latency: 4, - logErrorRate: 5, - logRate: 5, - throughput: 5, - }, - ]; - - const result = mergeMetrics(metrics); - - expect(result).toEqual({ - failedTransactionRate: [0], - latency: [4], - logErrorRate: [5], - logRate: [5], - throughput: [5], - }); - }); - - it('does not return metrics with null', () => { - const metrics = [ - { - failedTransactionRate: null, - latency: null, - logErrorRate: 5, - logRate: 5, - throughput: 5, - }, - { - failedTransactionRate: 5, - latency: null, - logErrorRate: 5, - logRate: 5, - throughput: 5, - }, - ]; - - const result = mergeMetrics(metrics); - - expect(result).toEqual({ - failedTransactionRate: [5], - logErrorRate: [5, 5], - logRate: [5, 5], - throughput: [5, 5], - }); - }); -}); diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/calculate_avg_metrics.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/calculate_avg_metrics.ts deleted file mode 100644 index bee5f7ce9cc2b..0000000000000 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/calculate_avg_metrics.ts +++ /dev/null @@ -1,45 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { mapValues, isNumber } from 'lodash'; -import { EntityMetrics } from '../../../../common/entities/types'; -import type { MergedServiceEntity } from './merge_entities'; - -export function calculateAvgMetrics(entities: MergedServiceEntity[]) { - return entities.map((entity) => { - const transformedMetrics = mergeMetrics(entity.metrics); - const averages = mapValues(transformedMetrics, (values: number[]) => { - const sum = values.reduce((acc: number, val: number) => acc + (val !== null ? val : 0), 0); - return sum / values.length; - }); - - return { - ...entity, - metrics: averages, - }; - }); -} -type MetricsKey = keyof EntityMetrics; - -export function mergeMetrics(metrics: EntityMetrics[]) { - return metrics.reduce((acc, metric) => { - for (const key in metric) { - if (Object.hasOwn(metric, key)) { - const metricsKey = key as MetricsKey; - - const value = metric[metricsKey]; - if (isNumber(value)) { - if (!acc[metricsKey]) { - acc[metricsKey] = []; - } - acc[metricsKey].push(value); - } - } - } - return acc; - }, {} as { [key in MetricsKey]: number[] }); -} diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/merge_entities.test.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/merge_entities.test.ts index 587cb03975105..bb5c4f48b4125 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/merge_entities.test.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/merge_entities.test.ts @@ -22,13 +22,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name', 'service.environment'], id: 'service-1:test', }, @@ -41,16 +34,6 @@ describe('mergeEntities', () => { dataStreamTypes: ['metrics', 'logs'], environments: ['test'], lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - hasLogMetrics: true, - metrics: [ - { - failedTransactionRate: 0.3333333333333333, - latency: 10, - logErrorRate: null, - logRate: 1, - throughput: 0, - }, - ], serviceName: 'service-1', }, ]); @@ -68,13 +51,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-03-05T10:34:40.810Z', lastSeenTimestamp: '2024-03-05T10:34:40.810Z', - metrics: { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name', 'service.environment'], id: 'service-1:env-service-1', }, @@ -89,13 +65,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-03-05T10:34:40.810Z', lastSeenTimestamp: '2024-03-05T10:34:40.810Z', - metrics: { - logRate: 10, - logErrorRate: 10, - throughput: 10, - failedTransactionRate: 10, - latency: 10, - }, identityFields: ['service.name', 'service.environment'], id: 'apm-only-1:synthtrace-env-2', }, @@ -110,13 +79,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 15, - logErrorRate: 15, - throughput: 15, - failedTransactionRate: 15, - latency: 15, - }, identityFields: ['service.name', 'service.environment'], id: 'service-2:env-service-3', }, @@ -131,13 +93,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 5, - logErrorRate: 5, - throughput: 5, - failedTransactionRate: 5, - latency: 5, - }, identityFields: ['service.name', 'service.environment'], id: 'service-2:env-service-3', }, @@ -151,23 +106,6 @@ describe('mergeEntities', () => { dataStreamTypes: ['foo', 'bar'], environments: ['env-service-1', 'env-service-2'], lastSeenTimestamp: '2024-03-05T10:34:40.810Z', - hasLogMetrics: true, - metrics: [ - { - failedTransactionRate: 0.3333333333333333, - latency: 10, - logErrorRate: null, - logRate: 1, - throughput: 0, - }, - { - failedTransactionRate: 10, - latency: 10, - logErrorRate: 10, - logRate: 10, - throughput: 10, - }, - ], serviceName: 'service-1', }, { @@ -175,23 +113,6 @@ describe('mergeEntities', () => { dataStreamTypes: ['baz'], environments: ['env-service-3', 'env-service-4'], lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - hasLogMetrics: true, - metrics: [ - { - failedTransactionRate: 15, - latency: 15, - logErrorRate: 15, - logRate: 15, - throughput: 15, - }, - { - failedTransactionRate: 5, - latency: 5, - logErrorRate: 5, - logRate: 5, - throughput: 5, - }, - ], serviceName: 'service-2', }, ]); @@ -208,13 +129,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 5, - logErrorRate: 5, - throughput: 5, - failedTransactionRate: 5, - latency: 5, - }, identityFields: ['service.name', 'service.environment'], id: 'service-1:test', }, @@ -229,13 +143,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 10, - logErrorRate: 10, - throughput: 10, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name', 'service.environment'], id: 'service-1:test', }, @@ -250,13 +157,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-23-05T10:34:40.810Z', lastSeenTimestamp: '2024-23-05T10:34:40.810Z', - metrics: { - logRate: 0.333, - logErrorRate: 0.333, - throughput: 0.333, - failedTransactionRate: 0.333, - latency: 0.333, - }, identityFields: ['service.name', 'service.environment'], id: 'service-1:prod', }, @@ -269,30 +169,6 @@ describe('mergeEntities', () => { dataStreamTypes: ['metrics', 'logs', 'foo'], environments: ['test', 'prod'], lastSeenTimestamp: '2024-23-05T10:34:40.810Z', - hasLogMetrics: true, - metrics: [ - { - failedTransactionRate: 5, - latency: 5, - logErrorRate: 5, - logRate: 5, - throughput: 5, - }, - { - failedTransactionRate: 0.3333333333333333, - latency: 10, - logErrorRate: 10, - logRate: 10, - throughput: 10, - }, - { - failedTransactionRate: 0.333, - latency: 0.333, - logErrorRate: 0.333, - logRate: 0.333, - throughput: 0.333, - }, - ], serviceName: 'service-1', }, ]); @@ -309,13 +185,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name'], id: 'service-1:test', }, @@ -328,16 +197,6 @@ describe('mergeEntities', () => { dataStreamTypes: [], environments: [], lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - hasLogMetrics: true, - metrics: [ - { - failedTransactionRate: 0.3333333333333333, - latency: 10, - logErrorRate: null, - logRate: 1, - throughput: 0, - }, - ], serviceName: 'service-1', }, ]); @@ -352,13 +211,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name'], id: 'service-1:test', }, @@ -372,13 +224,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name'], id: 'service-1:test', }, @@ -391,23 +236,6 @@ describe('mergeEntities', () => { dataStreamTypes: [], environments: [], lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - hasLogMetrics: true, - metrics: [ - { - failedTransactionRate: 0.3333333333333333, - latency: 10, - logErrorRate: null, - logRate: 1, - throughput: 0, - }, - { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, - ], serviceName: 'service-1', }, ]); @@ -424,13 +252,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name'], id: 'service-1:test', }, @@ -443,16 +264,6 @@ describe('mergeEntities', () => { dataStreamTypes: [], environments: [], lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - hasLogMetrics: true, - metrics: [ - { - failedTransactionRate: 0.3333333333333333, - latency: 10, - logErrorRate: null, - logRate: 1, - throughput: 0, - }, - ], serviceName: 'service-1', }, ]); @@ -467,13 +278,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name'], id: 'service-1:test', }, @@ -487,13 +291,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name'], id: 'service-1:test', }, @@ -506,23 +303,6 @@ describe('mergeEntities', () => { dataStreamTypes: [], environments: [], lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - hasLogMetrics: true, - metrics: [ - { - failedTransactionRate: 0.3333333333333333, - latency: 10, - logErrorRate: null, - logRate: 1, - throughput: 0, - }, - { - logRate: 1, - logErrorRate: null, - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, - ], serviceName: 'service-1', }, ]); @@ -540,11 +320,6 @@ describe('mergeEntities', () => { entity: { firstSeenTimestamp: '2024-06-05T10:34:40.810Z', lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - metrics: { - throughput: 0, - failedTransactionRate: 0.3333333333333333, - latency: 10, - }, identityFields: ['service.name', 'service.environment'], id: 'service-1:test', }, @@ -557,14 +332,6 @@ describe('mergeEntities', () => { dataStreamTypes: ['metrics'], environments: ['test'], lastSeenTimestamp: '2024-06-05T10:34:40.810Z', - hasLogMetrics: false, - metrics: [ - { - failedTransactionRate: 0.3333333333333333, - latency: 10, - throughput: 0, - }, - ], serviceName: 'service-1', }, ]); diff --git a/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/merge_entities.ts b/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/merge_entities.ts index 4017d922d63c5..c7269989a3564 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/merge_entities.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/entities/utils/merge_entities.ts @@ -7,17 +7,14 @@ import { compact, uniq } from 'lodash'; import type { EntityLatestServiceRaw } from '../types'; -import { isFiniteNumber } from '../../../../common/utils/is_finite_number'; import type { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; -import type { EntityDataStreamType, EntityMetrics } from '../../../../common/entities/types'; +import type { EntityDataStreamType } from '../../../../common/entities/types'; export interface MergedServiceEntity { serviceName: string; agentName: AgentName; dataStreamTypes: EntityDataStreamType[]; environments: string[]; - metrics: EntityMetrics[]; - hasLogMetrics: boolean; } export function mergeEntities({ @@ -40,10 +37,6 @@ export function mergeEntities({ } function mergeFunc(entity: EntityLatestServiceRaw, existingEntity?: MergedServiceEntity) { - const hasLogMetrics = isFiniteNumber(entity.entity.metrics.logRate) - ? entity.entity.metrics.logRate > 0 - : false; - const commonEntityFields = { serviceName: entity.service.name, agentName: entity.agent.name[0], @@ -55,8 +48,6 @@ function mergeFunc(entity: EntityLatestServiceRaw, existingEntity?: MergedServic ...commonEntityFields, dataStreamTypes: entity.source_data_stream.type, environments: compact([entity?.service.environment]), - metrics: [entity.entity.metrics], - hasLogMetrics, }; } return { @@ -65,7 +56,5 @@ function mergeFunc(entity: EntityLatestServiceRaw, existingEntity?: MergedServic compact([...(existingEntity?.dataStreamTypes ?? []), ...entity.source_data_stream.type]) ), environments: uniq(compact([...existingEntity?.environments, entity?.service.environment])), - metrics: [...existingEntity?.metrics, entity.entity.metrics], - hasLogMetrics: hasLogMetrics || existingEntity.hasLogMetrics, }; } diff --git a/x-pack/test/apm_api_integration/tests/entities/services/services_entities_detailed_statistics.spec.ts b/x-pack/test/apm_api_integration/tests/entities/services/services_entities_detailed_statistics.spec.ts deleted file mode 100644 index e1bf212c6e9c0..0000000000000 --- a/x-pack/test/apm_api_integration/tests/entities/services/services_entities_detailed_statistics.spec.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import expect from '@kbn/expect'; -import { APIClientRequestParamsOf } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; -import { FtrProviderContext } from '../../../common/ftr_provider_context'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - - const apmApiClient = getService('apmApiClient'); - - const start = '2024-01-01T00:00:00.000Z'; - const end = '2024-01-01T00:59:59.999Z'; - - const serviceNames = ['my-service', 'synth-go']; - - async function getServiceEntitiesDetailedStats( - overrides?: Partial< - APIClientRequestParamsOf<'POST /internal/apm/entities/services/detailed_statistics'>['params']['query'] - > - ) { - const response = await apmApiClient.readUser({ - endpoint: `POST /internal/apm/entities/services/detailed_statistics`, - params: { - query: { - start, - end, - environment: 'ENVIRONMENT_ALL', - kuery: '', - ...overrides, - }, - body: { - serviceNames: JSON.stringify(serviceNames), - }, - }, - }); - - return response; - } - - registry.when( - 'Services entities detailed statistics when no data is generated', - { config: 'basic', archives: [] }, - () => { - describe('Service entities detailed', () => { - it('handles the empty state', async () => { - const response = await getServiceEntitiesDetailedStats(); - expect(response.status).to.be(200); - expect(response.body.currentPeriod).to.empty(); - }); - }); - } - ); -} From 71fd96ad8b8cd06ac3c30f099895f2723cd6f3bc Mon Sep 17 00:00:00 2001 From: Rodney Norris Date: Wed, 9 Oct 2024 08:45:24 -0500 Subject: [PATCH 062/110] [Search][FTR] Solution Nav (#195327) ## Summary Adding `functional_search` suite with a set of test for the search solution navigation. But this suite will also grow to test search solution pages that do not require the enterprise search node. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed --- .buildkite/ftr_platform_stateful_configs.yml | 1 + .github/CODEOWNERS | 1 + .../page_objects/solution_navigation.ts | 12 + .../public/navigation_tree.ts | 14 +- x-pack/test/functional_search/config.ts | 31 ++ .../functional_search/ftr_provider_context.ts | 13 + x-pack/test/functional_search/index.ts | 15 + x-pack/test/functional_search/services.ts | 10 + .../tests/solution_navigation.ts | 314 ++++++++++++++++++ 9 files changed, 408 insertions(+), 3 deletions(-) create mode 100644 x-pack/test/functional_search/config.ts create mode 100644 x-pack/test/functional_search/ftr_provider_context.ts create mode 100644 x-pack/test/functional_search/index.ts create mode 100644 x-pack/test/functional_search/services.ts create mode 100644 x-pack/test/functional_search/tests/solution_navigation.ts diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index bc564624f8a5e..d8a538f82779e 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -272,6 +272,7 @@ enabled: - x-pack/test/functional/config.upgrade_assistant.ts - x-pack/test/functional_cloud/config.ts - x-pack/test/functional_solution_sidenav/config.ts + - x-pack/test/functional_search/config.ts - x-pack/test/kubernetes_security/basic/config.ts - x-pack/test/licensing_plugin/config.public.ts - x-pack/test/licensing_plugin/config.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a20e12d88c352..9b3c46d065fe1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1482,6 +1482,7 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints /x-pack/test_serverless/api_integration/test_suites/search @elastic/search-kibana /x-pack/test_serverless/functional/page_objects/svl_api_keys.ts @elastic/search-kibana /x-pack/test_serverless/functional/page_objects/svl_search_* @elastic/search-kibana +/x-pack/test/functional_search/ @elastic/search-kibana # Management Experience - Deployment Management /x-pack/test_serverless/**/test_suites/common/index_management/ @elastic/kibana-management diff --git a/test/functional/page_objects/solution_navigation.ts b/test/functional/page_objects/solution_navigation.ts index a0544e1100507..79e13b0f24943 100644 --- a/test/functional/page_objects/solution_navigation.ts +++ b/test/functional/page_objects/solution_navigation.ts @@ -138,6 +138,18 @@ export function SolutionNavigationProvider(ctx: Pick false, + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith( + prepend('/app/enterprise_search/app_search') + ); + }, link: 'appSearch:engines', title: i18n.translate( 'xpack.enterpriseSearch.searchNav.entsearch.appSearch', @@ -235,7 +239,11 @@ export const getNavigationTreeDefinition = ({ : {}), }, { - getIsActive: () => false, + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith( + prepend('/app/enterprise_search/workplace_search') + ); + }, link: 'workplaceSearch', ...(workplaceSearch ? { diff --git a/x-pack/test/functional_search/config.ts b/x-pack/test/functional_search/config.ts new file mode 100644 index 0000000000000..f997aaea7c5e2 --- /dev/null +++ b/x-pack/test/functional_search/config.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +/** + * NOTE: The solution view is currently only available in the cloud environment. + * This test suite fakes a cloud environement by setting the cloud.id and cloud.base_url + */ + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../functional/config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + kbnTestServer: { + ...functionalConfig.get('kbnTestServer'), + serverArgs: [ + ...functionalConfig.get('kbnTestServer.serverArgs'), + // Note: the base64 string in the cloud.id config contains the ES endpoint required in the functional tests + '--xpack.cloud.id=ftr_fake_cloud_id:aGVsbG8uY29tOjQ0MyRFUzEyM2FiYyRrYm4xMjNhYmM=', + '--xpack.cloud.base_url=https://cloud.elastic.co', + ], + }, + }; +} diff --git a/x-pack/test/functional_search/ftr_provider_context.ts b/x-pack/test/functional_search/ftr_provider_context.ts new file mode 100644 index 0000000000000..d6c0afa5ceffd --- /dev/null +++ b/x-pack/test/functional_search/ftr_provider_context.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { GenericFtrProviderContext } from '@kbn/test'; +import { pageObjects } from '../functional/page_objects'; +import { services } from './services'; + +export type FtrProviderContext = GenericFtrProviderContext; +export { pageObjects }; diff --git a/x-pack/test/functional_search/index.ts b/x-pack/test/functional_search/index.ts new file mode 100644 index 0000000000000..149b3dbcf7eca --- /dev/null +++ b/x-pack/test/functional_search/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +/* eslint-disable import/no-default-export */ + +import { FtrProviderContext } from './ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext): void => { + describe('Search solution tests', function () { + loadTestFile(require.resolve('./tests/solution_navigation')); + }); +}; diff --git a/x-pack/test/functional_search/services.ts b/x-pack/test/functional_search/services.ts new file mode 100644 index 0000000000000..9508ce5eba16d --- /dev/null +++ b/x-pack/test/functional_search/services.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { services as functionalServices } from '../functional/services'; + +export const services = functionalServices; diff --git a/x-pack/test/functional_search/tests/solution_navigation.ts b/x-pack/test/functional_search/tests/solution_navigation.ts new file mode 100644 index 0000000000000..8a06ad1193372 --- /dev/null +++ b/x-pack/test/functional_search/tests/solution_navigation.ts @@ -0,0 +1,314 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; + +export default function searchSolutionNavigation({ + getPageObjects, + getService, +}: FtrProviderContext) { + const { common, solutionNavigation } = getPageObjects(['common', 'solutionNavigation']); + const spaces = getService('spaces'); + const browser = getService('browser'); + + describe('Search Solution Navigation', () => { + let cleanUp: () => Promise; + let spaceCreated: { id: string } = { id: '' }; + + before(async () => { + // Navigate to the spaces management page which will log us in Kibana + await common.navigateToUrl('management', 'kibana/spaces', { + shouldUseHashForSubUrl: false, + }); + + // Create a space with the search solution and navigate to its home page + ({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'es' })); + await browser.navigateTo(spaces.getRootUrl(spaceCreated.id)); + }); + + after(async () => { + // Clean up space created + await cleanUp(); + }); + + it('renders expected side nav items', async () => { + // Verify all expected top-level links exist + await solutionNavigation.sidenav.expectLinkExists({ text: 'Overview' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Dev Tools' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Discover' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Dashboards' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Indices' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Connectors' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Web crawlers' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Playground' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Search applications' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Behavioral Analytics' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'App Search' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Workplace Search' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Other tools' }); + }); + + it('has expected navigation', async () => { + const expectNoPageReload = await solutionNavigation.createNoPageReloadCheck(); + + // check side nav links + await solutionNavigation.sidenav.expectSectionExists('search_project_nav'); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearch', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearch', + }); + + // check Dev tools + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'dev_tools', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'dev_tools', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Dev Tools' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'dev_tools', + }); + + // check Kibana + // > Discover + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'discover', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'discover', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Kibana' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Discover' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'discover', + }); + // > Dashboards + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'dashboards', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'dashboards', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Kibana' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Dashboards' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'dashboards', + }); + + // check the Content + // > Indices section + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'enterpriseSearchContent:searchIndices', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearchContent:searchIndices', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Content' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Indices' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearchContent:searchIndices', + }); + // > Connectors + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'enterpriseSearchContent:connectors', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearchContent:connectors', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Content' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Connectors' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearchContent:connectors', + }); + // > Web Crawlers + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'enterpriseSearchContent:webCrawlers', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearchContent:webCrawlers', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Content' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Web crawlers' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearchContent:webCrawlers', + }); + + // check Build + // > Playground + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'enterpriseSearchApplications:playground', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearchApplications:playground', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Build' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Playground' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearchApplications:playground', + }); + // > Search applications + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'enterpriseSearchApplications:searchApplications', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearchApplications:searchApplications', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Build' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Search applications', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearchApplications:searchApplications', + }); + // > Behavioral Analytics + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'enterpriseSearchAnalytics', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearchAnalytics', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Build' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Behavioral Analytics', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearchAnalytics', + }); + + // check Relevance + // > Inference Endpoints + // TODO: FTRs don't have enterprise license, so inference endpoints not shown + // await solutionNavigation.sidenav.clickLink({ + // deepLinkId: 'enterpriseSearchRelevance:inferenceEndpoints', + // }); + // await solutionNavigation.sidenav.expectLinkActive({ + // deepLinkId: 'enterpriseSearchRelevance:inferenceEndpoints', + // }); + // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Relevance' }); + // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + // text: 'Inference Endpoints', + // }); + // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + // deepLinkId: 'enterpriseSearchRelevance:inferenceEndpoints', + // }); + + // check Enterprise Search + // > App Search + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'appSearch:engines', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'appSearch:engines', + }); + // ent-search node not running for FTRs, so we see setup guide without breadcrumbs + // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + // text: 'App Search', + // }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'appSearch:engines', + }); + // > Workplace Search + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'workplaceSearch', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'workplaceSearch', + }); + // ent-search node not running for FTRs, so we see setup guide without breadcrumbs + // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + // text: 'Workplace Search', + // }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'workplaceSearch', + }); + + // Other tools + await solutionNavigation.sidenav.openSection('search_project_nav.otherTools'); + // > Maps + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'maps', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'maps', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Other tools' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Maps', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'maps', + }); + // > Canvas + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'canvas', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'canvas', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Other tools' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Canvas', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'canvas', + }); + // > Graph + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'graph', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'graph', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Other tools' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Graph', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'graph', + }); + await solutionNavigation.sidenav.closeSection('search_project_nav.otherTools'); + + await expectNoPageReload(); + }); + + it('renders only expected items', async () => { + await solutionNavigation.sidenav.openSection('search_project_nav.otherTools'); + await solutionNavigation.sidenav.openSection('project_settings_project_nav'); + await solutionNavigation.sidenav.expectOnlyDefinedLinks([ + 'search_project_nav', + 'enterpriseSearch', + 'dev_tools', + 'kibana', + 'discover', + 'dashboards', + 'content', + 'enterpriseSearchContent:searchIndices', + 'enterpriseSearchContent:connectors', + 'enterpriseSearchContent:webCrawlers', + 'build', + 'enterpriseSearchApplications:playground', + 'enterpriseSearchApplications:searchApplications', + 'enterpriseSearchAnalytics', + // 'relevance', + // 'enterpriseSearchRelevance:inferenceEndpoints', + 'entsearch', + 'appSearch:engines', + 'workplaceSearch', + 'otherTools', + 'maps', + 'canvas', + 'graph', + 'project_settings_project_nav', + 'ml:modelManagement', + 'stack_management', + ]); + }); + }); +} From e366c0ae7cbe094fc3363b6b0fa152575958346c Mon Sep 17 00:00:00 2001 From: Ilya Nikokoshev Date: Wed, 9 Oct 2024 16:49:59 +0300 Subject: [PATCH 063/110] [Auto Import] Add run names to LangSmith traces (#195576) ## Summary Adds a name wherever a LangSmith graph is compiled. This allows us to review the traces faster. --- .../server/graphs/categorization/graph.ts | 2 +- .../integration_assistant/server/graphs/ecs/graph.ts | 6 ++---- .../plugins/integration_assistant/server/graphs/kv/graph.ts | 2 +- .../server/graphs/log_type_detection/graph.ts | 2 +- .../integration_assistant/server/graphs/related/graph.ts | 2 +- .../server/graphs/unstructured/graph.ts | 2 +- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.ts index 2517cc1c31886..227bcd6939b94 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.ts @@ -243,6 +243,6 @@ export async function getCategorizationGraph({ client, model }: CategorizationGr } ); - const compiledCategorizationGraph = workflow.compile(); + const compiledCategorizationGraph = workflow.compile().withConfig({ runName: 'Categorization' }); return compiledCategorizationGraph; } diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts index efe2ac1aeb437..89a7e5c600723 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts @@ -78,8 +78,7 @@ export async function getEcsSubGraph({ model }: EcsGraphParams) { }) .addEdge('modelSubOutput', END); - const compiledEcsSubGraph = workflow.compile(); - + const compiledEcsSubGraph = workflow.compile().withConfig({ runName: 'ECS Mapping (Chunk)' }); return compiledEcsSubGraph; } @@ -120,7 +119,6 @@ export async function getEcsGraph({ model }: EcsGraphParams) { }) .addEdge('modelOutput', END); - const compiledEcsGraph = workflow.compile(); - + const compiledEcsGraph = workflow.compile().withConfig({ runName: 'ECS Mapping' }); return compiledEcsGraph; } diff --git a/x-pack/plugins/integration_assistant/server/graphs/kv/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/kv/graph.ts index 6f7b43ba40f22..f72984655c1f8 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/kv/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/kv/graph.ts @@ -139,6 +139,6 @@ export async function getKVGraph({ model, client }: KVGraphParams) { }) .addEdge('modelOutput', END); - const compiledKVGraph = workflow.compile(); + const compiledKVGraph = workflow.compile().withConfig({ runName: 'Key-Value' }); return compiledKVGraph; } diff --git a/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/graph.ts index b1cdecd39fe69..4a3f2e2536266 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/graph.ts @@ -128,6 +128,6 @@ export async function getLogFormatDetectionGraph({ model, client }: LogDetection } ); - const compiledLogFormatDetectionGraph = workflow.compile(); + const compiledLogFormatDetectionGraph = workflow.compile().withConfig({ runName: 'Log Format' }); return compiledLogFormatDetectionGraph; } diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/related/graph.ts index 4ab623788c84e..be4b00852485c 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/graph.ts @@ -207,6 +207,6 @@ export async function getRelatedGraph({ client, model }: RelatedGraphParams) { } ); - const compiledRelatedGraph = workflow.compile(); + const compiledRelatedGraph = workflow.compile().withConfig({ runName: 'Related' }); return compiledRelatedGraph; } diff --git a/x-pack/plugins/integration_assistant/server/graphs/unstructured/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/unstructured/graph.ts index 6048404728bfb..cf3a645effa68 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/unstructured/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/unstructured/graph.ts @@ -107,6 +107,6 @@ export async function getUnstructuredGraph({ model, client }: UnstructuredGraphP .addEdge('handleUnstructuredError', 'handleUnstructuredValidate') .addEdge('modelOutput', END); - const compiledUnstructuredGraph = workflow.compile(); + const compiledUnstructuredGraph = workflow.compile().withConfig({ runName: 'Unstructured' }); return compiledUnstructuredGraph; } From c20f6550126b05937c1faaf105dd2425fc57f861 Mon Sep 17 00:00:00 2001 From: Elena Stoeva <59341489+ElenaStoeva@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:53:55 +0100 Subject: [PATCH 064/110] [Console] Only suggest dot-prefixed indices when user types a dot (#195283) Closes https://github.com/elastic/kibana/issues/194801 ## Summary This PR filters the Console autocomplete suggestions in the URL path so that dot-prefixed indices are suggested only if a dot is typed in. https://github.com/user-attachments/assets/fe7fc155-f9a8-4fb0-953e-b84b0d052f2a --- .../editor/utils/autocomplete_utils.test.ts | 19 ++++++++++++++++++- .../editor/utils/autocomplete_utils.ts | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/plugins/console/public/application/containers/editor/utils/autocomplete_utils.test.ts b/src/plugins/console/public/application/containers/editor/utils/autocomplete_utils.test.ts index 0dc35062d015d..f7c6bd3b32054 100644 --- a/src/plugins/console/public/application/containers/editor/utils/autocomplete_utils.test.ts +++ b/src/plugins/console/public/application/containers/editor/utils/autocomplete_utils.test.ts @@ -160,6 +160,10 @@ describe('autocomplete_utils', () => { name: 'index2', meta: 'index', }, + { + name: '.index', + meta: 'index', + }, ] as AutoCompleteContext['autoCompleteSet']; // mock the populateContext function that finds the correct autocomplete endpoint object and puts it into the context object mockPopulateContext.mockImplementation((...args) => { @@ -189,7 +193,7 @@ describe('autocomplete_utils', () => { expect(items.every((item) => item.detail === 'index')).toBe(true); }); - it('suggest endpoints and index names if no comma', () => { + it('suggest endpoints and index names, excluding dot-prefixed ones, if no comma and no dot', () => { const mockModel = { getValueInRange: () => 'GET _search', getWordUntilPosition: () => ({ startColumn: 12 }), @@ -197,6 +201,19 @@ describe('autocomplete_utils', () => { const mockPosition = { lineNumber: 1, column: 12 } as unknown as monaco.Position; const items = getUrlPathCompletionItems(mockModel, mockPosition); expect(items.length).toBe(4); + expect( + items.every((item) => typeof item.label === 'string' && item.label.startsWith('.')) + ).toBe(false); + }); + + it('suggests all endpoints and indices, including dot-prefixed ones, if last char is a dot', () => { + const mockModel = { + getValueInRange: () => 'GET .', + getWordUntilPosition: () => ({ startColumn: 6 }), + } as unknown as monaco.editor.ITextModel; + const mockPosition = { lineNumber: 1, column: 6 } as unknown as monaco.Position; + const items = getUrlPathCompletionItems(mockModel, mockPosition); + expect(items.length).toBe(5); }); }); }); diff --git a/src/plugins/console/public/application/containers/editor/utils/autocomplete_utils.ts b/src/plugins/console/public/application/containers/editor/utils/autocomplete_utils.ts index cfe0341c39780..c36542b43e75e 100644 --- a/src/plugins/console/public/application/containers/editor/utils/autocomplete_utils.ts +++ b/src/plugins/console/public/application/containers/editor/utils/autocomplete_utils.ts @@ -154,6 +154,12 @@ export const getUrlPathCompletionItems = ( }; return ( filterTermsWithoutName(autoCompleteSet) + .filter( + (term) => + // Only keep dot-prefixed terms if the user typed in a dot + !(typeof term.name === 'string' && term.name.startsWith('.')) || + lineContent.trim().endsWith('.') + ) // map autocomplete items to completion items .map((item) => { return { From 3618ecab40e0e3b8ac8395638f55896a1cf21640 Mon Sep 17 00:00:00 2001 From: Tre Date: Wed, 9 Oct 2024 14:54:20 +0100 Subject: [PATCH 065/110] [SKIP ON MKI] 2 Data Set Quality Files (#195554) ## Summary details: https://github.com/elastic/kibana/issues/195466 --- .../observability/dataset_quality/degraded_field_analyze.ts | 4 +++- .../observability/dataset_quality/degraded_field_flyout.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/degraded_field_analyze.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/degraded_field_analyze.ts index 056bde27fc33c..6dc8af72bea81 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/degraded_field_analyze.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/degraded_field_analyze.ts @@ -45,7 +45,9 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { .query({ lastBackingIndex }); } - describe('Degraded field analyze', () => { + describe('Degraded field analyze', function () { + // see details: https://github.com/elastic/kibana/issues/195466 + this.tags(['failsOnMKI']); let supertestAdminWithCookieCredentials: SupertestWithRoleScopeType; before(async () => { diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/degraded_field_flyout.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/degraded_field_flyout.ts index 263dc8652ad75..f5f0b1c76ee8e 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/degraded_field_flyout.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/degraded_field_flyout.ts @@ -38,7 +38,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const serviceName = 'test_service'; const count = 5; - describe('Degraded fields flyout', () => { + describe('Degraded fields flyout', function () { + // see details: https://github.com/elastic/kibana/issues/195466 + this.tags(['failsOnMKI']); before(async () => { await synthtrace.index([ // Ingest basic logs From ba0bd8ab8996d68a1a3ab1f914f5cc4b7a1a3311 Mon Sep 17 00:00:00 2001 From: "elastic-renovate-prod[bot]" <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 08:59:50 -0500 Subject: [PATCH 066/110] Update dependency @elastic/charts to v68 (main) (#195447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [@elastic/charts](https://togithub.com/elastic/elastic-charts) | dependencies | major | [`67.0.1` -> `68.0.0`](https://renovatebot.com/diffs/npm/@elastic%2fcharts/67.0.1/68.0.0) | --- ### Release Notes
    elastic/elastic-charts (@​elastic/charts) ### [`v68.0.0`](https://togithub.com/elastic/elastic-charts/blob/HEAD/CHANGELOG.md#6800-2024-10-08) [Compare Source](https://togithub.com/elastic/elastic-charts/compare/v67.0.1...v68.0.0) ##### Features - **xy:** render sorting ([#​2524](https://togithub.com/elastic/elastic-charts/issues/2524)) ([c514571](https://togithub.com/elastic/elastic-charts/commit/c5145713025cfa3d48cb526d2fcad884a036d393)) ##### BREAKING CHANGES - **xy:** The way mixed stacked/nonstacked series are colored now is different from the previous behaviour. Now we color them not by their insert index but by the way we display them in the rendering: from the left to right, bottom top, stacked, nonstacked. This align correctly also the legend colors by default. This does **not** affect colors assigned via a `SeriesColorAccessor`. #### [67.0.1](https://togithub.com/elastic/elastic-charts/compare/v67.0.0...v67.0.1) (2024-10-03) ##### Bug Fixes - **ChartStatus:** render complete if same parent size is dispatched ([#​2534](https://togithub.com/elastic/elastic-charts/issues/2534)) ([c3aba88](https://togithub.com/elastic/elastic-charts/commit/c3aba885b92f898ef59f452d3fed7812584d48b0))
    --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f699668ca55b5..57b84f1c46dcb 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "@elastic/apm-rum": "^5.16.1", "@elastic/apm-rum-core": "^5.21.1", "@elastic/apm-rum-react": "^2.0.3", - "@elastic/charts": "67.0.1", + "@elastic/charts": "68.0.0", "@elastic/datemath": "5.0.3", "@elastic/ebt": "^1.1.1", "@elastic/ecs": "^8.11.1", diff --git a/yarn.lock b/yarn.lock index 455ed178b85b7..54a38b2c0e5d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1643,10 +1643,10 @@ dependencies: object-hash "^1.3.0" -"@elastic/charts@67.0.1": - version "67.0.1" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-67.0.1.tgz#17ba397a97f207f99b6f682f136dde0aef474b57" - integrity sha512-6H9DUxm1vwp/R78PAx/zkBKechXF0g1LQuflfpfxMFplwRRw7OTz9cMMRjvrqUp1bVhkp9yLb4CWao+HWaIofA== +"@elastic/charts@68.0.0": + version "68.0.0" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-68.0.0.tgz#a61cc39d6b139006946a134f372c6af5e09fbadb" + integrity sha512-qtlI5U9olt9Y5ZkVUwy9VT2uvU8WzmCTYLjCM+l3b1g4ek0WW1ehZxaJha2Esqe5+QPSBH9LrVzBTayQbbprUA== dependencies: "@popperjs/core" "^2.11.8" bezier-easing "^2.1.0" From c103d2d21452f6c73b79036c5d10a24c018e1831 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 9 Oct 2024 16:06:02 +0200 Subject: [PATCH 067/110] [EDR Workflows] Enable response actions in base rule params (#194796) --- .../output/kibana.serverless.staging.yaml | 148 +- oas_docs/output/kibana.serverless.yaml | 148 +- oas_docs/output/kibana.staging.yaml | 148 +- oas_docs/output/kibana.yaml | 148 +- ...s_upgrade_and_rollback_checks.test.ts.snap | 2791 ++++++++++------- .../model/rule_schema/rule_schemas.gen.ts | 8 +- .../rule_schema/rule_schemas.schema.yaml | 25 +- .../common/detection_engine/utils.ts | 13 +- .../common/experimental_features.ts | 5 + ...ections_api_2023_10_31.bundled.schema.yaml | 148 +- ...ections_api_2023_10_31.bundled.schema.yaml | 148 +- .../components/step_rule_actions/index.tsx | 9 +- .../rule_assets/prebuilt_rule_asset.test.ts | 15 +- .../model/rule_assets/prebuilt_rule_asset.ts | 50 +- .../common_params_camel_to_snake.ts | 2 + .../convert_rule_response_to_alerting_rule.ts | 16 +- .../type_specific_camel_to_snake.ts | 6 - .../mergers/apply_rule_defaults.ts | 5 - .../mergers/apply_rule_patch.ts | 6 +- .../rule_management/utils/validate.ts | 33 +- .../schedule_notification_response_actions.ts | 3 + .../rule_schema/model/rule_schemas.ts | 6 +- .../rule_types/eql/create_eql_alert_type.ts | 9 +- .../detection_engine/rule_types/eql/eql.ts | 17 +- .../rule_types/esql/create_esql_alert_type.ts | 4 +- .../detection_engine/rule_types/esql/esql.ts | 16 +- .../create_indicator_match_alert_type.ts | 9 +- .../indicator_match/indicator_match.ts | 12 +- .../threat_mapping/create_threat_signals.ts | 7 +- .../indicator_match/threat_mapping/types.ts | 5 + .../rule_types/ml/create_ml_alert_type.ts | 4 +- .../detection_engine/rule_types/ml/ml.test.ts | 32 + .../lib/detection_engine/rule_types/ml/ml.ts | 15 +- .../new_terms/create_new_terms_alert_type.ts | 16 +- .../rule_types/query/query.ts | 16 +- .../threshold/create_threshold_alert_type.ts | 4 +- .../rule_types/threshold/threshold.test.ts | 46 +- .../rule_types/threshold/threshold.ts | 9 +- .../lib/detection_engine/rule_types/types.ts | 7 +- .../security_solution/server/plugin.ts | 26 +- 40 files changed, 2643 insertions(+), 1492 deletions(-) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index 18ce5022cdf02..bd2f5c597ecc4 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -41387,10 +41387,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array tiebreaker_field: $ref: '#/components/schemas/Security_Detections_API_TiebreakerField' timestamp_field: @@ -41480,6 +41476,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -41604,6 +41604,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -41725,6 +41729,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -41829,6 +41837,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -41963,6 +41975,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42087,6 +42103,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42132,10 +42152,6 @@ components: properties: alert_suppression: $ref: '#/components/schemas/Security_Detections_API_AlertSuppression' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_EsqlRulePatchProps: allOf: - type: object @@ -42206,6 +42222,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42332,6 +42352,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42571,6 +42595,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42698,6 +42726,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42825,6 +42857,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42948,6 +42984,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43061,6 +43101,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43190,6 +43234,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43247,10 +43295,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_NewTermsRulePatchFields: allOf: - type: object @@ -43335,6 +43379,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43466,6 +43514,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43700,6 +43752,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43826,6 +43882,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43884,10 +43944,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array saved_id: $ref: '#/components/schemas/Security_Detections_API_SavedQueryId' Security_Detections_API_QueryRulePatchFields: @@ -43967,6 +44023,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -44090,6 +44150,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -44799,6 +44863,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -44928,6 +44996,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -44987,10 +45059,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' query: $ref: '#/components/schemas/Security_Detections_API_RuleQuery' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_SavedQueryRulePatchFields: allOf: - type: object @@ -45071,6 +45139,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45197,6 +45269,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45447,6 +45523,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45576,6 +45656,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45731,6 +45815,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45866,6 +45954,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -46066,6 +46158,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -46195,6 +46291,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -46337,6 +46437,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -46466,6 +46570,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index 18ce5022cdf02..bd2f5c597ecc4 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -41387,10 +41387,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array tiebreaker_field: $ref: '#/components/schemas/Security_Detections_API_TiebreakerField' timestamp_field: @@ -41480,6 +41476,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -41604,6 +41604,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -41725,6 +41729,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -41829,6 +41837,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -41963,6 +41975,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42087,6 +42103,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42132,10 +42152,6 @@ components: properties: alert_suppression: $ref: '#/components/schemas/Security_Detections_API_AlertSuppression' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_EsqlRulePatchProps: allOf: - type: object @@ -42206,6 +42222,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42332,6 +42352,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42571,6 +42595,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42698,6 +42726,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42825,6 +42857,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -42948,6 +42984,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43061,6 +43101,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43190,6 +43234,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43247,10 +43295,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_NewTermsRulePatchFields: allOf: - type: object @@ -43335,6 +43379,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43466,6 +43514,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43700,6 +43752,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43826,6 +43882,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -43884,10 +43944,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array saved_id: $ref: '#/components/schemas/Security_Detections_API_SavedQueryId' Security_Detections_API_QueryRulePatchFields: @@ -43967,6 +44023,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -44090,6 +44150,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -44799,6 +44863,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -44928,6 +44996,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -44987,10 +45059,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' query: $ref: '#/components/schemas/Security_Detections_API_RuleQuery' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_SavedQueryRulePatchFields: allOf: - type: object @@ -45071,6 +45139,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45197,6 +45269,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45447,6 +45523,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45576,6 +45656,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45731,6 +45815,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -45866,6 +45954,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -46066,6 +46158,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -46195,6 +46291,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -46337,6 +46437,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -46466,6 +46570,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index bafecfccde407..544315cd12646 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -50007,10 +50007,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array tiebreaker_field: $ref: '#/components/schemas/Security_Detections_API_TiebreakerField' timestamp_field: @@ -50100,6 +50096,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50224,6 +50224,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50345,6 +50349,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50449,6 +50457,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50583,6 +50595,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50707,6 +50723,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50752,10 +50772,6 @@ components: properties: alert_suppression: $ref: '#/components/schemas/Security_Detections_API_AlertSuppression' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_EsqlRulePatchProps: allOf: - type: object @@ -50826,6 +50842,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50952,6 +50972,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51214,6 +51238,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51341,6 +51369,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51468,6 +51500,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51591,6 +51627,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51802,6 +51842,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51931,6 +51975,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51988,10 +52036,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_NewTermsRulePatchFields: allOf: - type: object @@ -52076,6 +52120,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52207,6 +52255,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52441,6 +52493,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52567,6 +52623,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52625,10 +52685,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array saved_id: $ref: '#/components/schemas/Security_Detections_API_SavedQueryId' Security_Detections_API_QueryRulePatchFields: @@ -52708,6 +52764,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52831,6 +52891,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -53540,6 +53604,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -53669,6 +53737,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -53728,10 +53800,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' query: $ref: '#/components/schemas/Security_Detections_API_RuleQuery' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_SavedQueryRulePatchFields: allOf: - type: object @@ -53812,6 +53880,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -53938,6 +54010,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54195,6 +54271,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54324,6 +54404,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54479,6 +54563,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54614,6 +54702,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54814,6 +54906,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54943,6 +55039,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -55085,6 +55185,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -55214,6 +55318,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index bafecfccde407..544315cd12646 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -50007,10 +50007,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array tiebreaker_field: $ref: '#/components/schemas/Security_Detections_API_TiebreakerField' timestamp_field: @@ -50100,6 +50096,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50224,6 +50224,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50345,6 +50349,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50449,6 +50457,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50583,6 +50595,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50707,6 +50723,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50752,10 +50772,6 @@ components: properties: alert_suppression: $ref: '#/components/schemas/Security_Detections_API_AlertSuppression' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_EsqlRulePatchProps: allOf: - type: object @@ -50826,6 +50842,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -50952,6 +50972,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51214,6 +51238,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51341,6 +51369,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51468,6 +51500,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51591,6 +51627,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51802,6 +51842,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51931,6 +51975,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -51988,10 +52036,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_NewTermsRulePatchFields: allOf: - type: object @@ -52076,6 +52120,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52207,6 +52255,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52441,6 +52493,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52567,6 +52623,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52625,10 +52685,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_RuleFilterArray' index: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array saved_id: $ref: '#/components/schemas/Security_Detections_API_SavedQueryId' Security_Detections_API_QueryRulePatchFields: @@ -52708,6 +52764,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -52831,6 +52891,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -53540,6 +53604,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -53669,6 +53737,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -53728,10 +53800,6 @@ components: $ref: '#/components/schemas/Security_Detections_API_IndexPatternArray' query: $ref: '#/components/schemas/Security_Detections_API_RuleQuery' - response_actions: - items: - $ref: '#/components/schemas/Security_Detections_API_ResponseAction' - type: array Security_Detections_API_SavedQueryRulePatchFields: allOf: - type: object @@ -53812,6 +53880,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -53938,6 +54010,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54195,6 +54271,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54324,6 +54404,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54479,6 +54563,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54614,6 +54702,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54814,6 +54906,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -54943,6 +55039,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -55085,6 +55185,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: @@ -55214,6 +55318,10 @@ components: $ref: >- #/components/schemas/Security_Detections_API_RequiredFieldInput type: array + response_actions: + items: + $ref: '#/components/schemas/Security_Detections_API_ResponseAction' + type: array risk_score: $ref: '#/components/schemas/Security_Detections_API_RiskScore' risk_score_mapping: diff --git a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap index 4dc2abbc5f6a8..c283cc1087682 100644 --- a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap +++ b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap @@ -5829,6 +5829,175 @@ Object { }, "type": "array", }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, "riskScore": Object { "maximum": 100, "minimum": 0, @@ -6135,204 +6304,35 @@ Object { "query": Object { "type": "string", }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/1/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - ], - }, - "type": "array", - }, - "tiebreakerField": Object { - "type": "string", - }, - "timestampField": Object { - "type": "string", - }, - "type": Object { - "const": "eql", - "type": "string", - }, - }, - "required": Array [ - "type", - "language", - "query", - ], - "type": "object", - }, - ], -} -`; - -exports[`Serverless upgrade and rollback checks detect param changes to review for: siem.indicatorRule 1`] = ` -Object { - "$schema": "http://json-schema.org/draft-07/schema#", - "allOf": Array [ - Object { - "properties": Object { - "author": Object { + "tiebreakerField": Object { + "type": "string", + }, + "timestampField": Object { + "type": "string", + }, + "type": Object { + "const": "eql", + "type": "string", + }, + }, + "required": Array [ + "type", + "language", + "query", + ], + "type": "object", + }, + ], +} +`; + +exports[`Serverless upgrade and rollback checks detect param changes to review for: siem.indicatorRule 1`] = ` +Object { + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": Array [ + Object { + "properties": Object { + "author": Object { "items": Object { "type": "string", }, @@ -6497,34 +6497,203 @@ Object { }, "type": "array", }, - "riskScore": Object { - "maximum": 100, - "minimum": 0, - "type": "integer", - }, - "riskScoreMapping": Object { + "responseActions": Object { "items": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "operator": Object { - "const": "equals", - "type": "string", - }, - "risk_score": Object { - "$ref": "#/allOf/0/properties/riskScore", - }, - "value": Object { - "type": "string", + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", }, - }, - "required": Array [ - "field", - "operator", - "value", - ], + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, + "riskScore": Object { + "maximum": 100, + "minimum": 0, + "type": "integer", + }, + "riskScoreMapping": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "operator": Object { + "const": "equals", + "type": "string", + }, + "risk_score": Object { + "$ref": "#/allOf/0/properties/riskScore", + }, + "value": Object { + "type": "string", + }, + }, + "required": Array [ + "field", + "operator", + "value", + ], "type": "object", }, "type": "array", @@ -7059,483 +7228,172 @@ Object { }, "type": "array", }, - "riskScore": Object { - "maximum": 100, - "minimum": 0, - "type": "integer", - }, - "riskScoreMapping": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "operator": Object { - "const": "equals", - "type": "string", - }, - "risk_score": Object { - "$ref": "#/allOf/0/properties/riskScore", - }, - "value": Object { - "type": "string", - }, - }, - "required": Array [ - "field", - "operator", - "value", - ], - "type": "object", - }, - "type": "array", - }, - "ruleId": Object { - "type": "string", - }, - "ruleNameOverride": Object { - "type": "string", - }, - "ruleSource": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "isCustomized": Object { - "type": "boolean", - }, - "type": Object { - "const": "external", - "type": "string", - }, - }, - "required": Array [ - "type", - "isCustomized", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "type": Object { - "const": "internal", - "type": "string", - }, - }, - "required": Array [ - "type", - ], - "type": "object", - }, - ], - }, - "setup": Object { - "type": "string", - }, - "severity": Object { - "enum": Array [ - "low", - "medium", - "high", - "critical", - ], - "type": "string", - }, - "severityMapping": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "operator": Object { - "const": "equals", - "type": "string", - }, - "severity": Object { - "$ref": "#/allOf/0/properties/severity", - }, - "value": Object { - "type": "string", - }, - }, - "required": Array [ - "field", - "operator", - "severity", - "value", - ], - "type": "object", - }, - "type": "array", - }, - "threat": Object { + "responseActions": Object { "items": Object { - "additionalProperties": false, - "properties": Object { - "framework": Object { - "type": "string", - }, - "tactic": Object { + "anyOf": Array [ + Object { "additionalProperties": false, "properties": Object { - "id": Object { - "type": "string", - }, - "name": Object { - "type": "string", - }, - "reference": Object { + "actionTypeId": Object { + "const": ".osquery", "type": "string", }, - }, - "required": Array [ - "id", - "name", - "reference", - ], - "type": "object", - }, - "technique": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "id": Object { - "type": "string", - }, - "name": Object { - "type": "string", - }, - "reference": Object { - "type": "string", - }, - "subtechnique": Object { - "items": Object { + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { "additionalProperties": false, "properties": Object { - "id": Object { - "type": "string", - }, - "name": Object { + "command": Object { + "const": "isolate", "type": "string", }, - "reference": Object { + "comment": Object { "type": "string", }, }, "required": Array [ - "id", - "name", - "reference", + "command", ], "type": "object", }, - "type": "array", - }, - }, - "required": Array [ - "id", - "name", - "reference", - ], - "type": "object", - }, - "type": "array", - }, - }, - "required": Array [ - "framework", - "tactic", - ], - "type": "object", - }, - "type": "array", - }, - "timelineId": Object { - "type": "string", - }, - "timelineTitle": Object { - "type": "string", - }, - "timestampOverride": Object { - "type": "string", - }, - "timestampOverrideFallbackDisabled": Object { - "type": "boolean", - }, - "to": Object { - "type": "string", - }, - "version": Object { - "minimum": 1, - "type": "integer", - }, - }, - "required": Array [ - "author", - "description", - "falsePositives", - "from", - "ruleId", - "immutable", - "outputIndex", - "maxSignals", - "riskScore", - "riskScoreMapping", - "severity", - "severityMapping", - "threat", - "to", - "references", - "version", - "exceptionsList", - ], - "type": "object", - }, - Object { - "properties": Object { - "alertSuppression": Object { - "additionalProperties": false, - "properties": Object { - "duration": Object { - "additionalProperties": false, - "properties": Object { - "unit": Object { - "enum": Array [ - "s", - "m", - "h", - ], - "type": "string", - }, - "value": Object { - "minimum": 1, - "type": "integer", - }, - }, - "required": Array [ - "value", - "unit", - ], - "type": "object", - }, - "groupBy": Object { - "items": Object { - "type": "string", - }, - "maxItems": 3, - "minItems": 1, - "type": "array", - }, - "missingFieldsStrategy": Object { - "enum": Array [ - "doNotSuppress", - "suppress", - ], - "type": "string", - }, - }, - "required": Array [ - "groupBy", - ], - "type": "object", - }, - "anomalyThreshold": Object { - "minimum": 0, - "type": "integer", - }, - "machineLearningJobId": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "type": Object { - "const": "machine_learning", - "type": "string", - }, - }, - "required": Array [ - "type", - "anomalyThreshold", - "machineLearningJobId", - ], - "type": "object", - }, - ], -} -`; - -exports[`Serverless upgrade and rollback checks detect param changes to review for: siem.newTermsRule 1`] = ` -Object { - "$schema": "http://json-schema.org/draft-07/schema#", - "allOf": Array [ - Object { - "properties": Object { - "author": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "buildingBlockType": Object { - "type": "string", - }, - "description": Object { - "minLength": 1, - "type": "string", - }, - "exceptionsList": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "id": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "list_id": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "namespace_type": Object { - "enum": Array [ - "agnostic", - "single", - ], - "type": "string", - }, - "type": Object { - "enum": Array [ - "detection", - "rule_default", - "endpoint", - "endpoint_trusted_apps", - "endpoint_events", - "endpoint_host_isolation_exceptions", - "endpoint_blocklists", - ], - "type": "string", - }, - }, - "required": Array [ - "id", - "list_id", - "type", - "namespace_type", - ], - "type": "object", - }, - "type": "array", - }, - "falsePositives": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "from": Object { - "type": "string", - }, - "immutable": Object { - "type": "boolean", - }, - "investigationFields": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "field_names": Object { - "items": Object { - "minLength": 1, - "pattern": "^(?! *$).+$", - "type": "string", + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], }, - "minItems": 1, - "type": "array", }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", }, - "required": Array [ - "field_names", - ], - "type": "object", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - "license": Object { - "type": "string", - }, - "maxSignals": Object { - "minimum": 1, - "type": "integer", - }, - "meta": Object { - "additionalProperties": Object {}, - "properties": Object {}, - "type": "object", - }, - "namespace": Object { - "type": "string", - }, - "note": Object { - "type": "string", - }, - "outputIndex": Object { - "type": "string", - }, - "references": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "relatedIntegrations": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "integration": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "package": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "version": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - }, - "required": Array [ - "package", - "version", - ], - "type": "object", - }, - "type": "array", - }, - "requiredFields": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs": Object { - "type": "boolean", - }, - "name": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "type": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - }, - "required": Array [ - "name", - "type", - "ecs", ], - "type": "object", }, "type": "array", }, @@ -7822,39 +7680,202 @@ Object { ], "type": "object", }, - "dataViewId": Object { + "anomalyThreshold": Object { + "minimum": 0, + "type": "integer", + }, + "machineLearningJobId": Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + "type": Object { + "const": "machine_learning", "type": "string", }, - "filters": Object { - "items": Object {}, + }, + "required": Array [ + "type", + "anomalyThreshold", + "machineLearningJobId", + ], + "type": "object", + }, + ], +} +`; + +exports[`Serverless upgrade and rollback checks detect param changes to review for: siem.newTermsRule 1`] = ` +Object { + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": Array [ + Object { + "properties": Object { + "author": Object { + "items": Object { + "type": "string", + }, "type": "array", }, - "historyWindowStart": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + "buildingBlockType": Object { + "type": "string", }, - "index": Object { + "description": Object { + "minLength": 1, + "type": "string", + }, + "exceptionsList": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "id": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "list_id": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "namespace_type": Object { + "enum": Array [ + "agnostic", + "single", + ], + "type": "string", + }, + "type": Object { + "enum": Array [ + "detection", + "rule_default", + "endpoint", + "endpoint_trusted_apps", + "endpoint_events", + "endpoint_host_isolation_exceptions", + "endpoint_blocklists", + ], + "type": "string", + }, + }, + "required": Array [ + "id", + "list_id", + "type", + "namespace_type", + ], + "type": "object", + }, + "type": "array", + }, + "falsePositives": Object { "items": Object { "type": "string", }, "type": "array", }, - "language": Object { - "enum": Array [ - "kuery", - "lucene", + "from": Object { + "type": "string", + }, + "immutable": Object { + "type": "boolean", + }, + "investigationFields": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "field_names": Object { + "items": Object { + "minLength": 1, + "pattern": "^(?! *$).+$", + "type": "string", + }, + "minItems": 1, + "type": "array", + }, + }, + "required": Array [ + "field_names", + ], + "type": "object", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, ], + }, + "license": Object { + "type": "string", + }, + "maxSignals": Object { + "minimum": 1, + "type": "integer", + }, + "meta": Object { + "additionalProperties": Object {}, + "properties": Object {}, + "type": "object", + }, + "namespace": Object { + "type": "string", + }, + "note": Object { + "type": "string", + }, + "outputIndex": Object { "type": "string", }, - "newTermsFields": Object { + "references": Object { "items": Object { "type": "string", }, - "maxItems": 3, - "minItems": 1, "type": "array", }, - "query": Object { - "type": "string", + "relatedIntegrations": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "integration": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "package": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "version": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "package", + "version", + ], + "type": "object", + }, + "type": "array", + }, + "requiredFields": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs": Object { + "type": "boolean", + }, + "name": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "type": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "name", + "type", + "ecs", + ], + "type": "object", + }, + "type": "array", }, "responseActions": Object { "items": Object { @@ -7903,7 +7924,7 @@ Object { "additionalProperties": false, "properties": Object { "ecs_mapping": Object { - "$ref": "#/allOf/1/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", }, "id": Object { "type": "string", @@ -8015,16 +8036,333 @@ Object { ], }, }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, + "riskScore": Object { + "maximum": 100, + "minimum": 0, + "type": "integer", + }, + "riskScoreMapping": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "operator": Object { + "const": "equals", + "type": "string", + }, + "risk_score": Object { + "$ref": "#/allOf/0/properties/riskScore", + }, + "value": Object { + "type": "string", + }, + }, + "required": Array [ + "field", + "operator", + "value", + ], + "type": "object", + }, + "type": "array", + }, + "ruleId": Object { + "type": "string", + }, + "ruleNameOverride": Object { + "type": "string", + }, + "ruleSource": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "isCustomized": Object { + "type": "boolean", + }, + "type": Object { + "const": "external", + "type": "string", + }, + }, + "required": Array [ + "type", + "isCustomized", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "type": Object { + "const": "internal", + "type": "string", + }, + }, + "required": Array [ + "type", + ], + "type": "object", + }, + ], + }, + "setup": Object { + "type": "string", + }, + "severity": Object { + "enum": Array [ + "low", + "medium", + "high", + "critical", + ], + "type": "string", + }, + "severityMapping": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "operator": Object { + "const": "equals", + "type": "string", + }, + "severity": Object { + "$ref": "#/allOf/0/properties/severity", + }, + "value": Object { + "type": "string", + }, + }, + "required": Array [ + "field", + "operator", + "severity", + "value", + ], + "type": "object", + }, + "type": "array", + }, + "threat": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "framework": Object { + "type": "string", + }, + "tactic": Object { + "additionalProperties": false, + "properties": Object { + "id": Object { + "type": "string", + }, + "name": Object { + "type": "string", + }, + "reference": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "name", + "reference", + ], + "type": "object", + }, + "technique": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "id": Object { + "type": "string", + }, + "name": Object { + "type": "string", + }, + "reference": Object { + "type": "string", + }, + "subtechnique": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "id": Object { + "type": "string", + }, + "name": Object { + "type": "string", + }, + "reference": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "name", + "reference", + ], + "type": "object", + }, + "type": "array", + }, + }, + "required": Array [ + "id", + "name", + "reference", + ], + "type": "object", + }, + "type": "array", + }, + }, + "required": Array [ + "framework", + "tactic", + ], + "type": "object", + }, + "type": "array", + }, + "timelineId": Object { + "type": "string", + }, + "timelineTitle": Object { + "type": "string", + }, + "timestampOverride": Object { + "type": "string", + }, + "timestampOverrideFallbackDisabled": Object { + "type": "boolean", + }, + "to": Object { + "type": "string", + }, + "version": Object { + "minimum": 1, + "type": "integer", + }, + }, + "required": Array [ + "author", + "description", + "falsePositives", + "from", + "ruleId", + "immutable", + "outputIndex", + "maxSignals", + "riskScore", + "riskScoreMapping", + "severity", + "severityMapping", + "threat", + "to", + "references", + "version", + "exceptionsList", + ], + "type": "object", + }, + Object { + "properties": Object { + "alertSuppression": Object { + "additionalProperties": false, + "properties": Object { + "duration": Object { + "additionalProperties": false, + "properties": Object { + "unit": Object { + "enum": Array [ + "s", + "m", + "h", + ], + "type": "string", + }, + "value": Object { + "minimum": 1, + "type": "integer", + }, }, - ], + "required": Array [ + "value", + "unit", + ], + "type": "object", + }, + "groupBy": Object { + "items": Object { + "type": "string", + }, + "maxItems": 3, + "minItems": 1, + "type": "array", + }, + "missingFieldsStrategy": Object { + "enum": Array [ + "doNotSuppress", + "suppress", + ], + "type": "string", + }, + }, + "required": Array [ + "groupBy", + ], + "type": "object", + }, + "dataViewId": Object { + "type": "string", + }, + "filters": Object { + "items": Object {}, + "type": "array", + }, + "historyWindowStart": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "index": Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + "language": Object { + "enum": Array [ + "kuery", + "lucene", + ], + "type": "string", + }, + "newTermsFields": Object { + "items": Object { + "type": "string", }, + "maxItems": 3, + "minItems": 1, "type": "array", }, + "query": Object { + "type": "string", + }, "type": Object { "const": "new_terms", "type": "string", @@ -8233,13 +8571,182 @@ Object { "type": Object { "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", }, - }, - "required": Array [ - "name", - "type", - "ecs", + }, + "required": Array [ + "name", + "type", + "ecs", + ], + "type": "object", + }, + "type": "array", + }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, ], - "type": "object", }, "type": "array", }, @@ -8552,175 +9059,6 @@ Object { "query": Object { "type": "string", }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - ], - }, - "type": "array", - }, "savedId": Object { "type": "string", }, @@ -8757,12 +9095,6 @@ Object { "query": Object { "$ref": "#/allOf/1/anyOf/0/properties/query", }, - "responseActions": Object { - "items": Object { - "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items", - }, - "type": "array", - }, "savedId": Object { "$ref": "#/allOf/1/anyOf/0/properties/savedId", }, @@ -8942,16 +9274,185 @@ Object { "name": Object { "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", }, - "type": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + "type": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "name", + "type", + "ecs", + ], + "type": "object", + }, + "type": "array", + }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", }, - }, - "required": Array [ - "name", - "type", - "ecs", ], - "type": "object", }, "type": "array", }, @@ -9178,261 +9679,92 @@ Object { "immutable", "outputIndex", "maxSignals", - "riskScore", - "riskScoreMapping", - "severity", - "severityMapping", - "threat", - "to", - "references", - "version", - "exceptionsList", - ], - "type": "object", - }, - Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "alertSuppression": Object { - "additionalProperties": false, - "properties": Object { - "duration": Object { - "additionalProperties": false, - "properties": Object { - "unit": Object { - "enum": Array [ - "s", - "m", - "h", - ], - "type": "string", - }, - "value": Object { - "minimum": 1, - "type": "integer", - }, - }, - "required": Array [ - "value", - "unit", - ], - "type": "object", - }, - "groupBy": Object { - "items": Object { - "type": "string", - }, - "maxItems": 3, - "minItems": 1, - "type": "array", - }, - "missingFieldsStrategy": Object { - "enum": Array [ - "doNotSuppress", - "suppress", - ], - "type": "string", - }, - }, - "required": Array [ - "groupBy", - ], - "type": "object", - }, - "dataViewId": Object { - "type": "string", - }, - "filters": Object { - "items": Object {}, - "type": "array", - }, - "index": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "language": Object { - "enum": Array [ - "kuery", - "lucene", - ], - "type": "string", - }, - "query": Object { - "type": "string", - }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, + "riskScore", + "riskScoreMapping", + "severity", + "severityMapping", + "threat", + "to", + "references", + "version", + "exceptionsList", + ], + "type": "object", + }, + Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "alertSuppression": Object { + "additionalProperties": false, + "properties": Object { + "duration": Object { + "additionalProperties": false, + "properties": Object { + "unit": Object { + "enum": Array [ + "s", + "m", + "h", + ], + "type": "string", + }, + "value": Object { + "minimum": 1, + "type": "integer", }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", }, - ], + "required": Array [ + "value", + "unit", + ], + "type": "object", + }, + "groupBy": Object { + "items": Object { + "type": "string", + }, + "maxItems": 3, + "minItems": 1, + "type": "array", + }, + "missingFieldsStrategy": Object { + "enum": Array [ + "doNotSuppress", + "suppress", + ], + "type": "string", + }, + }, + "required": Array [ + "groupBy", + ], + "type": "object", + }, + "dataViewId": Object { + "type": "string", + }, + "filters": Object { + "items": Object {}, + "type": "array", + }, + "index": Object { + "items": Object { + "type": "string", }, "type": "array", }, + "language": Object { + "enum": Array [ + "kuery", + "lucene", + ], + "type": "string", + }, + "query": Object { + "type": "string", + }, "savedId": Object { "type": "string", }, @@ -9469,12 +9801,6 @@ Object { "query": Object { "$ref": "#/allOf/1/anyOf/0/properties/query", }, - "responseActions": Object { - "items": Object { - "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items", - }, - "type": "array", - }, "savedId": Object { "$ref": "#/allOf/1/anyOf/0/properties/savedId", }, @@ -9667,6 +9993,175 @@ Object { }, "type": "array", }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, "riskScore": Object { "maximum": 100, "minimum": 0, diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts index da4661ae8464c..e15ab0f06e082 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts @@ -68,13 +68,13 @@ import { SavedQueryId, KqlQueryLanguage, } from './common_attributes.gen'; +import { ResponseAction } from '../rule_response_actions/response_actions.gen'; import { RuleExecutionSummary } from '../../rule_monitoring/model/execution_summary.gen'; import { EventCategoryOverride, TiebreakerField, TimestampField, } from './specific_attributes/eql_attributes.gen'; -import { ResponseAction } from '../rule_response_actions/response_actions.gen'; import { Threshold, ThresholdAlertSuppression, @@ -117,6 +117,7 @@ export const BaseOptionalFields = z.object({ meta: RuleMetadata.optional(), investigation_fields: InvestigationFields.optional(), throttle: RuleActionThrottle.optional(), + response_actions: z.array(ResponseAction).optional(), }); export type BaseDefaultableFields = z.infer; @@ -224,7 +225,6 @@ export const EqlOptionalFields = z.object({ tiebreaker_field: TiebreakerField.optional(), timestamp_field: TimestampField.optional(), alert_suppression: AlertSuppression.optional(), - response_actions: z.array(ResponseAction).optional(), }); export type EqlRuleCreateFields = z.infer; @@ -262,7 +262,6 @@ export const QueryRuleOptionalFields = z.object({ data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), saved_id: SavedQueryId.optional(), - response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), }); @@ -313,7 +312,6 @@ export const SavedQueryRuleOptionalFields = z.object({ index: IndexPatternArray.optional(), data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), - response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), query: RuleQuery.optional(), }); @@ -522,7 +520,6 @@ export const NewTermsRuleOptionalFields = z.object({ data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), alert_suppression: AlertSuppression.optional(), - response_actions: z.array(ResponseAction).optional(), }); export type NewTermsRuleDefaultableFields = z.infer; @@ -576,7 +573,6 @@ export const EsqlRuleRequiredFields = z.object({ export type EsqlRuleOptionalFields = z.infer; export const EsqlRuleOptionalFields = z.object({ alert_suppression: AlertSuppression.optional(), - response_actions: z.array(ResponseAction).optional(), }); export type EsqlRulePatchFields = z.infer; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml index d8aba232c26f9..f362b41ab6e86 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml @@ -74,6 +74,11 @@ components: throttle: $ref: './common_attributes.schema.yaml#/components/schemas/RuleActionThrottle' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' + BaseDefaultableFields: x-inline: true type: object @@ -293,10 +298,6 @@ components: $ref: './specific_attributes/eql_attributes.schema.yaml#/components/schemas/TimestampField' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' EqlRuleCreateFields: allOf: @@ -359,10 +360,6 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' saved_id: $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' @@ -440,10 +437,6 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' filters: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' query: @@ -767,10 +760,6 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' NewTermsRuleDefaultableFields: type: object @@ -849,10 +838,6 @@ components: properties: alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' EsqlRulePatchFields: allOf: diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.ts index 5068f35b6be1a..a98ca169a41d7 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.ts @@ -93,9 +93,16 @@ export const isSuppressionRuleConfiguredWithMissingFields = (ruleType: Type) => export const isSuppressionRuleInGA = (ruleType: Type): boolean => { return isSuppressibleAlertRule(ruleType) && SUPPRESSIBLE_ALERT_RULES_GA.includes(ruleType); }; - -export const shouldShowResponseActions = (ruleType: Type | undefined) => { +export const shouldShowResponseActions = ( + ruleType: Type | undefined, + automatedResponseActionsForAllRulesEnabled: boolean +) => { return ( - isQueryRule(ruleType) || isEsqlRule(ruleType) || isEqlRule(ruleType) || isNewTermsRule(ruleType) + isQueryRule(ruleType) || + isEsqlRule(ruleType) || + isEqlRule(ruleType) || + isNewTermsRule(ruleType) || + (automatedResponseActionsForAllRulesEnabled && + (isThresholdRule(ruleType) || isThreatMatchRule(ruleType) || isMlRule(ruleType))) ); }; diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 8ee859421d012..ba7a8795f7e08 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -52,6 +52,11 @@ export const allowedExperimentalValues = Object.freeze({ */ automatedProcessActionsEnabled: true, + /** + * Temporary feature flag to enable the Response Actions in Rules UI - intermediate release + */ + automatedResponseActionsForAllRulesEnabled: false, + /** * Enables the ability to send Response actions to SentinelOne and persist the results * in ES. Adds API changes to support `agentType` and supports `isolate` and `release` diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml index 8fca765f4fb3f..ebd4c93280090 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -2051,10 +2051,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array tiebreaker_field: $ref: '#/components/schemas/TiebreakerField' timestamp_field: @@ -2137,6 +2133,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2252,6 +2252,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2364,6 +2368,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2459,6 +2467,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2584,6 +2596,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2699,6 +2715,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2742,10 +2762,6 @@ components: properties: alert_suppression: $ref: '#/components/schemas/AlertSuppression' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array EsqlRulePatchProps: allOf: - type: object @@ -2809,6 +2825,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2926,6 +2946,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3178,6 +3202,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3293,6 +3321,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3408,6 +3440,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3519,6 +3555,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3720,6 +3760,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3836,6 +3880,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3890,10 +3938,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array NewTermsRulePatchFields: allOf: - type: object @@ -3969,6 +4013,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4089,6 +4137,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4312,6 +4364,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4428,6 +4484,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4484,10 +4544,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array saved_id: $ref: '#/components/schemas/SavedQueryId' QueryRulePatchFields: @@ -4559,6 +4615,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4673,6 +4733,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5359,6 +5423,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5475,6 +5543,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5531,10 +5603,6 @@ components: $ref: '#/components/schemas/IndexPatternArray' query: $ref: '#/components/schemas/RuleQuery' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array SavedQueryRulePatchFields: allOf: - type: object @@ -5606,6 +5674,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5720,6 +5792,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5967,6 +6043,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6083,6 +6163,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6226,6 +6310,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6349,6 +6437,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6538,6 +6630,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6654,6 +6750,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6783,6 +6883,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6900,6 +7004,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml index 38b419972a681..30a7ae3ea343e 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -1325,10 +1325,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array tiebreaker_field: $ref: '#/components/schemas/TiebreakerField' timestamp_field: @@ -1411,6 +1407,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1526,6 +1526,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1638,6 +1642,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1733,6 +1741,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1858,6 +1870,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1973,6 +1989,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2016,10 +2036,6 @@ components: properties: alert_suppression: $ref: '#/components/schemas/AlertSuppression' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array EsqlRulePatchProps: allOf: - type: object @@ -2083,6 +2099,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2200,6 +2220,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2429,6 +2453,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2544,6 +2572,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2659,6 +2691,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2770,6 +2806,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2873,6 +2913,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2989,6 +3033,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3043,10 +3091,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array NewTermsRulePatchFields: allOf: - type: object @@ -3122,6 +3166,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3242,6 +3290,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3465,6 +3517,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3581,6 +3637,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3637,10 +3697,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array saved_id: $ref: '#/components/schemas/SavedQueryId' QueryRulePatchFields: @@ -3712,6 +3768,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3826,6 +3886,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4512,6 +4576,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4628,6 +4696,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4684,10 +4756,6 @@ components: $ref: '#/components/schemas/IndexPatternArray' query: $ref: '#/components/schemas/RuleQuery' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array SavedQueryRulePatchFields: allOf: - type: object @@ -4759,6 +4827,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4873,6 +4945,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5113,6 +5189,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5229,6 +5309,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5372,6 +5456,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5495,6 +5583,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5684,6 +5776,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5800,6 +5896,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5929,6 +6029,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6046,6 +6150,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx index 9e6346cc9040e..06168ce97a2c7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx @@ -16,6 +16,7 @@ import type { } from '@kbn/triggers-actions-ui-plugin/public'; import { UseArray } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { shouldShowResponseActions } from '../../../../../common/detection_engine/utils'; import type { RuleObjectId } from '../../../../../common/api/detection_engine/model/rule_schema'; import { ResponseActionsForm } from '../../../rule_response_actions/response_actions_form'; @@ -84,7 +85,9 @@ const StepRuleActionsComponent: FC = ({ const { services: { application }, } = useKibana(); - + const automatedResponseActionsForAllRulesEnabled = useIsExperimentalFeatureEnabled( + 'automatedResponseActionsForAllRulesEnabled' + ); const displayActionsOptions = useMemo( () => ( <> @@ -102,7 +105,7 @@ const StepRuleActionsComponent: FC = ({ [actionMessageParams, summaryActionMessageParams] ); const displayResponseActionsOptions = useMemo(() => { - if (shouldShowResponseActions(ruleType)) { + if (shouldShowResponseActions(ruleType, automatedResponseActionsForAllRulesEnabled)) { return ( {ResponseActionsForm} @@ -110,7 +113,7 @@ const StepRuleActionsComponent: FC = ({ ); } return null; - }, [ruleType]); + }, [automatedResponseActionsForAllRulesEnabled, ruleType]); // only display the actions dropdown if the user has "read" privileges for actions const displayActionsDropDown = useMemo(() => { return application.capabilities.actions.show ? ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts index 45a561996e0a9..5d963db71cdea 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts @@ -7,23 +7,10 @@ import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { getListArrayMock } from '../../../../../../common/detection_engine/schemas/types/lists.mock'; -import { PrebuiltRuleAsset, TypeSpecificFields } from './prebuilt_rule_asset'; +import { PrebuiltRuleAsset } from './prebuilt_rule_asset'; import { getPrebuiltRuleMock, getPrebuiltThreatMatchRuleMock } from './prebuilt_rule_asset.mock'; -import { TypeSpecificCreatePropsInternal } from '../../../../../../common/api/detection_engine'; describe('Prebuilt rule asset schema', () => { - it('can be of all rule types that are supported', () => { - // Check that the discriminated union TypeSpecificFields, which is used to create - // the PrebuiltRuleAsset schema, contains all the rule types that are supported. - const createPropsTypes = TypeSpecificCreatePropsInternal.options.map( - (option) => option.shape.type.value - ); - const fieldsTypes = TypeSpecificFields.options.map((option) => option.shape.type.value); - - expect(createPropsTypes).toHaveLength(fieldsTypes.length); - expect(new Set(createPropsTypes)).toEqual(new Set(fieldsTypes)); - }); - test('empty objects do not validate', () => { const payload: Partial = {}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts index 2d7b056f86248..cc7e38632547f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts @@ -6,20 +6,11 @@ */ import * as z from '@kbn/zod'; -import type { IsEqual } from 'type-fest'; -import type { TypeSpecificCreateProps } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { RuleSignatureId, RuleVersion, BaseCreateProps, - EqlRuleCreateFields, - EsqlRuleCreateFields, - MachineLearningRuleCreateFields, - NewTermsRuleCreateFields, - QueryRuleCreateFields, - SavedQueryRuleCreateFields, - ThreatMatchRuleCreateFields, - ThresholdRuleCreateFields, + TypeSpecificCreatePropsInternal, } from '../../../../../../common/api/detection_engine/model/rule_schema'; function zodMaskFor() { @@ -38,6 +29,7 @@ function zodMaskFor() { */ const BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET = zodMaskFor()([ 'actions', + 'response_actions', 'throttle', 'meta', 'output_index', @@ -47,40 +39,6 @@ const BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET = zodMaskFor( 'outcome', ]); -/** - * Aditionally remove fields which are part only of the optional fields in the rule types that make up - * the TypeSpecificCreateProps discriminatedUnion, by recreating a discriminated union of the types, but - * with the necessary fields omitted, in the types where they exist. Fields to extract: - * - response_actions: from Query and SavedQuery rules - */ -const TYPE_SPECIFIC_FIELDS_TO_OMIT = ['response_actions'] as const; - -const TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES = zodMaskFor()([ - ...TYPE_SPECIFIC_FIELDS_TO_OMIT, -]); -const TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_SAVED_QUERY_RULES = - zodMaskFor()([...TYPE_SPECIFIC_FIELDS_TO_OMIT]); - -export type TypeSpecificFields = z.infer; -export const TypeSpecificFields = z.discriminatedUnion('type', [ - EqlRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES), - QueryRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES), - SavedQueryRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_SAVED_QUERY_RULES), - ThresholdRuleCreateFields, - ThreatMatchRuleCreateFields, - MachineLearningRuleCreateFields, - NewTermsRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES), - EsqlRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES), -]); - -// Make sure the type-specific fields contain all the same rule types as the type-specific rule params. -// TS will throw a type error if the types are not equal (for example, if a new rule type is added to -// the TypeSpecificCreateProps and the new type is not reflected in TypeSpecificFields). -export const areTypesEqual: IsEqual< - typeof TypeSpecificCreateProps._type.type, - typeof TypeSpecificFields._type.type -> = true; - export const PrebuiltAssetBaseProps = BaseCreateProps.omit( BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET ); @@ -101,7 +59,7 @@ export const PrebuiltAssetBaseProps = BaseCreateProps.omit( * - some fields are omitted because they are not present in https://github.com/elastic/detection-rules */ export type PrebuiltRuleAsset = z.infer; -export const PrebuiltRuleAsset = PrebuiltAssetBaseProps.and(TypeSpecificFields).and( +export const PrebuiltRuleAsset = PrebuiltAssetBaseProps.and(TypeSpecificCreatePropsInternal).and( z.object({ rule_id: RuleSignatureId, version: RuleVersion, @@ -112,7 +70,7 @@ function createUpgradableRuleFieldsPayloadByType() { const baseFields = Object.keys(PrebuiltAssetBaseProps.shape); return new Map( - TypeSpecificFields.options.map((option) => { + TypeSpecificCreatePropsInternal.options.map((option) => { const typeName = option.shape.type.value; const typeSpecificFieldsForType = Object.keys(option.shape); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts index f86abd4f08d8d..38e40ab67611f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts @@ -6,6 +6,7 @@ */ import snakecaseKeys from 'snakecase-keys'; +import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; import type { BaseRuleParams } from '../../../../rule_schema'; import { migrateLegacyInvestigationFields } from '../../../utils/utils'; @@ -44,6 +45,7 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { rule_source: convertObjectKeysToSnakeCase(params.ruleSource), related_integrations: params.relatedIntegrations ?? [], required_fields: params.requiredFields ?? [], + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), setup: params.setup ?? '', }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts index 2348c11027c65..0c2edf5535f35 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts @@ -53,6 +53,9 @@ export const convertRuleResponseToAlertingRule = ( const alertActions = ruleActions?.map((action) => transformRuleToAlertAction(action)) ?? []; const actions = transformToActionFrequency(alertActions as RuleActionCamel[], rule.throttle); + const responseActions = rule.response_actions?.map((ruleResponseAction) => + transformRuleToAlertResponseAction(ruleResponseAction) + ); // Because of Omit Typescript doesn't recognize // that rule is assignable to TypeSpecificCreateProps despite omitted fields // are not part of type specific props. So we need to cast here. @@ -94,6 +97,7 @@ export const convertRuleResponseToAlertingRule = ( note: rule.note, version: rule.version, exceptionsList: rule.exceptions_list, + responseActions, ...typeSpecificParams, }, schedule: { interval: rule.interval }, @@ -119,9 +123,6 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific eventCategoryOverride: params.event_category_override, tiebreakerField: params.tiebreaker_field, alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), }; } case 'esql': { @@ -130,9 +131,6 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific language: params.language, query: params.query, alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), }; } case 'threat_match': { @@ -164,9 +162,6 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific query: params.query ?? '', filters: params.filters, savedId: params.saved_id, - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } @@ -216,9 +211,6 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific language: params.language ?? 'kuery', dataViewId: params.data_view_id, alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), }; } default: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts index a4b74e31ba291..5a2f7ba0d3548 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts @@ -6,7 +6,6 @@ */ import type { RequiredOptional } from '@kbn/zod-helpers'; -import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import type { TypeSpecificResponse } from '../../../../../../../common/api/detection_engine/model/rule_schema'; import { assertUnreachable } from '../../../../../../../common/utility_types'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; @@ -28,7 +27,6 @@ export const typeSpecificCamelToSnake = ( event_category_override: params.eventCategoryOverride, tiebreaker_field: params.tiebreakerField, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } case 'esql': { @@ -37,7 +35,6 @@ export const typeSpecificCamelToSnake = ( language: params.language, query: params.query, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } case 'threat_match': { @@ -69,7 +66,6 @@ export const typeSpecificCamelToSnake = ( query: params.query, filters: params.filters, saved_id: params.savedId, - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } @@ -82,7 +78,6 @@ export const typeSpecificCamelToSnake = ( filters: params.filters, saved_id: params.savedId, data_view_id: params.dataViewId, - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } @@ -120,7 +115,6 @@ export const typeSpecificCamelToSnake = ( language: params.language, data_view_id: params.dataViewId, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } default: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts index 388b1ab695269..40f0b3eca3b98 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts @@ -86,7 +86,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { event_category_override: props.event_category_override, tiebreaker_field: props.tiebreaker_field, alert_suppression: props.alert_suppression, - response_actions: props.response_actions, }; } case 'esql': { @@ -95,7 +94,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { language: props.language, query: props.query, alert_suppression: props.alert_suppression, - response_actions: props.response_actions, }; } case 'threat_match': { @@ -127,7 +125,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { query: props.query ?? '', filters: props.filters, saved_id: props.saved_id, - response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } @@ -140,7 +137,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { filters: props.filters, saved_id: props.saved_id, data_view_id: props.data_view_id, - response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } @@ -178,7 +174,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { language: props.language ?? 'kuery', data_view_id: props.data_view_id, alert_suppression: props.alert_suppression, - response_actions: props.response_actions, }; } default: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts index d864170746ed3..ba21037ba376f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts @@ -111,6 +111,7 @@ export const applyRulePatch = async ({ interval: rulePatch.interval ?? existingRule.interval, throttle: rulePatch.throttle ?? existingRule.throttle, actions: rulePatch.actions ?? existingRule.actions, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, ...typeSpecificParams, }; @@ -138,7 +139,6 @@ const patchEqlParams = ( rulePatch.event_category_override ?? existingRule.event_category_override, tiebreaker_field: rulePatch.tiebreaker_field ?? existingRule.tiebreaker_field, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, }; }; @@ -151,7 +151,6 @@ const patchEsqlParams = ( language: rulePatch.language ?? existingRule.language, query: rulePatch.query ?? existingRule.query, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, }; }; @@ -191,7 +190,6 @@ const patchQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; @@ -208,7 +206,6 @@ const patchSavedQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; @@ -260,7 +257,6 @@ const patchNewTermsParams = ( new_terms_fields: params.new_terms_fields ?? existingRule.new_terms_fields, history_window_start: params.history_window_start ?? existingRule.history_window_start, alert_suppression: params.alert_suppression ?? existingRule.alert_suppression, - response_actions: params.response_actions ?? existingRule.response_actions, }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index 96aaef64b57c9..3d07f935deb7b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -6,15 +6,9 @@ */ import type { PartialRule } from '@kbn/alerting-plugin/server'; -import type { Rule } from '@kbn/alerting-plugin/common'; import { isEqual, xorWith } from 'lodash'; import { stringifyZodError } from '@kbn/zod-helpers'; -import type { - EqlRule, - EsqlRule, - NewTermsRule, - QueryRule, -} from '../../../../../common/api/detection_engine'; +import { shouldShowResponseActions } from '../../../../../common/detection_engine/utils'; import { type ResponseAction, type RuleCreateProps, @@ -26,16 +20,9 @@ import { RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP, RESPONSE_CONSOLE_ACTION_COMMANDS_TO_REQUIRED_AUTHZ, } from '../../../../../common/endpoint/service/response_actions/constants'; -import { shouldShowResponseActions } from '../../../../../common/detection_engine/utils'; import type { SecuritySolutionApiRequestHandlerContext } from '../../../..'; import { CustomHttpRequestError } from '../../../../utils/custom_http_request_error'; -import type { EqlRuleParams, EsqlRuleParams, NewTermsRuleParams } from '../../rule_schema'; -import { - hasValidRuleType, - type RuleAlertType, - type RuleParams, - type UnifiedQueryRuleParams, -} from '../../rule_schema'; +import { hasValidRuleType, type RuleAlertType, type RuleParams } from '../../rule_schema'; import { type BulkError, createBulkErrorObject } from '../../routes/utils'; import { internalRuleToAPIResponse } from '../logic/detection_rules_client/converters/internal_rule_to_api_response'; @@ -70,7 +57,13 @@ export const validateResponseActionsPermissions = async ( ruleUpdate: RuleCreateProps | RuleUpdateProps, existingRule?: RuleAlertType | null ): Promise => { - if (!shouldShowResponseActions(ruleUpdate.type)) { + const { experimentalFeatures } = await securitySolution.getConfig(); + if ( + !shouldShowResponseActions( + ruleUpdate.type, + experimentalFeatures.automatedResponseActionsForAllRulesEnabled + ) + ) { return; } @@ -117,14 +110,10 @@ export const validateResponseActionsPermissions = async ( }); }; -function rulePayloadContainsResponseActions( - rule: RuleCreateProps | RuleUpdateProps -): rule is QueryRule | EsqlRule | EqlRule | NewTermsRule { +function rulePayloadContainsResponseActions(rule: RuleCreateProps | RuleUpdateProps) { return 'response_actions' in rule; } -function ruleObjectContainsResponseActions( - rule?: RuleAlertType -): rule is Rule { +function ruleObjectContainsResponseActions(rule?: RuleAlertType) { return rule != null && 'params' in rule && 'responseActions' in rule?.params; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts index b4f4689fed0ff..f3d9b42d24213 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts @@ -32,6 +32,9 @@ export const getScheduleNotificationResponseActionsService = const nestedAlerts = signals.map((signal) => expandDottedObject(signal as object)) as Alert[]; const alerts = nestedAlerts.filter((alert) => alert.agent?.id) as AlertWithAgent[]; + if (!alerts.length) { + return; + } return Promise.all( responseActions.map(async (responseAction) => { if ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts index e651ffeebaf49..c1192e9a75fd1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts @@ -148,6 +148,7 @@ export const BaseRuleParams = z.object({ relatedIntegrations: RelatedIntegrationArray.optional(), requiredFields: RequiredFieldArray.optional(), setup: SetupGuide.optional(), + responseActions: z.array(RuleResponseAction).optional(), }); export type EqlSpecificRuleParams = z.infer; @@ -162,7 +163,6 @@ export const EqlSpecificRuleParams = z.object({ timestampField: TimestampField.optional(), tiebreakerField: TiebreakerField.optional(), alertSuppression: AlertSuppressionCamel.optional(), - responseActions: z.array(RuleResponseAction).optional(), }); export type EqlRuleParams = BaseRuleParams & EqlSpecificRuleParams; @@ -174,7 +174,6 @@ export const EsqlSpecificRuleParams = z.object({ language: z.literal('esql'), query: RuleQuery, alertSuppression: AlertSuppressionCamel.optional(), - responseActions: z.array(RuleResponseAction).optional(), }); export type EsqlRuleParams = BaseRuleParams & EsqlSpecificRuleParams; @@ -212,7 +211,6 @@ export const QuerySpecificRuleParams = z.object({ filters: RuleFilterArray.optional(), savedId: SavedQueryId.optional(), dataViewId: DataViewId.optional(), - responseActions: z.array(RuleResponseAction).optional(), alertSuppression: AlertSuppressionCamel.optional(), }); @@ -228,7 +226,6 @@ export const SavedQuerySpecificRuleParams = z.object({ query: RuleQuery.optional(), filters: RuleFilterArray.optional(), savedId: SavedQueryId, - responseActions: z.array(RuleResponseAction).optional(), alertSuppression: AlertSuppressionCamel.optional(), }); @@ -282,7 +279,6 @@ export const NewTermsSpecificRuleParams = z.object({ language: KqlQueryLanguage, dataViewId: DataViewId.optional(), alertSuppression: AlertSuppressionCamel.optional(), - responseActions: z.array(RuleResponseAction).optional(), }); export type NewTermsRuleParams = BaseRuleParams & NewTermsSpecificRuleParams; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts index 9de8641d7b17c..12af1966b7dce 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts @@ -11,19 +11,14 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; import { EqlRuleParams } from '../../rule_schema'; import { eqlExecutor } from './eql'; -import type { - CreateRuleOptions, - SecurityAlertType, - SignalSourceHit, - CreateRuleAdditionalOptions, -} from '../types'; +import type { CreateRuleOptions, SecurityAlertType, SignalSourceHit } from '../types'; import { validateIndexPatterns } from '../utils'; import type { BuildReasonMessage } from '../utils/reason_formatters'; import { wrapSuppressedAlerts } from '../utils/wrap_suppressed_alerts'; import { getIsAlertSuppressionActive } from '../utils/get_is_alert_suppression_active'; export const createEqlAlertType = ( - createOptions: CreateRuleOptions & CreateRuleAdditionalOptions + createOptions: CreateRuleOptions ): SecurityAlertType => { const { experimentalFeatures, version, licensing, scheduleNotificationResponseActionsService } = createOptions; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts index 47e298392d7d9..cd8b76a93d23b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts @@ -26,7 +26,7 @@ import type { SearchAfterAndBulkCreateReturnType, SignalSource, WrapSuppressedHits, - CreateRuleAdditionalOptions, + CreateRuleOptions, } from '../types'; import { addToSearchAfterReturn, @@ -71,7 +71,7 @@ interface EqlExecutorParams { isAlertSuppressionActive: boolean; experimentalFeatures: ExperimentalFeatures; state?: Record; - scheduleNotificationResponseActionsService: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; + scheduleNotificationResponseActionsService: CreateRuleOptions['scheduleNotificationResponseActionsService']; } export const eqlExecutor = async ({ @@ -104,7 +104,6 @@ export const eqlExecutor = async ({ const isLoggedRequestsEnabled = state?.isLoggedRequestsEnabled ?? false; const loggedRequests: RulePreviewLoggedRequest[] = []; - // eslint-disable-next-line complexity return withSecuritySpan('eqlExecutor', async () => { const result = createSearchAfterReturnType(); @@ -213,13 +212,11 @@ export const eqlExecutor = async ({ result.warningMessages.push(maxSignalsWarning); } - if (scheduleNotificationResponseActionsService) { - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - signalsCount: result.createdSignalsCount, - responseActions: completeRule.ruleParams.responseActions, - }); - } + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); return { result, ...(isLoggedRequestsEnabled ? { loggedRequests } : {}) }; } catch (error) { if ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts index 31afe8d2a191f..043b8e3b3a851 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts @@ -11,10 +11,10 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; import { EsqlRuleParams } from '../../rule_schema'; import { esqlExecutor } from './esql'; -import type { CreateRuleOptions, SecurityAlertType, CreateRuleAdditionalOptions } from '../types'; +import type { CreateRuleOptions, SecurityAlertType } from '../types'; export const createEsqlAlertType = ( - createOptions: CreateRuleOptions & CreateRuleAdditionalOptions + createOptions: CreateRuleOptions ): SecurityAlertType => { const { version, experimentalFeatures, licensing, scheduleNotificationResponseActionsService } = createOptions; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts index 1e5b1749e94f5..a076ea0c62635 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts @@ -28,7 +28,7 @@ import { rowToDocument } from './utils'; import { fetchSourceDocuments } from './fetch_source_documents'; import { buildReasonMessageForEsqlAlert } from '../utils/reason_formatters'; import type { RulePreviewLoggedRequest } from '../../../../../common/api/detection_engine/rule_preview/rule_preview.gen'; -import type { RunOpts, SignalSource, CreateRuleAdditionalOptions } from '../types'; +import type { CreateRuleOptions, RunOpts, SignalSource } from '../types'; import { logEsqlRequest } from '../utils/logged_requests'; import * as i18n from '../translations'; @@ -74,7 +74,7 @@ export const esqlExecutor = async ({ version: string; experimentalFeatures: ExperimentalFeatures; licensing: LicensingPluginSetup; - scheduleNotificationResponseActionsService: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; + scheduleNotificationResponseActionsService: CreateRuleOptions['scheduleNotificationResponseActionsService']; }) => { const loggedRequests: RulePreviewLoggedRequest[] = []; const ruleParams = completeRule.ruleParams; @@ -245,13 +245,11 @@ export const esqlExecutor = async ({ } } - if (scheduleNotificationResponseActionsService) { - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - signalsCount: result.createdSignalsCount, - responseActions: completeRule.ruleParams.responseActions, - }); - } + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); // no more results will be found if (response.values.length < size) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts index d7f3e96d9a43d..9c51d22d31ee1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts @@ -20,7 +20,13 @@ import type { BuildReasonMessage } from '../utils/reason_formatters'; export const createIndicatorMatchAlertType = ( createOptions: CreateRuleOptions ): SecurityAlertType => { - const { eventsTelemetry, version, licensing, experimentalFeatures } = createOptions; + const { + eventsTelemetry, + version, + licensing, + experimentalFeatures, + scheduleNotificationResponseActionsService, + } = createOptions; return { id: INDICATOR_RULE_TYPE_ID, name: 'Indicator Match Rule', @@ -122,6 +128,7 @@ export const createIndicatorMatchAlertType = ( runOpts, licensing, experimentalFeatures, + scheduleNotificationResponseActionsService, }); return { ...result, state }; }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/indicator_match.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/indicator_match.ts index b8392a82bb6c0..d243943b9417c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/indicator_match.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/indicator_match.ts @@ -16,7 +16,14 @@ import type { } from '@kbn/alerting-plugin/server'; import type { ListClient } from '@kbn/lists-plugin/server'; import type { Filter } from '@kbn/es-query'; -import type { RuleRangeTuple, BulkCreate, WrapHits, WrapSuppressedHits, RunOpts } from '../types'; +import type { + RuleRangeTuple, + BulkCreate, + WrapHits, + WrapSuppressedHits, + RunOpts, + CreateRuleOptions, +} from '../types'; import type { ITelemetryEventsSender } from '../../../telemetry/sender'; import { createThreatSignals } from './threat_mapping/create_threat_signals'; import type { CompleteRule, ThreatRuleParams } from '../../rule_schema'; @@ -47,6 +54,7 @@ export const indicatorMatchExecutor = async ({ runOpts, licensing, experimentalFeatures, + scheduleNotificationResponseActionsService, }: { inputIndex: string[]; runtimeMappings: estypes.MappingRuntimeFields | undefined; @@ -67,6 +75,7 @@ export const indicatorMatchExecutor = async ({ wrapSuppressedHits: WrapSuppressedHits; runOpts: RunOpts; licensing: LicensingPluginSetup; + scheduleNotificationResponseActionsService: CreateRuleOptions['scheduleNotificationResponseActionsService']; experimentalFeatures: ExperimentalFeatures; }) => { const ruleParams = completeRule.ruleParams; @@ -107,6 +116,7 @@ export const indicatorMatchExecutor = async ({ runOpts, licensing, experimentalFeatures, + scheduleNotificationResponseActionsService, }); }); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/create_threat_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/create_threat_signals.ts index 4d477d53604a4..f05914201ad09 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/create_threat_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/create_threat_signals.ts @@ -74,6 +74,7 @@ export const createThreatSignals = async ({ unprocessedExceptions, licensing, experimentalFeatures, + scheduleNotificationResponseActionsService, }: CreateThreatSignalsOptions): Promise => { const threatMatchedFields = getMatchedFields(threatMapping); const threatFieldsLength = threatMatchedFields.threat.length; @@ -460,7 +461,11 @@ export const createThreatSignals = async ({ `Error trying to close point in time: "${threatPitId}", it will expire within "${THREAT_PIT_KEEP_ALIVE}". Error is: "${error}"` ); } - + scheduleNotificationResponseActionsService({ + signals: results.createdSignals, + signalsCount: results.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); ruleExecutionLogger.debug('Indicator matching rule has completed'); return results; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/types.ts index 37bc9d1810137..4eac8bd6a8864 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/types.ts @@ -38,6 +38,7 @@ import type { WrapSuppressedHits, OverrideBodyQuery, RunOpts, + CreateRuleOptions, } from '../../types'; import type { CompleteRule, ThreatRuleParams } from '../../../rule_schema'; import type { IRuleExecutionLogForExecutors } from '../../../rule_monitoring'; @@ -80,6 +81,7 @@ export interface CreateThreatSignalsOptions { runOpts: RunOpts; licensing: LicensingPluginSetup; experimentalFeatures: ExperimentalFeatures; + scheduleNotificationResponseActionsService: CreateRuleOptions['scheduleNotificationResponseActionsService']; } export interface CreateThreatSignalOptions { @@ -172,6 +174,7 @@ export interface CreateEventSignalOptions { } type EntryKey = 'field' | 'value'; + export interface BuildThreatMappingFilterOptions { chunkSize?: number; threatList: ThreatListItem[]; @@ -273,6 +276,7 @@ interface BaseThreatNamedQuery { value: string; queryType: string; } + export interface ThreatMatchNamedQuery extends BaseThreatNamedQuery { id: string; index: string; @@ -325,6 +329,7 @@ export interface EventDoc { } export type EventItem = estypes.SearchHit; + export interface EventCountOptions { esClient: ElasticsearchClient; index: string[]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts index 09a4a2e4cb1ee..4d896c4efdaa4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts @@ -19,7 +19,8 @@ import { wrapSuppressedAlerts } from '../utils/wrap_suppressed_alerts'; export const createMlAlertType = ( createOptions: CreateRuleOptions ): SecurityAlertType => { - const { experimentalFeatures, ml, licensing } = createOptions; + const { experimentalFeatures, ml, licensing, scheduleNotificationResponseActionsService } = + createOptions; return { id: ML_RULE_TYPE_ID, name: 'Machine Learning Rule', @@ -106,6 +107,7 @@ export const createMlAlertType = ( alertWithSuppression, isAlertSuppressionActive, experimentalFeatures, + scheduleNotificationResponseActionsService, }); return { ...result, state }; }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/ml.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/ml.test.ts index 59a0204ef9545..2a3fa8360e3f8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/ml.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/ml.test.ts @@ -23,6 +23,7 @@ jest.mock('./bulk_create_ml_signals'); describe('ml_executor', () => { let mockExperimentalFeatures: jest.Mocked; + let mockScheduledNotificationResponseAction: jest.Mock; let jobsSummaryMock: jest.Mock; let forceStartDatafeedsMock: jest.Mock; let stopDatafeedsMock: jest.Mock; @@ -40,6 +41,7 @@ describe('ml_executor', () => { beforeEach(() => { mockExperimentalFeatures = {} as jest.Mocked; + mockScheduledNotificationResponseAction = jest.fn(); jobsSummaryMock = jest.fn(); mlMock = mlPluginServerMock.createSetupContract(); mlMock.jobServiceProvider.mockReturnValue({ @@ -88,6 +90,7 @@ describe('ml_executor', () => { alertWithSuppression: jest.fn(), isAlertSuppressionActive: true, experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduledNotificationResponseAction, }) ).rejects.toThrow('ML plugin unavailable during rule execution'); }); @@ -110,6 +113,7 @@ describe('ml_executor', () => { alertWithSuppression: jest.fn(), isAlertSuppressionActive: true, experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduledNotificationResponseAction, }); expect(ruleExecutionLogger.warn).toHaveBeenCalled(); expect(ruleExecutionLogger.warn.mock.calls[0][0]).toContain( @@ -143,6 +147,7 @@ describe('ml_executor', () => { alertWithSuppression: jest.fn(), isAlertSuppressionActive: true, experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduledNotificationResponseAction, }); expect(ruleExecutionLogger.warn).toHaveBeenCalled(); expect(ruleExecutionLogger.warn.mock.calls[0][0]).toContain( @@ -172,6 +177,7 @@ describe('ml_executor', () => { alertWithSuppression: jest.fn(), isAlertSuppressionActive: true, experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduledNotificationResponseAction, }); expect(result.userError).toEqual(true); expect(result.success).toEqual(false); @@ -204,6 +210,7 @@ describe('ml_executor', () => { alertWithSuppression: jest.fn(), isAlertSuppressionActive: true, experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduledNotificationResponseAction, }); expect(result).toEqual( @@ -212,4 +219,29 @@ describe('ml_executor', () => { }) ); }); + it('should call scheduleNotificationResponseActionsService', async () => { + const result = await mlExecutor({ + completeRule: mlCompleteRule, + tuple, + ml: mlMock, + services: alertServices, + ruleExecutionLogger, + listClient, + bulkCreate: jest.fn(), + wrapHits: jest.fn(), + exceptionFilter: undefined, + unprocessedExceptions: [], + wrapSuppressedHits: jest.fn(), + alertTimestampOverride: undefined, + alertWithSuppression: jest.fn(), + isAlertSuppressionActive: true, + experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduledNotificationResponseAction, + }); + expect(mockScheduledNotificationResponseAction).toBeCalledWith({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: mlCompleteRule.ruleParams.responseActions, + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/ml.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/ml.ts index 4b7de9b27a667..1da14640c5a51 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/ml.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/ml.ts @@ -23,7 +23,13 @@ import type { CompleteRule, MachineLearningRuleParams } from '../../rule_schema' import { bulkCreateMlSignals } from './bulk_create_ml_signals'; import { filterEventsAgainstList } from '../utils/large_list_filters/filter_events_against_list'; import { findMlSignals } from './find_ml_signals'; -import type { BulkCreate, RuleRangeTuple, WrapHits, WrapSuppressedHits } from '../types'; +import type { + BulkCreate, + CreateRuleOptions, + RuleRangeTuple, + WrapHits, + WrapSuppressedHits, +} from '../types'; import { addToSearchAfterReturn, createErrorsFromShard, @@ -54,6 +60,7 @@ interface MachineLearningRuleExecutorParams { alertWithSuppression: SuppressedAlertService; isAlertSuppressionActive: boolean; experimentalFeatures: ExperimentalFeatures; + scheduleNotificationResponseActionsService: CreateRuleOptions['scheduleNotificationResponseActionsService']; } export const mlExecutor = async ({ @@ -72,6 +79,7 @@ export const mlExecutor = async ({ alertTimestampOverride, alertWithSuppression, experimentalFeatures, + scheduleNotificationResponseActionsService, }: MachineLearningRuleExecutorParams) => { const result = createSearchAfterReturnType(); const ruleParams = completeRule.ruleParams; @@ -191,6 +199,11 @@ export const mlExecutor = async ({ const searchErrors = createErrorsFromShard({ errors: shardFailures, }); + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); return mergeReturns([ result, createSearchAfterReturnType({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts index fc0c4b31426df..6b50f0fe0505e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts @@ -12,7 +12,7 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; import { NewTermsRuleParams } from '../../rule_schema'; -import type { CreateRuleOptions, SecurityAlertType, CreateRuleAdditionalOptions } from '../types'; +import type { CreateRuleOptions, SecurityAlertType } from '../types'; import { singleSearchAfter } from '../utils/single_search_after'; import { getFilter } from '../utils/get_filter'; import { wrapNewTermsAlerts } from './wrap_new_terms_alerts'; @@ -46,7 +46,7 @@ import { multiTermsComposite } from './multi_terms_composite'; import type { GenericBulkCreateResponse } from '../utils/bulk_create_with_suppression'; export const createNewTermsAlertType = ( - createOptions: CreateRuleOptions & CreateRuleAdditionalOptions + createOptions: CreateRuleOptions ): SecurityAlertType => { const { logger, licensing, experimentalFeatures, scheduleNotificationResponseActionsService } = createOptions; @@ -415,13 +415,11 @@ export const createNewTermsAlertType = ( afterKey = searchResultWithAggs.aggregations.new_terms.after_key; } - if (scheduleNotificationResponseActionsService) { - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - signalsCount: result.createdSignalsCount, - responseActions: completeRule.ruleParams.responseActions, - }); - } + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); return { ...result, state }; }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts index edf7ece7cc84b..8c235c5e8f238 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts @@ -22,7 +22,7 @@ import type { UnifiedQueryRuleParams } from '../../rule_schema'; import type { ExperimentalFeatures } from '../../../../../common/experimental_features'; import { buildReasonMessageForQueryAlert } from '../utils/reason_formatters'; import { withSecuritySpan } from '../../../../utils/with_security_span'; -import type { CreateRuleAdditionalOptions, RunOpts } from '../types'; +import type { CreateRuleOptions, RunOpts } from '../types'; export const queryExecutor = async ({ runOpts, @@ -42,7 +42,7 @@ export const queryExecutor = async ({ version: string; spaceId: string; bucketHistory?: BucketHistory[]; - scheduleNotificationResponseActionsService: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; + scheduleNotificationResponseActionsService: CreateRuleOptions['scheduleNotificationResponseActionsService']; licensing: LicensingPluginSetup; }) => { const completeRule = runOpts.completeRule; @@ -98,13 +98,11 @@ export const queryExecutor = async ({ state: {}, }; - if (scheduleNotificationResponseActionsService) { - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - signalsCount: result.createdSignalsCount, - responseActions: completeRule.ruleParams.responseActions, - }); - } + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); return result; }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts index f48cea676b953..a890315aa2688 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts @@ -19,7 +19,8 @@ import { validateIndexPatterns } from '../utils'; export const createThresholdAlertType = ( createOptions: CreateRuleOptions ): SecurityAlertType => { - const { version, licensing, experimentalFeatures } = createOptions; + const { version, licensing, experimentalFeatures, scheduleNotificationResponseActionsService } = + createOptions; return { id: THRESHOLD_RULE_TYPE_ID, name: 'Threshold Rule', @@ -102,6 +103,7 @@ export const createThresholdAlertType = ( runOpts: execOptions.runOpts, licensing, experimentalFeatures, + scheduleNotificationResponseActionsService, }); return result; }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/threshold.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/threshold.test.ts index 8c790596b99ba..de4af3354794d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/threshold.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/threshold.test.ts @@ -27,7 +27,7 @@ jest.mock('../utils/get_filter', () => ({ getFilter: jest.fn() })); describe('threshold_executor', () => { let alertServices: RuleExecutorServicesMock; let ruleExecutionLogger: ReturnType; - + let mockScheduledNotificationResponseAction: jest.Mock; const version = '8.0.0'; const params = getThresholdRuleParams(); const thresholdCompleteRule = getCompleteRuleMock(params); @@ -54,6 +54,7 @@ describe('threshold_executor', () => { ruleName: thresholdCompleteRule.ruleConfig.name, ruleType: thresholdCompleteRule.ruleConfig.ruleTypeId, }); + mockScheduledNotificationResponseAction = jest.fn(); }); describe('thresholdExecutor', () => { @@ -113,6 +114,7 @@ describe('threshold_executor', () => { runOpts: {} as RunOpts, licensing, experimentalFeatures: {} as ExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduledNotificationResponseAction, }); expect(response.state).toEqual({ initialized: true, @@ -178,6 +180,7 @@ describe('threshold_executor', () => { runOpts: {} as RunOpts, licensing, experimentalFeatures: {} as ExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduledNotificationResponseAction, }); expect(result.warningMessages).toEqual([ `The following exceptions won't be applied to rule execution: ${ @@ -185,5 +188,46 @@ describe('threshold_executor', () => { }`, ]); }); + it('should call scheduleNotificationResponseActionsService', async () => { + const ruleDataClientMock = createRuleDataClientMock(); + const state = { + initialized: true, + signalHistory: {}, + }; + const result = await thresholdExecutor({ + completeRule: thresholdCompleteRule, + tuple, + services: alertServices, + state, + version, + ruleExecutionLogger, + startedAt: new Date(), + bulkCreate: jest.fn().mockImplementation((hits) => ({ + errors: [], + success: true, + bulkCreateDuration: '0', + createdItemsCount: 0, + createdItems: [], + })), + wrapHits: jest.fn(), + ruleDataClient: ruleDataClientMock, + runtimeMappings: {}, + inputIndex: ['auditbeat-*'], + primaryTimestamp: TIMESTAMP, + aggregatableTimestampField: TIMESTAMP, + exceptionFilter: undefined, + unprocessedExceptions: [getExceptionListItemSchemaMock()], + spaceId: 'default', + runOpts: {} as RunOpts, + licensing, + experimentalFeatures: {} as ExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduledNotificationResponseAction, + }); + expect(mockScheduledNotificationResponseAction).toBeCalledWith({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: thresholdCompleteRule.ruleParams.responseActions, + }); + }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/threshold.ts index 06a0ff89ccc40..d56e164438509 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/threshold.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/threshold.ts @@ -33,6 +33,7 @@ import type { SearchAfterAndBulkCreateReturnType, WrapHits, RunOpts, + CreateRuleOptions, } from '../types'; import type { ThresholdAlertState, ThresholdSignalHistory } from './types'; import { @@ -68,6 +69,7 @@ export const thresholdExecutor = async ({ runOpts, licensing, experimentalFeatures, + scheduleNotificationResponseActionsService, }: { inputIndex: string[]; runtimeMappings: estypes.MappingRuntimeFields | undefined; @@ -90,6 +92,7 @@ export const thresholdExecutor = async ({ runOpts: RunOpts; licensing: LicensingPluginSetup; experimentalFeatures: ExperimentalFeatures; + scheduleNotificationResponseActionsService: CreateRuleOptions['scheduleNotificationResponseActionsService']; }): Promise => { const result = createSearchAfterReturnType(); const ruleParams = completeRule.ruleParams; @@ -209,7 +212,11 @@ export const thresholdExecutor = async ({ result.errors.push(...searchErrors); result.warningMessages.push(...warnings); result.searchAfterTimes = searchDurations; - + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); return { ...result, state: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts index 6e2999ae5e3b2..34307ea495268 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts @@ -163,6 +163,7 @@ export interface CreateRuleOptions { eventsTelemetry?: ITelemetryEventsSender | undefined; version: string; licensing: LicensingPluginSetup; + scheduleNotificationResponseActionsService: (params: ScheduleNotificationActions) => void; } export interface ScheduleNotificationActions { @@ -171,11 +172,7 @@ export interface ScheduleNotificationActions { responseActions: RuleResponseAction[] | undefined; } -export interface CreateRuleAdditionalOptions { - scheduleNotificationResponseActionsService?: (params: ScheduleNotificationActions) => void; -} - -export interface CreateQueryRuleOptions extends CreateRuleOptions, CreateRuleAdditionalOptions { +export interface CreateQueryRuleOptions extends CreateRuleOptions { id: typeof QUERY_RULE_TYPE_ID | typeof SAVED_QUERY_RULE_TYPE_ID; name: 'Custom Query Rule' | 'Saved Query Rule'; } diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 5ea5c7ba5cd9e..1becac2c75f71 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -76,10 +76,7 @@ import { PolicyWatcher } from './endpoint/lib/policy/license_watch'; import previewPolicy from './lib/detection_engine/routes/index/preview_policy.json'; import type { IRuleMonitoringService } from './lib/detection_engine/rule_monitoring'; import { createRuleMonitoringService } from './lib/detection_engine/rule_monitoring'; -import type { - CreateRuleAdditionalOptions, - CreateRuleOptions, -} from './lib/detection_engine/rule_types/types'; +import type { CreateRuleOptions } from './lib/detection_engine/rule_types/types'; // eslint-disable-next-line no-restricted-imports import { isLegacyNotificationRuleExecutor, @@ -280,6 +277,10 @@ export class Plugin implements ISecuritySolutionPlugin { eventsTelemetry: this.telemetryEventsSender, version: pluginContext.env.packageInfo.version, licensing: plugins.licensing, + scheduleNotificationResponseActionsService: getScheduleNotificationResponseActionsService({ + endpointAppContextService: this.endpointAppContextService, + osqueryCreateActionService: plugins.osquery.createActionService, + }), }; const ruleDataServiceOptions = { @@ -321,28 +322,18 @@ export class Plugin implements ISecuritySolutionPlugin { analytics: core.analytics, }; - const ruleAdditionalOptions: CreateRuleAdditionalOptions = { - scheduleNotificationResponseActionsService: getScheduleNotificationResponseActionsService({ - endpointAppContextService: this.endpointAppContextService, - osqueryCreateActionService: plugins.osquery.createActionService, - }), - }; - const securityRuleTypeWrapper = createSecurityRuleTypeWrapper(securityRuleTypeOptions); - plugins.alerting.registerType( - securityRuleTypeWrapper(createEqlAlertType({ ...ruleOptions, ...ruleAdditionalOptions })) - ); + plugins.alerting.registerType(securityRuleTypeWrapper(createEqlAlertType({ ...ruleOptions }))); if (!experimentalFeatures.esqlRulesDisabled) { plugins.alerting.registerType( - securityRuleTypeWrapper(createEsqlAlertType({ ...ruleOptions, ...ruleAdditionalOptions })) + securityRuleTypeWrapper(createEsqlAlertType({ ...ruleOptions })) ); } plugins.alerting.registerType( securityRuleTypeWrapper( createQueryAlertType({ ...ruleOptions, - ...ruleAdditionalOptions, id: SAVED_QUERY_RULE_TYPE_ID, name: 'Saved Query Rule', }) @@ -356,7 +347,6 @@ export class Plugin implements ISecuritySolutionPlugin { securityRuleTypeWrapper( createQueryAlertType({ ...ruleOptions, - ...ruleAdditionalOptions, id: QUERY_RULE_TYPE_ID, name: 'Custom Query Rule', }) @@ -364,7 +354,7 @@ export class Plugin implements ISecuritySolutionPlugin { ); plugins.alerting.registerType(securityRuleTypeWrapper(createThresholdAlertType(ruleOptions))); plugins.alerting.registerType( - securityRuleTypeWrapper(createNewTermsAlertType({ ...ruleOptions, ...ruleAdditionalOptions })) + securityRuleTypeWrapper(createNewTermsAlertType({ ...ruleOptions })) ); // TODO We need to get the endpoint routes inside of initRoutes From 3dd1ee8ae00a40b582f2d1f784c96269a1d2e016 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Wed, 9 Oct 2024 08:13:05 -0600 Subject: [PATCH 068/110] [Security GenAI] Remove `assistantNaturalLanguageESQLTool` feature flag and enable by default (#195480) --- .../kbn_elastic_assistant_common.devdocs.json | 4 +- api_docs/security_solution.devdocs.json | 12 +- .../knowledge_base/crud_kb_route.gen.ts | 1 - .../knowledge_base/crud_kb_route.schema.yaml | 2 - .../use_knowledge_base_status.test.tsx | 1 - .../use_knowledge_base_status.tsx | 18 -- .../assistant/chat_send/use_chat_send.tsx | 4 +- .../impl/knowledge_base/const.ts | 9 - .../knowledge_base_settings.test.tsx | 15 +- .../knowledge_base_settings.tsx | 36 +-- .../setup_knowledge_base_button.tsx | 7 +- .../__mocks__/docs_from_directory_loader.ts | 38 +-- .../knowledge_base/index.ts | 13 - .../esql/documentation/esql_commands.asciidoc | 63 ----- .../documentation/esql_enrich_data.asciidoc | 126 --------- .../documentation/esql_functions.asciidoc | 140 ---------- .../esql_functions_operators.asciidoc | 43 --- .../documentation/esql_get_started.asciidoc | 8 - .../esql/documentation/esql_kibana.asciidoc | 15 -- .../esql/documentation/esql_language.asciidoc | 23 -- .../documentation/esql_limitations.asciidoc | 32 --- .../documentation/esql_query_api.asciidoc | 97 ------- .../esql/documentation/esql_rest.asciidoc | 249 ------------------ .../esql/documentation/esql_syntax.asciidoc | 90 ------- .../esql/documentation/functions/abs.asciidoc | 18 -- .../documentation/functions/acos.asciidoc | 33 --- .../functions/aggregation_functions.asciidoc | 30 --- .../documentation/functions/asin.asciidoc | 20 -- .../documentation/functions/atan.asciidoc | 20 -- .../documentation/functions/atan2.asciidoc | 21 -- .../functions/auto_bucket.asciidoc | 72 ----- .../esql/documentation/functions/avg.asciidoc | 15 -- .../documentation/functions/binary.asciidoc | 12 - .../documentation/functions/case.asciidoc | 42 --- .../documentation/functions/ceil.asciidoc | 24 -- .../functions/cidr_match.asciidoc | 16 -- .../documentation/functions/coalesce.asciidoc | 14 - .../documentation/functions/concat.asciidoc | 11 - ...itional_functions_and_expressions.asciidoc | 21 -- .../esql/documentation/functions/cos.asciidoc | 20 -- .../documentation/functions/cosh.asciidoc | 20 -- .../documentation/functions/count.asciidoc | 27 -- .../functions/count_distinct.asciidoc | 46 ---- .../functions/date_extract.asciidoc | 15 -- .../functions/date_format.asciidoc | 12 - .../functions/date_parse.asciidoc | 37 --- .../functions/date_time_functions.asciidoc | 24 -- .../functions/date_trunc.asciidoc | 13 - .../esql/documentation/functions/e.asciidoc | 16 -- .../functions/ends_with.asciidoc | 21 -- .../documentation/functions/floor.asciidoc | 24 -- .../documentation/functions/greatest.asciidoc | 25 -- .../esql/documentation/functions/in.asciidoc | 11 - .../functions/is_finite.asciidoc | 10 - .../functions/is_infinite.asciidoc | 10 - .../documentation/functions/is_nan.asciidoc | 10 - .../documentation/functions/least.asciidoc | 25 -- .../documentation/functions/left.asciidoc | 20 -- .../documentation/functions/length.asciidoc | 11 - .../documentation/functions/like.asciidoc | 20 -- .../documentation/functions/log10.asciidoc | 23 -- .../documentation/functions/logical.asciidoc | 9 - .../documentation/functions/ltrim.asciidoc | 13 - .../functions/math_functions.asciidoc | 52 ---- .../esql/documentation/functions/max.asciidoc | 13 - .../documentation/functions/median.asciidoc | 22 -- .../median_absolute_deviation.asciidoc | 29 -- .../esql/documentation/functions/min.asciidoc | 13 - .../documentation/functions/mv_avg.asciidoc | 17 -- .../functions/mv_concat.asciidoc | 26 -- .../documentation/functions/mv_count.asciidoc | 16 -- .../functions/mv_dedupe.asciidoc | 15 -- .../functions/mv_functions.asciidoc | 28 -- .../documentation/functions/mv_max.asciidoc | 25 -- .../functions/mv_median.asciidoc | 27 -- .../documentation/functions/mv_min.asciidoc | 25 -- .../documentation/functions/mv_sum.asciidoc | 16 -- .../esql/documentation/functions/now.asciidoc | 9 - .../functions/operators.asciidoc | 36 --- .../functions/percentile.asciidoc | 30 --- .../esql/documentation/functions/pi.asciidoc | 16 -- .../esql/documentation/functions/pow.asciidoc | 96 ------- .../functions/predicates.asciidoc | 23 -- .../documentation/functions/replace.asciidoc | 17 -- .../documentation/functions/right.asciidoc | 20 -- .../documentation/functions/rlike.asciidoc | 15 -- .../documentation/functions/round.asciidoc | 15 -- .../documentation/functions/rtrim.asciidoc | 13 - .../esql/documentation/functions/sin.asciidoc | 20 -- .../documentation/functions/sinh.asciidoc | 20 -- .../documentation/functions/split.asciidoc | 18 -- .../documentation/functions/sqrt.asciidoc | 23 -- .../functions/starts_with.asciidoc | 21 -- .../functions/string_functions.asciidoc | 32 --- .../functions/substring.asciidoc | 38 --- .../esql/documentation/functions/sum.asciidoc | 13 - .../esql/documentation/functions/tan.asciidoc | 20 -- .../documentation/functions/tanh.asciidoc | 20 -- .../esql/documentation/functions/tau.asciidoc | 16 -- .../functions/to_boolean.asciidoc | 25 -- .../functions/to_datetime.asciidoc | 47 ---- .../functions/to_degrees.asciidoc | 19 -- .../functions/to_double.asciidoc | 38 --- .../functions/to_integer.asciidoc | 38 --- .../documentation/functions/to_ip.asciidoc | 28 -- .../documentation/functions/to_long.asciidoc | 36 --- .../functions/to_radians.asciidoc | 19 -- .../functions/to_string.asciidoc | 33 --- .../functions/to_unsigned_long.asciidoc | 38 --- .../functions/to_version.asciidoc | 24 -- .../documentation/functions/trim.asciidoc | 20 -- .../type_conversion_functions.asciidoc | 34 --- .../functions/types/abs.asciidoc | 8 - .../functions/types/acos.asciidoc | 8 - .../functions/types/asin.asciidoc | 8 - .../functions/types/atan.asciidoc | 8 - .../functions/types/atan2.asciidoc | 20 -- .../functions/types/auto_bucket.asciidoc | 5 - .../functions/types/case.asciidoc | 5 - .../functions/types/ceil.asciidoc | 8 - .../functions/types/coalesce.asciidoc | 9 - .../functions/types/concat.asciidoc | 6 - .../functions/types/cos.asciidoc | 8 - .../functions/types/cosh.asciidoc | 8 - .../functions/types/date_extract.asciidoc | 5 - .../functions/types/date_parse.asciidoc | 6 - .../documentation/functions/types/e.asciidoc | 5 - .../functions/types/ends_with.asciidoc | 5 - .../functions/types/floor.asciidoc | 8 - .../functions/types/greatest.asciidoc | 12 - .../functions/types/is_finite.asciidoc | 5 - .../functions/types/is_infinite.asciidoc | 5 - .../functions/types/least.asciidoc | 12 - .../functions/types/left.asciidoc | 5 - .../functions/types/length.asciidoc | 5 - .../functions/types/log10.asciidoc | 8 - .../functions/types/ltrim.asciidoc | 6 - .../functions/types/mv_avg.asciidoc | 8 - .../functions/types/mv_concat.asciidoc | 8 - .../functions/types/mv_count.asciidoc | 10 - .../functions/types/mv_dedupe.asciidoc | 9 - .../functions/types/mv_max.asciidoc | 10 - .../functions/types/mv_median.asciidoc | 8 - .../functions/types/mv_min.asciidoc | 10 - .../functions/types/mv_sum.asciidoc | 5 - .../documentation/functions/types/pi.asciidoc | 5 - .../functions/types/pow.asciidoc | 10 - .../functions/types/replace.asciidoc | 12 - .../functions/types/right.asciidoc | 5 - .../functions/types/round.asciidoc | 5 - .../functions/types/rtrim.asciidoc | 6 - .../functions/types/sin.asciidoc | 8 - .../functions/types/sinh.asciidoc | 8 - .../functions/types/split.asciidoc | 5 - .../functions/types/sqrt.asciidoc | 8 - .../functions/types/starts_with.asciidoc | 5 - .../functions/types/substring.asciidoc | 5 - .../functions/types/tan.asciidoc | 8 - .../functions/types/tanh.asciidoc | 8 - .../functions/types/tau.asciidoc | 5 - .../functions/types/to_ip.asciidoc | 6 - .../functions/types/to_string.asciidoc | 14 - .../functions/types/to_version.asciidoc | 7 - .../functions/types/trim.asciidoc | 6 - .../esql/documentation/index.asciidoc | 71 ----- .../documentation/metadata_fields.asciidoc | 55 ---- .../documentation/multivalued_fields.asciidoc | 240 ----------------- .../processing_commands/dissect.asciidoc | 19 -- .../processing_commands/drop.asciidoc | 18 -- .../processing_commands/enrich.asciidoc | 101 ------- .../processing_commands/eval.asciidoc | 30 --- .../processing_commands/grok.asciidoc | 21 -- .../processing_commands/keep.asciidoc | 35 --- .../processing_commands/limit.asciidoc | 13 - .../processing_commands/mv_expand.asciidoc | 14 - .../processing_commands/rename.asciidoc | 27 -- .../processing_commands/sort.asciidoc | 37 --- .../processing_commands/stats.asciidoc | 45 ---- .../processing_commands/where.asciidoc | 33 --- .../source_commands/from.asciidoc | 37 --- .../source_commands/row.asciidoc | 29 -- .../source_commands/show.asciidoc | 10 - .../documentation/task_management.asciidoc | 35 --- .../language_definition/esql_base_lexer.g4 | 191 -------------- .../esql_base_lexer.tokens | 137 ---------- .../language_definition/esql_base_parser.g4 | 246 ----------------- .../esql_base_parser.tokens | 137 ---------- .../add_required_kb_resource_metadata.test.ts | 3 +- .../content_loaders/esql_loader.test.ts | 125 --------- .../langchain/content_loaders/esql_loader.ts | 97 ------- .../elasticsearch_store.test.ts | 54 +--- .../elasticsearch_store.ts | 9 +- .../get_required_kb_docs_terms_query_dsl.ts | 16 +- .../lib/telemetry/event_based_telemetry.ts | 6 +- .../server/routes/knowledge_base/constants.ts | 3 - .../knowledge_base/entries/find_route.ts | 8 +- .../get_knowledge_base_status.test.ts | 13 +- .../get_knowledge_base_status.ts | 9 +- .../knowledge_base/post_knowledge_base.ts | 4 - .../common/experimental_features.ts | 5 - .../common.ts | 0 .../nl_to_esql_tool.test.ts | 0 .../nl_to_esql_tool.ts | 0 .../esql_language_knowledge_base_tool.test.ts | 135 ---------- .../esql_language_knowledge_base_tool.ts | 80 ------ .../server/assistant/tools/index.test.ts | 2 +- .../server/assistant/tools/index.ts | 7 +- .../security_solution/server/plugin.ts | 2 - 208 files changed, 56 insertions(+), 5626 deletions(-) delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/const.ts delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_commands.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_enrich_data.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_functions.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_functions_operators.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_get_started.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_kibana.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_language.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_limitations.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_query_api.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_rest.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_syntax.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/abs.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/acos.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/aggregation_functions.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/asin.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/atan.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/atan2.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/auto_bucket.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/avg.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/binary.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/case.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ceil.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cidr_match.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/coalesce.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/concat.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/conditional_functions_and_expressions.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cos.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cosh.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/count.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/count_distinct.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_extract.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_format.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_parse.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_time_functions.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_trunc.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/e.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ends_with.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/floor.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/greatest.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/in.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_finite.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_infinite.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_nan.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/least.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/left.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/length.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/like.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/log10.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/logical.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ltrim.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/math_functions.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/max.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/median.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/median_absolute_deviation.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/min.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_avg.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_concat.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_count.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_dedupe.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_functions.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_max.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_median.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_min.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_sum.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/now.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/operators.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/percentile.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/pi.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/pow.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/predicates.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/replace.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/right.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/rlike.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/round.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/rtrim.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sin.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sinh.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/split.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sqrt.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/starts_with.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/string_functions.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/substring.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sum.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tan.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tanh.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tau.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_boolean.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_datetime.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_degrees.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_double.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_integer.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_ip.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_long.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_radians.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_string.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_unsigned_long.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_version.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/trim.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/type_conversion_functions.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/abs.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/acos.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/asin.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/atan.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/atan2.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/auto_bucket.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/case.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ceil.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/coalesce.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/concat.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/cos.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/cosh.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/date_extract.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/date_parse.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/e.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ends_with.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/floor.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/greatest.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/is_finite.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/is_infinite.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/least.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/left.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/length.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/log10.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ltrim.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_avg.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_concat.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_count.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_dedupe.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_max.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_median.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_min.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_sum.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/pi.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/pow.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/replace.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/right.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/round.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/rtrim.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sin.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sinh.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/split.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sqrt.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/starts_with.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/substring.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tan.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tanh.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tau.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_ip.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_string.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_version.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/trim.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/index.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/metadata_fields.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/multivalued_fields.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/dissect.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/drop.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/enrich.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/eval.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/grok.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/keep.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/limit.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/mv_expand.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/rename.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/sort.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/stats.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/where.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/from.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/row.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/show.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/task_management.asciidoc delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.g4 delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.tokens delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_parser.g4 delete mode 100644 x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_parser.tokens delete mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.test.ts delete mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.ts rename x-pack/plugins/security_solution/server/assistant/tools/{esql_language_knowledge_base => esql}/common.ts (100%) rename x-pack/plugins/security_solution/server/assistant/tools/{esql_language_knowledge_base => esql}/nl_to_esql_tool.test.ts (100%) rename x-pack/plugins/security_solution/server/assistant/tools/{esql_language_knowledge_base => esql}/nl_to_esql_tool.ts (100%) delete mode 100644 x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.test.ts delete mode 100644 x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.ts diff --git a/api_docs/kbn_elastic_assistant_common.devdocs.json b/api_docs/kbn_elastic_assistant_common.devdocs.json index d06fdf76fcd6e..e7f944dfbcc10 100644 --- a/api_docs/kbn_elastic_assistant_common.devdocs.json +++ b/api_docs/kbn_elastic_assistant_common.devdocs.json @@ -3443,7 +3443,7 @@ "label": "ReadKnowledgeBaseResponse", "description": [], "signature": [ - "{ elser_exists?: boolean | undefined; esql_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; }" + "{ elser_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", "deprecated": false, @@ -5737,7 +5737,7 @@ "label": "ReadKnowledgeBaseResponse", "description": [], "signature": [ - "Zod.ZodObject<{ elser_exists: Zod.ZodOptional; esql_exists: Zod.ZodOptional; index_exists: Zod.ZodOptional; is_setup_available: Zod.ZodOptional; is_setup_in_progress: Zod.ZodOptional; pipeline_exists: Zod.ZodOptional; security_labs_exists: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { elser_exists?: boolean | undefined; esql_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; }, { elser_exists?: boolean | undefined; esql_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; }>" + "Zod.ZodObject<{ elser_exists: Zod.ZodOptional; index_exists: Zod.ZodOptional; is_setup_available: Zod.ZodOptional; is_setup_in_progress: Zod.ZodOptional; pipeline_exists: Zod.ZodOptional; security_labs_exists: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { elser_exists?: boolean | undefined; esql_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; }, { elser_exists?: boolean | undefined; esql_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_available?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; security_labs_exists?: boolean | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", "deprecated": false, diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index a9bcc310b662d..9a94122c32223 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -420,7 +420,7 @@ "\nExperimental flag needed to enable the link" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"assistantNaturalLanguageESQLTool\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"loggingRequestsEnabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"loggingRequestsEnabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -500,7 +500,7 @@ "\nExperimental flag needed to disable the link. Opposite of experimentalKey" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"assistantNaturalLanguageESQLTool\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"loggingRequestsEnabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"endpointManagementSpaceAwarenessEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewDisabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"loggingRequestsEnabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"responseActionsTelemetryEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | \"dataIngestionHubEnabled\" | \"entityStoreEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -1864,7 +1864,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantNaturalLanguageESQLTool: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -3032,7 +3032,7 @@ "\nThe security solution generic experimental features" ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantNaturalLanguageESQLTool: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", "deprecated": false, @@ -3208,7 +3208,7 @@ "label": "ExperimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantNaturalLanguageESQLTool: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly endpointManagementSpaceAwarenessEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly loggingRequestsEnabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly responseActionsTelemetryEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; readonly dataIngestionHubEnabled: boolean; readonly entityStoreEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3274,7 +3274,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly endpointManagementSpaceAwarenessEnabled: false; readonly securitySolutionNotesEnabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly assistantNaturalLanguageESQLTool: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly loggingRequestsEnabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly responseActionsTelemetryEnabled: false; readonly jamfDataInAnalyzerEnabled: true; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: false; readonly entityStoreEnabled: false; }" + "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly endpointManagementSpaceAwarenessEnabled: false; readonly securitySolutionNotesEnabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly loggingRequestsEnabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly responseActionsTelemetryEnabled: false; readonly jamfDataInAnalyzerEnabled: true; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: false; readonly entityStoreEnabled: false; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts index 4eb41f0c1f136..fd599f5798cdc 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts @@ -76,7 +76,6 @@ export type ReadKnowledgeBaseRequestParamsInput = z.input; export const ReadKnowledgeBaseResponse = z.object({ elser_exists: z.boolean().optional(), - esql_exists: z.boolean().optional(), index_exists: z.boolean().optional(), is_setup_available: z.boolean().optional(), is_setup_in_progress: z.boolean().optional(), diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml index 07d271e860756..a61e98602ab40 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml @@ -68,8 +68,6 @@ paths: properties: elser_exists: type: boolean - esql_exists: - type: boolean index_exists: type: boolean is_setup_available: diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx index aaad50afacd91..80ce3d27d8dcb 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx @@ -32,7 +32,6 @@ jest.mock('@tanstack/react-query', () => ({ const statusResponse = { elser_exists: true, - esql_exists: true, index_exists: true, pipeline_exists: true, }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx index 7f248e1c4c260..ba6317329d350 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx @@ -78,21 +78,3 @@ export const useInvalidateKnowledgeBaseStatus = () => { }); }, [queryClient]); }; - -/** - * Helper for determining if Knowledge Base setup is complete. - * - * Note: Consider moving to API - * - * @param kbStatus ReadKnowledgeBaseResponse - */ -export const isKnowledgeBaseSetup = (kbStatus: ReadKnowledgeBaseResponse | undefined): boolean => { - return ( - (kbStatus?.elser_exists && - kbStatus?.esql_exists && - kbStatus?.security_labs_exists && - kbStatus?.index_exists && - kbStatus?.pipeline_exists) ?? - false - ); -}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx index 0fabba65110b4..4ea376518b5a7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx @@ -10,7 +10,6 @@ import { HttpSetup } from '@kbn/core-http-browser'; import { i18n } from '@kbn/i18n'; import { Replacements } from '@kbn/elastic-assistant-common'; import { useKnowledgeBaseStatus } from '../api/knowledge_base/use_knowledge_base_status'; -import { ESQL_RESOURCE } from '../../knowledge_base/setup_knowledge_base_button'; import { DataStreamApis } from '../use_data_stream_apis'; import { NEW_CHAT } from '../conversations/conversation_sidepanel/translations'; import type { ClientMessage } from '../../assistant_context/types'; @@ -58,12 +57,11 @@ export const useChatSend = ({ const { isLoading, sendMessage, abortStream } = useSendMessage(); const { clearConversation, removeLastMessage } = useConversation(); - const { data: kbStatus } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); + const { data: kbStatus } = useKnowledgeBaseStatus({ http }); const isSetupComplete = kbStatus?.elser_exists && kbStatus?.index_exists && kbStatus?.pipeline_exists && - kbStatus?.esql_exists && kbStatus?.security_labs_exists; // Handles sending latest user prompt to API diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/const.ts b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/const.ts deleted file mode 100644 index 3cfd0cf3b4205..0000000000000 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/const.ts +++ /dev/null @@ -1,9 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -export const ESQL_RESOURCE = 'esql'; -export const KNOWLEDGE_BASE_INDEX_PATTERN_OLD = '.kibana-elastic-ai-assistant-kb'; -export const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-knowledge-base-(SPACE)'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx index 67b48ac9354d7..3d18885902326 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx @@ -69,7 +69,6 @@ jest.mock('../assistant/api/knowledge_base/use_knowledge_base_status', () => ({ return { data: { elser_exists: true, - esql_exists: true, index_exists: true, pipeline_exists: true, }, @@ -83,22 +82,11 @@ describe('Knowledge base settings', () => { beforeEach(() => { jest.clearAllMocks(); }); - it('Shows correct description when esql is installed', () => { - const { getByTestId, queryByTestId } = render( - - - - ); - - expect(getByTestId('esql-installed')).toBeInTheDocument(); - expect(queryByTestId('install-esql')).not.toBeInTheDocument(); - }); it('On enable knowledge base, call setup knowledge base setup', () => { (useKnowledgeBaseStatus as jest.Mock).mockImplementation(() => { return { data: { elser_exists: true, - esql_exists: false, index_exists: false, pipeline_exists: false, is_setup_available: true, @@ -115,14 +103,13 @@ describe('Knowledge base settings', () => { expect(queryByTestId('kb-installed')).not.toBeInTheDocument(); expect(getByTestId('install-kb')).toBeInTheDocument(); fireEvent.click(getByTestId('setupKnowledgeBaseButton')); - expect(mockSetup).toHaveBeenCalledWith('esql'); + expect(mockSetup).toHaveBeenCalled(); }); it('If elser does not exist, do not offer knowledge base', () => { (useKnowledgeBaseStatus as jest.Mock).mockImplementation(() => { return { data: { elser_exists: false, - esql_exists: false, index_exists: false, pipeline_exists: false, }, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx index df254805d9cee..b56abafafd5db 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx @@ -31,7 +31,6 @@ import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_know import { useSetupKnowledgeBase } from '../assistant/api/knowledge_base/use_setup_knowledge_base'; import { SETUP_KNOWLEDGE_BASE_BUTTON_TOOLTIP } from './translations'; -const ESQL_RESOURCE = 'esql'; const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-knowledge-base-(SPACE)'; interface Props { @@ -45,20 +44,14 @@ interface Props { export const KnowledgeBaseSettings: React.FC = React.memo( ({ knowledgeBase, setUpdatedKnowledgeBaseSettings }) => { const { http, toasts } = useAssistantContext(); - const { - data: kbStatus, - isLoading, - isFetching, - } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); + const { data: kbStatus, isLoading, isFetching } = useKnowledgeBaseStatus({ http }); const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http, toasts }); // Resource enabled state const isElserEnabled = kbStatus?.elser_exists ?? false; - const isESQLEnabled = kbStatus?.esql_exists ?? false; const isSecurityLabsEnabled = kbStatus?.security_labs_exists ?? false; const isKnowledgeBaseSetup = (isElserEnabled && - isESQLEnabled && isSecurityLabsEnabled && kbStatus?.index_exists && kbStatus?.pipeline_exists) ?? @@ -72,12 +65,11 @@ export const KnowledgeBaseSettings: React.FC = React.memo( // Calculated health state for EuiHealth component const elserHealth = isElserEnabled ? 'success' : 'subdued'; const knowledgeBaseHealth = isKnowledgeBaseSetup ? 'success' : 'subdued'; - const esqlHealth = isESQLEnabled ? 'success' : 'subdued'; ////////////////////////////////////////////////////////////////////////////////////////// // Main `Knowledge Base` setup button const onSetupKnowledgeBaseButtonClick = useCallback(() => { - setupKB(ESQL_RESOURCE); + setupKB(); }, [setupKB]); const toolTipContent = !isSetupAvailable ? SETUP_KNOWLEDGE_BASE_BUTTON_TOOLTIP : undefined; @@ -119,16 +111,6 @@ export const KnowledgeBaseSettings: React.FC = React.memo( ); }, [isKnowledgeBaseSetup]); - ////////////////////////////////////////////////////////////////////////////////////////// - // ESQL Resource - const esqlDescription = useMemo(() => { - return isESQLEnabled ? ( - {i18n.ESQL_DESCRIPTION_INSTALLED} - ) : ( - {i18n.ESQL_DESCRIPTION} - ); - }, [isESQLEnabled]); - return ( <> @@ -208,20 +190,6 @@ export const KnowledgeBaseSettings: React.FC = React.memo(
    - - - {i18n.ESQL_LABEL} - - {esqlDescription} - - - diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx index 533f3fe35922c..d697fc7120d01 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx @@ -13,8 +13,6 @@ import { useAssistantContext } from '../..'; import { useSetupKnowledgeBase } from '../assistant/api/knowledge_base/use_setup_knowledge_base'; import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_knowledge_base_status'; -export const ESQL_RESOURCE = 'esql'; - interface Props { display?: 'mini'; } @@ -26,7 +24,7 @@ interface Props { export const SetupKnowledgeBaseButton: React.FC = React.memo(({ display }: Props) => { const { http, toasts } = useAssistantContext(); - const { data: kbStatus } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); + const { data: kbStatus } = useKnowledgeBaseStatus({ http }); const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http, toasts }); const isSetupInProgress = kbStatus?.is_setup_in_progress || isSettingUpKB; @@ -34,11 +32,10 @@ export const SetupKnowledgeBaseButton: React.FC = React.memo(({ display } kbStatus?.elser_exists && kbStatus?.index_exists && kbStatus?.pipeline_exists && - kbStatus?.esql_exists && kbStatus?.security_labs_exists; const onInstallKnowledgeBase = useCallback(() => { - setupKB(ESQL_RESOURCE); + setupKB(); }, [setupKB]); if (isSetupComplete) { diff --git a/x-pack/plugins/elastic_assistant/server/__mocks__/docs_from_directory_loader.ts b/x-pack/plugins/elastic_assistant/server/__mocks__/docs_from_directory_loader.ts index 152d8c83987a3..e8cdf4b20dbde 100644 --- a/x-pack/plugins/elastic_assistant/server/__mocks__/docs_from_directory_loader.ts +++ b/x-pack/plugins/elastic_assistant/server/__mocks__/docs_from_directory_loader.ts @@ -8,43 +8,7 @@ import { Document } from 'langchain/document'; /** - * Mock LangChain `Document`s from `knowledge_base/esql/documentation`, loaded from a LangChain `DirectoryLoader` - */ -export const mockEsqlDocsFromDirectoryLoader: Document[] = [ - { - pageContent: - '[[esql-agg-avg]]\n=== `AVG`\nThe average of a numeric field.\n\n[source.merge.styled,esql]\n----\ninclude::{esql-specs}/stats.csv-spec[tag=avg]\n----\n[%header.monospaced.styled,format=dsv,separator=|]\n|===\ninclude::{esql-specs}/stats.csv-spec[tag=avg-result]\n|===\n\nThe result is always a `double` not matter the input type.\n', - metadata: { - source: - '/Users/andrew.goldstein/Projects/forks/andrew-goldstein/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/aggregation_functions/avg.asciidoc', - }, - }, -]; - -/** - * Mock LangChain `Document`s from `knowledge_base/esql/language_definition`, loaded from a LangChain `DirectoryLoader` - */ -export const mockEsqlLanguageDocsFromDirectoryLoader: Document[] = [ - { - pageContent: - "lexer grammar EsqlBaseLexer;\n\nDISSECT : 'dissect' -> pushMode(EXPRESSION);\nDROP : 'drop' -> pushMode(SOURCE_IDENTIFIERS);\nENRICH : 'enrich' -> pushMode(SOURCE_IDENTIFIERS);\nEVAL : 'eval' -> pushMode(EXPRESSION);\nEXPLAIN : 'explain' -> pushMode(EXPLAIN_MODE);\nFROM : 'from' -> pushMode(SOURCE_IDENTIFIERS);\nGROK : 'grok' -> pushMode(EXPRESSION);\nINLINESTATS : 'inlinestats' -> pushMode(EXPRESSION);\nKEEP : 'keep' -> pushMode(SOURCE_IDENTIFIERS);\nLIMIT : 'limit' -> pushMode(EXPRESSION);\nMV_EXPAND : 'mv_expand' -> pushMode(SOURCE_IDENTIFIERS);\nPROJECT : 'project' -> pushMode(SOURCE_IDENTIFIERS);\nRENAME : 'rename' -> pushMode(SOURCE_IDENTIFIERS);\nROW : 'row' -> pushMode(EXPRESSION);\nSHOW : 'show' -> pushMode(EXPRESSION);\nSORT : 'sort' -> pushMode(EXPRESSION);\nSTATS : 'stats' -> pushMode(EXPRESSION);\nWHERE : 'where' -> pushMode(EXPRESSION);\nUNKNOWN_CMD : ~[ \\r\\n\\t[\\]/]+ -> pushMode(EXPRESSION);\n\nLINE_COMMENT\n : '//' ~[\\r\\n]* '\\r'? '\\n'? -> channel(HIDDEN)\n ;\n\nMULTILINE_COMMENT\n : '/*' (MULTILINE_COMMENT|.)*? '*/' -> channel(HIDDEN)\n ;\n\nWS\n : [ \\r\\n\\t]+ -> channel(HIDDEN)\n ;\n\n\nmode EXPLAIN_MODE;\nEXPLAIN_OPENING_BRACKET : '[' -> type(OPENING_BRACKET), pushMode(DEFAULT_MODE);\nEXPLAIN_PIPE : '|' -> type(PIPE), popMode;\nEXPLAIN_WS : WS -> channel(HIDDEN);\nEXPLAIN_LINE_COMMENT : LINE_COMMENT -> channel(HIDDEN);\nEXPLAIN_MULTILINE_COMMENT : MULTILINE_COMMENT -> channel(HIDDEN);\n\nmode EXPRESSION;\n\nPIPE : '|' -> popMode;\n\nfragment DIGIT\n : [0-9]\n ;\n\nfragment LETTER\n : [A-Za-z]\n ;\n\nfragment ESCAPE_SEQUENCE\n : '\\\\' [tnr\"\\\\]\n ;\n\nfragment UNESCAPED_CHARS\n : ~[\\r\\n\"\\\\]\n ;\n\nfragment EXPONENT\n : [Ee] [+-]? DIGIT+\n ;\n\nSTRING\n : '\"' (ESCAPE_SEQUENCE | UNESCAPED_CHARS)* '\"'\n | '\"\"\"' (~[\\r\\n])*? '\"\"\"' '\"'? '\"'?\n ;\n\nINTEGER_LITERAL\n : DIGIT+\n ;\n\nDECIMAL_LITERAL\n : DIGIT+ DOT DIGIT*\n | DOT DIGIT+\n | DIGIT+ (DOT DIGIT*)? EXPONENT\n | DOT DIGIT+ EXPONENT\n ;\n\nBY : 'by';\n\nAND : 'and';\nASC : 'asc';\nASSIGN : '=';\nCOMMA : ',';\nDESC : 'desc';\nDOT : '.';\nFALSE : 'false';\nFIRST : 'first';\nLAST : 'last';\nLP : '(';\nIN: 'in';\nIS: 'is';\nLIKE: 'like';\nNOT : 'not';\nNULL : 'null';\nNULLS : 'nulls';\nOR : 'or';\nPARAM: '?';\nRLIKE: 'rlike';\nRP : ')';\nTRUE : 'true';\nINFO : 'info';\nFUNCTIONS : 'functions';\n\nEQ : '==';\nNEQ : '!=';\nLT : '<';\nLTE : '<=';\nGT : '>';\nGTE : '>=';\n\nPLUS : '+';\nMINUS : '-';\nASTERISK : '*';\nSLASH : '/';\nPERCENT : '%';\n\n// Brackets are funny. We can happen upon a CLOSING_BRACKET in two ways - one\n// way is to start in an explain command which then shifts us to expression\n// mode. Thus, the two popModes on CLOSING_BRACKET. The other way could as\n// the start of a multivalued field constant. To line up with the double pop\n// the explain mode needs, we double push when we see that.\nOPENING_BRACKET : '[' -> pushMode(EXPRESSION), pushMode(EXPRESSION);\nCLOSING_BRACKET : ']' -> popMode, popMode;\n\n\nUNQUOTED_IDENTIFIER\n : LETTER (LETTER | DIGIT | '_')*\n // only allow @ at beginning of identifier to keep the option to allow @ as infix operator in the future\n // also, single `_` and `@` characters are not valid identifiers\n | ('_' | '@') (LETTER | DIGIT | '_')+\n ;\n\nQUOTED_IDENTIFIER\n : '`' ( ~'`' | '``' )* '`'\n ;\n\nEXPR_LINE_COMMENT\n : LINE_COMMENT -> channel(HIDDEN)\n ;\n\nEXPR_MULTILINE_COMMENT\n : MULTILINE_COMMENT -> channel(HIDDEN)\n ;\n\nEXPR_WS\n : WS -> channel(HIDDEN)\n ;\n\n\n\nmode SOURCE_IDENTIFIERS;\n\nSRC_PIPE : '|' -> type(PIPE), popMode;\nSRC_OPENING_BRACKET : '[' -> type(OPENING_BRACKET), pushMode(SOURCE_IDENTIFIERS), pushMode(SOURCE_IDENTIFIERS);\nSRC_CLOSING_BRACKET : ']' -> popMode, popMode, type(CLOSING_BRACKET);\nSRC_COMMA : ',' -> type(COMMA);\nSRC_ASSIGN : '=' -> type(ASSIGN);\nAS : 'as';\nMETADATA: 'metadata';\nON : 'on';\nWITH : 'with';\n\nSRC_UNQUOTED_IDENTIFIER\n : SRC_UNQUOTED_IDENTIFIER_PART+\n ;\n\nfragment SRC_UNQUOTED_IDENTIFIER_PART\n : ~[=`|,[\\]/ \\t\\r\\n]+\n | '/' ~[*/] // allow single / but not followed by another / or * which would start a comment\n ;\n\nSRC_QUOTED_IDENTIFIER\n : QUOTED_IDENTIFIER\n ;\n\nSRC_LINE_COMMENT\n : LINE_COMMENT -> channel(HIDDEN)\n ;\n\nSRC_MULTILINE_COMMENT\n : MULTILINE_COMMENT -> channel(HIDDEN)\n ;\n\nSRC_WS\n : WS -> channel(HIDDEN)\n ;\n", - metadata: { - source: - '/Users/andrew.goldstein/Projects/forks/andrew-goldstein/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.g4', - }, - }, - { - pageContent: - "DISSECT=1\nDROP=2\nENRICH=3\nEVAL=4\nEXPLAIN=5\nFROM=6\nGROK=7\nINLINESTATS=8\nKEEP=9\nLIMIT=10\nMV_EXPAND=11\nPROJECT=12\nRENAME=13\nROW=14\nSHOW=15\nSORT=16\nSTATS=17\nWHERE=18\nUNKNOWN_CMD=19\nLINE_COMMENT=20\nMULTILINE_COMMENT=21\nWS=22\nEXPLAIN_WS=23\nEXPLAIN_LINE_COMMENT=24\nEXPLAIN_MULTILINE_COMMENT=25\nPIPE=26\nSTRING=27\nINTEGER_LITERAL=28\nDECIMAL_LITERAL=29\nBY=30\nAND=31\nASC=32\nASSIGN=33\nCOMMA=34\nDESC=35\nDOT=36\nFALSE=37\nFIRST=38\nLAST=39\nLP=40\nIN=41\nIS=42\nLIKE=43\nNOT=44\nNULL=45\nNULLS=46\nOR=47\nPARAM=48\nRLIKE=49\nRP=50\nTRUE=51\nINFO=52\nFUNCTIONS=53\nEQ=54\nNEQ=55\nLT=56\nLTE=57\nGT=58\nGTE=59\nPLUS=60\nMINUS=61\nASTERISK=62\nSLASH=63\nPERCENT=64\nOPENING_BRACKET=65\nCLOSING_BRACKET=66\nUNQUOTED_IDENTIFIER=67\nQUOTED_IDENTIFIER=68\nEXPR_LINE_COMMENT=69\nEXPR_MULTILINE_COMMENT=70\nEXPR_WS=71\nAS=72\nMETADATA=73\nON=74\nWITH=75\nSRC_UNQUOTED_IDENTIFIER=76\nSRC_QUOTED_IDENTIFIER=77\nSRC_LINE_COMMENT=78\nSRC_MULTILINE_COMMENT=79\nSRC_WS=80\nEXPLAIN_PIPE=81\n'dissect'=1\n'drop'=2\n'enrich'=3\n'eval'=4\n'explain'=5\n'from'=6\n'grok'=7\n'inlinestats'=8\n'keep'=9\n'limit'=10\n'mv_expand'=11\n'project'=12\n'rename'=13\n'row'=14\n'show'=15\n'sort'=16\n'stats'=17\n'where'=18\n'by'=30\n'and'=31\n'asc'=32\n'desc'=35\n'.'=36\n'false'=37\n'first'=38\n'last'=39\n'('=40\n'in'=41\n'is'=42\n'like'=43\n'not'=44\n'null'=45\n'nulls'=46\n'or'=47\n'?'=48\n'rlike'=49\n')'=50\n'true'=51\n'info'=52\n'functions'=53\n'=='=54\n'!='=55\n'<'=56\n'<='=57\n'>'=58\n'>='=59\n'+'=60\n'-'=61\n'*'=62\n'/'=63\n'%'=64\n']'=66\n'as'=72\n'metadata'=73\n'on'=74\n'with'=75\n", - metadata: { - source: - '/Users/andrew.goldstein/Projects/forks/andrew-goldstein/kibana/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.tokens', - }, - }, -]; - -/** - * Mock LangChain `Document`s from `knowledge_base/esql/example_queries`, loaded from a LangChain `DirectoryLoader` + * Mock LangChain `Document`s loaded from a LangChain `DirectoryLoader` */ export const mockExampleQueryDocsFromDirectoryLoader: Document[] = [ { diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts index 7f665fa7f9a16..a81e18630138e 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts @@ -25,7 +25,6 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWith import { StructuredTool } from '@langchain/core/tools'; import { ElasticsearchClient } from '@kbn/core/server'; import { AIAssistantDataClient, AIAssistantDataClientParams } from '..'; -import { loadESQL } from '../../lib/langchain/content_loaders/esql_loader'; import { AssistantToolParams, GetElser } from '../../types'; import { createKnowledgeBaseEntry, @@ -200,17 +199,14 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { * * @param options * @param options.soClient SavedObjectsClientContract for installing ELSER so that ML SO's are in sync - * @param options.installEsqlDocs Whether to install ESQL documents as part of setup (e.g. not needed in test env) * * @returns Promise */ public setupKnowledgeBase = async ({ soClient, - installEsqlDocs = true, installSecurityLabsDocs = true, }: { soClient: SavedObjectsClientContract; - installEsqlDocs?: boolean; installSecurityLabsDocs?: boolean; }): Promise => { if (this.options.getIsKBSetupInProgress()) { @@ -254,15 +250,6 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { } this.options.logger.debug(`Checking if Knowledge Base docs have been loaded...`); - if (installEsqlDocs) { - const kbDocsLoaded = await this.isESQLDocsLoaded(); - if (!kbDocsLoaded) { - this.options.logger.debug(`Loading KB docs...`); - await loadESQL(this, this.options.logger); - } else { - this.options.logger.debug(`Knowledge Base docs already loaded!`); - } - } if (installSecurityLabsDocs) { const labsDocsLoaded = await this.isSecurityLabsDocsLoaded(); diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_commands.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_commands.asciidoc deleted file mode 100644 index 8b0e99344add1..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_commands.asciidoc +++ /dev/null @@ -1,63 +0,0 @@ -[[esql-commands]] -=== {esql} commands - -++++ -Commands -++++ - -// tag::source_commands[] -==== Source commands - -An {esql} source command produces a table, typically with data from {es}. An {esql} query must start with a source command. - -image::images/esql/source-command.svg[A source command producing a table from {es},align="center"] - -{esql} supports these source commands: - -* <> -* <> -* <> - -// end::source_command[] - -// tag::proc_commands[] -==== Processing commands - -{esql} processing commands change an input table by adding, removing, or changing -rows and columns. - -image::images/esql/processing-command.svg[A processing command changing an input table,align="center"] - -{esql} supports these processing commands: - -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> - -// end::proc_command[] - -include::source-commands/from.asciidoc[] -include::source-commands/row.asciidoc[] -include::source-commands/show.asciidoc[] - -include::processing-commands/dissect.asciidoc[] -include::processing-commands/drop.asciidoc[] -include::processing-commands/enrich.asciidoc[] -include::processing-commands/eval.asciidoc[] -include::processing-commands/grok.asciidoc[] -include::processing-commands/keep.asciidoc[] -include::processing-commands/limit.asciidoc[] -include::processing-commands/mv_expand.asciidoc[] -include::processing-commands/rename.asciidoc[] -include::processing-commands/sort.asciidoc[] -include::processing-commands/stats.asciidoc[] -include::processing-commands/where.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_enrich_data.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_enrich_data.asciidoc deleted file mode 100644 index 9708728e6b305..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_enrich_data.asciidoc +++ /dev/null @@ -1,126 +0,0 @@ -[[esql-enrich-data]] -=== Enrich data - -++++ -Enrich data -++++ - -You can use {esql}'s <> processing command to enrich a table with -data from indices in {es}. - -For example, you can use `ENRICH` to: - -* Identify web services or vendors based on known IP addresses -* Add product information to retail orders based on product IDs -* Supplement contact information based on an email address - -[[esql-how-enrich-works]] -==== How the `ENRICH` command works - -The `ENRICH` command adds new columns to a table, with data from {es} indices. -It requires a few special components: - -image::images/esql/esql-enrich.png[align="center"] - -[[esql-enrich-policy]] -Enrich policy:: -+ --- -A set of configuration options used to add the right enrich data to the input -table. - -An enrich policy contains: - -include::../ingest/enrich.asciidoc[tag=enrich-policy-fields] - -After <>, it must be -<> before it can be used. Executing an -enrich policy uses data from the policy's source indices to create a streamlined -system index called the _enrich index_. The `ENRICH` command uses this index to -match and enrich an input table. --- - -[[esql-source-index]] -Source index:: -An index which stores enrich data that the `ENRICH` command can add to input -tables. You can create and manage these indices just like a regular {es} index. -You can use multiple source indices in an enrich policy. You also can use the -same source index in multiple enrich policies. - -[[esql-enrich-index]] -Enrich index:: -+ --- -A special system index tied to a specific enrich policy. - -Directly matching rows from input tables to documents in source indices could be -slow and resource intensive. To speed things up, the `ENRICH` command uses an -enrich index. - -include::../ingest/enrich.asciidoc[tag=enrich-index] --- - -[[esql-set-up-enrich-policy]] -==== Set up an enrich policy - -To start using `ENRICH`, follow these steps: - -. Check the <>. -. <>. -. <>. -. <>. -. <> - -Once you have enrich policies set up, you can <> and <>. - -[IMPORTANT] -==== -The `ENRICH` command performs several operations and may impact the speed of -your query. -==== - -[[esql-enrich-prereqs]] -==== Prerequisites - -include::{es-repo-dir}/ingest/apis/enrich/put-enrich-policy.asciidoc[tag=enrich-policy-api-prereqs] - -[[esql-create-enrich-source-index]] -==== Add enrich data - -include::../ingest/enrich.asciidoc[tag=create-enrich-source-index] - -[[esql-create-enrich-policy]] -==== Create an enrich policy - -include::../ingest/enrich.asciidoc[tag=create-enrich-policy] - -[[esql-execute-enrich-policy]] -==== Execute the enrich policy - -include::../ingest/enrich.asciidoc[tag=execute-enrich-policy1] - -image::images/esql/esql-enrich-policy.png[align="center"] - -include::../ingest/enrich.asciidoc[tag=execute-enrich-policy2] - -[[esql-use-enrich]] -==== Use the enrich policy - -After the policy has been executed, you can use the <> to enrich your data. - -image::images/esql/esql-enrich-command.png[align="center",width=50%] - -include::processing-commands/enrich.asciidoc[tag=examples] - -[[esql-update-enrich-data]] -==== Update an enrich index - -include::{es-repo-dir}/ingest/apis/enrich/execute-enrich-policy.asciidoc[tag=update-enrich-index] - -[[esql-update-enrich-policies]] -==== Update an enrich policy - -include::../ingest/enrich.asciidoc[tag=update-enrich-policy] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_functions.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_functions.asciidoc deleted file mode 100644 index b921719fc097b..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_functions.asciidoc +++ /dev/null @@ -1,140 +0,0 @@ -[[esql-functions]] -== {esql} functions - -++++ -Functions -++++ - -<>, <> and <> support -these functions: - -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> - -include::functions/abs.asciidoc[] -include::functions/acos.asciidoc[] -include::functions/asin.asciidoc[] -include::functions/atan.asciidoc[] -include::functions/atan2.asciidoc[] -include::functions/auto_bucket.asciidoc[] -include::functions/case.asciidoc[] -include::functions/ceil.asciidoc[] -include::functions/cidr_match.asciidoc[] -include::functions/coalesce.asciidoc[] -include::functions/concat.asciidoc[] -include::functions/cos.asciidoc[] -include::functions/cosh.asciidoc[] -include::functions/date_extract.asciidoc[] -include::functions/date_format.asciidoc[] -include::functions/date_parse.asciidoc[] -include::functions/date_trunc.asciidoc[] -include::functions/e.asciidoc[] -include::functions/ends_with.asciidoc[] -include::functions/floor.asciidoc[] -include::functions/greatest.asciidoc[] -include::functions/is_finite.asciidoc[] -include::functions/is_infinite.asciidoc[] -include::functions/is_nan.asciidoc[] -include::functions/least.asciidoc[] -include::functions/left.asciidoc[] -include::functions/length.asciidoc[] -include::functions/log10.asciidoc[] -include::functions/ltrim.asciidoc[] -include::functions/mv_avg.asciidoc[] -include::functions/mv_concat.asciidoc[] -include::functions/mv_count.asciidoc[] -include::functions/mv_dedupe.asciidoc[] -include::functions/mv_max.asciidoc[] -include::functions/mv_median.asciidoc[] -include::functions/mv_min.asciidoc[] -include::functions/mv_sum.asciidoc[] -include::functions/now.asciidoc[] -include::functions/pi.asciidoc[] -include::functions/pow.asciidoc[] -include::functions/replace.asciidoc[] -include::functions/right.asciidoc[] -include::functions/round.asciidoc[] -include::functions/rtrim.asciidoc[] -include::functions/sin.asciidoc[] -include::functions/sinh.asciidoc[] -include::functions/split.asciidoc[] -include::functions/sqrt.asciidoc[] -include::functions/starts_with.asciidoc[] -include::functions/substring.asciidoc[] -include::functions/tan.asciidoc[] -include::functions/tanh.asciidoc[] -include::functions/tau.asciidoc[] -include::functions/to_boolean.asciidoc[] -include::functions/to_datetime.asciidoc[] -include::functions/to_degrees.asciidoc[] -include::functions/to_double.asciidoc[] -include::functions/to_integer.asciidoc[] -include::functions/to_ip.asciidoc[] -include::functions/to_long.asciidoc[] -include::functions/to_radians.asciidoc[] -include::functions/to_string.asciidoc[] -include::functions/to_unsigned_long.asciidoc[] -include::functions/to_version.asciidoc[] -include::functions/trim.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_functions_operators.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_functions_operators.asciidoc deleted file mode 100644 index 375bb4ee9dd00..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_functions_operators.asciidoc +++ /dev/null @@ -1,43 +0,0 @@ -[[esql-functions-operators]] -=== {esql} functions and operators - -++++ -Functions and operators -++++ - -{esql} provides a comprehensive set of functions and operators for working with data. -The functions are divided into the following categories: - -[[esql-functions]] -<>:: -include::functions/aggregation-functions.asciidoc[tag=agg_list] - -<>:: -include::functions/math-functions.asciidoc[tag=math_list] - -<>:: -include::functions/string-functions.asciidoc[tag=string_list] - -<>:: -include::functions/date-time-functions.asciidoc[tag=date_list] - -<>:: -include::functions/type-conversion-functions.asciidoc[tag=type_list] - -<>:: -include::functions/conditional-functions-and-expressions.asciidoc[tag=cond_list] - -<>:: -include::functions/mv-functions.asciidoc[tag=mv_list] - -<>:: -include::functions/operators.asciidoc[tag=op_list] - -include::functions/aggregation-functions.asciidoc[] -include::functions/math-functions.asciidoc[] -include::functions/string-functions.asciidoc[] -include::functions/date-time-functions.asciidoc[] -include::functions/type-conversion-functions.asciidoc[] -include::functions/conditional-functions-and-expressions.asciidoc[] -include::functions/mv-functions.asciidoc[] -include::functions/operators.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_get_started.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_get_started.asciidoc deleted file mode 100644 index 1f3cdf85c173e..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_get_started.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[[esql-getting-started]] -== Getting started with {esql} - -++++ -Getting started -++++ - -coming::[8.11] \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_kibana.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_kibana.asciidoc deleted file mode 100644 index 534cba22ed1a1..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_kibana.asciidoc +++ /dev/null @@ -1,15 +0,0 @@ -[[esql-kibana]] -== Using {esql} in {kib} - -++++ -Kibana -++++ - - -Use {esql} in Discover to explore a data set. From the data view dropdown, -select *Try {esql}* to get started. - -NOTE: {esql} queries in Discover and Lens are subject to the time range selected -with the time filter. - - diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_language.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_language.asciidoc deleted file mode 100644 index 2becd04cec948..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_language.asciidoc +++ /dev/null @@ -1,23 +0,0 @@ -[[esql-language]] -== Working with the {esql} language - -++++ -Working with the {esql} language -++++ - -Detailed information about the {esql} language: - -* <> -* <> -* <> -* <> -* <> -* <> - -include::esql-syntax.asciidoc[] -include::esql-commands.asciidoc[] -include::esql-functions-operators.asciidoc[] -include::multivalued-fields.asciidoc[] -include::metadata-fields.asciidoc[] -include::esql-enrich-data.asciidoc[] - diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_limitations.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_limitations.asciidoc deleted file mode 100644 index f39ff73744276..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_limitations.asciidoc +++ /dev/null @@ -1,32 +0,0 @@ -[[esql-limitations]] -== {esql} limitations - -++++ -Limitations -++++ - -[discrete] -[[esql-supported-types]] -=== Supported types - -* {esql} currently supports the following <>: - -** `alias` -** `boolean` -** `date` -** `double` (`float`, `half_float`, `scaled_float` are represented as `double`) -** `ip` -** `keyword` family including `keyword`, `constant_keyword`, and `wildcard` -** `int` (`short` and `byte` are represented as `int`) -** `long` -** `null` -** `text` -** `unsigned_long` -** `version` - -[discrete] -[[esql-max-rows]] -=== 10,000 row maximum - -A single query will not return more than 10,000 rows, regardless of the -`LIMIT` command's value. \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_query_api.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_query_api.asciidoc deleted file mode 100644 index 437871d31a88f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_query_api.asciidoc +++ /dev/null @@ -1,97 +0,0 @@ -[[esql-query-api]] -== {esql} query API -++++ -{esql} query API -++++ - -Returns search results for an <> query. - -[source,console] ----- -POST /_query -{ - "query": """ - FROM library - | EVAL year = DATE_TRUNC(1 YEARS, release_date) - | STATS MAX(page_count) BY year - | SORT year - | LIMIT 5 - """ -} ----- -// TEST[setup:library] - -[discrete] -[[esql-query-api-request]] -=== {api-request-title} - -`POST _query` - -[discrete] -[[esql-query-api-prereqs]] -=== {api-prereq-title} - -* If the {es} {security-features} are enabled, you must have the `read` -<> for the data stream, index, -or alias you search. - -[discrete] -[[esql-query-api-query-params]] -=== {api-query-parms-title} - -`delimiter`:: -(Optional, string) Separator for CSV results. Defaults to `,`. The API only -supports this parameter for CSV responses. - -`format`:: -(Optional, string) Format for the response. For valid values, refer to -<>. -+ -You can also specify a format using the `Accept` HTTP header. If you specify -both this parameter and the `Accept` HTTP header, this parameter takes -precedence. - -[discrete] -[role="child_attributes"] -[[esql-query-api-request-body]] -=== {api-request-body-title} - -`columnar`:: -(Optional, Boolean) If `true`, returns results in a columnar format. Defaults to -`false`. The API only supports this parameter for CBOR, JSON, SMILE, and YAML -responses. See <>. - -`params`:: -(Optional, array) Values for parameters in the `query`. For syntax, refer to -<>. - -`query`:: -(Required, object) {esql} query to run. For syntax, refer to <>. - -[[esql-search-api-time-zone]] -`time_zone`:: -(Optional, string) ISO-8601 time zone ID for the search. Several {esql} -date/time functions use this time zone. Defaults to `Z` (UTC). - -[discrete] -[role="child_attributes"] -[[esql-query-api-response-body]] -=== {api-response-body-title} - -`columns`:: -(array of objects) -Column headings for the search results. Each object is a column. -+ -.Properties of `columns` objects -[%collapsible%open] -==== -`name`:: -(string) Name of the column. - -`type`:: -(string) Data type for the column. -==== - -`rows`:: -(array of arrays) -Values for the search results. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_rest.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_rest.asciidoc deleted file mode 100644 index 55c9946ad08b4..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_rest.asciidoc +++ /dev/null @@ -1,249 +0,0 @@ -[[esql-rest]] -== {esql} REST API - -++++ -REST API -++++ - -[discrete] -[[esql-rest-overview]] -=== Overview - -The <> accepts an {esql} query string in the -`query` parameter, runs it, and returns the results. For example: - -[source,console] ----- -POST /_query?format=txt -{ - "query": "FROM library | KEEP author, name, page_count, release_date | SORT page_count DESC | LIMIT 5" -} ----- -// TEST[setup:library] - -Which returns: - -[source,text] ----- - author | name | page_count | release_date ------------------+--------------------+---------------+------------------------ -Peter F. Hamilton|Pandora's Star |768 |2004-03-02T00:00:00.000Z -Vernor Vinge |A Fire Upon the Deep|613 |1992-06-01T00:00:00.000Z -Frank Herbert |Dune |604 |1965-06-01T00:00:00.000Z -Alastair Reynolds|Revelation Space |585 |2000-03-15T00:00:00.000Z -James S.A. Corey |Leviathan Wakes |561 |2011-06-02T00:00:00.000Z ----- -// TESTRESPONSE[s/\|/\\|/ s/\+/\\+/] -// TESTRESPONSE[non_json] - -[discrete] -[[esql-kibana-console]] -=== Kibana Console - -If you are using {kibana-ref}/console-kibana.html[Kibana Console] (which is -highly recommended), take advantage of the triple quotes `"""` when creating the -query. This not only automatically escapes double quotes (`"`) inside the query -string but also supports multi-line requests: - -// tag::esql-query-api[] -[source,console] ----- -POST /_query?format=txt -{ - "query": """ - FROM library - | KEEP author, name, page_count, release_date - | SORT page_count DESC - | LIMIT 5 - """ -} ----- -// TEST[setup:library] - -[discrete] -[[esql-rest-format]] -=== Response formats - -{esql} can return the data in the following human readable and binary formats. -You can set the format by specifying the `format` parameter in the URL or by -setting the `Accept` or `Content-Type` HTTP header. - -NOTE: The URL parameter takes precedence over the HTTP headers. If neither is -specified then the response is returned in the same format as the request. - -[cols="m,4m,8"] - -|=== -s|`format` -s|HTTP header -s|Description - -3+h| Human readable - -|csv -|text/csv -|{wikipedia}/Comma-separated_values[Comma-separated values] - -|json -|application/json -|https://www.json.org/[JSON] (JavaScript Object Notation) human-readable format - -|tsv -|text/tab-separated-values -|{wikipedia}/Tab-separated_values[Tab-separated values] - -|txt -|text/plain -|CLI-like representation - -|yaml -|application/yaml -|{wikipedia}/YAML[YAML] (YAML Ain't Markup Language) human-readable format - -3+h| Binary - -|cbor -|application/cbor -|https://cbor.io/[Concise Binary Object Representation] - -|smile -|application/smile -|{wikipedia}/Smile_(data_interchange_format)[Smile] binary data format similar -to CBOR - -|=== - -The `csv` format accepts a formatting URL query attribute, `delimiter`, which -indicates which character should be used to separate the CSV values. It defaults -to comma (`,`) and cannot take any of the following values: double quote (`"`), -carriage-return (`\r`) and new-line (`\n`). The tab (`\t`) can also not be used. -Use the `tsv` format instead. - -[discrete] -[[esql-rest-filtering]] -=== Filtering using {es} Query DSL - -Specify a Query DSL query in the `filter` parameter to filter the set of -documents that an {esql} query runs on. - -[source,console] ----- -POST /_query?format=txt -{ - "query": """ - FROM library - | KEEP author, name, page_count, release_date - | SORT page_count DESC - | LIMIT 5 - """, - "filter": { - "range": { - "page_count": { - "gte": 100, - "lte": 200 - } - } - } -} ----- -// TEST[setup:library] - -Which returns: - -[source,text] --------------------------------------------------- - author | name | page_count | release_date ----------------+------------------------------------+---------------+------------------------ -Douglas Adams |The Hitchhiker's Guide to the Galaxy|180 |1979-10-12T00:00:00.000Z --------------------------------------------------- -// TESTRESPONSE[s/\|/\\|/ s/\+/\\+/] -// TESTRESPONSE[non_json] - -[discrete] -[[esql-rest-columnar]] -=== Columnar results - -By default, {esql} returns results as rows. For example, `FROM` returns each -individual document as one row. For the `json`, `yaml`, `cbor` and `smile` -<>, {esql} can return the results in a columnar -fashion where one row represents all the values of a certain column in the -results. - -[source,console] ----- -POST /_query?format=json -{ - "query": """ - FROM library - | KEEP author, name, page_count, release_date - | SORT page_count DESC - | LIMIT 5 - """, - "columnar": true -} ----- -// TEST[setup:library] - -Which returns: - -[source,console-result] ----- -{ - "columns": [ - {"name": "author", "type": "text"}, - {"name": "name", "type": "text"}, - {"name": "page_count", "type": "integer"}, - {"name": "release_date", "type": "date"} - ], - "values": [ - ["Peter F. Hamilton", "Vernor Vinge", "Frank Herbert", "Alastair Reynolds", "James S.A. Corey"], - ["Pandora's Star", "A Fire Upon the Deep", "Dune", "Revelation Space", "Leviathan Wakes"], - [768, 613, 604, 585, 561], - ["2004-03-02T00:00:00.000Z", "1992-06-01T00:00:00.000Z", "1965-06-01T00:00:00.000Z", "2000-03-15T00:00:00.000Z", "2011-06-02T00:00:00.000Z"] - ] -} ----- - -[discrete] -[[esql-rest-params]] -=== Passing parameters to a query - -Values, for example for a condition, can be passed to a query "inline", by -integrating the value in the query string itself: - -[source,console] ----- -POST /_query -{ - "query": """ - FROM library - | EVAL year = DATE_EXTRACT("year", release_date) - | WHERE page_count > 300 AND author == "Frank Herbert" - | STATS count = COUNT(*) by year - | WHERE count > 0 - | LIMIT 5 - """ -} ----- -// TEST[setup:library] - -To avoid any attempts of hacking or code injection, extract the values in a -separate list of parameters. Use question mark placeholders (`?`) in the query -string for each of the parameters: - -[source,console] ----- -POST /_query -{ - "query": """ - FROM library - | EVAL year = DATE_EXTRACT("year", release_date) - | WHERE page_count > ? AND author == ? - | STATS count = COUNT(*) by year - | WHERE count > ? - | LIMIT 5 - """, - "params": [300, "Frank Herbert", 0] -} ----- -// TEST[setup:library] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_syntax.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_syntax.asciidoc deleted file mode 100644 index 725b1d3ff1e03..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/esql_syntax.asciidoc +++ /dev/null @@ -1,90 +0,0 @@ -[[esql-syntax]] -=== {esql} syntax reference - -++++ -Syntax reference -++++ - -[discrete] -[[esql-basic-syntax]] -=== Basic syntax - -An {esql} query is composed of a <> followed -by an optional series of <>, -separated by a pipe character: `|`. For example: - -[source,esql] ----- -source-command -| processing-command1 -| processing-command2 ----- - -The result of a query is the table produced by the final processing command. - -For an overview of all supported commands, functions, and operators, refer to <> and <>. - -[NOTE] -==== -For readability, this documentation puts each processing command on a new -line. However, you can write an {esql} query as a single line. The following -query is identical to the previous one: - -[source,esql] ----- -source-command | processing-command1 | processing-command2 ----- -==== - -[discrete] -[[esql-comments]] -==== Comments -{esql} uses C++ style comments: - -* double slash `//` for single line comments -* `/*` and `*/` for block comments - -[source,esql] ----- -// Query the employees index -FROM employees -| WHERE height > 2 ----- - -[source,esql] ----- -FROM /* Query the employees index */ employees -| WHERE height > 2 ----- - -[source,esql] ----- -FROM employees -/* Query the - * employees - * index */ -| WHERE height > 2 ----- - -[discrete] -[[esql-timespan-literals]] -==== Timespan literals - -Datetime intervals and timespans can be expressed using timespan literals. -Timespan literals are a combination of a number and a qualifier. These -qualifiers are supported: - -* `millisecond`/`milliseconds` -* `second`/`seconds` -* `minute`/`minutes` -* `hour`/`hours` -* `day`/`days` -* `week`/`weeks` -* `month`/`months` -* `year`/`years` - -Timespan literals are not whitespace sensitive. These expressions are all valid: - -* `1day` -* `1 day` -* `1 day` diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/abs.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/abs.asciidoc deleted file mode 100644 index 3adb7dff07043..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/abs.asciidoc +++ /dev/null @@ -1,18 +0,0 @@ -[discrete] -[[esql-abs]] -=== `ABS` -[.text-center] -image::esql/functions/signature/abs.svg[Embedded,opts=inline] - -Returns the absolute value. - -[source,esql] ----- -FROM employees -| KEEP first_name, last_name, height -| EVAL abs_height = ABS(0.0 - height) ----- - -Supported types: - -include::types/abs.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/acos.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/acos.asciidoc deleted file mode 100644 index e4d04bd169c78..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/acos.asciidoc +++ /dev/null @@ -1,33 +0,0 @@ -[discrete] -[[esql-acos]] -=== `ACOS` - -*Syntax* - -[.text-center] -image::esql/functions/signature/acos.svg[Embedded,opts=inline] - -*Parameters* - -`n`:: -Numeric expression. If `null`, the function returns `null`. - -*Description* - -Returns the {wikipedia}/Inverse_trigonometric_functions[arccosine] of `n` as an -angle, expressed in radians. - -*Supported types* - -include::types/acos.asciidoc[] - -*Example* - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=acos] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=acos-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/aggregation_functions.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/aggregation_functions.asciidoc deleted file mode 100644 index bd501ea49f158..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/aggregation_functions.asciidoc +++ /dev/null @@ -1,30 +0,0 @@ -[[esql-agg-functions]] -==== {esql} aggregate functions - -++++ -Aggregate functions -++++ - -The <> function supports these aggregate functions: - -// tag::agg_list[] -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -// end::agg_list[] - -include::avg.asciidoc[] -include::count.asciidoc[] -include::count-distinct.asciidoc[] -include::max.asciidoc[] -include::median.asciidoc[] -include::median-absolute-deviation.asciidoc[] -include::min.asciidoc[] -include::percentile.asciidoc[] -include::sum.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/asin.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/asin.asciidoc deleted file mode 100644 index f03b5276b7dd6..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/asin.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-asin]] -=== `ASIN` -[.text-center] -image::esql/functions/signature/asin.svg[Embedded,opts=inline] - -Inverse https://en.wikipedia.org/wiki/Inverse_trigonometric_functions[sine] trigonometric function. - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=asin] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=asin-result] -|=== - -Supported types: - -include::types/asin.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/atan.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/atan.asciidoc deleted file mode 100644 index 3813e096aeba1..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/atan.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-atan]] -=== `ATAN` -[.text-center] -image::esql/functions/signature/atan.svg[Embedded,opts=inline] - -Inverse https://en.wikipedia.org/wiki/Inverse_trigonometric_functions[tangent] trigonometric function. - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=atan] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=atan-result] -|=== - -Supported types: - -include::types/atan.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/atan2.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/atan2.asciidoc deleted file mode 100644 index e78a219333344..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/atan2.asciidoc +++ /dev/null @@ -1,21 +0,0 @@ -[discrete] -[[esql-atan2]] -=== `ATAN2` -[.text-center] -image::esql/functions/signature/atan2.svg[Embedded,opts=inline] - -The https://en.wikipedia.org/wiki/Atan2[angle] between the positive x-axis and the -ray from the origin to the point (x , y) in the Cartesian plane. - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=atan2] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=atan2-result] -|=== - -Supported types: - -include::types/atan2.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/auto_bucket.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/auto_bucket.asciidoc deleted file mode 100644 index 47e453f382229..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/auto_bucket.asciidoc +++ /dev/null @@ -1,72 +0,0 @@ -[discrete] -[[esql-auto_bucket]] -=== `AUTO_BUCKET` -Creates human-friendly buckets and returns a `datetime` value for each row that -corresponds to the resulting bucket the row falls into. Combine `AUTO_BUCKET` -with <> to create a date histogram. - -You provide a target number of buckets, a start date, and an end date, and it -picks an appropriate bucket size to generate the target number of buckets or -fewer. For example, this asks for at most 20 buckets over a whole year, which -picks monthly buckets: - -[source.merge.styled,esql] ----- -include::{esql-specs}/date.csv-spec[tag=auto_bucket_month] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/date.csv-spec[tag=auto_bucket_month-result] -|=== - -The goal isn't to provide *exactly* the target number of buckets, it's to pick a -range that people are comfortable with that provides at most the target number of -buckets. - -If you ask for more buckets then `AUTO_BUCKET` can pick a smaller range. For example, -asking for at most 100 buckets in a year will get you week long buckets: - -[source.merge.styled,esql] ----- -include::{esql-specs}/date.csv-spec[tag=auto_bucket_week] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/date.csv-spec[tag=auto_bucket_week-result] -|=== - -`AUTO_BUCKET` does not filter any rows. It only uses the provided time range to -pick a good bucket size. For rows with a date outside of the range, it returns a -`datetime` that corresponds to a bucket outside the range. Combine `AUTO_BUCKET` -with <> to filter rows. - -A more complete example might look like: - -[source.merge.styled,esql] ----- -include::{esql-specs}/date.csv-spec[tag=auto_bucket_in_agg] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/date.csv-spec[tag=auto_bucket_in_agg-result] -|=== - -NOTE: `AUTO_BUCKET` does not create buckets that don't match any documents. That's -why the example above is missing `1985-03-01` and other dates. - -==== Numeric fields - -`auto_bucket` can also operate on numeric fields like this: -[source.merge.styled,esql] ----- -include::{esql-specs}/ints.csv-spec[tag=auto_bucket] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/ints.csv-spec[tag=auto_bucket-result] -|=== - -Unlike the example above where you are intentionally filtering on a date range, -you rarely want to filter on a numeric range. So you have find the `min` and `max` -separately. We don't yet have an easy way to do that automatically. Improvements -coming! diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/avg.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/avg.asciidoc deleted file mode 100644 index 972d30545ceb4..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/avg.asciidoc +++ /dev/null @@ -1,15 +0,0 @@ -[discrete] -[[esql-agg-avg]] -=== `AVG` -The average of a numeric field. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats.csv-spec[tag=avg] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats.csv-spec[tag=avg-result] -|=== - -The result is always a `double` not matter the input type. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/binary.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/binary.asciidoc deleted file mode 100644 index ba93f57af7ad6..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/binary.asciidoc +++ /dev/null @@ -1,12 +0,0 @@ -[discrete] -[[esql-binary-operators]] -=== Binary operators - -These binary comparison operators are supported: - -* equality: `==` -* inequality: `!=` -* less than: `<` -* less than or equal: `<=` -* larger than: `>` -* larger than or equal: `>=` \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/case.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/case.asciidoc deleted file mode 100644 index b243adf875cb4..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/case.asciidoc +++ /dev/null @@ -1,42 +0,0 @@ -[discrete] -[[esql-case]] -=== `CASE` - -*Syntax* - -[source,txt] ----- -CASE(condition1, value1[, ..., conditionN, valueN][, default_value]) ----- - -*Parameters* - -`conditionX`:: -A condition. - -`valueX`:: -The value that's returned when the corresponding condition is the first to -evaluate to `true`. - -`default_value`:: -The default value that's is returned when no condition matches. - -*Description* - -Accepts pairs of conditions and values. The function returns the value that -belongs to the first condition that evaluates to `true`. - -If the number of arguments is odd, the last argument is the default value which -is returned when no condition matches. - -*Example* - -[source,esql] -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=case] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=case-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ceil.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ceil.asciidoc deleted file mode 100644 index f977e544e6c3f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ceil.asciidoc +++ /dev/null @@ -1,24 +0,0 @@ -[discrete] -[[esql-ceil]] -=== `CEIL` -[.text-center] -image::esql/functions/signature/ceil.svg[Embedded,opts=inline] - -Round a number up to the nearest integer. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=ceil] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=ceil-result] -|=== - -NOTE: This is a noop for `long` (including unsigned) and `integer`. - For `double` this picks the the closest `double` value to the integer ala - {javadoc}/java.base/java/lang/Math.html#ceil(double)[Math.ceil]. - -Supported types: - -include::types/ceil.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cidr_match.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cidr_match.asciidoc deleted file mode 100644 index 5072a6eef7fd5..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cidr_match.asciidoc +++ /dev/null @@ -1,16 +0,0 @@ -[discrete] -[[esql-cidr_match]] -=== `CIDR_MATCH` - -Returns `true` if the provided IP is contained in one of the provided CIDR -blocks. - -`CIDR_MATCH` accepts two or more arguments. The first argument is the IP -address of type `ip` (both IPv4 and IPv6 are supported). Subsequent arguments -are the CIDR blocks to test the IP against. - -[source,esql] ----- -FROM hosts -| WHERE CIDR_MATCH(ip, "127.0.0.2/32", "127.0.0.3/32") ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/coalesce.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/coalesce.asciidoc deleted file mode 100644 index 550780eaa070d..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/coalesce.asciidoc +++ /dev/null @@ -1,14 +0,0 @@ -[discrete] -[[esql-coalesce]] -=== `COALESCE` - -Returns the first non-null value. - -[source.merge.styled,esql] ----- -include::{esql-specs}/null.csv-spec[tag=coalesce] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/null.csv-spec[tag=coalesce-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/concat.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/concat.asciidoc deleted file mode 100644 index 4864f5623a170..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/concat.asciidoc +++ /dev/null @@ -1,11 +0,0 @@ -[discrete] -[[esql-concat]] -=== `CONCAT` -Concatenates two or more strings. - -[source,esql] ----- -FROM employees -| KEEP first_name, last_name, height -| EVAL fullname = CONCAT(first_name, " ", last_name) ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/conditional_functions_and_expressions.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/conditional_functions_and_expressions.asciidoc deleted file mode 100644 index d835a14856c03..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/conditional_functions_and_expressions.asciidoc +++ /dev/null @@ -1,21 +0,0 @@ -[[esql-conditional-functions-and-expressions]] -==== {esql} conditional functions and expressions - -++++ -Conditional functions and expressions -++++ - -Conditional functions return one of their arguments by evaluating in an if-else -manner. {esql} supports these conditional functions: - -// tag::cond_list[] -* <> -* <> -* <> -* <> -// end::cond_list[] - -include::case.asciidoc[] -include::coalesce.asciidoc[] -include::greatest.asciidoc[] -include::least.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cos.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cos.asciidoc deleted file mode 100644 index 5dcbb7bea37f4..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cos.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-cos]] -=== `COS` -[.text-center] -image::esql/functions/signature/cos.svg[Embedded,opts=inline] - -https://en.wikipedia.org/wiki/Sine_and_cosine[Cosine] trigonometric function. - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=cos] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=cos-result] -|=== - -Supported types: - -include::types/cos.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cosh.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cosh.asciidoc deleted file mode 100644 index 7bf0840958655..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/cosh.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-cosh]] -=== `COSH` -[.text-center] -image::esql/functions/signature/cosh.svg[Embedded,opts=inline] - -https://en.wikipedia.org/wiki/Hyperbolic_functions[Cosine] hyperbolic function. - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=cosh] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=cosh-result] -|=== - -Supported types: - -include::types/cosh.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/count.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/count.asciidoc deleted file mode 100644 index a148df07edb4d..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/count.asciidoc +++ /dev/null @@ -1,27 +0,0 @@ -[discrete] -[[esql-agg-count]] -=== `COUNT` -Counts field values. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats.csv-spec[tag=count] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats.csv-spec[tag=count-result] -|=== - -Can take any field type as input and the result is always a `long` not matter -the input type. - -To count the number of rows, use `COUNT(*)`: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=countAll] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=countAll-result] -|=== \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/count_distinct.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/count_distinct.asciidoc deleted file mode 100644 index b5b1659140f63..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/count_distinct.asciidoc +++ /dev/null @@ -1,46 +0,0 @@ -[discrete] -[[esql-agg-count-distinct]] -=== `COUNT_DISTINCT` -The approximate number of distinct values. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats_count_distinct.csv-spec[tag=count-distinct] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats_count_distinct.csv-spec[tag=count-distinct-result] -|=== - -Can take any field type as input and the result is always a `long` not matter -the input type. - -[discrete] -==== Counts are approximate - -Computing exact counts requires loading values into a set and returning its -size. This doesn't scale when working on high-cardinality sets and/or large -values as the required memory usage and the need to communicate those -per-shard sets between nodes would utilize too many resources of the cluster. - -This `COUNT_DISTINCT` function is based on the -https://static.googleusercontent.com/media/research.google.com/fr//pubs/archive/40671.pdf[HyperLogLog++] -algorithm, which counts based on the hashes of the values with some interesting -properties: - -include::../../aggregations/metrics/cardinality-aggregation.asciidoc[tag=explanation] - -[discrete] -==== Precision is configurable - -The `COUNT_DISTINCT` function takes an optional second parameter to configure the -precision discussed previously. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats_count_distinct.csv-spec[tag=count-distinct-precision] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats_count_distinct.csv-spec[tag=count-distinct-precision-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_extract.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_extract.asciidoc deleted file mode 100644 index 89ef1cf261094..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_extract.asciidoc +++ /dev/null @@ -1,15 +0,0 @@ -[discrete] -[[esql-date_extract]] -=== `DATE_EXTRACT` -Extracts parts of a date, like year, month, day, hour. -The supported field types are those provided by https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoField.html[java.time.temporal.ChronoField]. - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=dateExtract] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=dateExtract-result] -|=== - diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_format.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_format.asciidoc deleted file mode 100644 index 5a87f31412cc8..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_format.asciidoc +++ /dev/null @@ -1,12 +0,0 @@ -[discrete] -[[esql-date_format]] -=== `DATE_FORMAT` -Returns a string representation of a date in the provided format. If no format -is specified, the `yyyy-MM-dd'T'HH:mm:ss.SSSZ` format is used. - -[source,esql] ----- -FROM employees -| KEEP first_name, last_name, hire_date -| EVAL hired = DATE_FORMAT("YYYY-MM-dd", hire_date) ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_parse.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_parse.asciidoc deleted file mode 100644 index c74656ff1dbd7..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_parse.asciidoc +++ /dev/null @@ -1,37 +0,0 @@ -[discrete] -[[esql-date_parse]] -=== `DATE_PARSE` - -*Syntax* - -[source,txt] ----- -DATE_PARSE([format,] date_string) ----- - -*Parameters* - -`format`:: -The date format. Refer to the -https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/time/format/DateTimeFormatter.html[`DateTimeFormatter` -documentation] for the syntax. If `null`, the function returns `null`. - -`date_string`:: -Date expression as a string. If `null` or an empty string, the function returns -`null`. - -*Description* - -Returns a date by parsing the second argument using the format specified in the -first argument. - -*Example* - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=dateParse] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=dateParse-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_time_functions.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_time_functions.asciidoc deleted file mode 100644 index 8ff7b1e974eeb..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_time_functions.asciidoc +++ /dev/null @@ -1,24 +0,0 @@ -[[esql-date-time-functions]] -==== {esql} date-time functions - -++++ -Date-time functions -++++ - -{esql} supports these date-time functions: - -// tag::date_list[] -* <> -* <> -* <> -* <> -* <> -* <> -// end::date_list[] - -include::auto_bucket.asciidoc[] -include::date_extract.asciidoc[] -include::date_format.asciidoc[] -include::date_parse.asciidoc[] -include::date_trunc.asciidoc[] -include::now.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_trunc.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_trunc.asciidoc deleted file mode 100644 index cacfefe73d0fd..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/date_trunc.asciidoc +++ /dev/null @@ -1,13 +0,0 @@ -[discrete] -[[esql-date_trunc]] -=== `DATE_TRUNC` -Rounds down a date to the closest interval. Intervals can be expressed using the -<>. - -[source,esql] ----- -FROM employees -| EVAL year_hired = DATE_TRUNC(1 year, hire_date) -| STATS count(emp_no) BY year_hired -| SORT year_hired ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/e.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/e.asciidoc deleted file mode 100644 index 56bf97fd01740..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/e.asciidoc +++ /dev/null @@ -1,16 +0,0 @@ -[discrete] -[[esql-e]] -=== `E` -[.text-center] -image::esql/functions/signature/e.svg[Embedded,opts=inline] - -{wikipedia}/E_(mathematical_constant)[Euler's number]. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=e] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=e-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ends_with.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ends_with.asciidoc deleted file mode 100644 index fd2d99931163a..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ends_with.asciidoc +++ /dev/null @@ -1,21 +0,0 @@ -[discrete] -[[esql-ends_with]] -=== `ENDS_WITH` -[.text-center] -image::esql/functions/signature/ends_with.svg[Embedded,opts=inline] - -Returns a boolean that indicates whether a keyword string ends with another -string: - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=endsWith] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=endsWith-result] -|=== - -Supported types: - -include::types/ends_with.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/floor.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/floor.asciidoc deleted file mode 100644 index 109033bb18827..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/floor.asciidoc +++ /dev/null @@ -1,24 +0,0 @@ -[discrete] -[[esql-floor]] -=== `FLOOR` -[.text-center] -image::esql/functions/signature/floor.svg[Embedded,opts=inline] - -Round a number down to the nearest integer. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=floor] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=floor-result] -|=== - -NOTE: This is a noop for `long` (including unsigned) and `integer`. - For `double` this picks the the closest `double` value to the integer ala - {javadoc}/java.base/java/lang/Math.html#floor(double)[Math.floor]. - -Supported types: - -include::types/floor.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/greatest.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/greatest.asciidoc deleted file mode 100644 index 24dd08de2819c..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/greatest.asciidoc +++ /dev/null @@ -1,25 +0,0 @@ -[discrete] -[[esql-greatest]] -=== `GREATEST` -[.text-center] -image::esql/functions/signature/greatest.svg[Embedded,opts=inline] - -Returns the maximum value from many columns. This is similar to <> -except it's intended to run on multiple columns at once. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=greatest] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=greatest-result] -|=== - -NOTE: When run on `keyword` or `text` fields, this'll return the last string - in alphabetical order. When run on `boolean` columns this will return - `true` if any values are `true`. - -Supported types: - -include::types/greatest.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/in.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/in.asciidoc deleted file mode 100644 index be5688250ecc7..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/in.asciidoc +++ /dev/null @@ -1,11 +0,0 @@ -[discrete] -[[esql-in-operator]] -=== `IN` - -The `IN` operator allows testing whether a field or expression equals -an element in a list of literals, fields or expressions: - -[source,esql] ----- -include::{esql-specs}/row.csv-spec[tag=in-with-expressions] ----- \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_finite.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_finite.asciidoc deleted file mode 100644 index f7b7ad73a3952..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_finite.asciidoc +++ /dev/null @@ -1,10 +0,0 @@ -[discrete] -[[esql-is_finite]] -=== `IS_FINITE` -Returns a boolean that indicates whether its input is a finite number. - -[source,esql] ----- -ROW d = 1.0 -| EVAL s = IS_FINITE(d/0) ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_infinite.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_infinite.asciidoc deleted file mode 100644 index 56158a786c020..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_infinite.asciidoc +++ /dev/null @@ -1,10 +0,0 @@ -[discrete] -[[esql-is_infinite]] -=== `IS_INFINITE` -Returns a boolean that indicates whether its input is infinite. - -[source,esql] ----- -ROW d = 1.0 -| EVAL s = IS_INFINITE(d/0) ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_nan.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_nan.asciidoc deleted file mode 100644 index 25b50a9e96bba..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/is_nan.asciidoc +++ /dev/null @@ -1,10 +0,0 @@ -[discrete] -[[esql-is_nan]] -=== `IS_NAN` -Returns a boolean that indicates whether its input is not a number. - -[source,esql] ----- -ROW d = 1.0 -| EVAL s = IS_NAN(d) ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/least.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/least.asciidoc deleted file mode 100644 index 62d7406199cd4..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/least.asciidoc +++ /dev/null @@ -1,25 +0,0 @@ -[discrete] -[[esql-least]] -=== `LEAST` -[.text-center] -image::esql/functions/signature/least.svg[Embedded,opts=inline] - -Returns the minimum value from many columns. This is similar to <> -except it's intended to run on multiple columns at once. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=least] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=least-result] -|=== - -NOTE: When run on `keyword` or `text` fields, this'll return the first string - in alphabetical order. When run on `boolean` columns this will return - `false` if any values are `false`. - -Supported types: - -include::types/least.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/left.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/left.asciidoc deleted file mode 100644 index 67e739377aa46..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/left.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-left]] -=== `LEFT` -[.text-center] -image::esql/functions/signature/left.svg[Embedded,opts=inline] - -Return the substring that extracts 'length' chars from the 'string' starting from the left. - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=left] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=left-result] -|=== - -Supported types: - -include::types/left.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/length.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/length.asciidoc deleted file mode 100644 index 12e1bed3d0a66..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/length.asciidoc +++ /dev/null @@ -1,11 +0,0 @@ -[discrete] -[[esql-length]] -=== `LENGTH` -Returns the character length of a string. - -[source,esql] ----- -FROM employees -| KEEP first_name, last_name, height -| EVAL fn_length = LENGTH(first_name) ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/like.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/like.asciidoc deleted file mode 100644 index 9d06a3d051b93..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/like.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-like-operator]] -=== `LIKE` - -Use `LIKE` to filter data based on string patterns using wildcards. `LIKE` -usually acts on a field placed on the left-hand side of the operator, but it can -also act on a constant (literal) expression. The right-hand side of the operator -represents the pattern. - -The following wildcard characters are supported: - -* `*` matches zero or more characters. -* `?` matches one character. - -[source,esql] ----- -FROM employees -| WHERE first_name LIKE "?b*" -| KEEP first_name, last_name ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/log10.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/log10.asciidoc deleted file mode 100644 index 219519ca2a0d7..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/log10.asciidoc +++ /dev/null @@ -1,23 +0,0 @@ -[discrete] -[[esql-log10]] -=== `LOG10` -[.text-center] -image::esql/functions/signature/log10.svg[Embedded,opts=inline] - -Returns the log base 10. The input can be any numeric value, the return value -is always a double. - -Logs of negative numbers are NaN. Logs of infinites are infinite, as is the log of 0. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=log10] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=log10-result] -|=== - -Supported types: - -include::types/log10.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/logical.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/logical.asciidoc deleted file mode 100644 index 674ad67f99cde..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/logical.asciidoc +++ /dev/null @@ -1,9 +0,0 @@ -[discrete] -[[esql-logical-operators]] -=== Logical operators - -The following logical operators are supported: - -* `AND` -* `OR` -* `NOT` diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ltrim.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ltrim.asciidoc deleted file mode 100644 index 6e6d30a73b865..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/ltrim.asciidoc +++ /dev/null @@ -1,13 +0,0 @@ -[discrete] -[[esql-ltrim]] -=== `LTRIM` -Removes leading whitespaces from strings. - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=ltrim] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=ltrim-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/math_functions.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/math_functions.asciidoc deleted file mode 100644 index 21131ae9074d7..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/math_functions.asciidoc +++ /dev/null @@ -1,52 +0,0 @@ -[[esql-math-functions]] -==== {esql} mathematical functions - -++++ -Mathematical functions -++++ - -{esql} supports these mathematical functions: - -// tag::math_list[] -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -// end::math_list[] - -include::abs.asciidoc[] -include::acos.asciidoc[] -include::asin.asciidoc[] -include::atan.asciidoc[] -include::atan2.asciidoc[] -include::ceil.asciidoc[] -include::cos.asciidoc[] -include::cosh.asciidoc[] -include::e.asciidoc[] -include::floor.asciidoc[] -include::log10.asciidoc[] -include::pi.asciidoc[] -include::pow.asciidoc[] -include::round.asciidoc[] -include::sin.asciidoc[] -include::sinh.asciidoc[] -include::sqrt.asciidoc[] -include::tan.asciidoc[] -include::tanh.asciidoc[] -include::tau.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/max.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/max.asciidoc deleted file mode 100644 index 53997e501b37f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/max.asciidoc +++ /dev/null @@ -1,13 +0,0 @@ -[discrete] -[[esql-agg-max]] -=== `MAX` -The maximum value of a numeric field. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats.csv-spec[tag=max] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats.csv-spec[tag=max-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/median.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/median.asciidoc deleted file mode 100644 index 5a0d0c049602e..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/median.asciidoc +++ /dev/null @@ -1,22 +0,0 @@ -[discrete] -[[esql-agg-median]] -=== `MEDIAN` -The value that is greater than half of all values and less than half of -all values, also known as the 50% <>. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats_percentile.csv-spec[tag=median] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats_percentile.csv-spec[tag=median-result] -|=== - -NOTE: Like <>, `MEDIAN` is <>. - -[WARNING] -==== -`MEDIAN` is also {wikipedia}/Nondeterministic_algorithm[non-deterministic]. -This means you can get slightly different results using the same data. -==== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/median_absolute_deviation.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/median_absolute_deviation.asciidoc deleted file mode 100644 index fe0923da1fb88..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/median_absolute_deviation.asciidoc +++ /dev/null @@ -1,29 +0,0 @@ -[discrete] -[[esql-agg-median-absolute-deviation]] -=== `MEDIAN_ABSOLUTE_DEVIATION` -The median absolute deviation, a measure of variability. It is a robust -statistic, meaning that it is useful for describing data that may have outliers, -or may not be normally distributed. For such data it can be more descriptive than -standard deviation. - -It is calculated as the median of each data point’s deviation from the median of -the entire sample. That is, for a random variable `X`, the median absolute deviation -is `median(|median(X) - Xi|)`. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats_percentile.csv-spec[tag=median-absolute-deviation] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats_percentile.csv-spec[tag=median-absolute-deviation-result] -|=== - -NOTE: Like <>, `MEDIAN_ABSOLUTE_DEVIATION` is - <>. - -[WARNING] -==== -`MEDIAN_ABSOLUTE_DEVIATION` is also {wikipedia}/Nondeterministic_algorithm[non-deterministic]. -This means you can get slightly different results using the same data. -==== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/min.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/min.asciidoc deleted file mode 100644 index a143cca69c01a..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/min.asciidoc +++ /dev/null @@ -1,13 +0,0 @@ -[discrete] -[[esql-agg-min]] -=== `MIN` -The minimum value of a numeric field. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats.csv-spec[tag=min] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats.csv-spec[tag=min-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_avg.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_avg.asciidoc deleted file mode 100644 index ad5f672205516..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_avg.asciidoc +++ /dev/null @@ -1,17 +0,0 @@ -[discrete] -[[esql-mv_avg]] -=== `MV_AVG` -Converts a multivalued field into a single valued field containing the average -of all of the values. For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=mv_avg] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=mv_avg-result] -|=== - - -NOTE: The output type is always a `double` and the input type can be any number. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_concat.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_concat.asciidoc deleted file mode 100644 index d4be458455131..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_concat.asciidoc +++ /dev/null @@ -1,26 +0,0 @@ -[discrete] -[[esql-mv_concat]] -=== `MV_CONCAT` -Converts a multivalued string field into a single valued field containing the -concatenation of all values separated by a delimiter: - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=mv_concat] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=mv_concat-result] -|=== - -If you want to concat non-string fields call <> on them first: - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=mv_concat-to_string] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=mv_concat-to_string-result] -|=== - diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_count.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_count.asciidoc deleted file mode 100644 index 5bcda53ca5a9b..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_count.asciidoc +++ /dev/null @@ -1,16 +0,0 @@ -[discrete] -[[esql-mv_count]] -=== `MV_COUNT` -Converts a multivalued field into a single valued field containing a count of the number -of values: - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=mv_count] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=mv_count-result] -|=== - -NOTE: This function accepts all types and always returns an `integer`. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_dedupe.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_dedupe.asciidoc deleted file mode 100644 index c6af3f2d1aa3f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_dedupe.asciidoc +++ /dev/null @@ -1,15 +0,0 @@ -[discrete] -[[esql-mv_dedupe]] -=== `MV_DEDUPE` -Removes duplicates from a multivalued field. For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=mv_dedupe] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=mv_dedupe-result] -|=== - -NOTE: `MV_DEDUPE` may, but won't always, sort the values in the field. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_functions.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_functions.asciidoc deleted file mode 100644 index 83dbaaadc5c06..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_functions.asciidoc +++ /dev/null @@ -1,28 +0,0 @@ -[[esql-mv-functions]] -==== {esql} multivalue functions - -++++ -Multivalue functions -++++ - -{esql} supports these multivalue functions: - -// tag::mv_list[] -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -// end::mv_list[] - -include::mv_avg.asciidoc[] -include::mv_concat.asciidoc[] -include::mv_count.asciidoc[] -include::mv_dedupe.asciidoc[] -include::mv_max.asciidoc[] -include::mv_median.asciidoc[] -include::mv_min.asciidoc[] -include::mv_sum.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_max.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_max.asciidoc deleted file mode 100644 index e8ef951f168f5..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_max.asciidoc +++ /dev/null @@ -1,25 +0,0 @@ -[discrete] -[[esql-mv_max]] -=== `MV_MAX` -Converts a multivalued field into a single valued field containing the maximum value. For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=mv_max] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=mv_max-result] -|=== - -It can be used by any field type, including `keyword` fields. In that case picks the -last string, comparing their utf-8 representation byte by byte: - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=mv_max] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=mv_max-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_median.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_median.asciidoc deleted file mode 100644 index c84cf7a895da5..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_median.asciidoc +++ /dev/null @@ -1,27 +0,0 @@ -[discrete] -[[esql-mv_median]] -=== `MV_MEDIAN` -Converts a multivalued field into a single valued field containing the median value. For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=mv_median] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=mv_median-result] -|=== - -It can be used by any numeric field type and returns a value of the same type. If the -row has an even number of values for a column the result will be the average of the -middle two entries. If the field is not floating point then the average rounds *down*: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=mv_median_round_down] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=mv_median_round_down-result] -|=== - diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_min.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_min.asciidoc deleted file mode 100644 index 235e5c3c2bb5e..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_min.asciidoc +++ /dev/null @@ -1,25 +0,0 @@ -[discrete] -[[esql-mv_min]] -=== `MV_MIN` -Converts a multivalued field into a single valued field containing the minimum value. For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=mv_min] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=mv_min-result] -|=== - -It can be used by any field type, including `keyword` fields. In that case picks the -first string, comparing their utf-8 representation byte by byte: - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=mv_min] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=mv_min-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_sum.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_sum.asciidoc deleted file mode 100644 index 646af03305954..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/mv_sum.asciidoc +++ /dev/null @@ -1,16 +0,0 @@ -[discrete] -[[esql-mv_sum]] -=== `MV_SUM` -Converts a multivalued field into a single valued field containing the sum -of all of the values. For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=mv_sum] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=mv_sum-result] -|=== - -NOTE: The input type can be any number and the output type is the same as the input type. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/now.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/now.asciidoc deleted file mode 100644 index 5d33449a1e906..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/now.asciidoc +++ /dev/null @@ -1,9 +0,0 @@ -[discrete] -[[esql-now]] -=== `NOW` -Returns current date and time. - -[source,esql] ----- -ROW current_date = NOW() ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/operators.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/operators.asciidoc deleted file mode 100644 index c236413b5dd7e..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/operators.asciidoc +++ /dev/null @@ -1,36 +0,0 @@ -[[esql-operators]] -==== {esql} operators - -++++ -Operators -++++ - -Boolean operators for comparing against one or multiple expressions. - -// tag::op_list[] -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -// end::op_list[] - -include::binary.asciidoc[] -include::logical.asciidoc[] -include::predicates.asciidoc[] -include::cidr_match.asciidoc[] -include::ends_with.asciidoc[] -include::in.asciidoc[] -include::is_finite.asciidoc[] -include::is_infinite.asciidoc[] -include::is_nan.asciidoc[] -include::like.asciidoc[] -include::rlike.asciidoc[] -include::starts_with.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/percentile.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/percentile.asciidoc deleted file mode 100644 index 917a4a81e7b4f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/percentile.asciidoc +++ /dev/null @@ -1,30 +0,0 @@ -[discrete] -[[esql-agg-percentile]] -=== `PERCENTILE` -The value at which a certain percentage of observed values occur. For example, -the 95th percentile is the value which is greater than 95% of the observed values and -the 50th percentile is the <>. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats_percentile.csv-spec[tag=percentile] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats_percentile.csv-spec[tag=percentile-result] -|=== - -[discrete] -[[esql-agg-percentile-approximate]] -==== `PERCENTILE` is (usually) approximate - -include::../../aggregations/metrics/percentile-aggregation.asciidoc[tag=approximate] - -[WARNING] -==== -`PERCENTILE` is also {wikipedia}/Nondeterministic_algorithm[non-deterministic]. -This means you can get slightly different results using the same data. -==== - - - diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/pi.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/pi.asciidoc deleted file mode 100644 index cd630aaabadcd..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/pi.asciidoc +++ /dev/null @@ -1,16 +0,0 @@ -[discrete] -[[esql-pi]] -=== `PI` -[.text-center] -image::esql/functions/signature/pi.svg[Embedded,opts=inline] - -The {wikipedia}/Pi[ratio] of a circle's circumference to its diameter. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=pi] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=pi-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/pow.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/pow.asciidoc deleted file mode 100644 index 9f7805bfd3eae..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/pow.asciidoc +++ /dev/null @@ -1,96 +0,0 @@ -[discrete] -[[esql-pow]] -=== `POW` -[.text-center] -image::esql/functions/signature/pow.svg[Embedded,opts=inline] - -Returns the value of a base (first argument) raised to the power of an exponent (second argument). -Both arguments must be numeric. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=powDI] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=powDI-result] -|=== - -[discrete] -==== Type rules - -The type of the returned value is determined by the types of the base and exponent. -The following rules are applied to determine the result type: - -* If either of the base or exponent are of a floating point type, the result will be a double -* Otherwise, if either the base or the exponent are 64-bit (long or unsigned long), the result will be a long -* Otherwise, the result will be a 32-bit integer (this covers all other numeric types, including int, short and byte) - -For example, using simple integers as arguments will lead to an integer result: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=powII] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=powII-result] -|=== - -NOTE: The actual power function is performed using double precision values for all cases. -This means that for very large non-floating point values there is a small chance that the -operation can lead to slightly different answers than expected. -However, a more likely outcome of very large non-floating point values is numerical overflow. - -[discrete] -==== Arithmetic errors - -Arithmetic errors and numeric overflow do not result in an error. Instead, the result will be `null` -and a warning for the `ArithmeticException` added. -For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=powULOverrun] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=powULOverrun-warning] -|=== -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=powULOverrun-result] -|=== - -If it is desired to protect against numerical overruns, use `TO_DOUBLE` on either of the arguments: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=pow2d] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=pow2d-result] -|=== - -[discrete] -==== Fractional exponents - -The exponent can be a fraction, which is similar to performing a root. -For example, the exponent of `0.5` will give the square root of the base: - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=powID-sqrt] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=powID-sqrt-result] -|=== - -[discrete] -==== Table of supported input and output types - -For clarity, the following table describes the output result type for all combinations of numeric input types: - -include::types/pow.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/predicates.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/predicates.asciidoc deleted file mode 100644 index 9a3ea89e9aa73..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/predicates.asciidoc +++ /dev/null @@ -1,23 +0,0 @@ -[discrete] -[[esql-predicates]] -=== `IS NULL` and `IS NOT NULL` predicates - -For NULL comparison, use the `IS NULL` and `IS NOT NULL` predicates: - -[source.merge.styled,esql] ----- -include::{esql-specs}/null.csv-spec[tag=is-null] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/null.csv-spec[tag=is-null-result] -|=== - -[source.merge.styled,esql] ----- -include::{esql-specs}/null.csv-spec[tag=is-not-null] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/null.csv-spec[tag=is-not-null-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/replace.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/replace.asciidoc deleted file mode 100644 index 9bc0f85fdddce..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/replace.asciidoc +++ /dev/null @@ -1,17 +0,0 @@ -[discrete] -[[esql-replace]] -=== `REPLACE` -The function substitutes in the string (1st argument) any match of the regular expression (2nd argument) with the replacement string (3rd argument). - -If any of the arguments are `NULL`, the result is `NULL`. - -. This example replaces an occurrence of the word "World" with the word "Universe": - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=replaceString] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=replaceString-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/right.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/right.asciidoc deleted file mode 100644 index a0f18192d410d..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/right.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-right]] -=== `RIGHT` -[.text-center] -image::esql/functions/signature/right.svg[Embedded,opts=inline] - -Return the substring that extracts 'length' chars from the 'string' starting from the right. - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=right] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=right-result] -|=== - -Supported types: - -include::types/right.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/rlike.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/rlike.asciidoc deleted file mode 100644 index 0fd8d8ab319da..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/rlike.asciidoc +++ /dev/null @@ -1,15 +0,0 @@ -[discete] -[[esql-rlike-operator]] -==== `RLIKE` - -Use `RLIKE` to filter data based on string patterns using using -<>. `RLIKE` usually acts on a field placed on -the left-hand side of the operator, but it can also act on a constant (literal) -expression. The right-hand side of the operator represents the pattern. - -[source,esql] ----- -FROM employees -| WHERE first_name RLIKE ".leja.*" -| KEEP first_name, last_name ----- \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/round.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/round.asciidoc deleted file mode 100644 index 4ec71cf682d0f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/round.asciidoc +++ /dev/null @@ -1,15 +0,0 @@ -[discrete] -[[esql-round]] -=== `ROUND` -Rounds a number to the closest number with the specified number of digits. -Defaults to 0 digits if no number of digits is provided. If the specified number -of digits is negative, rounds to the number of digits left of the decimal point. - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=round] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=round-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/rtrim.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/rtrim.asciidoc deleted file mode 100644 index 3224331e9ed6a..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/rtrim.asciidoc +++ /dev/null @@ -1,13 +0,0 @@ -[discrete] -[[esql-rtrim]] -=== `RTRIM` -Removes trailing whitespaces from strings. - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=rtrim] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=rtrim-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sin.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sin.asciidoc deleted file mode 100644 index 5fa33a315392d..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sin.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-sin]] -=== `SIN` -[.text-center] -image::esql/functions/signature/sin.svg[Embedded,opts=inline] - -https://en.wikipedia.org/wiki/Sine_and_cosine[Sine] trigonometric function. - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=sin] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=sin-result] -|=== - -Supported types: - -include::types/sin.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sinh.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sinh.asciidoc deleted file mode 100644 index 11d1ea29bffef..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sinh.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-sinh]] -=== `SINH` -[.text-center] -image::esql/functions/signature/sinh.svg[Embedded,opts=inline] - -https://en.wikipedia.org/wiki/Hyperbolic_functions[Sine] hyperbolic function. - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=sinh] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=sinh-result] -|=== - -Supported types: - -include::types/sinh.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/split.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/split.asciidoc deleted file mode 100644 index a6f8869bf89ca..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/split.asciidoc +++ /dev/null @@ -1,18 +0,0 @@ -[discrete] -[[esql-split]] -=== `SPLIT` -Split a single valued string into multiple strings. For example: - -[source,esql] ----- -include::{esql-specs}/string.csv-spec[tag=split] ----- - -Which splits `"foo;bar;baz;qux;quux;corge"` on `;` and returns an array: - -[%header,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=split-result] -|=== - -WARNING: Only single byte delimiters are currently supported. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sqrt.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sqrt.asciidoc deleted file mode 100644 index 02f7060089971..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sqrt.asciidoc +++ /dev/null @@ -1,23 +0,0 @@ -[discrete] -[[esql-sqrt]] -=== `SQRT` -[.text-center] -image::esql/functions/signature/sqrt.svg[Embedded,opts=inline] - -Returns the square root of a number. The input can be any numeric value, the return value -is always a double. - -Square roots of negative numbers are NaN. Square roots of infinites are infinite. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=sqrt] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=sqrt-result] -|=== - -Supported types: - -include::types/sqrt.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/starts_with.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/starts_with.asciidoc deleted file mode 100644 index 38cee79ea63f8..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/starts_with.asciidoc +++ /dev/null @@ -1,21 +0,0 @@ -[discrete] -[[esql-starts_with]] -=== `STARTS_WITH` -[.text-center] -image::esql/functions/signature/ends_with.svg[Embedded,opts=inline] - -Returns a boolean that indicates whether a keyword string starts with another -string: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=startsWith] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=startsWith-result] -|=== - -Supported types: - -include::types/starts_with.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/string_functions.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/string_functions.asciidoc deleted file mode 100644 index b209244b93297..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/string_functions.asciidoc +++ /dev/null @@ -1,32 +0,0 @@ -[[esql-string-functions]] -==== {esql} string functions - -++++ -String functions -++++ - -{esql} supports these string functions: - -// tag::string_list[] -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -// end::string_list[] - -include::concat.asciidoc[] -include::left.asciidoc[] -include::length.asciidoc[] -include::ltrim.asciidoc[] -include::replace.asciidoc[] -include::right.asciidoc[] -include::rtrim.asciidoc[] -include::split.asciidoc[] -include::substring.asciidoc[] -include::trim.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/substring.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/substring.asciidoc deleted file mode 100644 index 8b8234de05bba..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/substring.asciidoc +++ /dev/null @@ -1,38 +0,0 @@ -[discrete] -[[esql-substring]] -=== `SUBSTRING` -Returns a substring of a string, specified by a start position and an optional -length. This example returns the first three characters of every last name: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=substring] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=substring-result] -|=== - -A negative start position is interpreted as being relative to the end of the -string. This example returns the last three characters of of every last name: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=substringEnd] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=substringEnd-result] -|=== - -If length is omitted, substring returns the remainder of the string. This -example returns all characters except for the first: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=substringRemainder] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=substringRemainder-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sum.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sum.asciidoc deleted file mode 100644 index abf790040114d..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/sum.asciidoc +++ /dev/null @@ -1,13 +0,0 @@ -[discrete] -[[esql-agg-sum]] -=== `SUM` -The sum of a numeric field. - -[source.merge.styled,esql] ----- -include::{esql-specs}/stats.csv-spec[tag=sum] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/stats.csv-spec[tag=sum-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tan.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tan.asciidoc deleted file mode 100644 index 1c66562eada7a..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tan.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-tan]] -=== `TAN` -[.text-center] -image::esql/functions/signature/tan.svg[Embedded,opts=inline] - -https://en.wikipedia.org/wiki/Sine_and_cosine[Tangent] trigonometric function. - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=tan] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=tan-result] -|=== - -Supported types: - -include::types/tan.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tanh.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tanh.asciidoc deleted file mode 100644 index 218a0155d861c..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tanh.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-tanh]] -=== `TANH` -[.text-center] -image::esql/functions/signature/tanh.svg[Embedded,opts=inline] - -https://en.wikipedia.org/wiki/Hyperbolic_functions[Tangent] hyperbolic function. - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=tanh] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=tanh-result] -|=== - -Supported types: - -include::types/tanh.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tau.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tau.asciidoc deleted file mode 100644 index 61f352b0db8de..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/tau.asciidoc +++ /dev/null @@ -1,16 +0,0 @@ -[discrete] -[[esql-tau]] -=== `TAU` -[.text-center] -image::esql/functions/signature/tau.svg[Embedded,opts=inline] - -The https://tauday.com/tau-manifesto[ratio] of a circle's circumference to its radius. - -[source.merge.styled,esql] ----- -include::{esql-specs}/math.csv-spec[tag=tau] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/math.csv-spec[tag=tau-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_boolean.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_boolean.asciidoc deleted file mode 100644 index 03f21a503218c..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_boolean.asciidoc +++ /dev/null @@ -1,25 +0,0 @@ -[discrete] -[[esql-to_boolean]] -=== `TO_BOOLEAN` -Converts an input value to a boolean value. - -The input can be a single- or multi-valued field or an expression. The input -type must be of a string or numeric type. - -A string value of *"true"* will be case-insensitive converted to the Boolean -*true*. For anything else, including the empty string, the function will -return *false*. For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/boolean.csv-spec[tag=to_boolean] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/boolean.csv-spec[tag=to_boolean-result] -|=== - -The numerical value of *0* will be converted to *false*, anything else will be -converted to *true*. - -Alias: TO_BOOL diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_datetime.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_datetime.asciidoc deleted file mode 100644 index 750c8025cb6c2..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_datetime.asciidoc +++ /dev/null @@ -1,47 +0,0 @@ -[discrete] -[[esql-to_datetime]] -=== `TO_DATETIME` -Converts an input value to a date value. - -The input can be a single- or multi-valued field or an expression. The input -type must be of a string or numeric type. - -A string will only be successfully converted if it's respecting the format -`yyyy-MM-dd'T'HH:mm:ss.SSS'Z'` (to convert dates in other formats, use <>). For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/date.csv-spec[tag=to_datetime-str] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/date.csv-spec[tag=to_datetime-str-result] -|=== - -Note that in this example, the last value in the source multi-valued -field has not been converted. The reason being that if the date format is not -respected, the conversion will result in a *null* value. When this happens a -_Warning_ header is added to the response. The header will provide information -on the source of the failure: - -`"Line 1:112: evaluation of [TO_DATETIME(string)] failed, treating result as null. Only first 20 failures recorded."` - -A following header will contain the failure reason and the offending value: - -`"java.lang.IllegalArgumentException: failed to parse date field [1964-06-02 00:00:00] with format [yyyy-MM-dd'T'HH:mm:ss.SSS'Z']"` - - -If the input parameter is of a numeric type, its value will be interpreted as -milliseconds since the https://en.wikipedia.org/wiki/Unix_time[Unix epoch]. -For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/date.csv-spec[tag=to_datetime-int] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/date.csv-spec[tag=to_datetime-int-result] -|=== - -Alias: TO_DT diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_degrees.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_degrees.asciidoc deleted file mode 100644 index 71b480253fe35..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_degrees.asciidoc +++ /dev/null @@ -1,19 +0,0 @@ -[discrete] -[[esql-to_degrees]] -=== `TO_DEGREES` -Converts a number in https://en.wikipedia.org/wiki/Radian[radians] -to https://en.wikipedia.org/wiki/Degree_(angle)[degrees]. - -The input can be a single- or multi-valued field or an expression. The input -type must be of a numeric type and result is always `double`. - -Example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=to_degrees] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=to_degrees-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_double.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_double.asciidoc deleted file mode 100644 index 27ad84e4c7762..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_double.asciidoc +++ /dev/null @@ -1,38 +0,0 @@ -[discrete] -[[esql-to_double]] -=== `TO_DOUBLE` -Converts an input value to a double value. - -The input can be a single- or multi-valued field or an expression. The input -type must be of a boolean, date, string or numeric type. - -Example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=to_double-str] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=to_double-str-result] -|=== - -Note that in this example, the last conversion of the string isn't -possible. When this happens, the result is a *null* value. In this case a -_Warning_ header is added to the response. The header will provide information -on the source of the failure: - -`"Line 1:115: evaluation of [TO_DOUBLE(str2)] failed, treating result as null. Only first 20 failures recorded."` - -A following header will contain the failure reason and the offending value: - -`"java.lang.NumberFormatException: For input string: \"foo\""` - - -If the input parameter is of a date type, its value will be interpreted as -milliseconds since the https://en.wikipedia.org/wiki/Unix_time[Unix epoch], -converted to double. - -Boolean *true* will be converted to double *1.0*, *false* to *0.0*. - -Alias: TO_DBL diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_integer.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_integer.asciidoc deleted file mode 100644 index e185b87d6d95d..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_integer.asciidoc +++ /dev/null @@ -1,38 +0,0 @@ -[discrete] -[[esql-to_integer]] -=== `TO_INTEGER` -Converts an input value to an integer value. - -The input can be a single- or multi-valued field or an expression. The input -type must be of a boolean, date, string or numeric type. - -Example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/ints.csv-spec[tag=to_int-long] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/ints.csv-spec[tag=to_int-long-result] -|=== - -Note that in this example, the last value of the multi-valued field cannot -be converted as an integer. When this happens, the result is a *null* value. -In this case a _Warning_ header is added to the response. The header will -provide information on the source of the failure: - -`"Line 1:61: evaluation of [TO_INTEGER(long)] failed, treating result as null. Only first 20 failures recorded."` - -A following header will contain the failure reason and the offending value: - -`"org.elasticsearch.xpack.ql.QlIllegalArgumentException: [501379200000] out of [integer] range"` - - -If the input parameter is of a date type, its value will be interpreted as -milliseconds since the https://en.wikipedia.org/wiki/Unix_time[Unix epoch], -converted to integer. - -Boolean *true* will be converted to integer *1*, *false* to *0*. - -Alias: TO_INT diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_ip.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_ip.asciidoc deleted file mode 100644 index dea147eba1a41..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_ip.asciidoc +++ /dev/null @@ -1,28 +0,0 @@ -[discrete] -[[esql-to_ip]] -=== `TO_IP` -Converts an input string to an IP value. - -The input can be a single- or multi-valued field or an expression. - -Example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/ip.csv-spec[tag=to_ip] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/ip.csv-spec[tag=to_ip-result] -|=== - -Note that in the example above the last conversion of the string isn't -possible. When this happens, the result is a *null* value. In this case a -_Warning_ header is added to the response. The header will provide information -on the source of the failure: - -`"Line 1:68: evaluation of [TO_IP(str2)] failed, treating result as null. Only first 20 failures recorded."` - -A following header will contain the failure reason and the offending value: - -`"java.lang.IllegalArgumentException: 'foo' is not an IP string literal."` diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_long.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_long.asciidoc deleted file mode 100644 index 9501c28a31657..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_long.asciidoc +++ /dev/null @@ -1,36 +0,0 @@ -[discrete] -[[esql-to_long]] -=== `TO_LONG` -Converts an input value to a long value. - -The input can be a single- or multi-valued field or an expression. The input -type must be of a boolean, date, string or numeric type. - -Example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/ints.csv-spec[tag=to_long-str] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/ints.csv-spec[tag=to_long-str-result] -|=== - -Note that in this example, the last conversion of the string isn't -possible. When this happens, the result is a *null* value. In this case a -_Warning_ header is added to the response. The header will provide information -on the source of the failure: - -`"Line 1:113: evaluation of [TO_LONG(str3)] failed, treating result as null. Only first 20 failures recorded."` - -A following header will contain the failure reason and the offending value: - -`"java.lang.NumberFormatException: For input string: \"foo\""` - - -If the input parameter is of a date type, its value will be interpreted as -milliseconds since the https://en.wikipedia.org/wiki/Unix_time[Unix epoch], -converted to long. - -Boolean *true* will be converted to long *1*, *false* to *0*. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_radians.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_radians.asciidoc deleted file mode 100644 index 1f86f1fb983cc..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_radians.asciidoc +++ /dev/null @@ -1,19 +0,0 @@ -[discrete] -[[esql-to_radians]] -=== `TO_RADIANS` -Converts a number in https://en.wikipedia.org/wiki/Degree_(angle)[degrees] to -https://en.wikipedia.org/wiki/Radian[radians]. - -The input can be a single- or multi-valued field or an expression. The input -type must be of a numeric type and result is always `double`. - -Example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/floats.csv-spec[tag=to_radians] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/floats.csv-spec[tag=to_radians-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_string.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_string.asciidoc deleted file mode 100644 index d03b6511b8de5..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_string.asciidoc +++ /dev/null @@ -1,33 +0,0 @@ -[discrete] -[[esql-to_string]] -=== `TO_STRING` -[.text-center] -image::esql/functions/signature/to_string.svg[Embedded,opts=inline] - -Converts a field into a string. For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=to_string] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=to_string-result] -|=== - -It also works fine on multivalued fields: - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=to_string_multivalue] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=to_string_multivalue-result] -|=== - -Alias: TO_STR - -Supported types: - -include::types/to_string.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_unsigned_long.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_unsigned_long.asciidoc deleted file mode 100644 index af3ff05bf055c..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_unsigned_long.asciidoc +++ /dev/null @@ -1,38 +0,0 @@ -[discrete] -[[esql-to_unsigned_long]] -=== `TO_UNSIGNED_LONG` -Converts an input value to an unsigned long value. - -The input can be a single- or multi-valued field or an expression. The input -type must be of a boolean, date, string or numeric type. - -Example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/ints.csv-spec[tag=to_unsigned_long-str] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/ints.csv-spec[tag=to_unsigned_long-str-result] -|=== - -Note that in this example, the last conversion of the string isn't -possible. When this happens, the result is a *null* value. In this case a -_Warning_ header is added to the response. The header will provide information -on the source of the failure: - -`"Line 1:133: evaluation of [TO_UL(str3)] failed, treating result as null. Only first 20 failures recorded."` - -A following header will contain the failure reason and the offending value: - -`"java.lang.NumberFormatException: Character f is neither a decimal digit number, decimal point, nor \"e\" notation exponential mark."` - - -If the input parameter is of a date type, its value will be interpreted as -milliseconds since the https://en.wikipedia.org/wiki/Unix_time[Unix epoch], -converted to unsigned long. - -Boolean *true* will be converted to unsigned long *1*, *false* to *0*. - -Alias: TO_ULONG, TO_UL diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_version.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_version.asciidoc deleted file mode 100644 index 33419233c4788..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/to_version.asciidoc +++ /dev/null @@ -1,24 +0,0 @@ -[discrete] -[[esql-to_version]] -=== `TO_VERSION` -[.text-center] -image::esql/functions/signature/to_version.svg[Embedded,opts=inline] - -Converts an input string to a version value. For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/version.csv-spec[tag=to_version] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/version.csv-spec[tag=to_version-result] -|=== - -The input can be a single- or multi-valued field or an expression. - -Alias: TO_VER - -Supported types: - -include::types/to_version.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/trim.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/trim.asciidoc deleted file mode 100644 index 6ace6118dd757..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/trim.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[discrete] -[[esql-trim]] -=== `TRIM` -[.text-center] -image::esql/functions/signature/trim.svg[Embedded,opts=inline] - -Removes leading and trailing whitespaces from strings. - -[source.merge.styled,esql] ----- -include::{esql-specs}/string.csv-spec[tag=trim] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/string.csv-spec[tag=trim-result] -|=== - -Supported types: - -include::types/trim.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/type_conversion_functions.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/type_conversion_functions.asciidoc deleted file mode 100644 index 640006c936526..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/type_conversion_functions.asciidoc +++ /dev/null @@ -1,34 +0,0 @@ -[[esql-type-conversion-functions]] -==== {esql} type conversion functions - -++++ -Type conversion functions -++++ - -{esql} supports these type conversion functions: - -// tag::type_list[] -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -// end::type_list[] - -include::to_boolean.asciidoc[] -include::to_datetime.asciidoc[] -include::to_degrees.asciidoc[] -include::to_double.asciidoc[] -include::to_integer.asciidoc[] -include::to_ip.asciidoc[] -include::to_long.asciidoc[] -include::to_radians.asciidoc[] -include::to_string.asciidoc[] -include::to_unsigned_long.asciidoc[] -include::to_version.asciidoc[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/abs.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/abs.asciidoc deleted file mode 100644 index 54341360fed3f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/abs.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | integer -long | long -unsigned_long | unsigned_long -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/acos.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/acos.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/acos.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/asin.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/asin.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/asin.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/atan.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/atan.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/atan.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/atan2.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/atan2.asciidoc deleted file mode 100644 index 74fffe9056a16..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/atan2.asciidoc +++ /dev/null @@ -1,20 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -y | x | result -double | double | double -double | integer | double -double | long | double -double | unsigned_long | double -integer | double | double -integer | integer | double -integer | long | double -integer | unsigned_long | double -long | double | double -long | integer | double -long | long | double -long | unsigned_long | double -unsigned_long | double | double -unsigned_long | integer | double -unsigned_long | long | double -unsigned_long | unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/auto_bucket.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/auto_bucket.asciidoc deleted file mode 100644 index d2f134b99fbb0..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/auto_bucket.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | arg3 | arg4 | result - -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/case.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/case.asciidoc deleted file mode 100644 index 7062d7000115a..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/case.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | result - -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ceil.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ceil.asciidoc deleted file mode 100644 index 54341360fed3f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ceil.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | integer -long | long -unsigned_long | unsigned_long -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/coalesce.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/coalesce.asciidoc deleted file mode 100644 index e36316ab87bb5..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/coalesce.asciidoc +++ /dev/null @@ -1,9 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | result -boolean | boolean | boolean -integer | integer | integer -keyword | keyword | keyword -long | long | long -text | text | text -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/concat.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/concat.asciidoc deleted file mode 100644 index f422b45f0b34c..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/concat.asciidoc +++ /dev/null @@ -1,6 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | result -keyword | keyword | keyword -text | text | keyword -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/cos.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/cos.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/cos.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/cosh.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/cosh.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/cosh.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/date_extract.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/date_extract.asciidoc deleted file mode 100644 index 9963c85b2af85..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/date_extract.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | result -keyword | datetime | long -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/date_parse.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/date_parse.asciidoc deleted file mode 100644 index f4922b9bf9c61..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/date_parse.asciidoc +++ /dev/null @@ -1,6 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -datePattern | dateString | result -keyword | keyword | datetime -keyword | text | datetime -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/e.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/e.asciidoc deleted file mode 100644 index 5854465d5fb49..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/e.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -result - -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ends_with.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ends_with.asciidoc deleted file mode 100644 index 6c406b80c0cad..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ends_with.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | result -keyword | keyword | boolean -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/floor.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/floor.asciidoc deleted file mode 100644 index 54341360fed3f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/floor.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | integer -long | long -unsigned_long | unsigned_long -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/greatest.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/greatest.asciidoc deleted file mode 100644 index 0e4ebb2d45a31..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/greatest.asciidoc +++ /dev/null @@ -1,12 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -first | rest | result -boolean | boolean | boolean -double | double | double -integer | integer | integer -ip | ip | ip -keyword | keyword | keyword -long | long | long -text | text | text -version | version | version -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/is_finite.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/is_finite.asciidoc deleted file mode 100644 index 0c555059004c1..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/is_finite.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -double | boolean -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/is_infinite.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/is_infinite.asciidoc deleted file mode 100644 index 0c555059004c1..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/is_infinite.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -double | boolean -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/least.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/least.asciidoc deleted file mode 100644 index 0e4ebb2d45a31..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/least.asciidoc +++ /dev/null @@ -1,12 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -first | rest | result -boolean | boolean | boolean -double | double | double -integer | integer | integer -ip | ip | ip -keyword | keyword | keyword -long | long | long -text | text | text -version | version | version -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/left.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/left.asciidoc deleted file mode 100644 index c30a055f3be49..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/left.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -string | length | result -keyword | integer | keyword -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/length.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/length.asciidoc deleted file mode 100644 index 9af62defcb2a9..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/length.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -keyword | integer -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/log10.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/log10.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/log10.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ltrim.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ltrim.asciidoc deleted file mode 100644 index 11c02c8f0c3bb..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/ltrim.asciidoc +++ /dev/null @@ -1,6 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -keyword | keyword -text | text -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_avg.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_avg.asciidoc deleted file mode 100644 index dd4f6b0725cc8..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_avg.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_concat.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_concat.asciidoc deleted file mode 100644 index 2836799f335e8..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_concat.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | result -keyword | keyword | keyword -keyword | text | keyword -text | keyword | keyword -text | text | keyword -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_count.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_count.asciidoc deleted file mode 100644 index 2fcdfc65fa63b..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_count.asciidoc +++ /dev/null @@ -1,10 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -boolean | integer -double | integer -integer | integer -keyword | integer -long | integer -unsigned_long | integer -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_dedupe.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_dedupe.asciidoc deleted file mode 100644 index 4e12c68422662..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_dedupe.asciidoc +++ /dev/null @@ -1,9 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -boolean | boolean -double | double -integer | integer -keyword | keyword -long | long -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_max.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_max.asciidoc deleted file mode 100644 index 50740a71e4b49..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_max.asciidoc +++ /dev/null @@ -1,10 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -boolean | boolean -double | double -integer | integer -keyword | keyword -long | long -unsigned_long | unsigned_long -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_median.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_median.asciidoc deleted file mode 100644 index f1831429aa95c..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_median.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -double | double -integer | integer -long | long -unsigned_long | unsigned_long -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_min.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_min.asciidoc deleted file mode 100644 index 50740a71e4b49..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_min.asciidoc +++ /dev/null @@ -1,10 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -boolean | boolean -double | double -integer | integer -keyword | keyword -long | long -unsigned_long | unsigned_long -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_sum.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_sum.asciidoc deleted file mode 100644 index 09cb78511d275..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/mv_sum.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -double | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/pi.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/pi.asciidoc deleted file mode 100644 index 5854465d5fb49..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/pi.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -result - -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/pow.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/pow.asciidoc deleted file mode 100644 index 37bddc60c118f..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/pow.asciidoc +++ /dev/null @@ -1,10 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -base | exponent | result -double | double | double -double | integer | double -integer | double | double -integer | integer | integer -long | double | double -long | integer | long -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/replace.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/replace.asciidoc deleted file mode 100644 index 6824d1fd97128..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/replace.asciidoc +++ /dev/null @@ -1,12 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | arg3 | result -keyword | keyword | keyword | keyword -keyword | keyword | text | keyword -keyword | text | keyword | keyword -keyword | text | text | keyword -text | keyword | keyword | keyword -text | keyword | text | keyword -text | text | keyword | keyword -text | text | text | keyword -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/right.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/right.asciidoc deleted file mode 100644 index c30a055f3be49..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/right.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -string | length | result -keyword | integer | keyword -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/round.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/round.asciidoc deleted file mode 100644 index 5ba9e2f776d75..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/round.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | result -double | integer | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/rtrim.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/rtrim.asciidoc deleted file mode 100644 index 11c02c8f0c3bb..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/rtrim.asciidoc +++ /dev/null @@ -1,6 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -keyword | keyword -text | text -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sin.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sin.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sin.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sinh.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sinh.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sinh.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/split.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/split.asciidoc deleted file mode 100644 index f1f744dbe4126..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/split.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | result -keyword | keyword | keyword -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sqrt.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sqrt.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/sqrt.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/starts_with.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/starts_with.asciidoc deleted file mode 100644 index 6c406b80c0cad..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/starts_with.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | result -keyword | keyword | boolean -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/substring.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/substring.asciidoc deleted file mode 100644 index 2aa96ceeb7e43..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/substring.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | arg2 | arg3 | result -keyword | integer | integer | keyword -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tan.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tan.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tan.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tanh.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tanh.asciidoc deleted file mode 100644 index 1df8dd6526f18..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tanh.asciidoc +++ /dev/null @@ -1,8 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -n | result -double | double -integer | double -long | double -unsigned_long | double -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tau.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tau.asciidoc deleted file mode 100644 index 5854465d5fb49..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/tau.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -result - -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_ip.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_ip.asciidoc deleted file mode 100644 index a21bbf14d87ca..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_ip.asciidoc +++ /dev/null @@ -1,6 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -ip | ip -keyword | ip -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_string.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_string.asciidoc deleted file mode 100644 index b8fcd4477aa70..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_string.asciidoc +++ /dev/null @@ -1,14 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -v | result -boolean | keyword -datetime | keyword -double | keyword -integer | keyword -ip | keyword -keyword | keyword -long | keyword -text | keyword -unsigned_long | keyword -version | keyword -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_version.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_version.asciidoc deleted file mode 100644 index ebb83f03a6fe6..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/to_version.asciidoc +++ /dev/null @@ -1,7 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -v | result -keyword | version -text | version -version | version -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/trim.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/trim.asciidoc deleted file mode 100644 index 11c02c8f0c3bb..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/functions/types/trim.asciidoc +++ /dev/null @@ -1,6 +0,0 @@ -[%header.monospaced.styled,format=dsv,separator=|] -|=== -arg1 | result -keyword | keyword -text | text -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/index.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/index.asciidoc deleted file mode 100644 index 09b74740a5b67..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/index.asciidoc +++ /dev/null @@ -1,71 +0,0 @@ -[[esql]] -= {esql} - -:esql-tests: {xes-repo-dir}/../../plugin/esql/qa -:esql-specs: {esql-tests}/testFixtures/src/main/resources - -[partintro] - -preview::[] - -The {es} Query Language ({esql}) provides a powerful way to filter, transform, and analyze data stored in {es}. -Users can author {esql} queries to find specific events, perform statistical analysis, and generate visualizations. -It supports a wide range of commands and functions that enable users to perform various data operations, -such as filtering, aggregation, time-series analysis, and more. - -The {es} Query Language ({esql}) makes use of "pipes" to manipulate and transform data in a step-by-step fashion. -This approach allows users to compose a series of operations, where the output of one operation becomes the input for the next, -enabling complex data transformations and analysis. - -A simple example of an {esql} query is shown below: -[source,esql] ----- -FROM employees -| EVAL age = DATE_DIFF(NOW(), birth_date, 'Y') -| STATS AVG(age) BY department -| SORT age DESC ----- - -Each {esql} query starts with a <>. A source command produces -a table, typically with data from {es}. - -image::images/esql/source-command.svg[A source command producing a table from {es},align="center"] - -A source command can be followed by one or more -<>. Processing commands change an -input table by adding, removing, or changing rows and columns. -Processing commands can perform filtering, projection, aggregation, and more. - -image::images/esql/processing-command.svg[A processing command changing an input table,align="center"] - -You can chain processing commands, separated by a pipe character: `|`. Each -processing command works on the output table of the previous command. - -image::images/esql/chaining-processing-commands.svg[Processing commands can be chained,align="center"] - -The result of a query is the table produced by the final processing command. - -[discrete] -=== The {esql} Compute Engine - -{esql} is more than a language. It represents a significant investment in new compute capabilities within {es}. -To achieve both the functional and performance requirements for {esql}, it was necessary to build an entirely new -compute architecture. {esql} search, aggregation, and transformation functions are directly executed within Elasticsearch -itself. Query expressions are not transpiled to Query DSL for execution. This approach allows {esql} to be extremely performant and versatile. - -The new {esql} execution engine was designed with performance in mind — it operates on blocks at a time instead of per row, targets vectorization and cache locality, and embraces specialization and multi-threading. It is a separate component from the existing Elasticsearch aggregation framework with different performance characteristics. - -include::esql-get-started.asciidoc[] - -include::esql-language.asciidoc[] - -include::esql-rest.asciidoc[] - -include::esql-kibana.asciidoc[] - -include::task-management.asciidoc[] - -include::esql-limitations.asciidoc[] - -:esql-tests!: -:esql-specs!: diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/metadata_fields.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/metadata_fields.asciidoc deleted file mode 100644 index c034d4d0dd2b3..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/metadata_fields.asciidoc +++ /dev/null @@ -1,55 +0,0 @@ -[[esql-metadata-fields]] -=== {esql} metadata fields - -++++ -Metadata fields -++++ - -{esql} can access <>. The currently -supported ones are: - - * <>: the index to which the document belongs. - The field is of the type <>. - - * <>: the source document's ID. The field is of the - type <>. - - * `_version`: the source document's version. The field is of the type - <>. - -To enable the access to these fields, the <> source command needs -to be provided with a dedicated directive: - -[source,esql] ----- -FROM index [METADATA _index, _id] ----- - -Metadata fields are only available if the source of the data is an index. -Consequently, `FROM` is the only source commands that supports the `METADATA` -directive. - -Once enabled, the fields are then available to subsequent processing commands, just -like the other index fields: - -[source.merge.styled,esql] ----- -include::{esql-specs}/metadata-ignoreCsvTests.csv-spec[tag=multipleIndices] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/metadata-ignoreCsvTests.csv-spec[tag=multipleIndices-result] -|=== - -Also, similar to the index fields, once an aggregation is performed, a -metadata field will no longer be accessible to subsequent commands, unless -used as grouping field: - -[source.merge.styled,esql] ----- -include::{esql-specs}/metadata-ignoreCsvTests.csv-spec[tag=metaIndexInAggs] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/metadata-ignoreCsvTests.csv-spec[tag=metaIndexInAggs-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/multivalued_fields.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/multivalued_fields.asciidoc deleted file mode 100644 index 5e48eb4ef8af8..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/multivalued_fields.asciidoc +++ /dev/null @@ -1,240 +0,0 @@ -[[esql-multivalued-fields]] -=== {esql} multivalued fields - -++++ -Multivalued fields -++++ - -{esql} is fine reading from multivalued fields: - -[source,console,id=esql-multivalued-fields-reorders] ----- -POST /mv/_bulk?refresh -{ "index" : {} } -{ "a": 1, "b": [2, 1] } -{ "index" : {} } -{ "a": 2, "b": 3 } - -POST /_query -{ - "query": "FROM mv | LIMIT 2" -} ----- - -Multivalued fields come back as a JSON array: - -[source,console-result] ----- -{ - "columns": [ - { "name": "a", "type": "long"}, - { "name": "b", "type": "long"} - ], - "values": [ - [1, [1, 2]], - [2, 3] - ] -} ----- - -The relative order of values in a multivalued field is undefined. They'll frequently be in -ascending order but don't rely on that. - -[discrete] -[[esql-multivalued-fields-dups]] -==== Duplicate values - -Some field types, like <> remove duplicate values on write: - -[source,console,id=esql-multivalued-fields-kwdups] ----- -PUT /mv -{ - "mappings": { - "properties": { - "b": {"type": "keyword"} - } - } -} - -POST /mv/_bulk?refresh -{ "index" : {} } -{ "a": 1, "b": ["foo", "foo", "bar"] } -{ "index" : {} } -{ "a": 2, "b": ["bar", "bar"] } - -POST /_query -{ - "query": "FROM mv | LIMIT 2" -} ----- - -And {esql} sees that removal: - -[source,console-result] ----- -{ - "columns": [ - { "name": "a", "type": "long"}, - { "name": "b", "type": "keyword"} - ], - "values": [ - [1, ["bar", "foo"]], - [2, "bar"] - ] -} ----- - -But other types, like `long` don't remove duplicates. - -[source,console,id=esql-multivalued-fields-longdups] ----- -PUT /mv -{ - "mappings": { - "properties": { - "b": {"type": "long"} - } - } -} - -POST /mv/_bulk?refresh -{ "index" : {} } -{ "a": 1, "b": [2, 2, 1] } -{ "index" : {} } -{ "a": 2, "b": [1, 1] } - -POST /_query -{ - "query": "FROM mv | LIMIT 2" -} ----- - -And {esql} also sees that: - -[source,console-result] ----- -{ - "columns": [ - { "name": "a", "type": "long"}, - { "name": "b", "type": "long"} - ], - "values": [ - [1, [1, 2, 2]], - [2, [1, 1]] - ] -} ----- - -This is all at the storage layer. If you store duplicate `long`s and then -convert them to strings the duplicates will stay: - -[source,console,id=esql-multivalued-fields-longdups-tostring] ----- -PUT /mv -{ - "mappings": { - "properties": { - "b": {"type": "long"} - } - } -} - -POST /mv/_bulk?refresh -{ "index" : {} } -{ "a": 1, "b": [2, 2, 1] } -{ "index" : {} } -{ "a": 2, "b": [1, 1] } - -POST /_query -{ - "query": "FROM mv | EVAL b=TO_STRING(b) | LIMIT 2" -} ----- - -[source,console-result] ----- -{ - "columns": [ - { "name": "a", "type": "long"}, - { "name": "b", "type": "keyword"} - ], - "values": [ - [1, ["1", "2", "2"]], - [2, ["1", "1"]] - ] -} ----- - -[discrete] -[[esql-multivalued-fields-functions]] -==== Functions - -Unless otherwise documented functions will return `null` when applied to a multivalued -field. This behavior may change in a later version. - -[source,console,id=esql-multivalued-fields-mv-into-null] ----- -POST /mv/_bulk?refresh -{ "index" : {} } -{ "a": 1, "b": [2, 1] } -{ "index" : {} } -{ "a": 2, "b": 3 } - -POST /_query -{ - "query": "FROM mv | EVAL b + 2, a + b | LIMIT 4" -} ----- - -[source,console-result] ----- -{ - "columns": [ - { "name": "a", "type": "long"}, - { "name": "b", "type": "long"}, - { "name": "b+2", "type": "long"}, - { "name": "a+b", "type": "long"} - ], - "values": [ - [1, [1, 2], null, null], - [2, 3, 5, 5] - ] -} ----- - -Work around this limitation by converting the field to single value with one of: - -* <> -* <> -* <> -* <> -* <> -* <> -* <> - -[source,console,esql-multivalued-fields-mv-into-null] ----- -POST /_query -{ - "query": "FROM mv | EVAL b=MV_MIN(b) | EVAL b + 2, a + b | LIMIT 4" -} ----- -// TEST[continued] - -[source,console-result] ----- -{ - "columns": [ - { "name": "a", "type": "long"}, - { "name": "b", "type": "long"}, - { "name": "b+2", "type": "long"}, - { "name": "a+b", "type": "long"} - ], - "values": [ - [1, 1, 3, 2], - [2, 3, 5, 5] - ] -} ----- - diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/dissect.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/dissect.asciidoc deleted file mode 100644 index e6206615342f7..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/dissect.asciidoc +++ /dev/null @@ -1,19 +0,0 @@ -[discrete] -[[esql-dissect]] -=== `DISSECT` - -`DISSECT` enables you to extract structured data out of a string. `DISSECT` -matches the string against a delimiter-based pattern, and extracts the specified -keys as columns. - -Refer to the <> for the -syntax of dissect patterns. - -[source.merge.styled,esql] ----- -include::{esql-specs}/dissect.csv-spec[tag=dissect] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/dissect.csv-spec[tag=dissect-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/drop.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/drop.asciidoc deleted file mode 100644 index 50e3b27fb1b28..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/drop.asciidoc +++ /dev/null @@ -1,18 +0,0 @@ -[discrete] -[[esql-drop]] -=== `DROP` - -Use `DROP` to remove columns: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=dropheight] ----- - -Rather than specify each column by name, you can use wildcards to drop all -columns with a name that matches a pattern: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=dropheightwithwildcard] ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/enrich.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/enrich.asciidoc deleted file mode 100644 index 1e489119d4ca3..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/enrich.asciidoc +++ /dev/null @@ -1,101 +0,0 @@ -[discrete] -[[esql-enrich]] -=== `ENRICH` - -**Syntax** - -[source,txt] ----- -ENRICH policy [ON match_field] [WITH [new_name1 = ]field1, [new_name2 = ]field2, ...] ----- - -*Parameters* - -`policy`:: -The name of the enrich policy. You need to <> -and <> the enrich policy first. - -`ON match_field`:: -The match field. `ENRICH` uses its value to look for records in the enrich -index. If not specified, the match will be performed on the column with the same -name as the `match_field` defined in the <>. - -`WITH fieldX`:: -The enrich fields from the enrich index that are added to the result as new -columns. If a column with the same name as the enrich field already exists, the -existing column will be replaced by the new column. If not specified, each of -the enrich fields defined in the policy is added - -`new_nameX =`:: -Enables you to change the name of the column that's added for each of the enrich -fields. Defaults to the enrich field name. - -*Description* - -`ENRICH` enables you to add data from existing indices as new columns using an -enrich policy. Refer to <> for information about setting up a -policy. - -image::images/esql/esql-enrich.png[align="center"] - -TIP: Before you can use `ENRICH`, you need to <>. - -*Examples* - -// tag::examples[] -The following example uses the `languages_policy` enrich policy to add a new -column for each enrich field defined in the policy. The match is performed using -the `match_field` defined in the <> and -requires that the input table has a column with the same name (`language_code` -in this example). `ENRICH` will look for records in the -<> based on the match field value. - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs-ignoreCsvTests.csv-spec[tag=enrich] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs-ignoreCsvTests.csv-spec[tag=enrich-result] -|=== - -To use a column with a different name than the `match_field` defined in the -policy as the match field, use `ON `: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs-ignoreCsvTests.csv-spec[tag=enrich_on] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs-ignoreCsvTests.csv-spec[tag=enrich_on-result] -|=== - -By default, each of the enrich fields defined in the policy is added as a -column. To explicitly select the enrich fields that are added, use -`WITH , ...`: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs-ignoreCsvTests.csv-spec[tag=enrich_with] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs-ignoreCsvTests.csv-spec[tag=enrich_with-result] -|=== - -You can rename the columns that are added using `WITH new_name=`: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs-ignoreCsvTests.csv-spec[tag=enrich_rename] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs-ignoreCsvTests.csv-spec[tag=enrich_rename-result] -|=== - -In case of name collisions, the newly created columns will override existing -columns. -// end::examples[] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/eval.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/eval.asciidoc deleted file mode 100644 index a0a78f2a3bf97..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/eval.asciidoc +++ /dev/null @@ -1,30 +0,0 @@ -[discrete] -[[esql-eval]] -=== `EVAL` -`EVAL` enables you to append new columns: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=eval] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=eval-result] -|=== - -If the specified column already exists, the existing column will be dropped, and -the new column will be appended to the table: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=evalReplace] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=evalReplace-result] -|=== - -[discrete] -==== Functions -`EVAL` supports various functions for calculating values. Refer to -<> for more information. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/grok.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/grok.asciidoc deleted file mode 100644 index 914c13b2320eb..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/grok.asciidoc +++ /dev/null @@ -1,21 +0,0 @@ -[discrete] -[[esql-grok]] -=== `GROK` - -`GROK` enables you to extract structured data out of a string. `GROK` matches -the string against patterns, based on regular expressions, and extracts the -specified patterns as columns. - -Refer to the <> for the syntax for -of grok patterns. - -For example: - -[source.merge.styled,esql] ----- -include::{esql-specs}/grok.csv-spec[tag=grok] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/grok.csv-spec[tag=grok-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/keep.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/keep.asciidoc deleted file mode 100644 index 3e54e5a7d1c5c..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/keep.asciidoc +++ /dev/null @@ -1,35 +0,0 @@ -[discrete] -[[esql-keep]] -=== `KEEP` - -The `KEEP` command enables you to specify what columns are returned and the -order in which they are returned. - -To limit the columns that are returned, use a comma-separated list of column -names. The columns are returned in the specified order: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=keep] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=keep-result] -|=== - -Rather than specify each column by name, you can use wildcards to return all -columns with a name that matches a pattern: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=keepWildcard] ----- - -The asterisk wildcard (`*`) by itself translates to all columns that do not -match the other arguments. This query will first return all columns with a name -that starts with an h, followed by all other columns: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=keepDoubleWildcard] ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/limit.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/limit.asciidoc deleted file mode 100644 index c02b534af59e1..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/limit.asciidoc +++ /dev/null @@ -1,13 +0,0 @@ -[discrete] -[[esql-limit]] -=== `LIMIT` - -The `LIMIT` processing command enables you to limit the number of rows: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=limit] ----- - -If not specified, `LIMIT` defaults to `500`. A single query will not return -more than 10,000 rows, regardless of the `LIMIT` value. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/mv_expand.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/mv_expand.asciidoc deleted file mode 100644 index d62b28aabe440..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/mv_expand.asciidoc +++ /dev/null @@ -1,14 +0,0 @@ -[discrete] -[[esql-mv_expand]] -=== `MV_EXPAND` - -The `MV_EXPAND` processing command expands multivalued fields into one row per value, duplicating other fields: - -[source.merge.styled,esql] ----- -include::{esql-specs}/mv_expand.csv-spec[tag=simple] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/mv_expand.csv-spec[tag=simple-result] -|=== diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/rename.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/rename.asciidoc deleted file mode 100644 index 1dda424317976..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/rename.asciidoc +++ /dev/null @@ -1,27 +0,0 @@ -[discrete] -[[esql-rename]] -=== `RENAME` - -Use `RENAME` to rename a column using the following syntax: - -[source,esql] ----- -RENAME AS ----- - -For example: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=rename] ----- - -If a column with the new name already exists, it will be replaced by the new -column. - -Multiple columns can be renamed with a single `RENAME` command: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=renameMultipleColumns] ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/sort.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/sort.asciidoc deleted file mode 100644 index 76a9193375932..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/sort.asciidoc +++ /dev/null @@ -1,37 +0,0 @@ -[discrete] -[[esql-sort]] -=== `SORT` -Use the `SORT` command to sort rows on one or more fields: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=sort] ----- - -The default sort order is ascending. Set an explicit sort order using `ASC` or -`DESC`: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=sortDesc] ----- - -Two rows with the same sort key are considered equal. You can provide additional -sort expressions to act as tie breakers: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=sortTie] ----- - -[discrete] -==== `null` values -By default, `null` values are treated as being larger than any other value. With -an ascending sort order, `null` values are sorted last, and with a descending -sort order, `null` values are sorted first. You can change that by providing -`NULLS FIRST` or `NULLS LAST`: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=sortNullsFirst] ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/stats.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/stats.asciidoc deleted file mode 100644 index 71f4470e3dfb0..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/stats.asciidoc +++ /dev/null @@ -1,45 +0,0 @@ -[discrete] -[[esql-stats-by]] -=== `STATS ... BY` -Use `STATS ... BY` to group rows according to a common value and calculate one -or more aggregated values over the grouped rows. - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=stats] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=stats-result] -|=== - -If `BY` is omitted, the output table contains exactly one row with the -aggregations applied over the entire dataset: - -[source.merge.styled,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=statsWithoutBy] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/docs.csv-spec[tag=statsWithoutBy-result] -|=== - -It's possible to calculate multiple values: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=statsCalcMultipleValues] ----- - -It's also possible to group by multiple values (only supported for long and -keyword family fields): - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=statsGroupByMultipleValues] ----- - -The following aggregation functions are supported: - -include::../functions/aggregation-functions.asciidoc[tag=agg_list] diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/where.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/where.asciidoc deleted file mode 100644 index 8dd55df12b9e7..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/processing_commands/where.asciidoc +++ /dev/null @@ -1,33 +0,0 @@ -[discrete] -[[esql-where]] -=== `WHERE` - -Use `WHERE` to produce a table that contains all the rows from the input table -for which the provided condition evaluates to `true`: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=where] ----- - -Which, if `still_hired` is a boolean field, can be simplified to: - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=whereBoolean] ----- - -[discrete] -==== Operators - -Refer to <> for an overview of the supported operators. - -[discrete] -==== Functions -`WHERE` supports various functions for calculating values. Refer to -<> for more information. - -[source,esql] ----- -include::{esql-specs}/docs.csv-spec[tag=whereFunction] ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/from.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/from.asciidoc deleted file mode 100644 index 5718bfc27ac1c..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/from.asciidoc +++ /dev/null @@ -1,37 +0,0 @@ -[discrete] -[[esql-from]] -=== `FROM` - -The `FROM` source command returns a table with up to 10,000 documents from a -data stream, index, or alias. Each row in the resulting table represents a -document. Each column corresponds to a field, and can be accessed by the name -of that field. - -[source,esql] ----- -FROM employees ----- - -You can use <> to refer to indices, aliases -and data streams. This can be useful for time series data, for example to access -today's index: - -[source,esql] ----- -FROM ----- - -Use comma-separated lists or wildcards to query multiple data streams, indices, -or aliases: - -[source,esql] ----- -FROM employees-00001,other-employees-* ----- - -Use the `METADATA` directive to enable <>: - -[source,esql] ----- -FROM employees [METADATA _id] ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/row.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/row.asciidoc deleted file mode 100644 index edfe5ecbf7cf3..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/row.asciidoc +++ /dev/null @@ -1,29 +0,0 @@ -[discrete] -[[esql-row]] -=== `ROW` - -The `ROW` source command produces a row with one or more columns with values -that you specify. This can be useful for testing. - -[source.merge.styled,esql] ----- -include::{esql-specs}/row.csv-spec[tag=example] ----- -[%header.monospaced.styled,format=dsv,separator=|] -|=== -include::{esql-specs}/row.csv-spec[tag=example-result] -|=== - -Use square brackets to create multi-value columns: - -[source,esql] ----- -include::{esql-specs}/row.csv-spec[tag=multivalue] ----- - -`ROW` supports the use of <>: - -[source,esql] ----- -include::{esql-specs}/row.csv-spec[tag=function] ----- diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/show.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/show.asciidoc deleted file mode 100644 index 956baf628e9f3..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/source_commands/show.asciidoc +++ /dev/null @@ -1,10 +0,0 @@ -[discrete] -[[esql-show]] -=== `SHOW ` - -The `SHOW ` source command returns information about the deployment and -its capabilities: - -* Use `SHOW INFO` to return the deployment's version, build date and hash. -* Use `SHOW FUNCTIONS` to return a list of all supported functions and a -synopsis of each function. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/task_management.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/task_management.asciidoc deleted file mode 100644 index 96a624c89bf7d..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/documentation/task_management.asciidoc +++ /dev/null @@ -1,35 +0,0 @@ -[[esql-task-management]] -== {esql} task management - -++++ -Task management -++++ - -You can list running {esql} queries with the <>: - -[source,console,id=esql-task-management-get-all] ----- -GET /_tasks?pretty&detailed&group_by=parents&human&actions=*data/read/esql ----- - -Which returns a list of statuses like this: - -[source,js] ----- -include::{esql-specs}/query_task.json[] ----- -// NOTCONSOLE -// Tested in a unit test - -<1> The user submitted query. -<2> Time the query has been running. - -You can use this to find long running queries and, if you need to, cancel them -with the <>: - -[source,console,id=esql-task-management-cancelEsqlQueryRequestTests] ----- -POST _tasks/2j8UKw1bRO283PMwDugNNg:5326/_cancel ----- - -It may take a few seconds for the query to be stopped. diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.g4 b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.g4 deleted file mode 100644 index 747c1fdcd1921..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.g4 +++ /dev/null @@ -1,191 +0,0 @@ -lexer grammar EsqlBaseLexer; - -DISSECT : 'dissect' -> pushMode(EXPRESSION); -DROP : 'drop' -> pushMode(SOURCE_IDENTIFIERS); -ENRICH : 'enrich' -> pushMode(SOURCE_IDENTIFIERS); -EVAL : 'eval' -> pushMode(EXPRESSION); -EXPLAIN : 'explain' -> pushMode(EXPLAIN_MODE); -FROM : 'from' -> pushMode(SOURCE_IDENTIFIERS); -GROK : 'grok' -> pushMode(EXPRESSION); -INLINESTATS : 'inlinestats' -> pushMode(EXPRESSION); -KEEP : 'keep' -> pushMode(SOURCE_IDENTIFIERS); -LIMIT : 'limit' -> pushMode(EXPRESSION); -MV_EXPAND : 'mv_expand' -> pushMode(SOURCE_IDENTIFIERS); -PROJECT : 'project' -> pushMode(SOURCE_IDENTIFIERS); -RENAME : 'rename' -> pushMode(SOURCE_IDENTIFIERS); -ROW : 'row' -> pushMode(EXPRESSION); -SHOW : 'show' -> pushMode(EXPRESSION); -SORT : 'sort' -> pushMode(EXPRESSION); -STATS : 'stats' -> pushMode(EXPRESSION); -WHERE : 'where' -> pushMode(EXPRESSION); -UNKNOWN_CMD : ~[ \r\n\t[\]/]+ -> pushMode(EXPRESSION); - -LINE_COMMENT - : '//' ~[\r\n]* '\r'? '\n'? -> channel(HIDDEN) - ; - -MULTILINE_COMMENT - : '/*' (MULTILINE_COMMENT|.)*? '*/' -> channel(HIDDEN) - ; - -WS - : [ \r\n\t]+ -> channel(HIDDEN) - ; - - -mode EXPLAIN_MODE; -EXPLAIN_OPENING_BRACKET : '[' -> type(OPENING_BRACKET), pushMode(DEFAULT_MODE); -EXPLAIN_PIPE : '|' -> type(PIPE), popMode; -EXPLAIN_WS : WS -> channel(HIDDEN); -EXPLAIN_LINE_COMMENT : LINE_COMMENT -> channel(HIDDEN); -EXPLAIN_MULTILINE_COMMENT : MULTILINE_COMMENT -> channel(HIDDEN); - -mode EXPRESSION; - -PIPE : '|' -> popMode; - -fragment DIGIT - : [0-9] - ; - -fragment LETTER - : [A-Za-z] - ; - -fragment ESCAPE_SEQUENCE - : '\\' [tnr"\\] - ; - -fragment UNESCAPED_CHARS - : ~[\r\n"\\] - ; - -fragment EXPONENT - : [Ee] [+-]? DIGIT+ - ; - -STRING - : '"' (ESCAPE_SEQUENCE | UNESCAPED_CHARS)* '"' - | '"""' (~[\r\n])*? '"""' '"'? '"'? - ; - -INTEGER_LITERAL - : DIGIT+ - ; - -DECIMAL_LITERAL - : DIGIT+ DOT DIGIT* - | DOT DIGIT+ - | DIGIT+ (DOT DIGIT*)? EXPONENT - | DOT DIGIT+ EXPONENT - ; - -BY : 'by'; - -AND : 'and'; -ASC : 'asc'; -ASSIGN : '='; -COMMA : ','; -DESC : 'desc'; -DOT : '.'; -FALSE : 'false'; -FIRST : 'first'; -LAST : 'last'; -LP : '('; -IN: 'in'; -IS: 'is'; -LIKE: 'like'; -NOT : 'not'; -NULL : 'null'; -NULLS : 'nulls'; -OR : 'or'; -PARAM: '?'; -RLIKE: 'rlike'; -RP : ')'; -TRUE : 'true'; -INFO : 'info'; -FUNCTIONS : 'functions'; - -EQ : '=='; -NEQ : '!='; -LT : '<'; -LTE : '<='; -GT : '>'; -GTE : '>='; - -PLUS : '+'; -MINUS : '-'; -ASTERISK : '*'; -SLASH : '/'; -PERCENT : '%'; - -// Brackets are funny. We can happen upon a CLOSING_BRACKET in two ways - one -// way is to start in an explain command which then shifts us to expression -// mode. Thus, the two popModes on CLOSING_BRACKET. The other way could as -// the start of a multivalued field constant. To line up with the double pop -// the explain mode needs, we double push when we see that. -OPENING_BRACKET : '[' -> pushMode(EXPRESSION), pushMode(EXPRESSION); -CLOSING_BRACKET : ']' -> popMode, popMode; - - -UNQUOTED_IDENTIFIER - : LETTER (LETTER | DIGIT | '_')* - // only allow @ at beginning of identifier to keep the option to allow @ as infix operator in the future - // also, single `_` and `@` characters are not valid identifiers - | ('_' | '@') (LETTER | DIGIT | '_')+ - ; - -QUOTED_IDENTIFIER - : '`' ( ~'`' | '``' )* '`' - ; - -EXPR_LINE_COMMENT - : LINE_COMMENT -> channel(HIDDEN) - ; - -EXPR_MULTILINE_COMMENT - : MULTILINE_COMMENT -> channel(HIDDEN) - ; - -EXPR_WS - : WS -> channel(HIDDEN) - ; - - - -mode SOURCE_IDENTIFIERS; - -SRC_PIPE : '|' -> type(PIPE), popMode; -SRC_OPENING_BRACKET : '[' -> type(OPENING_BRACKET), pushMode(SOURCE_IDENTIFIERS), pushMode(SOURCE_IDENTIFIERS); -SRC_CLOSING_BRACKET : ']' -> popMode, popMode, type(CLOSING_BRACKET); -SRC_COMMA : ',' -> type(COMMA); -SRC_ASSIGN : '=' -> type(ASSIGN); -AS : 'as'; -METADATA: 'metadata'; -ON : 'on'; -WITH : 'with'; - -SRC_UNQUOTED_IDENTIFIER - : SRC_UNQUOTED_IDENTIFIER_PART+ - ; - -fragment SRC_UNQUOTED_IDENTIFIER_PART - : ~[=`|,[\]/ \t\r\n]+ - | '/' ~[*/] // allow single / but not followed by another / or * which would start a comment - ; - -SRC_QUOTED_IDENTIFIER - : QUOTED_IDENTIFIER - ; - -SRC_LINE_COMMENT - : LINE_COMMENT -> channel(HIDDEN) - ; - -SRC_MULTILINE_COMMENT - : MULTILINE_COMMENT -> channel(HIDDEN) - ; - -SRC_WS - : WS -> channel(HIDDEN) - ; diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.tokens b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.tokens deleted file mode 100644 index d8761f5eb0d73..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_lexer.tokens +++ /dev/null @@ -1,137 +0,0 @@ -DISSECT=1 -DROP=2 -ENRICH=3 -EVAL=4 -EXPLAIN=5 -FROM=6 -GROK=7 -INLINESTATS=8 -KEEP=9 -LIMIT=10 -MV_EXPAND=11 -PROJECT=12 -RENAME=13 -ROW=14 -SHOW=15 -SORT=16 -STATS=17 -WHERE=18 -UNKNOWN_CMD=19 -LINE_COMMENT=20 -MULTILINE_COMMENT=21 -WS=22 -EXPLAIN_WS=23 -EXPLAIN_LINE_COMMENT=24 -EXPLAIN_MULTILINE_COMMENT=25 -PIPE=26 -STRING=27 -INTEGER_LITERAL=28 -DECIMAL_LITERAL=29 -BY=30 -AND=31 -ASC=32 -ASSIGN=33 -COMMA=34 -DESC=35 -DOT=36 -FALSE=37 -FIRST=38 -LAST=39 -LP=40 -IN=41 -IS=42 -LIKE=43 -NOT=44 -NULL=45 -NULLS=46 -OR=47 -PARAM=48 -RLIKE=49 -RP=50 -TRUE=51 -INFO=52 -FUNCTIONS=53 -EQ=54 -NEQ=55 -LT=56 -LTE=57 -GT=58 -GTE=59 -PLUS=60 -MINUS=61 -ASTERISK=62 -SLASH=63 -PERCENT=64 -OPENING_BRACKET=65 -CLOSING_BRACKET=66 -UNQUOTED_IDENTIFIER=67 -QUOTED_IDENTIFIER=68 -EXPR_LINE_COMMENT=69 -EXPR_MULTILINE_COMMENT=70 -EXPR_WS=71 -AS=72 -METADATA=73 -ON=74 -WITH=75 -SRC_UNQUOTED_IDENTIFIER=76 -SRC_QUOTED_IDENTIFIER=77 -SRC_LINE_COMMENT=78 -SRC_MULTILINE_COMMENT=79 -SRC_WS=80 -EXPLAIN_PIPE=81 -'dissect'=1 -'drop'=2 -'enrich'=3 -'eval'=4 -'explain'=5 -'from'=6 -'grok'=7 -'inlinestats'=8 -'keep'=9 -'limit'=10 -'mv_expand'=11 -'project'=12 -'rename'=13 -'row'=14 -'show'=15 -'sort'=16 -'stats'=17 -'where'=18 -'by'=30 -'and'=31 -'asc'=32 -'desc'=35 -'.'=36 -'false'=37 -'first'=38 -'last'=39 -'('=40 -'in'=41 -'is'=42 -'like'=43 -'not'=44 -'null'=45 -'nulls'=46 -'or'=47 -'?'=48 -'rlike'=49 -')'=50 -'true'=51 -'info'=52 -'functions'=53 -'=='=54 -'!='=55 -'<'=56 -'<='=57 -'>'=58 -'>='=59 -'+'=60 -'-'=61 -'*'=62 -'/'=63 -'%'=64 -']'=66 -'as'=72 -'metadata'=73 -'on'=74 -'with'=75 diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_parser.g4 b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_parser.g4 deleted file mode 100644 index 044e920744375..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_parser.g4 +++ /dev/null @@ -1,246 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -parser grammar EsqlBaseParser; - -options {tokenVocab=EsqlBaseLexer;} - -singleStatement - : query EOF - ; - -query - : sourceCommand #singleCommandQuery - | query PIPE processingCommand #compositeQuery - ; - -sourceCommand - : explainCommand - | fromCommand - | rowCommand - | showCommand - ; - -processingCommand - : evalCommand - | inlinestatsCommand - | limitCommand - | keepCommand - | sortCommand - | statsCommand - | whereCommand - | dropCommand - | renameCommand - | dissectCommand - | grokCommand - | enrichCommand - | mvExpandCommand - ; - -whereCommand - : WHERE booleanExpression - ; - -booleanExpression - : NOT booleanExpression #logicalNot - | valueExpression #booleanDefault - | regexBooleanExpression #regexExpression - | left=booleanExpression operator=AND right=booleanExpression #logicalBinary - | left=booleanExpression operator=OR right=booleanExpression #logicalBinary - | valueExpression (NOT)? IN LP valueExpression (COMMA valueExpression)* RP #logicalIn - | valueExpression IS NOT? NULL #isNull - ; - -regexBooleanExpression - : valueExpression (NOT)? kind=LIKE pattern=string - | valueExpression (NOT)? kind=RLIKE pattern=string - ; - -valueExpression - : operatorExpression #valueExpressionDefault - | left=operatorExpression comparisonOperator right=operatorExpression #comparison - ; - -operatorExpression - : primaryExpression #operatorExpressionDefault - | operator=(MINUS | PLUS) operatorExpression #arithmeticUnary - | left=operatorExpression operator=(ASTERISK | SLASH | PERCENT) right=operatorExpression #arithmeticBinary - | left=operatorExpression operator=(PLUS | MINUS) right=operatorExpression #arithmeticBinary - ; - -primaryExpression - : constant #constantDefault - | qualifiedName #dereference - | functionExpression #function - | LP booleanExpression RP #parenthesizedExpression - ; - -functionExpression - : identifier LP (ASTERISK | (booleanExpression (COMMA booleanExpression)*))? RP - ; - -rowCommand - : ROW fields - ; - -fields - : field (COMMA field)* - ; - -field - : booleanExpression - | qualifiedName ASSIGN booleanExpression - ; - -fromCommand - : FROM sourceIdentifier (COMMA sourceIdentifier)* metadata? - ; - -metadata - : OPENING_BRACKET METADATA sourceIdentifier (COMMA sourceIdentifier)* CLOSING_BRACKET - ; - - -evalCommand - : EVAL fields - ; - -statsCommand - : STATS fields? (BY grouping)? - ; - -inlinestatsCommand - : INLINESTATS fields (BY grouping)? - ; - -grouping - : qualifiedName (COMMA qualifiedName)* - ; - -sourceIdentifier - : SRC_UNQUOTED_IDENTIFIER - | SRC_QUOTED_IDENTIFIER - ; - -qualifiedName - : identifier (DOT identifier)* - ; - - -identifier - : UNQUOTED_IDENTIFIER - | QUOTED_IDENTIFIER - ; - -constant - : NULL #nullLiteral - | integerValue UNQUOTED_IDENTIFIER #qualifiedIntegerLiteral - | decimalValue #decimalLiteral - | integerValue #integerLiteral - | booleanValue #booleanLiteral - | PARAM #inputParam - | string #stringLiteral - | OPENING_BRACKET numericValue (COMMA numericValue)* CLOSING_BRACKET #numericArrayLiteral - | OPENING_BRACKET booleanValue (COMMA booleanValue)* CLOSING_BRACKET #booleanArrayLiteral - | OPENING_BRACKET string (COMMA string)* CLOSING_BRACKET #stringArrayLiteral - ; - -limitCommand - : LIMIT INTEGER_LITERAL - ; - -sortCommand - : SORT orderExpression (COMMA orderExpression)* - ; - -orderExpression - : booleanExpression ordering=(ASC | DESC)? (NULLS nullOrdering=(FIRST | LAST))? - ; - -keepCommand - : KEEP sourceIdentifier (COMMA sourceIdentifier)* - | PROJECT sourceIdentifier (COMMA sourceIdentifier)* - ; - -dropCommand - : DROP sourceIdentifier (COMMA sourceIdentifier)* - ; - -renameCommand - : RENAME renameClause (COMMA renameClause)* - ; - -renameClause: - oldName=sourceIdentifier AS newName=sourceIdentifier - ; - -dissectCommand - : DISSECT primaryExpression string commandOptions? - ; - -grokCommand - : GROK primaryExpression string - ; - -mvExpandCommand - : MV_EXPAND sourceIdentifier - ; - -commandOptions - : commandOption (COMMA commandOption)* - ; - -commandOption - : identifier ASSIGN constant - ; - -booleanValue - : TRUE | FALSE - ; - -numericValue - : decimalValue - | integerValue - ; - -decimalValue - : (PLUS | MINUS)? DECIMAL_LITERAL - ; - -integerValue - : (PLUS | MINUS)? INTEGER_LITERAL - ; - -string - : STRING - ; - -comparisonOperator - : EQ | NEQ | LT | LTE | GT | GTE - ; - -explainCommand - : EXPLAIN subqueryExpression - ; - -subqueryExpression - : OPENING_BRACKET query CLOSING_BRACKET - ; - -showCommand - : SHOW INFO #showInfo - | SHOW FUNCTIONS #showFunctions - ; - -enrichCommand - : ENRICH policyName=sourceIdentifier (ON matchField=sourceIdentifier)? (WITH enrichWithClause (COMMA enrichWithClause)*)? - ; - -enrichWithClause - : (newName=sourceIdentifier ASSIGN)? enrichField=sourceIdentifier - ; diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_parser.tokens b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_parser.tokens deleted file mode 100644 index d8761f5eb0d73..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/language_definition/esql_base_parser.tokens +++ /dev/null @@ -1,137 +0,0 @@ -DISSECT=1 -DROP=2 -ENRICH=3 -EVAL=4 -EXPLAIN=5 -FROM=6 -GROK=7 -INLINESTATS=8 -KEEP=9 -LIMIT=10 -MV_EXPAND=11 -PROJECT=12 -RENAME=13 -ROW=14 -SHOW=15 -SORT=16 -STATS=17 -WHERE=18 -UNKNOWN_CMD=19 -LINE_COMMENT=20 -MULTILINE_COMMENT=21 -WS=22 -EXPLAIN_WS=23 -EXPLAIN_LINE_COMMENT=24 -EXPLAIN_MULTILINE_COMMENT=25 -PIPE=26 -STRING=27 -INTEGER_LITERAL=28 -DECIMAL_LITERAL=29 -BY=30 -AND=31 -ASC=32 -ASSIGN=33 -COMMA=34 -DESC=35 -DOT=36 -FALSE=37 -FIRST=38 -LAST=39 -LP=40 -IN=41 -IS=42 -LIKE=43 -NOT=44 -NULL=45 -NULLS=46 -OR=47 -PARAM=48 -RLIKE=49 -RP=50 -TRUE=51 -INFO=52 -FUNCTIONS=53 -EQ=54 -NEQ=55 -LT=56 -LTE=57 -GT=58 -GTE=59 -PLUS=60 -MINUS=61 -ASTERISK=62 -SLASH=63 -PERCENT=64 -OPENING_BRACKET=65 -CLOSING_BRACKET=66 -UNQUOTED_IDENTIFIER=67 -QUOTED_IDENTIFIER=68 -EXPR_LINE_COMMENT=69 -EXPR_MULTILINE_COMMENT=70 -EXPR_WS=71 -AS=72 -METADATA=73 -ON=74 -WITH=75 -SRC_UNQUOTED_IDENTIFIER=76 -SRC_QUOTED_IDENTIFIER=77 -SRC_LINE_COMMENT=78 -SRC_MULTILINE_COMMENT=79 -SRC_WS=80 -EXPLAIN_PIPE=81 -'dissect'=1 -'drop'=2 -'enrich'=3 -'eval'=4 -'explain'=5 -'from'=6 -'grok'=7 -'inlinestats'=8 -'keep'=9 -'limit'=10 -'mv_expand'=11 -'project'=12 -'rename'=13 -'row'=14 -'show'=15 -'sort'=16 -'stats'=17 -'where'=18 -'by'=30 -'and'=31 -'asc'=32 -'desc'=35 -'.'=36 -'false'=37 -'first'=38 -'last'=39 -'('=40 -'in'=41 -'is'=42 -'like'=43 -'not'=44 -'null'=45 -'nulls'=46 -'or'=47 -'?'=48 -'rlike'=49 -')'=50 -'true'=51 -'info'=52 -'functions'=53 -'=='=54 -'!='=55 -'<'=56 -'<='=57 -'>'=58 -'>='=59 -'+'=60 -'-'=61 -'*'=62 -'/'=63 -'%'=64 -']'=66 -'as'=72 -'metadata'=73 -'on'=74 -'with'=75 diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/add_required_kb_resource_metadata.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/add_required_kb_resource_metadata.test.ts index c66c18cd434ad..48aa99c2e09af 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/add_required_kb_resource_metadata.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/add_required_kb_resource_metadata.test.ts @@ -7,9 +7,10 @@ import { addRequiredKbResourceMetadata } from './add_required_kb_resource_metadata'; import { mockExampleQueryDocsFromDirectoryLoader } from '../../../__mocks__/docs_from_directory_loader'; +import { SECURITY_LABS_RESOURCE } from '../../../routes/knowledge_base/constants'; describe('addRequiredKbResourceMetadata', () => { - const kbResource = 'esql'; + const kbResource = SECURITY_LABS_RESOURCE; test('it includes the original metadata properties', () => { const EXPECTED_ADDITIONAL_KEYS_COUNT = 2; // two keys, `kbResource` and `required` diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.test.ts deleted file mode 100644 index 9c1c5976fd550..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.test.ts +++ /dev/null @@ -1,125 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Logger } from '@kbn/core/server'; - -import { addRequiredKbResourceMetadata } from './add_required_kb_resource_metadata'; -import { loadESQL } from './esql_loader'; -import { - mockEsqlDocsFromDirectoryLoader, - mockEsqlLanguageDocsFromDirectoryLoader, - mockExampleQueryDocsFromDirectoryLoader, -} from '../../../__mocks__/docs_from_directory_loader'; -import { ESQL_RESOURCE } from '../../../routes/knowledge_base/constants'; -import { AIAssistantKnowledgeBaseDataClient } from '../../../ai_assistant_data_clients/knowledge_base'; - -let mockLoad = jest.fn(); - -jest.mock('langchain/document_loaders/fs/directory', () => ({ - DirectoryLoader: jest.fn().mockImplementation(() => ({ - load: mockLoad, - })), -})); - -jest.mock('langchain/document_loaders/fs/text', () => ({ - TextLoader: jest.fn().mockImplementation(() => ({})), -})); - -const kbDataClient = { - addKnowledgeBaseDocuments: jest.fn().mockResolvedValue(['1', '2', '3', '4', '5']), -} as unknown as AIAssistantKnowledgeBaseDataClient; - -const logger = { - info: jest.fn(), - error: jest.fn(), -} as unknown as Logger; - -describe('loadESQL', () => { - beforeEach(() => { - jest.clearAllMocks(); - - mockLoad = jest - .fn() - .mockReturnValueOnce(mockEsqlDocsFromDirectoryLoader) - .mockReturnValueOnce(mockEsqlLanguageDocsFromDirectoryLoader) - .mockReturnValueOnce(mockExampleQueryDocsFromDirectoryLoader); - }); - - describe('loadESQL', () => { - beforeEach(async () => { - await loadESQL(kbDataClient, logger); - }); - - it('loads ES|QL docs, language files, and example queries into the Knowledge Base', async () => { - expect(kbDataClient.addKnowledgeBaseDocuments).toHaveBeenCalledWith({ - documents: [ - ...addRequiredKbResourceMetadata({ - docs: mockEsqlDocsFromDirectoryLoader, - kbResource: ESQL_RESOURCE, - required: false, - }), - ...addRequiredKbResourceMetadata({ - docs: mockEsqlLanguageDocsFromDirectoryLoader, - kbResource: ESQL_RESOURCE, - required: false, - }), - ...addRequiredKbResourceMetadata({ - docs: mockExampleQueryDocsFromDirectoryLoader, - kbResource: ESQL_RESOURCE, - required: true, - }), - ], - global: true, - }); - }); - - it('logs the expected (distinct) counts for each category of documents', async () => { - expect((logger.info as jest.Mock).mock.calls[0][0]).toEqual( - 'Loading 1 ES|QL docs, 2 language docs, and 3 example queries into the Knowledge Base' - ); - }); - - it('logs the expected total of all documents loaded', async () => { - expect((logger.info as jest.Mock).mock.calls[1][0]).toEqual( - 'Loaded 5 ES|QL docs, language docs, and example queries into the Knowledge Base' - ); - }); - - it('does NOT log an error in the happy path', async () => { - expect(logger.error).not.toHaveBeenCalled(); - }); - }); - - it('returns true if documents were loaded', async () => { - (kbDataClient.addKnowledgeBaseDocuments as jest.Mock).mockResolvedValueOnce([ - 'this is a response', - ]); - - const result = await loadESQL(kbDataClient, logger); - - expect(result).toBe(true); - }); - - it('returns false if documents were NOT loaded', async () => { - (kbDataClient.addKnowledgeBaseDocuments as jest.Mock).mockResolvedValueOnce([]); - - const result = await loadESQL(kbDataClient, logger); - - expect(result).toBe(false); - }); - - it('logs the expected error if loading fails', async () => { - const error = new Error('Failed to load documents'); - (kbDataClient.addKnowledgeBaseDocuments as jest.Mock).mockRejectedValueOnce(error); - - await loadESQL(kbDataClient, logger); - - expect(logger.error).toHaveBeenCalledWith( - 'Failed to load ES|QL docs, language docs, and example queries into the Knowledge Base\nError: Failed to load documents' - ); - }); -}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.ts deleted file mode 100644 index 4668671674bc3..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Logger } from '@kbn/core/server'; -import { DirectoryLoader } from 'langchain/document_loaders/fs/directory'; -import { TextLoader } from 'langchain/document_loaders/fs/text'; -import { resolve } from 'path'; -import { Document } from 'langchain/document'; - -import { Metadata } from '@kbn/elastic-assistant-common'; -import { addRequiredKbResourceMetadata } from './add_required_kb_resource_metadata'; -import { ESQL_RESOURCE } from '../../../routes/knowledge_base/constants'; -import { AIAssistantKnowledgeBaseDataClient } from '../../../ai_assistant_data_clients/knowledge_base'; - -/** - * Loads the ESQL docs and language files into the Knowledge Base. - */ -export const loadESQL = async ( - kbDataClient: AIAssistantKnowledgeBaseDataClient, - logger: Logger -): Promise => { - try { - const docsLoader = new DirectoryLoader( - resolve(__dirname, '../../../knowledge_base/esql/documentation'), - { - '.asciidoc': (path) => new TextLoader(path), - }, - true - ); - - const languageLoader = new DirectoryLoader( - resolve(__dirname, '../../../knowledge_base/esql/language_definition'), - { - '.g4': (path) => new TextLoader(path), - '.tokens': (path) => new TextLoader(path), - }, - true - ); - - const exampleQueriesLoader = new DirectoryLoader( - resolve(__dirname, '../../../knowledge_base/esql/example_queries'), - { - '.asciidoc': (path) => new TextLoader(path), - }, - true - ); - - const docs = (await docsLoader.load()) as Array>; - const languageDocs = (await languageLoader.load()) as Array>; - const rawExampleQueries = await exampleQueriesLoader.load(); - - // Add additional metadata to the example queries that indicates they are required KB documents: - const requiredExampleQueries = addRequiredKbResourceMetadata({ - docs: rawExampleQueries, - kbResource: ESQL_RESOURCE, - }) as Array>; - - // And make sure remaining docs have `kbResource:esql` - const docsWithMetadata = addRequiredKbResourceMetadata({ - docs, - kbResource: ESQL_RESOURCE, - required: false, - }) as Array>; - - const languageDocsWithMetadata = addRequiredKbResourceMetadata({ - docs: languageDocs, - kbResource: ESQL_RESOURCE, - required: false, - }) as Array>; - - logger.info( - `Loading ${docsWithMetadata.length} ES|QL docs, ${languageDocsWithMetadata.length} language docs, and ${requiredExampleQueries.length} example queries into the Knowledge Base` - ); - - const response = await kbDataClient.addKnowledgeBaseDocuments({ - documents: [...docsWithMetadata, ...languageDocsWithMetadata, ...requiredExampleQueries], - global: true, - }); - - logger.info( - `Loaded ${ - response?.length ?? 0 - } ES|QL docs, language docs, and example queries into the Knowledge Base` - ); - - return response.length > 0; - } catch (e) { - logger.error( - `Failed to load ES|QL docs, language docs, and example queries into the Knowledge Base\n${e}` - ); - return false; - } -}; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.test.ts index e45ad55999af6..4d32d7bc02da9 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.test.ts @@ -308,18 +308,7 @@ describe('ElasticsearchStore', () => { { query: { bool: { - must_not: [ - { - term: { - 'metadata.kbResource': 'esql', - }, - }, - { - term: { - 'metadata.required': true, - }, - }, - ], + must_not: [{ term: { 'metadata.required': true } }], must: [ { text_expansion: { @@ -340,18 +329,7 @@ describe('ElasticsearchStore', () => { { query: { bool: { - must: [ - { - term: { - 'metadata.kbResource': 'esql', - }, - }, - { - term: { - 'metadata.required': true, - }, - }, - ], + must: [{ term: { 'metadata.required': true } }], }, }, size: TERMS_QUERY_SIZE, @@ -374,18 +352,7 @@ describe('ElasticsearchStore', () => { { query: { bool: { - must_not: [ - { - term: { - 'metadata.kbResource': 'esql', - }, - }, - { - term: { - 'metadata.required': true, - }, - }, - ], + must_not: [{ term: { 'metadata.required': true } }], must: [ { text_expansion: { @@ -406,18 +373,7 @@ describe('ElasticsearchStore', () => { { query: { bool: { - must: [ - { - term: { - 'metadata.kbResource': 'esql', - }, - }, - { - term: { - 'metadata.required': true, - }, - }, - ], + must: [{ term: { 'metadata.required': true } }], }, }, size: TERMS_QUERY_SIZE, @@ -433,7 +389,6 @@ describe('ElasticsearchStore', () => { expect(reportEvent).toHaveBeenCalledWith(KNOWLEDGE_BASE_EXECUTION_SUCCESS_EVENT.eventType, { model: '.elser_model_2', - resourceAccessed: 'esql', responseTime: 142, resultCount: 2, }); @@ -446,7 +401,6 @@ describe('ElasticsearchStore', () => { expect(reportEvent).toHaveBeenCalledWith(KNOWLEDGE_BASE_EXECUTION_ERROR_EVENT.eventType, { model: '.elser_model_2', - resourceAccessed: 'esql', errorMessage: 'Oh no!', }); }); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts index 48ea50d9d4fe8..78c1b104685ad 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts @@ -26,7 +26,6 @@ import { getTermsSearchQuery } from './helpers/get_terms_search_query'; import { getVectorSearchQuery } from './helpers/get_vector_search_query'; import type { MsearchResponse } from './helpers/types'; import { - ESQL_RESOURCE, KNOWLEDGE_BASE_INDEX_PATTERN, KNOWLEDGE_BASE_INGEST_PIPELINE, } from '../../../routes/knowledge_base/constants'; @@ -72,7 +71,7 @@ export class ElasticsearchStore extends VectorStore { private readonly logger: Logger; private readonly telemetry: AnalyticsServiceSetup; private readonly model: string; - private kbResource: string; + private kbResource?: string; _vectorstoreType(): string { return 'elasticsearch'; @@ -93,7 +92,7 @@ export class ElasticsearchStore extends VectorStore { this.logger = logger; this.telemetry = telemetry; this.model = model ?? '.elser_model_2'; - this.kbResource = kbResource ?? ESQL_RESOURCE; + this.kbResource = kbResource; this.kbDataClient = kbDataClient; } @@ -269,7 +268,7 @@ export class ElasticsearchStore extends VectorStore { this.telemetry.reportEvent(KNOWLEDGE_BASE_EXECUTION_SUCCESS_EVENT.eventType, { model: this.model, - resourceAccessed: this.kbResource, + ...(this.kbResource != null ? { resourceAccessed: this.kbResource } : {}), resultCount: results.length, responseTime: result.took ?? 0, }); @@ -288,7 +287,7 @@ export class ElasticsearchStore extends VectorStore { const error = transformError(e); this.telemetry.reportEvent(KNOWLEDGE_BASE_EXECUTION_ERROR_EVENT.eventType, { model: this.model, - resourceAccessed: this.kbResource, + ...(this.kbResource != null ? { resourceAccessed: this.kbResource } : {}), errorMessage: error.message, }); this.logger.error(e); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/helpers/get_required_kb_docs_terms_query_dsl.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/helpers/get_required_kb_docs_terms_query_dsl.ts index ba5af8c3bfef7..df3e8f42ad63b 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/helpers/get_required_kb_docs_terms_query_dsl.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/helpers/get_required_kb_docs_terms_query_dsl.ts @@ -20,13 +20,17 @@ import type { Field, FieldValue, QueryDslTermQuery } from '@elastic/elasticsearc * @returns An array of `term`s that may be used in a `bool` Elasticsearch DSL query to filter in/out required KB documents */ export const getRequiredKbDocsTermsQueryDsl = ( - kbResource: string + kbResource?: string ): Array>> => [ - { - term: { - 'metadata.kbResource': kbResource, - }, - }, + ...(kbResource != null + ? [ + { + term: { + 'metadata.kbResource': kbResource, + }, + }, + ] + : []), { term: { 'metadata.required': true, diff --git a/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts b/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts index 4ba95896d7058..5ff5ff894dffe 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts @@ -9,7 +9,7 @@ import type { EventTypeOpts } from '@kbn/core/server'; export const KNOWLEDGE_BASE_EXECUTION_SUCCESS_EVENT: EventTypeOpts<{ model: string; - resourceAccessed: string; + resourceAccessed?: string; resultCount: number; responseTime: number; }> = { @@ -25,6 +25,7 @@ export const KNOWLEDGE_BASE_EXECUTION_SUCCESS_EVENT: EventTypeOpts<{ type: 'keyword', _meta: { description: 'Which knowledge base resource was accessed', + optional: true, }, }, resultCount: { @@ -44,7 +45,7 @@ export const KNOWLEDGE_BASE_EXECUTION_SUCCESS_EVENT: EventTypeOpts<{ export const KNOWLEDGE_BASE_EXECUTION_ERROR_EVENT: EventTypeOpts<{ model: string; - resourceAccessed: string; + resourceAccessed?: string; errorMessage: string; }> = { eventType: 'knowledge_base_execution_error', @@ -59,6 +60,7 @@ export const KNOWLEDGE_BASE_EXECUTION_ERROR_EVENT: EventTypeOpts<{ type: 'keyword', _meta: { description: 'Which knowledge base resource was accessed', + optional: true, }, }, errorMessage: { diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/constants.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/constants.ts index e50faf8a434e2..89970611df0e9 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/constants.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/constants.ts @@ -5,13 +5,10 @@ * 2.0. */ -export const MODEL_EVALUATION_RESULTS_INDEX_PATTERN = - '.kibana-elastic-ai-assistant-evaluation-results'; export const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-kb'; export const KNOWLEDGE_BASE_INGEST_PIPELINE = '.kibana-elastic-ai-assistant-kb-ingest-pipeline'; // Query for determining if ESQL docs have been loaded, searches for a specific doc. Intended for the ElasticsearchStore.similaritySearch() // Note: We may want to add a tag of the resource name to the document metadata, so we can CRUD by specific resource export const ESQL_DOCS_LOADED_QUERY = 'You can chain processing commands, separated by a pipe character: `|`.'; -export const ESQL_RESOURCE = 'esql'; export const SECURITY_LABS_RESOURCE = 'security_labs'; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts index 78b7ac720dd1a..f10876c4be3ee 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts @@ -26,7 +26,7 @@ import { performChecks } from '../../helpers'; import { transformESSearchToKnowledgeBaseEntry } from '../../../ai_assistant_data_clients/knowledge_base/transforms'; import { EsKnowledgeBaseEntrySchema } from '../../../ai_assistant_data_clients/knowledge_base/types'; import { getKBUserFilter } from './utils'; -import { ESQL_RESOURCE, SECURITY_LABS_RESOURCE } from '../constants'; +import { SECURITY_LABS_RESOURCE } from '../constants'; export const findKnowledgeBaseEntriesRoute = (router: ElasticAssistantPluginRouter) => { router.versioned @@ -108,12 +108,6 @@ export const findKnowledgeBaseEntriesRoute = (router: ElasticAssistantPluginRout }); const systemEntries = [ - { - bucketId: 'esqlDocsId', - kbResource: ESQL_RESOURCE, - name: 'ES|QL documents', - required: true, - }, { bucketId: 'securityLabsId', kbResource: SECURITY_LABS_RESOURCE, diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts index 7f1d1d0149f56..6244599a2af27 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts @@ -36,6 +36,8 @@ describe('Get Knowledge Base Status Route', () => { isModelInstalled: jest.fn().mockResolvedValue(true), isSetupAvailable: jest.fn().mockResolvedValue(true), isModelDeployed: jest.fn().mockResolvedValue(true), + isSetupInProgress: false, + isSecurityLabsDocsLoaded: jest.fn().mockResolvedValue(true), }); getKnowledgeBaseStatusRoute(server.router); @@ -44,10 +46,19 @@ describe('Get Knowledge Base Status Route', () => { describe('Status codes', () => { test('returns 200 if all statuses are false', async () => { const response = await server.inject( - getGetKnowledgeBaseStatusRequest('esql'), + getGetKnowledgeBaseStatusRequest(), requestContextMock.convertContext(context) ); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + elser_exists: true, + index_exists: true, + is_setup_in_progress: false, + is_setup_available: true, + pipeline_exists: true, + security_labs_exists: true, + }); }); }); }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts index 3e4fcbb7f404b..833e674b68ffd 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts @@ -15,10 +15,8 @@ import { } from '@kbn/elastic-assistant-common'; import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; import { KibanaRequest } from '@kbn/core/server'; -import { getKbResource } from './get_kb_resource'; import { buildResponse } from '../../lib/build_response'; import { ElasticAssistantPluginRouter } from '../../types'; -import { ESQL_RESOURCE } from './constants'; import { isV2KnowledgeBaseEnabled } from '../helpers'; /** @@ -51,9 +49,6 @@ export const getKnowledgeBaseStatusRoute = (router: ElasticAssistantPluginRouter const logger = ctx.elasticAssistant.logger; try { - // Use asInternalUser - const kbResource = getKbResource(request); - // FF Check for V2 KB const v2KnowledgeBaseEnabled = isV2KnowledgeBaseEnabled({ context: ctx, request }); @@ -78,13 +73,11 @@ export const getKnowledgeBaseStatusRoute = (router: ElasticAssistantPluginRouter pipeline_exists: pipelineExists, }; - if (indexExists && isModelDeployed && kbResource === ESQL_RESOURCE) { - const esqlExists = await kbDataClient.isESQLDocsLoaded(); + if (indexExists && isModelDeployed) { const securityLabsExists = await kbDataClient.isSecurityLabsDocsLoaded(); return response.ok({ body: { ...body, - esql_exists: esqlExists, security_labs_exists: v2KnowledgeBaseEnabled ? securityLabsExists : true, }, }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.ts index b5abf30b2bf07..e57018cac3706 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.ts @@ -17,7 +17,6 @@ import { IKibanaResponse } from '@kbn/core/server'; import { buildResponse } from '../../lib/build_response'; import { ElasticAssistantPluginRouter } from '../../types'; import { isV2KnowledgeBaseEnabled } from '../helpers'; -import { ESQL_RESOURCE } from './constants'; // Since we're awaiting on ELSER setup, this could take a bit (especially if ML needs to autoscale) // Consider just returning if attempt was successful, and switch to client polling @@ -55,7 +54,6 @@ export const postKnowledgeBaseRoute = (router: ElasticAssistantPluginRouter) => const assistantContext = ctx.elasticAssistant; const core = ctx.core; const soClient = core.savedObjects.getClient(); - const kbResource = request.params.resource; // FF Check for V2 KB const v2KnowledgeBaseEnabled = isV2KnowledgeBaseEnabled({ context: ctx, request }); @@ -73,10 +71,8 @@ export const postKnowledgeBaseRoute = (router: ElasticAssistantPluginRouter) => return response.custom({ body: { success: false }, statusCode: 500 }); } - const installEsqlDocs = kbResource === ESQL_RESOURCE; await knowledgeBaseDataClient.setupKnowledgeBase({ soClient, - installEsqlDocs, installSecurityLabsDocs: v2KnowledgeBaseEnabled, }); diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index ba7a8795f7e08..67b9a57af1628 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -118,11 +118,6 @@ export const allowedExperimentalValues = Object.freeze({ */ assistantKnowledgeBaseByDefault: false, - /** - * Enables the NaturalLanguageESQLTool and disables the ESQLKnowledgeBaseTool, introduced in `8.16.0`. - */ - assistantNaturalLanguageESQLTool: false, - /** * Enables the Managed User section inside the new user details flyout. */ diff --git a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/common.ts b/x-pack/plugins/security_solution/server/assistant/tools/esql/common.ts similarity index 100% rename from x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/common.ts rename to x-pack/plugins/security_solution/server/assistant/tools/esql/common.ts diff --git a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/nl_to_esql_tool.test.ts b/x-pack/plugins/security_solution/server/assistant/tools/esql/nl_to_esql_tool.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/nl_to_esql_tool.test.ts rename to x-pack/plugins/security_solution/server/assistant/tools/esql/nl_to_esql_tool.test.ts diff --git a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/nl_to_esql_tool.ts b/x-pack/plugins/security_solution/server/assistant/tools/esql/nl_to_esql_tool.ts similarity index 100% rename from x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/nl_to_esql_tool.ts rename to x-pack/plugins/security_solution/server/assistant/tools/esql/nl_to_esql_tool.ts diff --git a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.test.ts b/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.test.ts deleted file mode 100644 index 589c95e8483bf..0000000000000 --- a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.test.ts +++ /dev/null @@ -1,135 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { DynamicTool } from '@langchain/core/tools'; -import { ESQL_KNOWLEDGE_BASE_TOOL } from './esql_language_knowledge_base_tool'; -import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; -import type { KibanaRequest } from '@kbn/core-http-server'; -import type { ExecuteConnectorRequestBody } from '@kbn/elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen'; -import { loggerMock } from '@kbn/logging-mocks'; -import type { AIAssistantKnowledgeBaseDataClient } from '@kbn/elastic-assistant-plugin/server/ai_assistant_data_clients/knowledge_base'; -import { getPromptSuffixForOssModel } from './common'; - -describe('EsqlLanguageKnowledgeBaseTool', () => { - const kbDataClient = jest.fn() as unknown as AIAssistantKnowledgeBaseDataClient; - const esClient = { - search: jest.fn().mockResolvedValue({}), - } as unknown as ElasticsearchClient; - const request = { - body: { - isEnabledKnowledgeBase: false, - alertsIndexPattern: '.alerts-security.alerts-default', - allow: ['@timestamp', 'cloud.availability_zone', 'user.name'], - allowReplacement: ['user.name'], - replacements: { key: 'value' }, - size: 20, - }, - } as unknown as KibanaRequest; - const logger = loggerMock.create(); - const rest = { - kbDataClient, - esClient, - logger, - request, - }; - - describe('isSupported', () => { - it('returns false if isEnabledKnowledgeBase is false', () => { - const params = { - isEnabledKnowledgeBase: false, - modelExists: true, - ...rest, - }; - - expect(ESQL_KNOWLEDGE_BASE_TOOL.isSupported(params)).toBe(false); - }); - - it('returns false if modelExists is false (the ELSER model is not installed)', () => { - const params = { - isEnabledKnowledgeBase: true, - modelExists: false, // <-- ELSER model is not installed - ...rest, - }; - - expect(ESQL_KNOWLEDGE_BASE_TOOL.isSupported(params)).toBe(false); - }); - - it('returns true if isEnabledKnowledgeBase and modelExists are true', () => { - const params = { - isEnabledKnowledgeBase: true, - modelExists: true, - ...rest, - }; - - expect(ESQL_KNOWLEDGE_BASE_TOOL.isSupported(params)).toBe(true); - }); - }); - - describe('getTool', () => { - it('returns null if isEnabledKnowledgeBase is false', () => { - const tool = ESQL_KNOWLEDGE_BASE_TOOL.getTool({ - isEnabledKnowledgeBase: false, - modelExists: true, - ...rest, - }); - - expect(tool).toBeNull(); - }); - - it('returns null if modelExists is false (the ELSER model is not installed)', () => { - const tool = ESQL_KNOWLEDGE_BASE_TOOL.getTool({ - isEnabledKnowledgeBase: true, - modelExists: false, // <-- ELSER model is not installed - ...rest, - }); - - expect(tool).toBeNull(); - }); - - it('should return a Tool instance if isEnabledKnowledgeBase and modelExists are true', () => { - const tool = ESQL_KNOWLEDGE_BASE_TOOL.getTool({ - isEnabledKnowledgeBase: true, - modelExists: true, - ...rest, - }); - - expect(tool?.name).toEqual('ESQLKnowledgeBaseTool'); - }); - - it('should return a tool with the expected tags', () => { - const tool = ESQL_KNOWLEDGE_BASE_TOOL.getTool({ - isEnabledKnowledgeBase: true, - modelExists: true, - ...rest, - }) as DynamicTool; - - expect(tool.tags).toEqual(['esql', 'query-generation', 'knowledge-base']); - }); - - it('should return tool with the expected description for OSS model', () => { - const tool = ESQL_KNOWLEDGE_BASE_TOOL.getTool({ - isEnabledKnowledgeBase: true, - modelExists: true, - isOssModel: true, - ...rest, - }) as DynamicTool; - - expect(tool.description).toContain(getPromptSuffixForOssModel('ESQLKnowledgeBaseTool')); - }); - - it('should return tool with the expected description for non-OSS model', () => { - const tool = ESQL_KNOWLEDGE_BASE_TOOL.getTool({ - isEnabledKnowledgeBase: true, - modelExists: true, - isOssModel: false, - ...rest, - }) as DynamicTool; - - expect(tool.description).not.toContain(getPromptSuffixForOssModel('ESQLKnowledgeBaseTool')); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.ts b/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.ts deleted file mode 100644 index 37e037898cd20..0000000000000 --- a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.ts +++ /dev/null @@ -1,80 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DynamicStructuredTool } from '@langchain/core/tools'; -import { DirectoryLoader } from 'langchain/document_loaders/fs/directory'; -import { TextLoader } from 'langchain/document_loaders/fs/text'; -import type { Document } from 'langchain/document'; -import { resolve } from 'path'; -import { z } from '@kbn/zod'; -import type { AssistantTool, AssistantToolParams } from '@kbn/elastic-assistant-plugin/server'; -import { ESQL_RESOURCE } from '@kbn/elastic-assistant-plugin/server/routes/knowledge_base/constants'; -import { APP_UI_ID } from '../../../../common'; -import { getPromptSuffixForOssModel } from './common'; - -const TOOL_NAME = 'ESQLKnowledgeBaseTool'; - -const toolDetails = { - id: 'esql-knowledge-base-tool', - name: TOOL_NAME, - description: - 'Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language. Input must always be the user query on a single line, with no other text. Your answer will be parsed as JSON, so never use quotes within the output and instead use backticks. Do not add any additional text to describe your output.', -}; -export const ESQL_KNOWLEDGE_BASE_TOOL: AssistantTool = { - ...toolDetails, - sourceRegister: APP_UI_ID, - isSupported: (params: AssistantToolParams): params is AssistantToolParams => { - const { kbDataClient, isEnabledKnowledgeBase, modelExists } = params; - return isEnabledKnowledgeBase && modelExists && kbDataClient != null; - }, - getTool(params: AssistantToolParams) { - if (!this.isSupported(params)) return null; - - const { kbDataClient, isOssModel } = params as AssistantToolParams; - if (kbDataClient == null) return null; - - return new DynamicStructuredTool({ - name: toolDetails.name, - description: - toolDetails.description + (isOssModel ? getPromptSuffixForOssModel(TOOL_NAME) : ''), - schema: z.object({ - question: z.string().describe(`The user's exact question about ESQL`), - }), - func: async (input) => { - const exampleQueriesLoader = new DirectoryLoader( - resolve( - __dirname, - '../../../../../elastic_assistant/server/knowledge_base/esql/example_queries' - ), - { - '.asciidoc': (path) => new TextLoader(path), - }, - true - ); - const rawExampleQueries = await exampleQueriesLoader.load(); - - const docs = await kbDataClient.getKnowledgeBaseDocumentEntries({ - kbResource: ESQL_RESOURCE, - query: input.question, - }); - - let legacyDocs: Document[] = []; - - if (!kbDataClient?.isV2KnowledgeBaseEnabled) { - legacyDocs = await kbDataClient.getKnowledgeBaseDocumentEntries({ - kbResource: 'unknown', - query: input.question, - }); - } - - return JSON.stringify([...rawExampleQueries, ...docs, ...legacyDocs]).substring(0, 50000); - }, - tags: ['esql', 'query-generation', 'knowledge-base'], - // TODO: Remove after ZodAny is fixed https://github.com/langchain-ai/langchainjs/blob/main/langchain-core/src/tools.ts - }) as unknown as DynamicStructuredTool; - }, -}; diff --git a/x-pack/plugins/security_solution/server/assistant/tools/index.test.ts b/x-pack/plugins/security_solution/server/assistant/tools/index.test.ts index 0d719adc80fe2..70d0daea037ed 100644 --- a/x-pack/plugins/security_solution/server/assistant/tools/index.test.ts +++ b/x-pack/plugins/security_solution/server/assistant/tools/index.test.ts @@ -13,7 +13,7 @@ describe('getAssistantTools', () => { }); it('should return an array of applicable tools', () => { - const tools = getAssistantTools({ naturalLanguageESQLToolEnabled: true }); + const tools = getAssistantTools({}); const minExpectedTools = 3; // 3 tools are currently implemented diff --git a/x-pack/plugins/security_solution/server/assistant/tools/index.ts b/x-pack/plugins/security_solution/server/assistant/tools/index.ts index fa0098dce1eec..a704aaa44d0a1 100644 --- a/x-pack/plugins/security_solution/server/assistant/tools/index.ts +++ b/x-pack/plugins/security_solution/server/assistant/tools/index.ts @@ -7,8 +7,7 @@ import type { AssistantTool } from '@kbn/elastic-assistant-plugin/server'; -import { ESQL_KNOWLEDGE_BASE_TOOL } from './esql_language_knowledge_base/esql_language_knowledge_base_tool'; -import { NL_TO_ESQL_TOOL } from './esql_language_knowledge_base/nl_to_esql_tool'; +import { NL_TO_ESQL_TOOL } from './esql/nl_to_esql_tool'; import { ALERT_COUNTS_TOOL } from './alert_counts/alert_counts_tool'; import { OPEN_AND_ACKNOWLEDGED_ALERTS_TOOL } from './open_and_acknowledged_alerts/open_and_acknowledged_alerts_tool'; import { ATTACK_DISCOVERY_TOOL } from './attack_discovery/attack_discovery_tool'; @@ -17,16 +16,14 @@ import { KNOWLEDGE_BASE_WRITE_TOOL } from './knowledge_base/knowledge_base_write import { SECURITY_LABS_KNOWLEDGE_BASE_TOOL } from './security_labs/security_labs_tool'; export const getAssistantTools = ({ - naturalLanguageESQLToolEnabled, assistantKnowledgeBaseByDefault, }: { - naturalLanguageESQLToolEnabled?: boolean; assistantKnowledgeBaseByDefault?: boolean; }): AssistantTool[] => { const tools = [ ALERT_COUNTS_TOOL, ATTACK_DISCOVERY_TOOL, - naturalLanguageESQLToolEnabled ? NL_TO_ESQL_TOOL : ESQL_KNOWLEDGE_BASE_TOOL, + NL_TO_ESQL_TOOL, KNOWLEDGE_BASE_RETRIEVAL_TOOL, KNOWLEDGE_BASE_WRITE_TOOL, OPEN_AND_ACKNOWLEDGED_ALERTS_TOOL, diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 1becac2c75f71..1f144f8189ed7 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -536,8 +536,6 @@ export class Plugin implements ISecuritySolutionPlugin { plugins.elasticAssistant.registerTools( APP_UI_ID, getAssistantTools({ - naturalLanguageESQLToolEnabled: - config.experimentalFeatures.assistantNaturalLanguageESQLTool, assistantKnowledgeBaseByDefault: config.experimentalFeatures.assistantKnowledgeBaseByDefault, }) From 3b6cfb685d29e5db8c66c4239e709485a81d0db0 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 9 Oct 2024 08:26:43 -0600 Subject: [PATCH 069/110] Use dashboard factory directly instead of pulling from registry (#193480) PR removes dashboard embeddable from embeddable registry. No other application accesses the dashboard embeddable from the embeddable registry so registration is not needed. Plus, once lens embeddable is converted to a react embeddable, then we can remove the legacy embeddable registry prior to refactoring dashboard to not be an embeddable (which will be a large effort and we want to remove the legacy embeddable registry as soon as possible to avoid any one else using it). --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine --- .../dashboard_saved_object_references.ts | 20 +++++---- .../external_api/dashboard_renderer.test.tsx | 41 ++++++++++++++----- .../external_api/dashboard_renderer.tsx | 14 ++----- .../public/dashboard_container/index.ts | 5 +-- src/plugins/dashboard/public/plugin.tsx | 9 ---- 5 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts b/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts index 80644fa94dc36..1ede56a2b67a7 100644 --- a/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts +++ b/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts @@ -16,6 +16,10 @@ import { } from '../../lib/dashboard_panel_converters'; import { DashboardAttributesAndReferences, ParsedDashboardAttributesWithType } from '../../types'; import { DashboardAttributes, SavedDashboardPanel } from '../../content_management'; +import { + createExtract, + createInject, +} from '../../dashboard_container/persistable_state/dashboard_container_references'; export interface InjectExtractDeps { embeddablePersistableStateService: EmbeddablePersistableStateService; @@ -45,10 +49,8 @@ export function injectReferences( const parsedAttributes = parseDashboardAttributesWithType(attributes); // inject references back into panels via the Embeddable persistable state service. - const injectedState = deps.embeddablePersistableStateService.inject( - parsedAttributes, - references - ) as ParsedDashboardAttributesWithType; + const inject = createInject(deps.embeddablePersistableStateService); + const injectedState = inject(parsedAttributes, references) as ParsedDashboardAttributesWithType; const injectedPanels = convertPanelMapToSavedPanels(injectedState.panels); const newAttributes = { @@ -74,11 +76,11 @@ export function extractReferences( ); } - const { references: extractedReferences, state: extractedState } = - deps.embeddablePersistableStateService.extract(parsedAttributes) as { - references: Reference[]; - state: ParsedDashboardAttributesWithType; - }; + const extract = createExtract(deps.embeddablePersistableStateService); + const { references: extractedReferences, state: extractedState } = extract(parsedAttributes) as { + references: Reference[]; + state: ParsedDashboardAttributesWithType; + }; const extractedPanels = convertPanelMapToSavedPanels(extractedState.panels); const newAttributes = { diff --git a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx index fd41fdd5e764d..6a81a8c4fd601 100644 --- a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx +++ b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx @@ -18,11 +18,12 @@ import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; import { setStubKibanaServices as setPresentationPanelMocks } from '@kbn/presentation-panel-plugin/public/mocks'; import { BehaviorSubject } from 'rxjs'; import { DashboardContainerFactory } from '..'; -import { DASHBOARD_CONTAINER_TYPE, DashboardCreationOptions } from '../..'; -import { embeddableService } from '../../services/kibana_services'; +import { DashboardCreationOptions } from '../..'; import { DashboardContainer } from '../embeddable/dashboard_container'; import { DashboardRenderer } from './dashboard_renderer'; +jest.mock('../embeddable/dashboard_container_factory', () => ({})); + describe('dashboard renderer', () => { let mockDashboardContainer: DashboardContainer; let mockDashboardFactory: DashboardContainerFactory; @@ -38,7 +39,10 @@ describe('dashboard renderer', () => { mockDashboardFactory = { create: jest.fn().mockReturnValue(mockDashboardContainer), } as unknown as DashboardContainerFactory; - embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockDashboardFactory); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('../embeddable/dashboard_container_factory').DashboardContainerFactoryDefinition = jest + .fn() + .mockReturnValue(mockDashboardFactory); setPresentationPanelMocks(); }); @@ -46,7 +50,6 @@ describe('dashboard renderer', () => { await act(async () => { mountWithIntl(); }); - expect(embeddableService.getEmbeddableFactory).toHaveBeenCalledWith(DASHBOARD_CONTAINER_TYPE); expect(mockDashboardFactory.create).toHaveBeenCalled(); }); @@ -103,7 +106,10 @@ describe('dashboard renderer', () => { mockDashboardFactory = { create: jest.fn().mockReturnValue(mockErrorEmbeddable), } as unknown as DashboardContainerFactory; - embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockDashboardFactory); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('../embeddable/dashboard_container_factory').DashboardContainerFactoryDefinition = jest + .fn() + .mockReturnValue(mockDashboardFactory); let wrapper: ReactWrapper; await act(async () => { @@ -125,7 +131,10 @@ describe('dashboard renderer', () => { const mockErrorFactory = { create: jest.fn().mockReturnValue(mockErrorEmbeddable), } as unknown as DashboardContainerFactory; - embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockErrorFactory); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('../embeddable/dashboard_container_factory').DashboardContainerFactoryDefinition = jest + .fn() + .mockReturnValue(mockErrorFactory); // render the dashboard - it should run into an error and render the error embeddable. let wrapper: ReactWrapper; @@ -146,7 +155,10 @@ describe('dashboard renderer', () => { const mockSuccessFactory = { create: jest.fn().mockReturnValue(mockSuccessEmbeddable), } as unknown as DashboardContainerFactory; - embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockSuccessFactory); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('../embeddable/dashboard_container_factory').DashboardContainerFactoryDefinition = jest + .fn() + .mockReturnValue(mockSuccessFactory); // update the saved object id to trigger another dashboard load. await act(async () => { @@ -175,7 +187,10 @@ describe('dashboard renderer', () => { const mockErrorFactory = { create: jest.fn().mockReturnValue(mockErrorEmbeddable), } as unknown as DashboardContainerFactory; - embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockErrorFactory); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('../embeddable/dashboard_container_factory').DashboardContainerFactoryDefinition = jest + .fn() + .mockReturnValue(mockErrorFactory); // render the dashboard - it should run into an error and render the error embeddable. let wrapper: ReactWrapper; @@ -238,7 +253,10 @@ describe('dashboard renderer', () => { const mockSuccessFactory = { create: jest.fn().mockReturnValue(mockSuccessEmbeddable), } as unknown as DashboardContainerFactory; - embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockSuccessFactory); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('../embeddable/dashboard_container_factory').DashboardContainerFactoryDefinition = jest + .fn() + .mockReturnValue(mockSuccessFactory); let wrapper: ReactWrapper; await act(async () => { @@ -263,7 +281,10 @@ describe('dashboard renderer', () => { const mockUseMarginFalseFactory = { create: jest.fn().mockReturnValue(mockUseMarginFalseEmbeddable), } as unknown as DashboardContainerFactory; - embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockUseMarginFalseFactory); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('../embeddable/dashboard_container_factory').DashboardContainerFactoryDefinition = jest + .fn() + .mockReturnValue(mockUseMarginFalseFactory); let wrapper: ReactWrapper; await act(async () => { diff --git a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx index a43bd6ddbc75b..40b54e42e6ffa 100644 --- a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx +++ b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx @@ -20,15 +20,11 @@ import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; import { LocatorPublic } from '@kbn/share-plugin/common'; -import { DASHBOARD_CONTAINER_TYPE } from '..'; import { DashboardContainerInput } from '../../../common'; import { DashboardApi } from '../../dashboard_api/types'; import { embeddableService, screenshotModeService } from '../../services/kibana_services'; import type { DashboardContainer } from '../embeddable/dashboard_container'; -import { - DashboardContainerFactory, - DashboardContainerFactoryDefinition, -} from '../embeddable/dashboard_container_factory'; +import { DashboardContainerFactoryDefinition } from '../embeddable/dashboard_container_factory'; import type { DashboardCreationOptions } from '../..'; import { DashboardLocatorParams, DashboardRedirect } from '../types'; import { Dashboard404Page } from './dashboard_404'; @@ -91,12 +87,8 @@ export function DashboardRenderer({ (async () => { const creationOptions = await getCreationOptions?.(); - const dashboardFactory = embeddableService.getEmbeddableFactory( - DASHBOARD_CONTAINER_TYPE - ) as DashboardContainerFactory & { - create: DashboardContainerFactoryDefinition['create']; - }; - const container = await dashboardFactory?.create( + const dashboardFactory = new DashboardContainerFactoryDefinition(embeddableService); + const container = await dashboardFactory.create( { id } as unknown as DashboardContainerInput, // Input from creationOptions is used instead. undefined, creationOptions, diff --git a/src/plugins/dashboard/public/dashboard_container/index.ts b/src/plugins/dashboard/public/dashboard_container/index.ts index 16314f52d38f8..b4ecb30f3c25d 100644 --- a/src/plugins/dashboard/public/dashboard_container/index.ts +++ b/src/plugins/dashboard/public/dashboard_container/index.ts @@ -15,10 +15,7 @@ export const DASHBOARD_CONTAINER_TYPE = 'dashboard'; export const LATEST_DASHBOARD_CONTAINER_VERSION = convertNumberToDashboardVersion(LATEST_VERSION); export type { DashboardContainer } from './embeddable/dashboard_container'; -export { - type DashboardContainerFactory, - DashboardContainerFactoryDefinition, -} from './embeddable/dashboard_container_factory'; +export { type DashboardContainerFactory } from './embeddable/dashboard_container_factory'; export { LazyDashboardRenderer } from './external_api/lazy_dashboard_renderer'; export type { DashboardLocatorParams } from './types'; diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index b1d60adc84d0f..0957bf9364524 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -72,7 +72,6 @@ import { LEGACY_DASHBOARD_APP_ID, SEARCH_SESSION_ID, } from './dashboard_constants'; -import { DashboardContainerFactoryDefinition } from './dashboard_container/embeddable/dashboard_container_factory'; import { GetPanelPlacementSettings, registerDashboardPanelPlacementSetting, @@ -227,14 +226,6 @@ export class DashboardPlugin }, }); - core.getStartServices().then(([, deps]) => { - const dashboardContainerFactory = new DashboardContainerFactoryDefinition(deps.embeddable); - embeddable.registerEmbeddableFactory( - dashboardContainerFactory.type, - dashboardContainerFactory - ); - }); - this.stopUrlTracking = () => { stopUrlTracker(); }; From f72ab5ef7e072636c87acdbb86da080bcb158a27 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:34:32 +0100 Subject: [PATCH 070/110] [Security Solution][Detection Engine] removes unsupported adv settings options for Serverless (#194108) ## Summary - addresses https://github.com/elastic/kibana/issues/188051 - removes adv settings options: - CCS rule privileges warning - Exclude cold and frozen tiers in Analyzer --- packages/kbn-management/settings/setting_ids/index.ts | 4 ---- packages/serverless/settings/security_project/index.ts | 2 -- 2 files changed, 6 deletions(-) diff --git a/packages/kbn-management/settings/setting_ids/index.ts b/packages/kbn-management/settings/setting_ids/index.ts index a7051804289bd..2b8c5de0b71df 100644 --- a/packages/kbn-management/settings/setting_ids/index.ts +++ b/packages/kbn-management/settings/setting_ids/index.ts @@ -178,13 +178,9 @@ export const SECURITY_SOLUTION_RULES_TABLE_REFRESH_ID = 'securitySolution:rulesT export const SECURITY_SOLUTION_ENABLE_NEWS_FEED_ID = 'securitySolution:enableNewsFeed'; export const SECURITY_SOLUTION_NEWS_FEED_URL_ID = 'securitySolution:newsFeedUrl'; export const SECURITY_SOLUTION_IP_REPUTATION_LINKS_ID = 'securitySolution:ipReputationLinks'; -export const SECURITY_SOLUTION_ENABLE_CCS_WARNING_ID = 'securitySolution:enableCcsWarning'; export const SECURITY_SOLUTION_SHOW_RELATED_INTEGRATIONS_ID = 'securitySolution:showRelatedIntegrations'; export const SECURITY_SOLUTION_DEFAULT_ALERT_TAGS_KEY = 'securitySolution:alertTags' as const; -/** This Kibana Advanced Setting allows users to enable/disable querying cold and frozen data tiers in analyzer */ -export const SECURITY_SOLUTION_EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER = - 'securitySolution:excludeColdAndFrozenTiersInAnalyzer' as const; /** This Kibana Advanced Setting allows users to enable/disable the Asset Criticality feature */ export const SECURITY_SOLUTION_ENABLE_ASSET_CRITICALITY_SETTING = 'securitySolution:enableAssetCriticality' as const; diff --git a/packages/serverless/settings/security_project/index.ts b/packages/serverless/settings/security_project/index.ts index 3932f924ea94d..dbbf6e506eda8 100644 --- a/packages/serverless/settings/security_project/index.ts +++ b/packages/serverless/settings/security_project/index.ts @@ -19,11 +19,9 @@ export const SECURITY_PROJECT_SETTINGS = [ settings.SECURITY_SOLUTION_DEFAULT_ANOMALY_SCORE_ID, settings.SECURITY_SOLUTION_RULES_TABLE_REFRESH_ID, settings.SECURITY_SOLUTION_IP_REPUTATION_LINKS_ID, - settings.SECURITY_SOLUTION_ENABLE_CCS_WARNING_ID, settings.SECURITY_SOLUTION_SHOW_RELATED_INTEGRATIONS_ID, settings.SECURITY_SOLUTION_NEWS_FEED_URL_ID, settings.SECURITY_SOLUTION_ENABLE_NEWS_FEED_ID, settings.SECURITY_SOLUTION_DEFAULT_ALERT_TAGS_KEY, settings.SECURITY_SOLUTION_ENABLE_ASSET_CRITICALITY_SETTING, - settings.SECURITY_SOLUTION_EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER, ]; From 4b695fd40e8fefba0df8febe888922c5c0856a40 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:37:09 +0100 Subject: [PATCH 071/110] [Security Solution][Detection Engine] adds ftr tests that cover synthetic source behaviour different to stored source (#193752) ## Summary - adds tests that capture [limitations](https://docs.google.com/document/d/1wDkYv37ExvaN3Qm2Z7G5bWjtVIFj7Be2s5ZIZxlRhcw/edit#heading=h.e6lq0pp7ny3k) of synthetic source mode - add tests that cover failures in [ftr tests](https://github.com/elastic/kibana/pull/191527#issuecomment-2360684346) when synthetic source enabled. Most of them can be attributed to array stings sorting and converting flattened(do-notation) objects properties to nested --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../execution_logic/index.ts | 1 + .../execution_logic/synthetic_source.ts | 465 ++++++++++++++++++ .../detections_response/utils/index.ts | 1 + .../utils/indices/index.ts | 8 + .../utils/indices/set_synthetic_source.ts | 17 + 5 files changed, 492 insertions(+) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/synthetic_source.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/indices/index.ts create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/indices/set_synthetic_source.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/index.ts index 2dc37a8b900f7..ffb728e23d31b 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/index.ts @@ -23,6 +23,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./indicator_match_alert_suppression')); loadTestFile(require.resolve('./threshold')); loadTestFile(require.resolve('./threshold_alert_suppression')); + loadTestFile(require.resolve('./synthetic_source')); loadTestFile(require.resolve('./non_ecs_fields')); loadTestFile(require.resolve('./custom_query')); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/synthetic_source.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/synthetic_source.ts new file mode 100644 index 0000000000000..e70fa226213d5 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/synthetic_source.ts @@ -0,0 +1,465 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { v4 as uuidv4 } from 'uuid'; + +import { QueryRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { + getPreviewAlerts, + previewRule, + dataGeneratorFactory, + setSyntheticSource, +} from '../../../../utils'; +import { + deleteAllRules, + deleteAllAlerts, + getRuleForAlertTesting, +} from '../../../../../../../common/utils/security_solution'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const es = getService('es'); + const log = getService('log'); + + const getRuleProps = (id: string, index: string): QueryRuleCreateProps => { + return { + ...getRuleForAlertTesting([index]), + query: `id:${id}`, + from: 'now-1h', + interval: '1h', + }; + }; + + describe('@ess @serverless synthetic source', () => { + describe('synthetic source limitations', () => { + const index = 'ecs_compliant'; + const { indexListOfDocuments } = dataGeneratorFactory({ es, index, log }); + + before(async () => { + await esArchiver.load(`x-pack/test/functional/es_archives/security_solution/${index}`); + await setSyntheticSource({ es, index }); + }); + + after(async () => { + await esArchiver.unload(`x-pack/test/functional/es_archives/security_solution/${index}`); + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + it('should convert dot-notation to nested objects', async () => { + const id = uuidv4(); + const timestamp = '2020-10-28T06:00:00.000Z'; + + const firstDoc = { + id, + '@timestamp': timestamp, + 'agent.name': 'agent-1', + }; + + await indexListOfDocuments([firstDoc]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + expect(previewAlerts.length).toEqual(1); + expect(previewAlerts[0]._source).toEqual({ + ...previewAlerts[0]._source, + // agent.name returned as nested object, but was indexed in original document with dot-notation + agent: { name: 'agent-1' }, + }); + }); + + it('should removed duplicated values in array', async () => { + const id = uuidv4(); + const timestamp = '2020-10-28T06:00:00.000Z'; + + const firstDoc = { + id, + '@timestamp': timestamp, + client: { ip: ['127.0.0.1', '127.0.0.1', '127.0.0.2'] }, + }; + + await indexListOfDocuments([firstDoc]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + expect(previewAlerts.length).toEqual(1); + expect(previewAlerts[0]._source).toEqual({ + ...previewAlerts[0]._source, + client: { ip: ['127.0.0.1', '127.0.0.2'] }, + }); + }); + + it('should sort duplicated values in array', async () => { + const id = uuidv4(); + const timestamp = '2020-10-28T06:00:00.000Z'; + + const firstDoc = { + id, + '@timestamp': timestamp, + client: { ip: ['127.0.0.3', '211.0.0.2', '127.0.0.1'] }, + }; + + await indexListOfDocuments([firstDoc]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + expect(previewAlerts.length).toEqual(1); + expect(previewAlerts[0]._source).toEqual({ + ...previewAlerts[0]._source, + client: { ip: ['127.0.0.1', '127.0.0.3', '211.0.0.2'] }, + }); + }); + + it('should convert array of objects to leaf structure', async () => { + const id = uuidv4(); + const timestamp = '2020-10-28T06:00:00.000Z'; + + const firstDoc = { + id, + '@timestamp': timestamp, + client: [{ ip: ['127.0.0.1'] }, { ip: ['127.0.0.2'] }], + }; + + await indexListOfDocuments([firstDoc]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + expect(previewAlerts.length).toEqual(1); + expect(previewAlerts[0]._source).toEqual({ + ...previewAlerts[0]._source, + client: { ip: ['127.0.0.1', '127.0.0.2'] }, + }); + }); + }); + + // this set of tests represent corrected failed test suits in https://github.com/elastic/kibana/pull/191527#issuecomment-2360684346 + // and ensures non-ecs fields are stripped when source mode is synthetic + describe('non ecs fields', () => { + const index = 'ecs_non_compliant'; + const { indexListOfDocuments } = dataGeneratorFactory({ es, index, log }); + const timestamp = '2020-10-28T06:00:00.000Z'; + + before(async () => { + await esArchiver.load(`x-pack/test/functional/es_archives/security_solution/${index}`); + await setSyntheticSource({ es, index }); + }); + + after(async () => { + await esArchiver.unload(`x-pack/test/functional/es_archives/security_solution/${index}`); + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + it('should not add multi field .text to ecs compliant flattened source', async () => { + const id = uuidv4(); + + const firstDoc = { + id, + '@timestamp': timestamp, + 'process.command_line': 'string longer than 10 characters', + }; + + await indexListOfDocuments([firstDoc]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + expect(previewAlerts[0]?._source?.process).toEqual({ + command_line: 'string longer than 10 characters', + }); + expect(previewAlerts[0]?._source).not.toHaveProperty('process.command_line.text'); + }); + + it('should not add multi field .text to ecs non compliant flattened source', async () => { + const id = uuidv4(); + + const firstDoc = { + id, + '@timestamp': timestamp, + 'nonEcs.command_line': 'string longer than 10 characters', + }; + + await indexListOfDocuments([firstDoc]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + expect(previewAlerts[0]?._source?.nonEcs).toEqual({ + command_line: 'string longer than 10 characters', + }); + expect(previewAlerts[0]?._source).not.toHaveProperty('process.nonEcs.text'); + }); + + it('should remove text field if the length of the string is more than 32766 bytes', async () => { + const id = uuidv4(); + + const document = { + id, + '@timestamp': timestamp, + 'event.original': 'z'.repeat(32767), + 'event.module': 'z'.repeat(32767), + 'event.action': 'z'.repeat(32767), + }; + + await indexListOfDocuments([document]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + const alertSource = previewAlerts[0]?._source; + + // keywords with `ignore_above` attribute which allows long text to be stored + expect(alertSource).toHaveProperty(['kibana.alert.original_event.module']); + expect(alertSource).toHaveProperty(['kibana.alert.original_event.original']); + expect(alertSource).toHaveProperty(['kibana.alert.original_event.action']); + + expect(alertSource?.event).toHaveProperty(['module']); + expect(alertSource?.event).toHaveProperty(['original']); + expect(alertSource?.event).toHaveProperty(['action']); + }); + + it('should not remove valid dates from ECS source field', async () => { + const id = uuidv4(); + + const validDates = [ + '2015-01-01T12:10:30.666Z', + '2015-01-01T12:10:30.666', + '2015-01-01T12:10:30Z', + '2015-01-01T12:10:30', + '2015-01-01T12:10Z', + '2015-01-01T12:10', + '2015-01-01T12Z', + '2015-01-01T12', + '2015-01-01', + '2015-01', + '2015-01-02T', + 123.3, + '23242', + -1, + '-1', + 0, + '0', + ]; + const document = { + id, + '@timestamp': timestamp, + event: { + created: validDates, + }, + }; + await indexListOfDocuments([document]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + // array of dates became sorted and duplicates removed + expect(previewAlerts[0]?._source).toHaveProperty( + ['event', 'created'], + [ + '-1', + '0', + '123.3', + '2015-01', + '2015-01-01', + '2015-01-01T12', + '2015-01-01T12:10', + '2015-01-01T12:10:30', + '2015-01-01T12:10:30.666', + '2015-01-01T12:10:30.666Z', + '2015-01-01T12:10:30Z', + '2015-01-01T12:10Z', + '2015-01-01T12Z', + '2015-01-02T', + '23242', + ] + ); + }); + + it('should not remove valid ips from ECS source field', async () => { + const id = uuidv4(); + const ip = [ + '127.0.0.1', + '::afff:4567:890a', + '::', + '::11.22.33.44', + '1111:2222:3333:4444:AAAA:BBBB:CCCC:DDDD', + ]; + + const document = { + id, + '@timestamp': timestamp, + client: { ip }, + }; + await indexListOfDocuments([document]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + // array of dates became sorted + expect(previewAlerts[0]?._source).toHaveProperty('client.ip', [ + '1111:2222:3333:4444:AAAA:BBBB:CCCC:DDDD', + '127.0.0.1', + '::', + '::11.22.33.44', + '::afff:4567:890a', + ]); + }); + + it('should remove source array of keywords field from alert if ECS field mapping is nested', async () => { + const id = uuidv4(); + + const document = { + id, + '@timestamp': timestamp, + threat: { + enrichments: ['non-valid-threat-1', 'non-valid-threat-2'], + 'indicator.port': 443, + }, + }; + await indexListOfDocuments([document]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + expect(previewAlerts[0]?._source).not.toHaveProperty('threat.enrichments'); + + expect(previewAlerts[0]?._source).toHaveProperty(['threat', 'indicator', 'port'], 443); + }); + + it('should strip invalid boolean values and left valid ones', async () => { + const id = uuidv4(); + + const document = { + id, + '@timestamp': timestamp, + dll: { + code_signature: { + valid: ['non-valid', 'true', 'false', [true, false], '', 'False', 'True', 1], + }, + }, + }; + await indexListOfDocuments([document]); + + const { previewId } = await previewRule({ + supertest, + rule: getRuleProps(id, index), + timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), + invocationCount: 1, + }); + + const previewAlerts = await getPreviewAlerts({ + es, + previewId, + }); + + // invalid ECS values is getting removed, duplicates not stored in synthetic source + expect(previewAlerts[0]?._source).toHaveProperty('dll.code_signature.valid', [ + '', + 'false', + 'true', + ]); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts index 2ce85256b0fbf..5667762ce95c4 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts @@ -12,6 +12,7 @@ export * from './data_generator'; export * from './telemetry'; export * from './event_log'; export * from './machine_learning'; +export * from './indices'; export * from './binary_to_string'; export * from './get_index_name_from_load'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/indices/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/indices/index.ts new file mode 100644 index 0000000000000..79cad822b8f36 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/indices/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './set_synthetic_source'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/indices/set_synthetic_source.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/indices/set_synthetic_source.ts new file mode 100644 index 0000000000000..b37bcd7664319 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/indices/set_synthetic_source.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Client } from '@elastic/elasticsearch'; + +interface UpdateMappingsProps { + es: Client; + index: string | string[]; +} + +export const setSyntheticSource = async ({ es, index }: UpdateMappingsProps) => { + await es.indices.putMapping({ _source: { mode: 'synthetic' }, index }); +}; From 5a71d8445de185a7b6a73163a123b6a448f63f90 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:56:42 +0100 Subject: [PATCH 072/110] [Security Solution][Detection Engine] fixes showing all the fields for all indices when trying to edit filters in a rule (#194678) ## Summary - addresses https://github.com/elastic/kibana/issues/179468 - fixes issue when rule configured with Data view **Steps to reproduce:** 1. Create a minimal new index and corresponding data view ```JSON PUT fields_index PUT fields_index/_mapping { "properties": { "@timestamp": { "type": "date" }, "field-1": { "type": "keyword" }, "field-2": { "type": "keyword" }, "field-3": { "type": "keyword" } } } POST fields_index/_doc { "@timestamp": "2024-10-01T09:26:30.425Z", "field-1": "test-0" } ``` 2. Create a security rule with that data view 3. Edit the rule and try to add a filter 4. Fields for all indices show up instead of the fields from the rule index 5. Switching to indices and back to data view on rule form fixes issue
    video with the bug https://github.com/user-attachments/assets/fc83356d-d727-4662-856e-a4f0b386b71f
    ### Additional benefit of fixing the issue. Previously, there would be 2 additional field_caps requests, querying ALL indices in ES, when rule edit page loads and rule configured with data view. ``` http://localhost:5601/kbn/internal/data_views/fields?pattern=&meta_fields=_source&meta_fields=_id&meta_fields=_index&meta_fields=_score&meta_fields=_ignored&allow_no_index=true&apiVersion=1 ``` Notice, there is `pattern=` query value, which results in querying all existing indices Now, these requests eliminated. #### Before Screenshot 2024-10-02 at 18 21 04 #### After Screenshot 2024-10-02 at 18 22 41 --- .../public/common/components/query_bar/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/query_bar/index.tsx b/x-pack/plugins/security_solution/public/common/components/query_bar/index.tsx index 039860093e423..793ca853598b3 100644 --- a/x-pack/plugins/security_solution/public/common/components/query_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/query_bar/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { cloneDeep } from 'lodash'; +import { cloneDeep, isEmpty } from 'lodash'; import React, { memo, useMemo, useCallback, useState, useEffect } from 'react'; import deepEqual from 'fast-deep-equal'; @@ -125,7 +125,7 @@ export const QueryBar = memo( let dv: DataView; if (isDataView(indexPattern)) { setDataView(indexPattern); - } else if (!isEsql) { + } else if (!isEsql && !isEmpty(indexPattern.title)) { const createDataView = async () => { dv = await data.dataViews.create({ id: indexPattern.title, title: indexPattern.title }); setDataView(dv); From f2b9348f976b96c296b3dc89949115a10c9b19f9 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Wed, 9 Oct 2024 17:40:10 +0200 Subject: [PATCH 073/110] [Search profiler] Migrate ace to monaco (#195343) --- .../public/application/components/_index.scss | 1 - .../_profile_query_editor.scss | 25 ----- .../editor/editor.test.tsx | 10 +- .../profile_query_editor/editor/editor.tsx | 97 ++++++++----------- .../profile_query_editor/editor/index.ts | 3 +- .../editor/init_editor.ts | 36 ------- .../profile_query_editor.tsx | 30 +++--- .../searchprofiler/public/shared_imports.ts | 2 - x-pack/plugins/searchprofiler/tsconfig.json | 3 +- .../apps/group1/search_profiler.ts | 6 +- .../apps/dev_tools/searchprofiler_editor.ts | 2 +- .../page_objects/search_profiler_page.ts | 9 +- .../common/dev_tools/search_profiler.ts | 14 +-- 13 files changed, 76 insertions(+), 162 deletions(-) delete mode 100644 x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/_profile_query_editor.scss delete mode 100644 x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/init_editor.ts diff --git a/x-pack/plugins/searchprofiler/public/application/components/_index.scss b/x-pack/plugins/searchprofiler/public/application/components/_index.scss index 9d6688a2d4d98..ee36c5e8e6567 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/_index.scss +++ b/x-pack/plugins/searchprofiler/public/application/components/_index.scss @@ -3,5 +3,4 @@ $badgeSize: $euiSize * 5.5; @import 'highlight_details_flyout/highlight_details_flyout'; @import 'license_warning_notice/license_warning_notice'; @import 'percentage_badge/percentage_badge'; -@import 'profile_query_editor/profile_query_editor'; @import 'profile_tree/index'; diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/_profile_query_editor.scss b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/_profile_query_editor.scss deleted file mode 100644 index 035ff16c990bb..0000000000000 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/_profile_query_editor.scss +++ /dev/null @@ -1,25 +0,0 @@ - -.prfDevTool__sense { - order: 1; - // To anchor ace editor - position: relative; - - // Ace Editor overrides - .ace_editor { - min-height: $euiSize * 10; - flex-grow: 1; - margin-bottom: $euiSize; - margin-top: $euiSize; - outline: solid 1px $euiColorLightShade; - } - - .errorMarker { - position: absolute; - background: rgba($euiColorDanger, .5); - z-index: 20; - } -} - -.prfDevTool__profileButtonContainer { - flex-shrink: 1; -} diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/editor.test.tsx b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/editor.test.tsx index 34e0867df8ec6..483f0ef7f6106 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/editor.test.tsx +++ b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/editor.test.tsx @@ -5,20 +5,14 @@ * 2.0. */ -import 'brace'; -import 'brace/mode/json'; - -import { coreMock } from '@kbn/core/public/mocks'; import { registerTestBed } from '@kbn/test-jest-helpers'; import { Editor, Props } from './editor'; -const coreStart = coreMock.createStart(); - describe('Editor Component', () => { it('renders', async () => { const props: Props = { - ...coreStart, - initialValue: '', + editorValue: '', + setEditorValue: () => {}, licenseEnabled: true, onEditorReady: (e: any) => {}, }; diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/editor.tsx b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/editor.tsx index 068673d4ce4c1..3701323d414c2 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/editor.tsx +++ b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/editor.tsx @@ -5,67 +5,37 @@ * 2.0. */ -import React, { memo, useRef, useEffect, useState } from 'react'; +import React, { memo, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiScreenReaderOnly } from '@elastic/eui'; -import { Editor as AceEditor } from 'brace'; +import { EuiScreenReaderOnly, EuiSpacer } from '@elastic/eui'; +import { CodeEditor } from '@kbn/code-editor'; +import { monaco, XJsonLang } from '@kbn/monaco'; -import { SearchProfilerStartServices } from '../../../../types'; -import { ace } from '../../../../shared_imports'; -import { initializeEditor } from './init_editor'; - -const { useUIAceKeyboardMode } = ace; - -type EditorShim = ReturnType; - -export type EditorInstance = EditorShim; - -export interface Props extends SearchProfilerStartServices { +export interface Props { licenseEnabled: boolean; - initialValue: string; - onEditorReady: (editor: EditorShim) => void; + editorValue: string; + setEditorValue: (value: string) => void; + onEditorReady: (props: EditorProps) => void; } -const createEditorShim = (aceEditor: AceEditor) => { - return { - getValue() { - return aceEditor.getValue(); - }, - focus() { - aceEditor.focus(); - }, - }; -}; - const EDITOR_INPUT_ID = 'SearchProfilerTextArea'; -export const Editor = memo( - ({ licenseEnabled, initialValue, onEditorReady, ...startServices }: Props) => { - const containerRef = useRef(null as any); - const editorInstanceRef = useRef(null as any); - - const [textArea, setTextArea] = useState(null); - - useUIAceKeyboardMode(textArea, startServices); - - useEffect(() => { - const divEl = containerRef.current; - editorInstanceRef.current = initializeEditor({ el: divEl, licenseEnabled }); - editorInstanceRef.current.setValue(initialValue, 1); - const textarea = divEl.querySelector('textarea'); - if (textarea) { - textarea.setAttribute('id', EDITOR_INPUT_ID); - } - setTextArea(licenseEnabled ? containerRef.current!.querySelector('textarea') : null); - - onEditorReady(createEditorShim(editorInstanceRef.current)); +export interface EditorProps { + focus: () => void; +} - return () => { - if (editorInstanceRef.current) { - editorInstanceRef.current.destroy(); - } - }; - }, [initialValue, onEditorReady, licenseEnabled]); +export const Editor = memo( + ({ licenseEnabled, editorValue, setEditorValue, onEditorReady }: Props) => { + const editorDidMountCallback = useCallback( + (editor: monaco.editor.IStandaloneCodeEditor) => { + onEditorReady({ + focus: () => { + editor.focus(); + }, + } as EditorProps); + }, + [onEditorReady] + ); return ( <> @@ -76,7 +46,26 @@ export const Editor = memo( })} -
    + + + + ); } diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/index.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/index.ts index 5d8be48041176..1ac3ec704bc5d 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/index.ts +++ b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/index.ts @@ -5,5 +5,4 @@ * 2.0. */ -export type { EditorInstance } from './editor'; -export { Editor } from './editor'; +export { Editor, type EditorProps } from './editor'; diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/init_editor.ts b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/init_editor.ts deleted file mode 100644 index 24d119254db78..0000000000000 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/editor/init_editor.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import ace from 'brace'; -import { installXJsonMode } from '@kbn/ace'; - -export function initializeEditor({ - el, - licenseEnabled, -}: { - el: HTMLDivElement; - licenseEnabled: boolean; -}) { - const editor: ace.Editor = ace.acequire('ace/ace').edit(el); - - installXJsonMode(editor); - editor.$blockScrolling = Infinity; - - if (!licenseEnabled) { - editor.setReadOnly(true); - editor.container.style.pointerEvents = 'none'; - editor.container.style.opacity = '0.5'; - const textArea = editor.container.querySelector('textarea'); - if (textArea) { - textArea.setAttribute('tabindex', '-1'); - } - editor.renderer.setStyle('disabled'); - editor.blur(); - } - - return editor; -} diff --git a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/profile_query_editor.tsx b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/profile_query_editor.tsx index 577c3e530e8cc..a88f1040caa3a 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/profile_query_editor.tsx +++ b/x-pack/plugins/searchprofiler/public/application/components/profile_query_editor/profile_query_editor.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useRef, memo, useCallback } from 'react'; +import React, { useRef, memo, useCallback, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiForm, @@ -23,7 +23,7 @@ import { decompressFromEncodedURIComponent } from 'lz-string'; import { useRequestProfile } from '../../hooks'; import { useAppContext } from '../../contexts/app_context'; import { useProfilerActionContext } from '../../contexts/profiler_context'; -import { Editor, EditorInstance } from './editor'; +import { Editor, type EditorProps } from './editor'; const DEFAULT_INDEX_VALUE = '_all'; @@ -39,33 +39,36 @@ const INITIAL_EDITOR_VALUE = `{ * Drives state changes for mine via profiler action context. */ export const ProfileQueryEditor = memo(() => { - const editorRef = useRef(null as any); + const editorPropsRef = useRef(null as any); const indexInputRef = useRef(null as any); const dispatch = useProfilerActionContext(); - const { getLicenseStatus, notifications, location, ...startServices } = useAppContext(); + const { getLicenseStatus, notifications, location } = useAppContext(); const queryParams = new URLSearchParams(location.search); const indexName = queryParams.get('index'); const searchProfilerQueryURI = queryParams.get('load_from'); + const searchProfilerQuery = searchProfilerQueryURI && decompressFromEncodedURIComponent(searchProfilerQueryURI.replace(/^data:text\/plain,/, '')); + const [editorValue, setEditorValue] = useState( + searchProfilerQuery ? searchProfilerQuery : INITIAL_EDITOR_VALUE + ); const requestProfile = useRequestProfile(); const handleProfileClick = async () => { dispatch({ type: 'setProfiling', value: true }); try { - const { current: editor } = editorRef; const { data: result, error } = await requestProfile({ - query: editorRef.current.getValue(), + query: editorValue, index: indexInputRef.current.value, }); if (error) { notifications.addDanger(error); - editor.focus(); + editorPropsRef.current.focus(); return; } if (result === null) { @@ -78,18 +81,13 @@ export const ProfileQueryEditor = memo(() => { }; const onEditorReady = useCallback( - (editorInstance: any) => (editorRef.current = editorInstance), + (editorPropsInstance: EditorProps) => (editorPropsRef.current = editorPropsInstance), [] ); const licenseEnabled = getLicenseStatus().valid; return ( - + {/* Form */} @@ -120,9 +118,9 @@ export const ProfileQueryEditor = memo(() => { diff --git a/x-pack/plugins/searchprofiler/public/shared_imports.ts b/x-pack/plugins/searchprofiler/public/shared_imports.ts index b1af4bab9e62d..3daab65e28db8 100644 --- a/x-pack/plugins/searchprofiler/public/shared_imports.ts +++ b/x-pack/plugins/searchprofiler/public/shared_imports.ts @@ -5,6 +5,4 @@ * 2.0. */ -export { ace } from '@kbn/es-ui-shared-plugin/public'; - export { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; diff --git a/x-pack/plugins/searchprofiler/tsconfig.json b/x-pack/plugins/searchprofiler/tsconfig.json index b99b0962e39fc..063b7dfa63ce6 100644 --- a/x-pack/plugins/searchprofiler/tsconfig.json +++ b/x-pack/plugins/searchprofiler/tsconfig.json @@ -20,9 +20,10 @@ "@kbn/expect", "@kbn/test-jest-helpers", "@kbn/i18n-react", - "@kbn/ace", "@kbn/config-schema", "@kbn/react-kibana-context-render", + "@kbn/code-editor", + "@kbn/monaco", ], "exclude": [ "target/**/*", diff --git a/x-pack/test/accessibility/apps/group1/search_profiler.ts b/x-pack/test/accessibility/apps/group1/search_profiler.ts index 522c5e4cf730e..fbd3649120ea1 100644 --- a/x-pack/test/accessibility/apps/group1/search_profiler.ts +++ b/x-pack/test/accessibility/apps/group1/search_profiler.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'security']); const testSubjects = getService('testSubjects'); - const aceEditor = getService('aceEditor'); + const monacoEditor = getService('monacoEditor'); const a11y = getService('a11y'); const esArchiver = getService('esArchiver'); @@ -27,7 +27,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); }); - it('input the JSON in the aceeditor', async () => { + it('input the JSON in the editor', async () => { const input = { query: { bool: { @@ -54,7 +54,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }, }; - await aceEditor.setValue('searchProfilerEditor', JSON.stringify(input)); + await monacoEditor.setCodeEditorValue(JSON.stringify(input), 0); await a11y.testAppSnapshot(); }); diff --git a/x-pack/test/functional/apps/dev_tools/searchprofiler_editor.ts b/x-pack/test/functional/apps/dev_tools/searchprofiler_editor.ts index 174f3d4527178..87c36de62bba6 100644 --- a/x-pack/test/functional/apps/dev_tools/searchprofiler_editor.ts +++ b/x-pack/test/functional/apps/dev_tools/searchprofiler_editor.ts @@ -67,7 +67,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { `parser errors to match expectation: HAS ${expectation ? 'ERRORS' : 'NO ERRORS'}`, async () => { const actual = await PageObjects.searchProfiler.editorHasParseErrors(); - return expectation === actual; + return expectation === actual?.length > 0; } ); } diff --git a/x-pack/test/functional/page_objects/search_profiler_page.ts b/x-pack/test/functional/page_objects/search_profiler_page.ts index a110bd16eeafe..151b9a613c356 100644 --- a/x-pack/test/functional/page_objects/search_profiler_page.ts +++ b/x-pack/test/functional/page_objects/search_profiler_page.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export function SearchProfilerPageProvider({ getService }: FtrProviderContext) { const find = getService('find'); const testSubjects = getService('testSubjects'); - const aceEditor = getService('aceEditor'); + const monacoEditor = getService('monacoEditor'); const editorTestSubjectSelector = 'searchProfilerEditor'; return { @@ -19,10 +19,10 @@ export function SearchProfilerPageProvider({ getService }: FtrProviderContext) { return await testSubjects.exists(editorTestSubjectSelector); }, async setQuery(query: any) { - await aceEditor.setValue(editorTestSubjectSelector, JSON.stringify(query)); + await monacoEditor.setCodeEditorValue(JSON.stringify(query), 0); }, async getQuery() { - return JSON.parse(await aceEditor.getValue(editorTestSubjectSelector)); + return JSON.parse(await monacoEditor.getCodeEditorValue(0)); }, async setIndexName(indexName: string) { await testSubjects.setValue('indexName', indexName); @@ -36,6 +36,7 @@ export function SearchProfilerPageProvider({ getService }: FtrProviderContext) { }, async getProfileContent() { const profileTree = await find.byClassName('prfDevTool__main__profiletree'); + // const profileTree = await find.byClassName('prfDevTool__page'); return profileTree.getVisibleText(); }, getUrlWithIndexAndQuery({ indexName, query }: { indexName: string; query: any }) { @@ -43,7 +44,7 @@ export function SearchProfilerPageProvider({ getService }: FtrProviderContext) { return `/searchprofiler?index=${indexName}&load_from=${searchQueryURI}`; }, async editorHasParseErrors() { - return await aceEditor.hasParseErrors(editorTestSubjectSelector); + return await monacoEditor.getCurrentMarkers(editorTestSubjectSelector); }, async editorHasErrorNotification() { const notification = await testSubjects.find('noShardsNotification'); diff --git a/x-pack/test_serverless/functional/test_suites/common/dev_tools/search_profiler.ts b/x-pack/test_serverless/functional/test_suites/common/dev_tools/search_profiler.ts index 6a908ce4e0fe8..979943ffa602c 100644 --- a/x-pack/test_serverless/functional/test_suites/common/dev_tools/search_profiler.ts +++ b/x-pack/test_serverless/functional/test_suites/common/dev_tools/search_profiler.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; -const testIndex = 'test-index'; +const indexName = 'my_index'; const testQuery = { query: { match_all: {}, @@ -53,10 +53,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }, }; - // Since we're not actually running the query in the test, - // this index name is just an input placeholder and does not exist - const indexName = 'my_index'; - await PageObjects.common.navigateToUrl( 'searchProfiler', PageObjects.searchProfiler.getUrlWithIndexAndQuery({ indexName, query }), @@ -77,21 +73,21 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('With a test index', () => { before(async () => { - await es.indices.create({ index: testIndex }); + await es.indices.create({ index: indexName }); }); after(async () => { - await es.indices.delete({ index: testIndex }); + await es.indices.delete({ index: indexName }); }); it('profiles a simple query', async () => { - await PageObjects.searchProfiler.setIndexName(testIndex); + await PageObjects.searchProfiler.setIndexName(indexName); await PageObjects.searchProfiler.setQuery(testQuery); await PageObjects.searchProfiler.clickProfileButton(); const content = await PageObjects.searchProfiler.getProfileContent(); - expect(content).to.contain(testIndex); + expect(content).to.contain(indexName); }); }); }); From d273c07edcc1d0ab00f73309a2fb385b43f6221b Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Wed, 9 Oct 2024 17:54:43 +0200 Subject: [PATCH 074/110] [Console] Delete unused sense models and unused files (#195344) --- NOTICE.txt | 31 - src/plugins/console/README.md | 8 +- .../editor_context/editor_registry.ts | 5 +- .../console/public/application/hooks/index.ts | 3 +- .../use_restore_request_from_history/index.ts | 10 - .../restore_request_from_history.ts | 48 - .../restore_request_from_history_to_monaco.ts | 25 - .../use_restore_request_from_history.ts | 21 - .../hooks/use_send_current_request/index.ts | 1 - .../hooks/use_send_current_request/track.ts | 34 - .../use_send_current_request.test.tsx | 130 - .../use_send_current_request.ts | 148 - .../application/hooks/use_set_input_editor.ts | 3 +- .../public/application/models/index.ts | 11 - .../models/legacy_core_editor/create.ts | 20 - .../legacy_core_editor/create_readonly.ts | 81 - .../models/legacy_core_editor/index.ts | 18 - .../models/legacy_core_editor/input.test.js | 559 ---- .../legacy_core_editor.test.mocks.ts | 29 - .../legacy_core_editor/legacy_core_editor.ts | 511 ---- .../models/legacy_core_editor/mode/input.ts | 79 - .../mode/input_highlight_rules.ts | 180 -- .../models/legacy_core_editor/mode/output.ts | 37 - .../mode/output_highlight_rules.test.ts | 56 - .../mode/output_highlight_rules.ts | 64 - .../models/legacy_core_editor/mode/script.ts | 48 - .../legacy_core_editor/mode/worker/index.d.ts | 10 - .../legacy_core_editor/mode/worker/index.js | 15 - .../legacy_core_editor/mode/worker/worker.js | 2392 ----------------- .../output_tokenization.test.js | 91 - .../models/legacy_core_editor/smart_resize.ts | 27 - .../legacy_core_editor/theme_sense_dark.js | 123 - .../__fixtures__/editor_input1.txt | 37 - .../application/models/sense_editor/create.ts | 22 - .../application/models/sense_editor/curl.ts | 194 -- .../application/models/sense_editor/index.ts | 14 - .../models/sense_editor/integration.test.js | 1279 --------- .../models/sense_editor/sense_editor.test.js | 641 ----- .../sense_editor/sense_editor.test.mocks.ts | 20 - .../models/sense_editor/sense_editor.ts | 534 ---- .../public/application/stores/editor.ts | 3 +- .../public/lib/ace_token_provider/index.ts | 10 - .../ace_token_provider/token_provider.test.ts | 223 -- .../lib/ace_token_provider/token_provider.ts | 84 - .../public/lib/autocomplete/autocomplete.ts | 1316 --------- .../get_endpoint_from_position.ts | 33 - .../autocomplete/looks_like_typing_in.test.ts | 224 -- .../lib/autocomplete/looks_like_typing_in.ts | 109 - .../autocomplete_entities.test.js | 1 - .../__fixtures__/curl_parsing.txt | 146 - .../console/public/lib/curl_parsing/curl.js | 194 -- .../lib/curl_parsing/curl_parsing.test.js | 37 - src/plugins/console/public/lib/kb/kb.test.js | 1 - .../console/public/lib/row_parser.test.ts | 107 - src/plugins/console/public/lib/row_parser.ts | 161 -- src/plugins/console/public/styles/_app.scss | 53 - .../console/public/types/core_editor.ts | 5 +- src/plugins/console/tsconfig.json | 2 - .../translations/translations/fr-FR.json | 6 - .../translations/translations/ja-JP.json | 6 - .../translations/translations/zh-CN.json | 6 - 61 files changed, 9 insertions(+), 10277 deletions(-) delete mode 100644 src/plugins/console/public/application/hooks/use_restore_request_from_history/index.ts delete mode 100644 src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts delete mode 100644 src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history_to_monaco.ts delete mode 100644 src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts delete mode 100644 src/plugins/console/public/application/hooks/use_send_current_request/track.ts delete mode 100644 src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.test.tsx delete mode 100644 src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts delete mode 100644 src/plugins/console/public/application/models/index.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/create.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/create_readonly.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/index.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/input.test.js delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/mode/input.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/mode/output.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.test.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/mode/script.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.d.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.js delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/output_tokenization.test.js delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/smart_resize.ts delete mode 100644 src/plugins/console/public/application/models/legacy_core_editor/theme_sense_dark.js delete mode 100644 src/plugins/console/public/application/models/sense_editor/__fixtures__/editor_input1.txt delete mode 100644 src/plugins/console/public/application/models/sense_editor/create.ts delete mode 100644 src/plugins/console/public/application/models/sense_editor/curl.ts delete mode 100644 src/plugins/console/public/application/models/sense_editor/index.ts delete mode 100644 src/plugins/console/public/application/models/sense_editor/integration.test.js delete mode 100644 src/plugins/console/public/application/models/sense_editor/sense_editor.test.js delete mode 100644 src/plugins/console/public/application/models/sense_editor/sense_editor.test.mocks.ts delete mode 100644 src/plugins/console/public/application/models/sense_editor/sense_editor.ts delete mode 100644 src/plugins/console/public/lib/ace_token_provider/index.ts delete mode 100644 src/plugins/console/public/lib/ace_token_provider/token_provider.test.ts delete mode 100644 src/plugins/console/public/lib/ace_token_provider/token_provider.ts delete mode 100644 src/plugins/console/public/lib/autocomplete/autocomplete.ts delete mode 100644 src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.ts delete mode 100644 src/plugins/console/public/lib/autocomplete/looks_like_typing_in.test.ts delete mode 100644 src/plugins/console/public/lib/autocomplete/looks_like_typing_in.ts delete mode 100644 src/plugins/console/public/lib/curl_parsing/__fixtures__/curl_parsing.txt delete mode 100644 src/plugins/console/public/lib/curl_parsing/curl.js delete mode 100644 src/plugins/console/public/lib/curl_parsing/curl_parsing.test.js delete mode 100644 src/plugins/console/public/lib/row_parser.test.ts delete mode 100644 src/plugins/console/public/lib/row_parser.ts diff --git a/NOTICE.txt b/NOTICE.txt index 3cee52c089cb4..80d49de19e5db 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -74,37 +74,6 @@ under a "BSD" license. Distributed under the BSD license: -Copyright (c) 2010, Ajax.org B.V. -All rights reserved. - - Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Ajax.org B.V. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---- -This product includes code that is based on Ace editor, which was available -under a "BSD" license. - -Distributed under the BSD license: - Copyright (c) 2010, Ajax.org B.V. All rights reserved. diff --git a/src/plugins/console/README.md b/src/plugins/console/README.md index 02da27229286a..35921de334380 100644 --- a/src/plugins/console/README.md +++ b/src/plugins/console/README.md @@ -44,7 +44,7 @@ POST /_some_endpoint ``` ## Architecture -Console uses Ace editor that is wrapped with [`CoreEditor`](https://github.com/elastic/kibana/blob/main/src/plugins/console/public/types/core_editor.ts), so that if needed it can easily be replaced with another editor, for example Monaco. +Console uses Monaco editor that is wrapped with [`kbn-monaco`](https://github.com/elastic/kibana/blob/main/packages/kbn-monaco/index.ts), so that if needed it can easily be replaced with another editor. The autocomplete logic is located in [`autocomplete`](https://github.com/elastic/kibana/blob/main/src/plugins/console/public/lib/autocomplete) folder. Autocomplete rules are computed by classes in `components` sub-folder. ## Autocomplete definitions @@ -317,8 +317,4 @@ Another change is replacing jQuery with the core http client to communicate with ### Outstanding issues #### Autocomplete suggestions for Kibana API endpoints Console currently supports autocomplete suggestions for Elasticsearch API endpoints. The autocomplete suggestions for Kibana API endpoints are not supported yet. -Related issue: [#130661](https://github.com/elastic/kibana/issues/130661) - -#### Migration to Monaco Editor -Console plugin is currently using Ace Editor and it is planned to migrate to Monaco Editor in the future. -Related issue: [#57435](https://github.com/elastic/kibana/issues/57435) \ No newline at end of file +Related issue: [#130661](https://github.com/elastic/kibana/issues/130661) \ No newline at end of file diff --git a/src/plugins/console/public/application/contexts/editor_context/editor_registry.ts b/src/plugins/console/public/application/contexts/editor_context/editor_registry.ts index 8197ff0460e86..dc7b58ecbd267 100644 --- a/src/plugins/console/public/application/contexts/editor_context/editor_registry.ts +++ b/src/plugins/console/public/application/contexts/editor_context/editor_registry.ts @@ -8,12 +8,11 @@ */ import { MonacoEditorActionsProvider } from '../../containers/editor/monaco_editor_actions_provider'; -import { SenseEditor } from '../../models/sense_editor'; export class EditorRegistry { - private inputEditor: SenseEditor | MonacoEditorActionsProvider | undefined; + private inputEditor: MonacoEditorActionsProvider | undefined; - setInputEditor(inputEditor: SenseEditor | MonacoEditorActionsProvider) { + setInputEditor(inputEditor: MonacoEditorActionsProvider) { this.inputEditor = inputEditor; } diff --git a/src/plugins/console/public/application/hooks/index.ts b/src/plugins/console/public/application/hooks/index.ts index b6b7211a940e4..29c554771dad0 100644 --- a/src/plugins/console/public/application/hooks/index.ts +++ b/src/plugins/console/public/application/hooks/index.ts @@ -8,7 +8,6 @@ */ export { useSetInputEditor } from './use_set_input_editor'; -export { useRestoreRequestFromHistory } from './use_restore_request_from_history'; -export { useSendCurrentRequest, sendRequest } from './use_send_current_request'; +export { sendRequest } from './use_send_current_request'; export { useSaveCurrentTextObject } from './use_save_current_text_object'; export { useDataInit } from './use_data_init'; diff --git a/src/plugins/console/public/application/hooks/use_restore_request_from_history/index.ts b/src/plugins/console/public/application/hooks/use_restore_request_from_history/index.ts deleted file mode 100644 index 47f12868d9bc6..0000000000000 --- a/src/plugins/console/public/application/hooks/use_restore_request_from_history/index.ts +++ /dev/null @@ -1,10 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export { useRestoreRequestFromHistory } from './use_restore_request_from_history'; diff --git a/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts b/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts deleted file mode 100644 index 897e499dc481e..0000000000000 --- a/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts +++ /dev/null @@ -1,48 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import RowParser from '../../../lib/row_parser'; -import { ESRequest } from '../../../types'; -import { SenseEditor } from '../../models/sense_editor'; -import { formatRequestBodyDoc } from '../../../lib/utils'; - -export function restoreRequestFromHistory(editor: SenseEditor, req: ESRequest) { - const coreEditor = editor.getCoreEditor(); - let pos = coreEditor.getCurrentPosition(); - let prefix = ''; - let suffix = '\n'; - const parser = new RowParser(coreEditor); - if (parser.isStartRequestRow(pos.lineNumber)) { - pos.column = 1; - suffix += '\n'; - } else if (parser.isEndRequestRow(pos.lineNumber)) { - const line = coreEditor.getLineValue(pos.lineNumber); - pos.column = line.length + 1; - prefix = '\n\n'; - } else if (parser.isInBetweenRequestsRow(pos.lineNumber)) { - pos.column = 1; - } else { - pos = editor.nextRequestEnd(pos); - prefix = '\n\n'; - } - - let s = prefix + req.method + ' ' + req.endpoint; - if (req.data) { - const indent = true; - const formattedData = formatRequestBodyDoc([req.data], indent); - s += '\n' + formattedData.data; - } - - s += suffix; - - coreEditor.insert(pos, s); - coreEditor.moveCursorToPosition({ lineNumber: pos.lineNumber + prefix.length, column: 1 }); - coreEditor.clearSelection(); - coreEditor.getContainer().focus(); -} diff --git a/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history_to_monaco.ts b/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history_to_monaco.ts deleted file mode 100644 index 08c2bc6af86a3..0000000000000 --- a/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history_to_monaco.ts +++ /dev/null @@ -1,25 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { formatRequestBodyDoc } from '../../../lib/utils'; -import { MonacoEditorActionsProvider } from '../../containers/editor/monaco_editor_actions_provider'; -import { ESRequest } from '../../../types'; - -export async function restoreRequestFromHistoryToMonaco( - provider: MonacoEditorActionsProvider, - req: ESRequest -) { - let s = req.method + ' ' + req.endpoint; - if (req.data) { - const indent = true; - const formattedData = formatRequestBodyDoc([req.data], indent); - s += '\n' + formattedData.data; - } - await provider.restoreRequestFromHistory(s); -} diff --git a/src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts b/src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts deleted file mode 100644 index 5ee0d185923c2..0000000000000 --- a/src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts +++ /dev/null @@ -1,21 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useCallback } from 'react'; -import { instance as registry } from '../../contexts/editor_context/editor_registry'; -import { ESRequest } from '../../../types'; -import { restoreRequestFromHistoryToMonaco } from './restore_request_from_history_to_monaco'; -import { MonacoEditorActionsProvider } from '../../containers/editor/monaco_editor_actions_provider'; - -export const useRestoreRequestFromHistory = () => { - return useCallback(async (req: ESRequest) => { - const editor = registry.getInputEditor(); - await restoreRequestFromHistoryToMonaco(editor as MonacoEditorActionsProvider, req); - }, []); -}; diff --git a/src/plugins/console/public/application/hooks/use_send_current_request/index.ts b/src/plugins/console/public/application/hooks/use_send_current_request/index.ts index 753184f67e998..656c0b939cf5b 100644 --- a/src/plugins/console/public/application/hooks/use_send_current_request/index.ts +++ b/src/plugins/console/public/application/hooks/use_send_current_request/index.ts @@ -7,5 +7,4 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { useSendCurrentRequest } from './use_send_current_request'; export { sendRequest } from './send_request'; diff --git a/src/plugins/console/public/application/hooks/use_send_current_request/track.ts b/src/plugins/console/public/application/hooks/use_send_current_request/track.ts deleted file mode 100644 index e663c0b8354c1..0000000000000 --- a/src/plugins/console/public/application/hooks/use_send_current_request/track.ts +++ /dev/null @@ -1,34 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SenseEditor } from '../../models/sense_editor'; -import { getEndpointFromPosition } from '../../../lib/autocomplete/get_endpoint_from_position'; -import { MetricsTracker } from '../../../types'; - -export const track = ( - requests: Array<{ method: string }>, - editor: SenseEditor, - trackUiMetric: MetricsTracker -) => { - const coreEditor = editor.getCoreEditor(); - // `getEndpointFromPosition` gets values from the server-side generated JSON files which - // are a combination of JS, automatically generated JSON and manual overrides. That means - // the metrics reported from here will be tied to the definitions in those files. - // See src/legacy/core_plugins/console/server/api_server/spec - const endpointDescription = getEndpointFromPosition( - coreEditor, - coreEditor.getCurrentPosition(), - editor.parser - ); - - if (requests[0] && endpointDescription) { - const eventName = `${requests[0].method}_${endpointDescription.id ?? 'unknown'}`; - trackUiMetric.count(eventName); - } -}; diff --git a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.test.tsx b/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.test.tsx deleted file mode 100644 index 7f3082d5ef3dc..0000000000000 --- a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.test.tsx +++ /dev/null @@ -1,130 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -jest.mock('./send_request', () => ({ sendRequest: jest.fn() })); -jest.mock('../../contexts/editor_context/editor_registry', () => ({ - instance: { getInputEditor: jest.fn() }, -})); -jest.mock('./track', () => ({ track: jest.fn() })); -jest.mock('../../contexts/request_context', () => ({ useRequestActionContext: jest.fn() })); -jest.mock('../../../lib/utils', () => ({ replaceVariables: jest.fn() })); - -import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; - -import { ContextValue, ServicesContextProvider } from '../../contexts'; -import { serviceContextMock } from '../../contexts/services_context.mock'; -import { useRequestActionContext } from '../../contexts/request_context'; -import { instance as editorRegistry } from '../../contexts/editor_context/editor_registry'; -import * as utils from '../../../lib/utils'; - -import { sendRequest } from './send_request'; -import { useSendCurrentRequest } from './use_send_current_request'; - -describe('useSendCurrentRequest', () => { - let mockContextValue: ContextValue; - let dispatch: (...args: unknown[]) => void; - const contexts = ({ children }: { children: JSX.Element }) => ( - {children} - ); - - beforeEach(() => { - mockContextValue = serviceContextMock.create(); - dispatch = jest.fn(); - (useRequestActionContext as jest.Mock).mockReturnValue(dispatch); - (utils.replaceVariables as jest.Mock).mockReturnValue(['test']); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('calls send request', async () => { - // Set up mocks - (mockContextValue.services.settings.toJSON as jest.Mock).mockReturnValue({}); - // This request should succeed - (sendRequest as jest.Mock).mockResolvedValue([]); - (editorRegistry.getInputEditor as jest.Mock).mockImplementation(() => ({ - getRequestsInRange: () => ['test'], - })); - - const { result } = renderHook(() => useSendCurrentRequest(), { wrapper: contexts }); - await act(() => result.current()); - expect(sendRequest).toHaveBeenCalledWith({ - http: mockContextValue.services.http, - requests: ['test'], - }); - - // Second call should be the request success - const [, [requestSucceededCall]] = (dispatch as jest.Mock).mock.calls; - expect(requestSucceededCall).toEqual({ type: 'requestSuccess', payload: { data: [] } }); - }); - - it('handles known errors', async () => { - // Set up mocks - (sendRequest as jest.Mock).mockRejectedValue({ response: 'nada' }); - (editorRegistry.getInputEditor as jest.Mock).mockImplementation(() => ({ - getRequestsInRange: () => ['test'], - })); - - const { result } = renderHook(() => useSendCurrentRequest(), { wrapper: contexts }); - await act(() => result.current()); - // Second call should be the request failure - const [, [requestFailedCall]] = (dispatch as jest.Mock).mock.calls; - - // The request must have concluded - expect(requestFailedCall).toEqual({ type: 'requestFail', payload: { response: 'nada' } }); - }); - - it('handles unknown errors', async () => { - // Set up mocks - (sendRequest as jest.Mock).mockRejectedValue(NaN /* unexpected error value */); - (editorRegistry.getInputEditor as jest.Mock).mockImplementation(() => ({ - getRequestsInRange: () => ['test'], - })); - - const { result } = renderHook(() => useSendCurrentRequest(), { wrapper: contexts }); - await act(() => result.current()); - // Second call should be the request failure - const [, [requestFailedCall]] = (dispatch as jest.Mock).mock.calls; - - // The request must have concluded - expect(requestFailedCall).toEqual({ type: 'requestFail', payload: undefined }); - // It also notified the user - expect(mockContextValue.services.notifications.toasts.addError).toHaveBeenCalledWith(NaN, { - title: 'Unknown Request Error', - }); - }); - - it('notifies the user about save to history errors once only', async () => { - // Set up mocks - (sendRequest as jest.Mock).mockReturnValue( - [{ request: {} }, { request: {} }] /* two responses to save history */ - ); - (mockContextValue.services.settings.toJSON as jest.Mock).mockReturnValue({ - isHistoryEnabled: true, - }); - (mockContextValue.services.history.addToHistory as jest.Mock).mockImplementation(() => { - // Mock throwing - throw new Error('cannot save!'); - }); - (editorRegistry.getInputEditor as jest.Mock).mockImplementation(() => ({ - getRequestsInRange: () => ['test', 'test'], - })); - - const { result } = renderHook(() => useSendCurrentRequest(), { wrapper: contexts }); - await act(() => result.current()); - - expect(dispatch).toHaveBeenCalledTimes(2); - - expect(mockContextValue.services.history.addToHistory).toHaveBeenCalledTimes(2); - // It only called notification once - expect(mockContextValue.services.notifications.toasts.addError).toHaveBeenCalledTimes(1); - }); -}); diff --git a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts b/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts deleted file mode 100644 index afdd5358432e9..0000000000000 --- a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts +++ /dev/null @@ -1,148 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { i18n } from '@kbn/i18n'; -import { useCallback } from 'react'; - -import { toMountPoint } from '../../../shared_imports'; -import { isQuotaExceededError } from '../../../services/history'; -import { instance as registry } from '../../contexts/editor_context/editor_registry'; -import { useRequestActionContext, useServicesContext } from '../../contexts'; -import { StorageQuotaError } from '../../components/storage_quota_error'; -import { sendRequest } from './send_request'; -import { track } from './track'; -import { replaceVariables } from '../../../lib/utils'; -import { StorageKeys } from '../../../services'; -import { DEFAULT_VARIABLES } from '../../../../common/constants'; -import { SenseEditor } from '../../models'; - -export const useSendCurrentRequest = () => { - const { - services: { history, settings, notifications, trackUiMetric, http, autocompleteInfo, storage }, - ...startServices - } = useServicesContext(); - - const dispatch = useRequestActionContext(); - - return useCallback(async () => { - try { - const editor = registry.getInputEditor() as SenseEditor; - const variables = storage.get(StorageKeys.VARIABLES, DEFAULT_VARIABLES); - let requests = await editor.getRequestsInRange(); - requests = replaceVariables(requests, variables); - if (!requests.length) { - notifications.toasts.add( - i18n.translate('console.notification.error.noRequestSelectedTitle', { - defaultMessage: - 'No request selected. Select a request by placing the cursor inside it.', - }) - ); - return; - } - - dispatch({ type: 'sendRequest', payload: undefined }); - - // Fire and forget - setTimeout(() => track(requests, editor as SenseEditor, trackUiMetric), 0); - - const results = await sendRequest({ http, requests }); - - let saveToHistoryError: undefined | Error; - const { isHistoryEnabled } = settings.toJSON(); - - if (isHistoryEnabled) { - results.forEach(({ request: { path, method, data } }) => { - try { - history.addToHistory(path, method, data); - } catch (e) { - // Grab only the first error - if (!saveToHistoryError) { - saveToHistoryError = e; - } - } - }); - } - - if (saveToHistoryError) { - const errorTitle = i18n.translate('console.notification.error.couldNotSaveRequestTitle', { - defaultMessage: 'Could not save request to Console history.', - }); - if (isQuotaExceededError(saveToHistoryError)) { - const toast = notifications.toasts.addWarning({ - title: i18n.translate('console.notification.error.historyQuotaReachedMessage', { - defaultMessage: - 'Request history is full. Clear the console history or disable saving new requests.', - }), - text: toMountPoint( - StorageQuotaError({ - onClearHistory: () => { - history.clearHistory(); - notifications.toasts.remove(toast); - }, - onDisableSavingToHistory: () => { - settings.setIsHistoryEnabled(false); - notifications.toasts.remove(toast); - }, - }), - startServices - ), - }); - } else { - // Best effort, but still notify the user. - notifications.toasts.addError(saveToHistoryError, { - title: errorTitle, - }); - } - } - - const { polling } = settings.toJSON(); - if (polling) { - // If the user has submitted a request against ES, something in the fields, indices, aliases, - // or templates may have changed, so we'll need to update this data. Assume that if - // the user disables polling they're trying to optimize performance or otherwise - // preserve resources, so they won't want this request sent either. - autocompleteInfo.retrieve(settings, settings.getAutocomplete()); - } - - dispatch({ - type: 'requestSuccess', - payload: { - data: results, - }, - }); - } catch (e) { - if (e?.response) { - dispatch({ - type: 'requestFail', - payload: e, - }); - } else { - dispatch({ - type: 'requestFail', - payload: undefined, - }); - notifications.toasts.addError(e, { - title: i18n.translate('console.notification.error.unknownErrorTitle', { - defaultMessage: 'Unknown Request Error', - }), - }); - } - } - }, [ - storage, - dispatch, - http, - settings, - notifications.toasts, - trackUiMetric, - history, - autocompleteInfo, - startServices, - ]); -}; diff --git a/src/plugins/console/public/application/hooks/use_set_input_editor.ts b/src/plugins/console/public/application/hooks/use_set_input_editor.ts index d6029420a1772..148ede97520ea 100644 --- a/src/plugins/console/public/application/hooks/use_set_input_editor.ts +++ b/src/plugins/console/public/application/hooks/use_set_input_editor.ts @@ -10,14 +10,13 @@ import { useCallback } from 'react'; import { useEditorActionContext } from '../contexts/editor_context'; import { instance as registry } from '../contexts/editor_context/editor_registry'; -import { SenseEditor } from '../models'; import { MonacoEditorActionsProvider } from '../containers/editor/monaco_editor_actions_provider'; export const useSetInputEditor = () => { const dispatch = useEditorActionContext(); return useCallback( - (editor: SenseEditor | MonacoEditorActionsProvider) => { + (editor: MonacoEditorActionsProvider) => { dispatch({ type: 'setInputEditor', payload: editor }); registry.setInputEditor(editor); }, diff --git a/src/plugins/console/public/application/models/index.ts b/src/plugins/console/public/application/models/index.ts deleted file mode 100644 index 0d4a8f474daee..0000000000000 --- a/src/plugins/console/public/application/models/index.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './legacy_core_editor/legacy_core_editor'; -export * from './sense_editor'; diff --git a/src/plugins/console/public/application/models/legacy_core_editor/create.ts b/src/plugins/console/public/application/models/legacy_core_editor/create.ts deleted file mode 100644 index b2631e8d6712b..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/create.ts +++ /dev/null @@ -1,20 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ace from 'brace'; -import { LegacyCoreEditor } from './legacy_core_editor'; - -export const create = (el: HTMLElement) => { - const actions = document.querySelector('#ConAppEditorActions'); - if (!actions) { - throw new Error('Could not find ConAppEditorActions element!'); - } - const aceEditor = ace.edit(el); - return new LegacyCoreEditor(aceEditor, actions); -}; diff --git a/src/plugins/console/public/application/models/legacy_core_editor/create_readonly.ts b/src/plugins/console/public/application/models/legacy_core_editor/create_readonly.ts deleted file mode 100644 index dc0a95c224395..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/create_readonly.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import _ from 'lodash'; -import ace from 'brace'; -import { Mode } from './mode/output'; -import smartResize from './smart_resize'; - -export interface CustomAceEditor extends ace.Editor { - update: (text: string, mode?: string | Mode, cb?: () => void) => void; - append: (text: string, foldPrevious?: boolean, cb?: () => void) => void; -} - -/** - * Note: using read-only ace editor leaks the Ace editor API - use this as sparingly as possible or - * create an interface for it so that we don't rely directly on vendor APIs. - */ -export function createReadOnlyAceEditor(element: HTMLElement): CustomAceEditor { - const output: CustomAceEditor = ace.acequire('ace/ace').edit(element); - - const outputMode = new Mode(); - - output.$blockScrolling = Infinity; - output.resize = smartResize(output); - output.update = (val, mode, cb) => { - if (typeof mode === 'function') { - cb = mode as () => void; - mode = void 0; - } - - const session = output.getSession(); - const currentMode = val ? mode || outputMode : 'ace/mode/text'; - - // @ts-ignore - // ignore ts error here due to type definition mistake in brace for setMode(mode: string): void; - // this method accepts string or SyntaxMode which is an object. See https://github.com/ajaxorg/ace/blob/13dc911dbc0ea31ca343d5744b3f472767458fc3/ace.d.ts#L467 - session.setMode(currentMode); - session.setValue(val); - if (typeof cb === 'function') { - setTimeout(cb); - } - }; - - output.append = (val: string, foldPrevious?: boolean, cb?: () => void) => { - if (typeof foldPrevious === 'function') { - cb = foldPrevious; - foldPrevious = true; - } - if (_.isUndefined(foldPrevious)) { - foldPrevious = true; - } - const session = output.getSession(); - const lastLine = session.getLength(); - if (foldPrevious) { - output.moveCursorTo(Math.max(0, lastLine - 1), 0); - } - session.insert({ row: lastLine, column: 0 }, '\n' + val); - output.moveCursorTo(lastLine + 1, 0); - if (typeof cb === 'function') { - setTimeout(cb); - } - }; - - (function setupSession(session) { - session.setMode('ace/mode/text'); - (session as unknown as { setFoldStyle: (v: string) => void }).setFoldStyle('markbeginend'); - session.setTabSize(2); - session.setUseWrapMode(true); - })(output.getSession()); - - output.setShowPrintMargin(false); - output.setReadOnly(true); - - return output; -} diff --git a/src/plugins/console/public/application/models/legacy_core_editor/index.ts b/src/plugins/console/public/application/models/legacy_core_editor/index.ts deleted file mode 100644 index e885257520245..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/index.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import 'brace'; -import 'brace/ext/language_tools'; -import 'brace/ext/searchbox'; -import 'brace/mode/json'; -import 'brace/mode/text'; - -export * from './legacy_core_editor'; -export * from './create_readonly'; -export * from './create'; diff --git a/src/plugins/console/public/application/models/legacy_core_editor/input.test.js b/src/plugins/console/public/application/models/legacy_core_editor/input.test.js deleted file mode 100644 index e472edc1af125..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/input.test.js +++ /dev/null @@ -1,559 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import './legacy_core_editor.test.mocks'; -import RowParser from '../../../lib/row_parser'; -import { createTokenIterator } from '../../factories'; -import $ from 'jquery'; -import { create } from './create'; - -describe('Input', () => { - let coreEditor; - beforeEach(() => { - // Set up our document body - document.body.innerHTML = `
    -
    -
    -
    -
    `; - - coreEditor = create(document.querySelector('#ConAppEditor')); - - $(coreEditor.getContainer()).show(); - }); - afterEach(() => { - $(coreEditor.getContainer()).hide(); - }); - - describe('.getLineCount', () => { - it('returns the correct line length', async () => { - await coreEditor.setValue('1\n2\n3\n4', true); - expect(coreEditor.getLineCount()).toBe(4); - }); - }); - - describe('Tokenization', () => { - function tokensAsList() { - const iter = createTokenIterator({ - editor: coreEditor, - position: { lineNumber: 1, column: 1 }, - }); - const ret = []; - let t = iter.getCurrentToken(); - const parser = new RowParser(coreEditor); - if (parser.isEmptyToken(t)) { - t = parser.nextNonEmptyToken(iter); - } - while (t) { - ret.push({ value: t.value, type: t.type }); - t = parser.nextNonEmptyToken(iter); - } - - return ret; - } - - let testCount = 0; - - function tokenTest(tokenList, prefix, data) { - if (data && typeof data !== 'string') { - data = JSON.stringify(data, null, 3); - } - if (data) { - if (prefix) { - data = prefix + '\n' + data; - } - } else { - data = prefix; - } - - test('Token test ' + testCount++ + ' prefix: ' + prefix, async function () { - await coreEditor.setValue(data, true); - const tokens = tokensAsList(); - const normTokenList = []; - for (let i = 0; i < tokenList.length; i++) { - normTokenList.push({ type: tokenList[i++], value: tokenList[i] }); - } - - expect(tokens).toEqual(normTokenList); - }); - } - - tokenTest(['method', 'GET', 'url.part', '_search'], 'GET _search'); - - tokenTest(['method', 'GET', 'url.slash', '/', 'url.part', '_search'], 'GET /_search'); - - tokenTest( - [ - 'method', - 'GET', - 'url.protocol_host', - 'http://somehost', - 'url.slash', - '/', - 'url.part', - '_search', - ], - 'GET http://somehost/_search' - ); - - tokenTest(['method', 'GET', 'url.protocol_host', 'http://somehost'], 'GET http://somehost'); - - tokenTest( - ['method', 'GET', 'url.protocol_host', 'http://somehost', 'url.slash', '/'], - 'GET http://somehost/' - ); - - tokenTest( - ['method', 'GET', 'url.protocol_host', 'http://test:user@somehost', 'url.slash', '/'], - 'GET http://test:user@somehost/' - ); - - tokenTest( - ['method', 'GET', 'url.part', '_cluster', 'url.slash', '/', 'url.part', 'nodes'], - 'GET _cluster/nodes' - ); - - tokenTest( - [ - 'method', - 'GET', - 'url.slash', - '/', - 'url.part', - '_cluster', - 'url.slash', - '/', - 'url.part', - 'nodes', - ], - 'GET /_cluster/nodes' - ); - - tokenTest( - ['method', 'GET', 'url.part', 'index', 'url.slash', '/', 'url.part', '_search'], - 'GET index/_search' - ); - - tokenTest(['method', 'GET', 'url.part', 'index'], 'GET index'); - - tokenTest( - ['method', 'GET', 'url.part', 'index', 'url.slash', '/', 'url.part', 'type'], - 'GET index/type' - ); - - tokenTest( - [ - 'method', - 'GET', - 'url.slash', - '/', - 'url.part', - 'index', - 'url.slash', - '/', - 'url.part', - 'type', - 'url.slash', - '/', - ], - 'GET /index/type/' - ); - - tokenTest( - [ - 'method', - 'GET', - 'url.part', - 'index', - 'url.slash', - '/', - 'url.part', - 'type', - 'url.slash', - '/', - 'url.part', - '_search', - ], - 'GET index/type/_search' - ); - - tokenTest( - [ - 'method', - 'GET', - 'url.part', - 'index', - 'url.slash', - '/', - 'url.part', - 'type', - 'url.slash', - '/', - 'url.part', - '_search', - 'url.questionmark', - '?', - 'url.param', - 'value', - 'url.equal', - '=', - 'url.value', - '1', - ], - 'GET index/type/_search?value=1' - ); - - tokenTest( - [ - 'method', - 'GET', - 'url.part', - 'index', - 'url.slash', - '/', - 'url.part', - 'type', - 'url.slash', - '/', - 'url.part', - '1', - ], - 'GET index/type/1' - ); - - tokenTest( - [ - 'method', - 'GET', - 'url.slash', - '/', - 'url.part', - 'index1', - 'url.comma', - ',', - 'url.part', - 'index2', - 'url.slash', - '/', - ], - 'GET /index1,index2/' - ); - - tokenTest( - [ - 'method', - 'GET', - 'url.slash', - '/', - 'url.part', - 'index1', - 'url.comma', - ',', - 'url.part', - 'index2', - 'url.slash', - '/', - 'url.part', - '_search', - ], - 'GET /index1,index2/_search' - ); - - tokenTest( - [ - 'method', - 'GET', - 'url.part', - 'index1', - 'url.comma', - ',', - 'url.part', - 'index2', - 'url.slash', - '/', - 'url.part', - '_search', - ], - 'GET index1,index2/_search' - ); - - tokenTest( - [ - 'method', - 'GET', - 'url.slash', - '/', - 'url.part', - 'index1', - 'url.comma', - ',', - 'url.part', - 'index2', - ], - 'GET /index1,index2' - ); - - tokenTest( - ['method', 'GET', 'url.part', 'index1', 'url.comma', ',', 'url.part', 'index2'], - 'GET index1,index2' - ); - - tokenTest( - ['method', 'GET', 'url.slash', '/', 'url.part', 'index1', 'url.comma', ','], - 'GET /index1,' - ); - - tokenTest( - ['method', 'PUT', 'url.slash', '/', 'url.part', 'index', 'url.slash', '/'], - 'PUT /index/' - ); - - tokenTest( - ['method', 'GET', 'url.part', 'index', 'url.slash', '/', 'url.part', '_search'], - 'GET index/_search ' - ); - - tokenTest(['method', 'PUT', 'url.slash', '/', 'url.part', 'index'], 'PUT /index'); - - tokenTest( - [ - 'method', - 'PUT', - 'url.slash', - '/', - 'url.part', - 'index1', - 'url.comma', - ',', - 'url.part', - 'index2', - 'url.slash', - '/', - 'url.part', - 'type1', - 'url.comma', - ',', - 'url.part', - 'type2', - ], - 'PUT /index1,index2/type1,type2' - ); - - tokenTest( - [ - 'method', - 'PUT', - 'url.slash', - '/', - 'url.part', - 'index1', - 'url.slash', - '/', - 'url.part', - 'type1', - 'url.comma', - ',', - 'url.part', - 'type2', - 'url.comma', - ',', - ], - 'PUT /index1/type1,type2,' - ); - - tokenTest( - [ - 'method', - 'PUT', - 'url.part', - 'index1', - 'url.comma', - ',', - 'url.part', - 'index2', - 'url.slash', - '/', - 'url.part', - 'type1', - 'url.comma', - ',', - 'url.part', - 'type2', - 'url.slash', - '/', - 'url.part', - '1234', - ], - 'PUT index1,index2/type1,type2/1234' - ); - - tokenTest( - [ - 'method', - 'POST', - 'url.part', - '_search', - 'paren.lparen', - '{', - 'variable', - '"q"', - 'punctuation.colon', - ':', - 'paren.lparen', - '{', - 'paren.rparen', - '}', - 'paren.rparen', - '}', - ], - 'POST _search\n' + '{\n' + ' "q": {}\n' + ' \n' + '}' - ); - - tokenTest( - [ - 'method', - 'POST', - 'url.part', - '_search', - 'paren.lparen', - '{', - 'variable', - '"q"', - 'punctuation.colon', - ':', - 'paren.lparen', - '{', - 'variable', - '"s"', - 'punctuation.colon', - ':', - 'paren.lparen', - '{', - 'paren.rparen', - '}', - 'paren.rparen', - '}', - 'paren.rparen', - '}', - ], - 'POST _search\n' + '{\n' + ' "q": { "s": {}}\n' + ' \n' + '}' - ); - - function statesAsList() { - const ret = []; - const maxLine = coreEditor.getLineCount(); - for (let line = 1; line <= maxLine; line++) ret.push(coreEditor.getLineState(line)); - return ret; - } - - function statesTest(statesList, prefix, data) { - if (data && typeof data !== 'string') { - data = JSON.stringify(data, null, 3); - } - if (data) { - if (prefix) { - data = prefix + '\n' + data; - } - } else { - data = prefix; - } - - test('States test ' + testCount++ + ' prefix: ' + prefix, async function () { - await coreEditor.setValue(data, true); - const modes = statesAsList(); - expect(modes).toEqual(statesList); - }); - } - - statesTest( - ['start', 'json', 'json', 'start'], - 'POST _search\n' + '{\n' + ' "query": { "match_all": {} }\n' + '}' - ); - - statesTest( - ['start', 'json', ['json', 'json'], ['json', 'json'], 'json', 'start'], - 'POST _search\n' + '{\n' + ' "query": { \n' + ' "match_all": {} \n' + ' }\n' + '}' - ); - - statesTest( - ['start', 'json', 'json', 'start'], - 'POST _search\n' + '{\n' + ' "script": { "source": "" }\n' + '}' - ); - - statesTest( - ['start', 'json', 'json', 'start'], - 'POST _search\n' + '{\n' + ' "script": ""\n' + '}' - ); - - statesTest( - ['start', 'json', ['json', 'json'], 'json', 'start'], - 'POST _search\n' + '{\n' + ' "script": {\n' + ' }\n' + '}' - ); - - statesTest( - [ - 'start', - 'json', - ['script-start', 'json', 'json', 'json'], - ['script-start', 'json', 'json', 'json'], - ['json', 'json'], - 'json', - 'start', - ], - 'POST _search\n' + - '{\n' + - ' "test": { "script": """\n' + - ' test script\n' + - ' """\n' + - ' }\n' + - '}' - ); - - statesTest( - ['start', 'json', ['script-start', 'json'], ['script-start', 'json'], 'json', 'start'], - 'POST _search\n' + '{\n' + ' "script": """\n' + ' test script\n' + ' """,\n' + '}' - ); - - statesTest( - ['start', 'json', 'json', 'start'], - 'POST _search\n' + '{\n' + ' "script": """test script""",\n' + '}' - ); - - statesTest( - ['start', 'json', ['string_literal', 'json'], ['string_literal', 'json'], 'json', 'start'], - 'POST _search\n' + '{\n' + ' "something": """\n' + ' test script\n' + ' """,\n' + '}' - ); - - statesTest( - [ - 'start', - 'json', - ['string_literal', 'json', 'json', 'json'], - ['string_literal', 'json', 'json', 'json'], - ['json', 'json'], - ['json', 'json'], - 'json', - 'start', - ], - 'POST _search\n' + - '{\n' + - ' "something": { "f" : """\n' + - ' test script\n' + - ' """,\n' + - ' "g": 1\n' + - ' }\n' + - '}' - ); - - statesTest( - ['start', 'json', 'json', 'start'], - 'POST _search\n' + '{\n' + ' "something": """test script""",\n' + '}' - ); - }); -}); diff --git a/src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts b/src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts deleted file mode 100644 index 2ef5551e893d1..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts +++ /dev/null @@ -1,29 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -jest.mock('./mode/worker', () => { - return { workerModule: { id: 'sense_editor/mode/worker', src: '' } }; -}); - -import '@kbn/web-worker-stub'; - -// @ts-ignore -window.URL = { - createObjectURL: () => { - return ''; - }, -}; - -import 'brace'; -import 'brace/ext/language_tools'; -import 'brace/ext/searchbox'; -import 'brace/mode/json'; -import 'brace/mode/text'; - -document.queryCommandSupported = () => true; diff --git a/src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.ts b/src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.ts deleted file mode 100644 index edeb64104be7f..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/legacy_core_editor.ts +++ /dev/null @@ -1,511 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ace, { type Annotation } from 'brace'; -import { Editor as IAceEditor, IEditSession as IAceEditSession } from 'brace'; -import $ from 'jquery'; -import { - CoreEditor, - Position, - Range, - Token, - TokensProvider, - EditorEvent, - AutoCompleterFunction, -} from '../../../types'; -import { AceTokensProvider } from '../../../lib/ace_token_provider'; -import * as curl from '../sense_editor/curl'; -import smartResize from './smart_resize'; -import * as InputMode from './mode/input'; - -const _AceRange = ace.acequire('ace/range').Range; - -const rangeToAceRange = ({ start, end }: Range) => - new _AceRange(start.lineNumber - 1, start.column - 1, end.lineNumber - 1, end.column - 1); - -export class LegacyCoreEditor implements CoreEditor { - private _aceOnPaste: Function; - $actions: JQuery; - resize: () => void; - - constructor(private readonly editor: IAceEditor, actions: HTMLElement) { - this.$actions = $(actions); - this.editor.setShowPrintMargin(false); - - const session = this.editor.getSession(); - // @ts-expect-error - // ignore ts error here due to type definition mistake in brace for setMode(mode: string): void; - // this method accepts string or SyntaxMode which is an object. See https://github.com/ajaxorg/ace/blob/13dc911dbc0ea31ca343d5744b3f472767458fc3/ace.d.ts#L467 - session.setMode(new InputMode.Mode()); - (session as unknown as { setFoldStyle: (style: string) => void }).setFoldStyle('markbeginend'); - session.setTabSize(2); - session.setUseWrapMode(true); - - this.resize = smartResize(this.editor); - - // Intercept ace on paste handler. - this._aceOnPaste = this.editor.onPaste; - this.editor.onPaste = this.DO_NOT_USE_onPaste.bind(this); - - this.editor.setOptions({ - enableBasicAutocompletion: true, - }); - - this.editor.$blockScrolling = Infinity; - this.hideActionsBar(); - this.editor.focus(); - } - - // dirty check for tokenizer state, uses a lot less cycles - // than listening for tokenizerUpdate - waitForLatestTokens(): Promise { - return new Promise((resolve) => { - const session = this.editor.getSession(); - const checkInterval = 25; - - const check = () => { - // If the bgTokenizer doesn't exist, we can assume that the underlying editor has been - // torn down, e.g. by closing the History tab, and we don't need to do anything further. - if (session.bgTokenizer) { - // Wait until the bgTokenizer is done running before executing the callback. - if ((session.bgTokenizer as unknown as { running: boolean }).running) { - setTimeout(check, checkInterval); - } else { - resolve(); - } - } - }; - - setTimeout(check, 0); - }); - } - - getLineState(lineNumber: number) { - const session = this.editor.getSession(); - return session.getState(lineNumber - 1); - } - - getValueInRange(range: Range): string { - return this.editor.getSession().getTextRange(rangeToAceRange(range)); - } - - getTokenProvider(): TokensProvider { - return new AceTokensProvider(this.editor.getSession()); - } - - getValue(): string { - return this.editor.getValue(); - } - - async setValue(text: string, forceRetokenize: boolean): Promise { - const session = this.editor.getSession(); - session.setValue(text); - if (forceRetokenize) { - await this.forceRetokenize(); - } - } - - getLineValue(lineNumber: number): string { - const session = this.editor.getSession(); - return session.getLine(lineNumber - 1); - } - - getCurrentPosition(): Position { - const cursorPosition = this.editor.getCursorPosition(); - return { - lineNumber: cursorPosition.row + 1, - column: cursorPosition.column + 1, - }; - } - - clearSelection(): void { - this.editor.clearSelection(); - } - - getTokenAt(pos: Position): Token | null { - const provider = this.getTokenProvider(); - return provider.getTokenAt(pos); - } - - insert(valueOrPos: string | Position, value?: string): void { - if (typeof valueOrPos === 'string') { - this.editor.insert(valueOrPos); - return; - } - const document = this.editor.getSession().getDocument(); - document.insert( - { - column: valueOrPos.column - 1, - row: valueOrPos.lineNumber - 1, - }, - value || '' - ); - } - - moveCursorToPosition(pos: Position): void { - this.editor.moveCursorToPosition({ row: pos.lineNumber - 1, column: pos.column - 1 }); - } - - replace(range: Range, value: string): void { - const session = this.editor.getSession(); - session.replace(rangeToAceRange(range), value); - } - - getLines(startLine: number, endLine: number): string[] { - const session = this.editor.getSession(); - return session.getLines(startLine - 1, endLine - 1); - } - - replaceRange(range: Range, value: string) { - const pos = this.editor.getCursorPosition(); - this.editor.getSession().replace(rangeToAceRange(range), value); - - const maxRow = Math.max(range.start.lineNumber - 1 + value.split('\n').length - 1, 1); - pos.row = Math.min(pos.row, maxRow); - this.editor.moveCursorToPosition(pos); - // ACE UPGRADE - check if needed - at the moment the above may trigger a selection. - this.editor.clearSelection(); - } - - getSelectionRange() { - const result = this.editor.getSelectionRange(); - return { - start: { - lineNumber: result.start.row + 1, - column: result.start.column + 1, - }, - end: { - lineNumber: result.end.row + 1, - column: result.end.column + 1, - }, - }; - } - - getLineCount() { - // Only use this function to return line count as it uses - // a cache. - return this.editor.getSession().getLength(); - } - - addMarker(range: Range) { - return this.editor - .getSession() - .addMarker(rangeToAceRange(range), 'ace_snippet-marker', 'fullLine', false); - } - - removeMarker(ref: number) { - this.editor.getSession().removeMarker(ref); - } - - getWrapLimit(): number { - return this.editor.getSession().getWrapLimit(); - } - - on(event: EditorEvent, listener: () => void) { - if (event === 'changeCursor') { - this.editor.getSession().selection.on(event, listener); - } else if (event === 'changeSelection') { - this.editor.on(event, listener); - } else { - this.editor.getSession().on(event, listener); - } - } - - off(event: EditorEvent, listener: () => void) { - if (event === 'changeSelection') { - this.editor.off(event, listener); - } - } - - isCompleterActive() { - return Boolean( - (this.editor as unknown as { completer: { activated: unknown } }).completer && - (this.editor as unknown as { completer: { activated: unknown } }).completer.activated - ); - } - - detachCompleter() { - // In some situations we need to detach the autocomplete suggestions element manually, - // such as when navigating away from Console when the suggestions list is open. - const completer = (this.editor as unknown as { completer: { detach(): void } }).completer; - return completer?.detach(); - } - - private forceRetokenize() { - const session = this.editor.getSession(); - return new Promise((resolve) => { - // force update of tokens, but not on this thread to allow for ace rendering. - setTimeout(function () { - let i; - for (i = 0; i < session.getLength(); i++) { - session.getTokens(i); - } - resolve(); - }); - }); - } - - // eslint-disable-next-line @typescript-eslint/naming-convention - private DO_NOT_USE_onPaste(text: string) { - if (text && curl.detectCURL(text)) { - const curlInput = curl.parseCURL(text); - this.editor.insert(curlInput); - return; - } - this._aceOnPaste.call(this.editor, text); - } - - private setActionsBar = (value: number | null, topOrBottom: 'top' | 'bottom' = 'top') => { - if (value === null) { - this.$actions.css('visibility', 'hidden'); - } else { - if (topOrBottom === 'top') { - this.$actions.css({ - bottom: 'auto', - top: value, - visibility: 'visible', - }); - } else { - this.$actions.css({ - top: 'auto', - bottom: value, - visibility: 'visible', - }); - } - } - }; - - private hideActionsBar = () => { - this.setActionsBar(null); - }; - - execCommand(cmd: string) { - this.editor.execCommand(cmd); - } - - getContainer(): HTMLDivElement { - return this.editor.container as HTMLDivElement; - } - - setStyles(styles: { wrapLines: boolean; fontSize: string }) { - this.editor.getSession().setUseWrapMode(styles.wrapLines); - this.editor.container.style.fontSize = styles.fontSize; - } - - registerKeyboardShortcut(opts: { keys: string; fn: () => void; name: string }): void { - this.editor.commands.addCommand({ - exec: opts.fn, - name: opts.name, - bindKey: opts.keys, - }); - } - - unregisterKeyboardShortcut(command: string) { - // @ts-ignore - this.editor.commands.removeCommand(command); - } - - legacyUpdateUI(range: Range) { - if (!this.$actions) { - return; - } - if (range) { - // elements are positioned relative to the editor's container - // pageY is relative to page, so subtract the offset - // from pageY to get the new top value - const offsetFromPage = $(this.editor.container).offset()!.top; - const startLine = range.start.lineNumber; - const startColumn = range.start.column; - const firstLine = this.getLineValue(startLine); - const maxLineLength = this.getWrapLimit() - 5; - const isWrapping = firstLine.length > maxLineLength; - const totalOffset = offsetFromPage - (window.pageYOffset || 0); - const getScreenCoords = (line: number) => - this.editor.renderer.textToScreenCoordinates(line - 1, startColumn).pageY - totalOffset; - const topOfReq = getScreenCoords(startLine); - - if (topOfReq >= 0) { - const { bottom: maxBottom } = this.editor.container.getBoundingClientRect(); - if (topOfReq > maxBottom - totalOffset) { - this.setActionsBar(0, 'bottom'); - return; - } - let offset = 0; - if (isWrapping) { - // Try get the line height of the text area in pixels. - const textArea = $(this.editor.container.querySelector('textArea')!); - const hasRoomOnNextLine = this.getLineValue(startLine).length < maxLineLength; - if (textArea && hasRoomOnNextLine) { - // Line height + the number of wraps we have on a line. - offset += this.getLineValue(startLine).length * textArea.height()!; - } else { - if (startLine > 1) { - this.setActionsBar(getScreenCoords(startLine - 1)); - return; - } - this.setActionsBar(getScreenCoords(startLine + 1)); - return; - } - } - this.setActionsBar(topOfReq + offset); - return; - } - - const bottomOfReq = - this.editor.renderer.textToScreenCoordinates(range.end.lineNumber, range.end.column).pageY - - offsetFromPage; - - if (bottomOfReq >= 0) { - this.setActionsBar(0); - return; - } - } - } - - registerAutocompleter(autocompleter: AutoCompleterFunction): void { - // Hook into Ace - - // disable standard context based autocompletion. - // @ts-ignore - ace.define( - 'ace/autocomplete/text_completer', - ['require', 'exports', 'module'], - function ( - require: unknown, - exports: { - getCompletions: ( - innerEditor: unknown, - session: unknown, - pos: unknown, - prefix: unknown, - callback: (e: null | Error, values: string[]) => void - ) => void; - } - ) { - exports.getCompletions = function (innerEditor, session, pos, prefix, callback) { - callback(null, []); - }; - } - ); - - const langTools = ace.acequire('ace/ext/language_tools'); - - langTools.setCompleters([ - { - identifierRegexps: [ - /[a-zA-Z_0-9\.\$\-\u00A2-\uFFFF]/, // adds support for dot character - ], - getCompletions: ( - // eslint-disable-next-line @typescript-eslint/naming-convention - DO_NOT_USE_1: IAceEditor, - aceEditSession: IAceEditSession, - pos: { row: number; column: number }, - prefix: string, - callback: (...args: unknown[]) => void - ) => { - const position: Position = { - lineNumber: pos.row + 1, - column: pos.column + 1, - }; - - const getAnnotationControls = () => { - let customAnnotation: Annotation; - return { - setAnnotation(text: string) { - const annotations = aceEditSession.getAnnotations(); - customAnnotation = { - text, - row: pos.row, - column: pos.column, - type: 'warning', - }; - - aceEditSession.setAnnotations([...annotations, customAnnotation]); - }, - removeAnnotation() { - aceEditSession.setAnnotations( - aceEditSession.getAnnotations().filter((a: Annotation) => a !== customAnnotation) - ); - }, - }; - }; - - autocompleter(position, prefix, callback, getAnnotationControls()); - }, - }, - ]); - } - - destroy() { - this.editor.destroy(); - } - - /** - * Formats body of the request in the editor by removing the extra whitespaces at the beginning of lines, - * And adds the correct indentation for each line - * @param reqRange request range to indent - */ - autoIndent(reqRange: Range) { - const session = this.editor.getSession(); - const mode = session.getMode(); - const startRow = reqRange.start.lineNumber; - const endRow = reqRange.end.lineNumber; - const tab = session.getTabString(); - - for (let row = startRow; row <= endRow; row++) { - let prevLineState = ''; - let prevLineIndent = ''; - if (row > 0) { - prevLineState = session.getState(row - 1); - const prevLine = session.getLine(row - 1); - prevLineIndent = mode.getNextLineIndent(prevLineState, prevLine, tab); - } - - const line = session.getLine(row); - // @ts-ignore - // Brace does not expose type definition for mode.$getIndent, though we have access to this method provided by the underlying Ace editor. - // See https://github.com/ajaxorg/ace/blob/87ce087ed1cf20eeabe56fb0894e048d9bc9c481/lib/ace/mode/text.js#L259 - const currLineIndent = mode.$getIndent(line); - if (prevLineIndent !== currLineIndent) { - if (currLineIndent.length > 0) { - // If current line has indentation, remove it. - // Next we will add the correct indentation by looking at the previous line - const range = new _AceRange(row, 0, row, currLineIndent.length); - session.remove(range); - } - if (prevLineIndent.length > 0) { - // If previous line has indentation, add indentation at the current line - session.insert({ row, column: 0 }, prevLineIndent); - } - } - - // Lastly outdent any closing braces - mode.autoOutdent(prevLineState, session, row); - } - } - - getAllFoldRanges(): Range[] { - const session = this.editor.getSession(); - // @ts-ignore - // Brace does not expose type definition for session.getAllFolds, though we have access to this method provided by the underlying Ace editor. - // See https://github.com/ajaxorg/ace/blob/13dc911dbc0ea31ca343d5744b3f472767458fc3/ace.d.ts#L82 - return session.getAllFolds().map((fold) => fold.range); - } - - addFoldsAtRanges(foldRanges: Range[]) { - const session = this.editor.getSession(); - foldRanges.forEach((range) => { - try { - session.addFold('...', _AceRange.fromPoints(range.start, range.end)); - } catch (e) { - // ignore the error if a fold fails - } - }); - } -} diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/input.ts b/src/plugins/console/public/application/models/legacy_core_editor/mode/input.ts deleted file mode 100644 index 450feec6e9c3d..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/input.ts +++ /dev/null @@ -1,79 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ace from 'brace'; -import { workerModule } from './worker'; -import { ScriptMode } from './script'; - -const TextMode = ace.acequire('ace/mode/text').Mode; - -const MatchingBraceOutdent = ace.acequire('ace/mode/matching_brace_outdent').MatchingBraceOutdent; -const CstyleBehaviour = ace.acequire('ace/mode/behaviour/cstyle').CstyleBehaviour; -const CStyleFoldMode = ace.acequire('ace/mode/folding/cstyle').FoldMode; -const WorkerClient = ace.acequire('ace/worker/worker_client').WorkerClient; -const AceTokenizer = ace.acequire('ace/tokenizer').Tokenizer; - -import { InputHighlightRules } from './input_highlight_rules'; - -export class Mode extends TextMode { - constructor() { - super(); - this.$tokenizer = new AceTokenizer(new InputHighlightRules().getRules()); - this.$outdent = new MatchingBraceOutdent(); - this.$behaviour = new CstyleBehaviour(); - this.foldingRules = new CStyleFoldMode(); - this.createModeDelegates({ - 'script-': ScriptMode, - }); - } -} - -(function (this: Mode) { - this.getCompletions = function () { - // autocomplete is done by the autocomplete module. - return []; - }; - - this.getNextLineIndent = function (state: string, line: string, tab: string) { - let indent = this.$getIndent(line); - - if (state !== 'string_literal') { - const match = line.match(/^.*[\{\(\[]\s*$/); - if (match) { - indent += tab; - } - } - - return indent; - }; - - this.checkOutdent = function (state: unknown, line: string, input: string) { - return this.$outdent.checkOutdent(line, input); - }; - - this.autoOutdent = function (state: unknown, doc: string, row: string) { - this.$outdent.autoOutdent(doc, row); - }; - this.createWorker = function (session: { - getDocument: () => string; - setAnnotations: (arg0: unknown) => void; - }) { - const worker = new WorkerClient(['ace', 'sense_editor'], workerModule, 'SenseWorker'); - worker.attachToDocument(session.getDocument()); - worker.on('error', function (e: { data: unknown }) { - session.setAnnotations([e.data]); - }); - - worker.on('ok', function (anno: { data: unknown }) { - session.setAnnotations(anno.data); - }); - - return worker; - }; -}).call(Mode.prototype); diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.ts b/src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.ts deleted file mode 100644 index 8a2f64b3c71f4..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/input_highlight_rules.ts +++ /dev/null @@ -1,180 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ace from 'brace'; -import { addXJsonToRules } from '@kbn/ace'; - -type Token = - | string - | { token?: string; regex?: string; next?: string; push?: boolean; include?: string }; - -export function addEOL( - tokens: Token[], - reg: string | RegExp, - nextIfEOL: string, - normalNext?: string -) { - if (typeof reg === 'object') { - reg = reg.source; - } - return [ - { token: tokens.concat(['whitespace']), regex: reg + '(\\s*)$', next: nextIfEOL }, - { token: tokens, regex: reg, next: normalNext }, - ]; -} - -export const mergeTokens = (...args: any[]) => [].concat.apply([], args); - -const TextHighlightRules = ace.acequire('ace/mode/text_highlight_rules').TextHighlightRules; -// translating this to monaco -export class InputHighlightRules extends TextHighlightRules { - constructor() { - super(); - this.$rules = { - // TODO - 'start-sql': [ - { token: 'whitespace', regex: '\\s+' }, - { token: 'paren.lparen', regex: '{', next: 'json-sql', push: true }, - { regex: '', next: 'start' }, - ], - start: mergeTokens( - [ - // done - { token: 'warning', regex: '#!.*$' }, - // done - { include: 'comments' }, - // done - { token: 'paren.lparen', regex: '{', next: 'json', push: true }, - ], - // done - addEOL(['method'], /([a-zA-Z]+)/, 'start', 'method_sep'), - [ - // done - { - token: 'whitespace', - regex: '\\s+', - }, - // done - { - token: 'text', - regex: '.+?', - }, - ] - ), - method_sep: mergeTokens( - // done - addEOL( - ['whitespace', 'url.protocol_host', 'url.slash'], - /(\s+)(https?:\/\/[^?\/,]+)(\/)/, - 'start', - 'url' - ), - // done - addEOL(['whitespace', 'variable.template'], /(\s+)(\${\w+})/, 'start', 'url'), - // done - addEOL(['whitespace', 'url.protocol_host'], /(\s+)(https?:\/\/[^?\/,]+)/, 'start', 'url'), - // done - addEOL(['whitespace', 'url.slash'], /(\s+)(\/)/, 'start', 'url'), - // done - addEOL(['whitespace'], /(\s+)/, 'start', 'url') - ), - url: mergeTokens( - // done - addEOL(['variable.template'], /(\${\w+})/, 'start'), - // TODO - addEOL(['url.part'], /(_sql)/, 'start-sql', 'url-sql'), - // done - addEOL(['url.part'], /([^?\/,\s]+)/, 'start'), - // done - addEOL(['url.comma'], /(,)/, 'start'), - // done - addEOL(['url.slash'], /(\/)/, 'start'), - // done - addEOL(['url.questionmark'], /(\?)/, 'start', 'urlParams'), - // done - addEOL(['whitespace', 'comment.punctuation', 'comment.line'], /(\s+)(\/\/)(.*$)/, 'start') - ), - urlParams: mergeTokens( - // done - addEOL(['url.param', 'url.equal', 'variable.template'], /([^&=]+)(=)(\${\w+})/, 'start'), - // done - addEOL(['url.param', 'url.equal', 'url.value'], /([^&=]+)(=)([^&]*)/, 'start'), - // done - addEOL(['url.param'], /([^&=]+)/, 'start'), - // done - addEOL(['url.amp'], /(&)/, 'start'), - // done - addEOL(['whitespace', 'comment.punctuation', 'comment.line'], /(\s+)(\/\/)(.*$)/, 'start') - ), - // TODO - 'url-sql': mergeTokens( - addEOL(['url.part'], /([^?\/,\s]+)/, 'start-sql'), - addEOL(['url.comma'], /(,)/, 'start-sql'), - addEOL(['url.slash'], /(\/)/, 'start-sql'), - addEOL(['url.questionmark'], /(\?)/, 'start-sql', 'urlParams-sql') - ), - // TODO - 'urlParams-sql': mergeTokens( - addEOL(['url.param', 'url.equal', 'url.value'], /([^&=]+)(=)([^&]*)/, 'start-sql'), - addEOL(['url.param'], /([^&=]+)/, 'start-sql'), - addEOL(['url.amp'], /(&)/, 'start-sql') - ), - /** - * Each key in this.$rules considered to be a state in state machine. Regular expressions define the tokens for the current state, as well as the transitions into another state. - * See for more details https://cloud9-sdk.readme.io/docs/highlighting-rules#section-defining-states - * * - * Define a state for comments, these comment rules then can be included in other states. E.g. in 'start' and 'json' states by including { include: 'comments' } - * This will avoid duplicating the same rules in other states - */ - comments: [ - { - // Capture a line comment, indicated by # - // done - token: ['comment.punctuation', 'comment.line'], - regex: /(#)(.*$)/, - }, - { - // Begin capturing a block comment, indicated by /* - // done - token: 'comment.punctuation', - regex: /\/\*/, - push: [ - { - // Finish capturing a block comment, indicated by */ - // done - token: 'comment.punctuation', - regex: /\*\//, - next: 'pop', - }, - { - // done - defaultToken: 'comment.block', - }, - ], - }, - { - // Capture a line comment, indicated by // - // done - token: ['comment.punctuation', 'comment.line'], - regex: /(\/\/)(.*$)/, - }, - ], - }; - - addXJsonToRules(this, 'json'); - // Add comment rules to json rule set - this.$rules.json.unshift({ include: 'comments' }); - - this.$rules.json.unshift({ token: 'variable.template', regex: /("\${\w+}")/ }); - - if (this instanceof InputHighlightRules) { - this.normalizeRules(); - } - } -} diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/output.ts b/src/plugins/console/public/application/models/legacy_core_editor/mode/output.ts deleted file mode 100644 index df7f3c37d55ec..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/output.ts +++ /dev/null @@ -1,37 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ace from 'brace'; - -import { OutputJsonHighlightRules } from './output_highlight_rules'; - -const JSONMode = ace.acequire('ace/mode/json').Mode; -const MatchingBraceOutdent = ace.acequire('ace/mode/matching_brace_outdent').MatchingBraceOutdent; -const CstyleBehaviour = ace.acequire('ace/mode/behaviour/cstyle').CstyleBehaviour; -const CStyleFoldMode = ace.acequire('ace/mode/folding/cstyle').FoldMode; -ace.acequire('ace/worker/worker_client'); -const AceTokenizer = ace.acequire('ace/tokenizer').Tokenizer; - -export class Mode extends JSONMode { - constructor() { - super(); - this.$tokenizer = new AceTokenizer(new OutputJsonHighlightRules().getRules()); - this.$outdent = new MatchingBraceOutdent(); - this.$behaviour = new CstyleBehaviour(); - this.foldingRules = new CStyleFoldMode(); - } -} - -(function (this: Mode) { - this.createWorker = function () { - return null; - }; - - this.$id = 'sense/mode/input'; -}).call(Mode.prototype); diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.test.ts b/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.test.ts deleted file mode 100644 index a18841aa4dc17..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.test.ts +++ /dev/null @@ -1,56 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { mapStatusCodeToBadge } from './output_highlight_rules'; - -describe('mapStatusCodeToBadge', () => { - const testCases = [ - { - description: 'treats 100 as as default', - value: '# PUT test-index 100 Continue', - badge: 'badge.badge--default', - }, - { - description: 'treats 200 as success', - value: '# PUT test-index 200 OK', - badge: 'badge.badge--success', - }, - { - description: 'treats 301 as primary', - value: '# PUT test-index 301 Moved Permanently', - badge: 'badge.badge--primary', - }, - { - description: 'treats 400 as warning', - value: '# PUT test-index 404 Not Found', - badge: 'badge.badge--warning', - }, - { - description: 'treats 502 as danger', - value: '# PUT test-index 502 Bad Gateway', - badge: 'badge.badge--danger', - }, - { - description: 'treats unexpected numbers as danger', - value: '# PUT test-index 666 Demonic Invasion', - badge: 'badge.badge--danger', - }, - { - description: 'treats no numbers as undefined', - value: '# PUT test-index', - badge: undefined, - }, - ]; - - testCases.forEach(({ description, value, badge }) => { - test(description, () => { - expect(mapStatusCodeToBadge(value)).toBe(badge); - }); - }); -}); diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.ts b/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.ts deleted file mode 100644 index 765ba3e263f22..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/output_highlight_rules.ts +++ /dev/null @@ -1,64 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ace from 'brace'; -import 'brace/mode/json'; -import { addXJsonToRules } from '@kbn/ace'; - -const JsonHighlightRules = ace.acequire('ace/mode/json_highlight_rules').JsonHighlightRules; - -export const mapStatusCodeToBadge = (value?: string) => { - const regExpMatchArray = value?.match(/\d+/); - if (regExpMatchArray) { - const status = parseInt(regExpMatchArray[0], 10); - if (status <= 199) { - return 'badge.badge--default'; - } - if (status <= 299) { - return 'badge.badge--success'; - } - if (status <= 399) { - return 'badge.badge--primary'; - } - if (status <= 499) { - return 'badge.badge--warning'; - } - return 'badge.badge--danger'; - } -}; - -export class OutputJsonHighlightRules extends JsonHighlightRules { - constructor() { - super(); - this.$rules = {}; - addXJsonToRules(this, 'start'); - this.$rules.start.unshift( - { - token: 'warning', - regex: '#!.*$', - }, - { - token: 'comment', - // match a comment starting with a hash at the start of the line - // ignore status codes and status texts at the end of the line (e.g. # GET _search/foo 200, # GET _search/foo 200 OK) - regex: /#(.*?)(?=[1-5][0-9][0-9]\s(?:[\sA-Za-z]+)|(?:[1-5][0-9][0-9])|$)/, - }, - { - token: mapStatusCodeToBadge, - // match status codes and status texts at the end of the line (e.g. # GET _search/foo 200, # GET _search/foo 200 OK) - // this rule allows us to highlight them with the corresponding badge color (e.g. 200 OK -> badge.badge--success) - regex: /([1-5][0-9][0-9]\s?[\sA-Za-z]+$)/, - } - ); - - if (this instanceof OutputJsonHighlightRules) { - this.normalizeRules(); - } - } -} diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/script.ts b/src/plugins/console/public/application/models/legacy_core_editor/mode/script.ts deleted file mode 100644 index f50b6d3abe8ab..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/script.ts +++ /dev/null @@ -1,48 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ace from 'brace'; -import { ScriptHighlightRules } from '@kbn/ace'; - -const TextMode = ace.acequire('ace/mode/text').Mode; -const MatchingBraceOutdent = ace.acequire('ace/mode/matching_brace_outdent').MatchingBraceOutdent; -const CstyleBehaviour = ace.acequire('ace/mode/behaviour/cstyle').CstyleBehaviour; -const CStyleFoldMode = ace.acequire('ace/mode/folding/cstyle').FoldMode; -ace.acequire('ace/tokenizer'); - -export class ScriptMode extends TextMode { - constructor() { - super(); - this.$outdent = new MatchingBraceOutdent(); - this.$behaviour = new CstyleBehaviour(); - this.foldingRules = new CStyleFoldMode(); - } -} - -(function (this: ScriptMode) { - this.HighlightRules = ScriptHighlightRules; - - this.getNextLineIndent = function (state: unknown, line: string, tab: string) { - let indent = this.$getIndent(line); - const match = line.match(/^.*[\{\[]\s*$/); - if (match) { - indent += tab; - } - - return indent; - }; - - this.checkOutdent = function (state: unknown, line: string, input: string) { - return this.$outdent.checkOutdent(line, input); - }; - - this.autoOutdent = function (state: unknown, doc: string, row: string) { - this.$outdent.autoOutdent(doc, row); - }; -}).call(ScriptMode.prototype); diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.d.ts b/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.d.ts deleted file mode 100644 index 8067bec3556ae..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.d.ts +++ /dev/null @@ -1,10 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export declare const workerModule: { id: string; src: string }; diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.js deleted file mode 100644 index 23f636b79e1a6..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/index.js +++ /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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import src from '!!raw-loader!./worker'; - -export const workerModule = { - id: 'sense_editor/mode/worker', - src, -}; diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js deleted file mode 100644 index 65567f377cc52..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js +++ /dev/null @@ -1,2392 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* @notice - * - * This product includes code that is based on Ace editor, which was available - * under a "BSD" license. - * - * Distributed under the BSD license: - * - * Copyright (c) 2010, Ajax.org B.V. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Ajax.org B.V. nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* eslint-disable prettier/prettier,prefer-const,eqeqeq,import/no-commonjs,no-undef,no-sequences, - block-scoped-var,no-use-before-define,no-var,one-var,guard-for-in,new-cap,no-nested-ternary,no-redeclare, - no-unused-vars,no-extend-native,no-empty,camelcase,no-proto,@kbn/imports/no_unresolvable_imports */ -/* - This file is loaded up as a blob by Brace to hand to Ace to load as Jsonp - (hence the redefining of everything). It is based on the javascript - mode from the brace distro. -*/ -function init(window) { - function resolveModuleId(id, paths) { - for (let testPath = id, tail = ''; testPath;) { - let alias = paths[testPath]; - if ('string' === typeof alias) return alias + tail; - if (alias) - {return (alias.location.replace(/\/*$/, '/') + (tail || alias.main || alias.name));} - if (alias === !1) return ''; - let i = testPath.lastIndexOf('/'); - if (-1 === i) break; - (tail = testPath.substr(i) + tail), (testPath = testPath.slice(0, i)); - } - return id; - } - if ( - !( - (void 0 !== window.window && window.document) || - (window.acequire && window.define) - ) - ) { - window.console || - ((window.console = function () { - let msgs = Array.prototype.slice.call(arguments, 0); - postMessage({ type: 'log', data: msgs }); - }), - (window.console.error = window.console.warn = window.console.log = window.console.trace = - window.console)), - (window.window = window), - (window.ace = window), - (window.onerror = function (message, file, line, col, err) { - postMessage({ - type: 'error', - data: { - message: message, - data: err.data, - file: file, - line: line, - col: col, - stack: err.stack, - }, - }); - }), - (window.normalizeModule = function (parentId, moduleName) { - if (-1 !== moduleName.indexOf('!')) { - let chunks = moduleName.split('!'); - return ( - window.normalizeModule(parentId, chunks[0]) + - '!' + - window.normalizeModule(parentId, chunks[1]) - ); - } - if ('.' == moduleName.charAt(0)) { - let base = parentId - .split('/') - .slice(0, -1) - .join('/'); - for ( - moduleName = (base ? base + '/' : '') + moduleName; - -1 !== moduleName.indexOf('.') && previous != moduleName; - - ) { - var previous = moduleName; - moduleName = moduleName - .replace(/^\.\//, '') - .replace(/\/\.\//, '/') - .replace(/[^\/]+\/\.\.\//, ''); - } - } - return moduleName; - }), - (window.acequire = function acequire(parentId, id) { - if ((id || ((id = parentId), (parentId = null)), !id.charAt)) - {throw Error( - 'worker.js acequire() accepts only (parentId, id) as arguments' - );} - id = window.normalizeModule(parentId, id); - let module = window.acequire.modules[id]; - if (module) - {return ( - module.initialized || - ((module.initialized = !0), - (module.exports = module.factory().exports)), - module.exports - );} - if (!window.acequire.tlns) return console.log('unable to load ' + id); - let path = resolveModuleId(id, window.acequire.tlns); - return ( - '.js' != path.slice(-3) && (path += '.js'), - (window.acequire.id = id), - (window.acequire.modules[id] = {}), - importScripts(path), - window.acequire(parentId, id) - ); - }), - (window.acequire.modules = {}), - (window.acequire.tlns = {}), - (window.define = function (id, deps, factory) { - if ( - (2 == arguments.length - ? ((factory = deps), - 'string' !== typeof id && ((deps = id), (id = window.acequire.id))) - : 1 == arguments.length && - ((factory = id), (deps = []), (id = window.acequire.id)), - 'function' !== typeof factory) - ) - {return ( - (window.acequire.modules[id] = { - exports: factory, - initialized: !0, - }), - void 0 - );} - deps.length || (deps = ['require', 'exports', 'module']); - let req = function (childId) { - return window.acequire(id, childId); - }; - window.acequire.modules[id] = { - exports: {}, - factory: function () { - let module = this, - returnExports = factory.apply( - this, - deps.map(function (dep) { - switch (dep) { - case 'require': - return req; - case 'exports': - return module.exports; - case 'module': - return module; - default: - return req(dep); - } - }) - ); - return returnExports && (module.exports = returnExports), module; - }, - }; - }), - (window.define.amd = {}), - (acequire.tlns = {}), - (window.initBaseUrls = function (topLevelNamespaces) { - for (let i in topLevelNamespaces) - {acequire.tlns[i] = topLevelNamespaces[i];} - }), - (window.initSender = function () { - let EventEmitter = window.acequire('ace/lib/event_emitter') - .EventEmitter, - oop = window.acequire('ace/lib/oop'), - Sender = function () {}; - return ( - function () { - oop.implement(this, EventEmitter), - (this.callback = function (data, callbackId) { - postMessage({ type: 'call', id: callbackId, data: data }); - }), - (this.emit = function (name, data) { - postMessage({ type: 'event', name: name, data: data }); - }); - }.call(Sender.prototype), - new Sender() - ); - }); - let main = (window.main = null), - sender = (window.sender = null); - window.onmessage = function (e) { - let msg = e.data; - if (msg.event && sender) sender._signal(msg.event, msg.data); - else if (msg.command) - {if (main[msg.command]) main[msg.command].apply(main, msg.args); - else { - if (!window[msg.command]) - throw Error('Unknown command:' + msg.command); - window[msg.command].apply(window, msg.args); - }} - else if (msg.init) { - window.initBaseUrls(msg.tlns), - acequire('ace/lib/es5-shim'), - (sender = window.sender = window.initSender()); - let clazz = acequire(msg.module)[msg.classname]; - main = window.main = new clazz(sender); - } - }; - } -} -init(this); -ace.define('ace/lib/oop', ['require', 'exports', 'module'], function ( - acequire, - exports -) { - (exports.inherits = function (ctor, superCtor) { - (ctor.super_ = superCtor), - (ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: !1, - writable: !0, - configurable: !0, - }, - })); - }), - (exports.mixin = function (obj, mixin) { - for (let key in mixin) obj[key] = mixin[key]; - return obj; - }), - (exports.implement = function (proto, mixin) { - exports.mixin(proto, mixin); - }); -}), -ace.define('ace/range', ['require', 'exports', 'module'], function ( - acequire, - exports -) { - let comparePoints = function (p1, p2) { - return p1.row - p2.row || p1.column - p2.column; - }, - Range = function (startRow, startColumn, endRow, endColumn) { - (this.start = { row: startRow, column: startColumn }), - (this.end = { row: endRow, column: endColumn }); - }; - (function () { - (this.isEqual = function (range) { - return ( - this.start.row === range.start.row && - this.end.row === range.end.row && - this.start.column === range.start.column && - this.end.column === range.end.column - ); - }), - (this.toString = function () { - return ( - 'Range: [' + - this.start.row + - '/' + - this.start.column + - '] -> [' + - this.end.row + - '/' + - this.end.column + - ']' - ); - }), - (this.contains = function (row, column) { - return 0 == this.compare(row, column); - }), - (this.compareRange = function (range) { - let cmp, - end = range.end, - start = range.start; - return ( - (cmp = this.compare(end.row, end.column)), - 1 == cmp - ? ((cmp = this.compare(start.row, start.column)), - 1 == cmp ? 2 : 0 == cmp ? 1 : 0) - : -1 == cmp - ? -2 - : ((cmp = this.compare(start.row, start.column)), - -1 == cmp ? -1 : 1 == cmp ? 42 : 0) - ); - }), - (this.comparePoint = function (p) { - return this.compare(p.row, p.column); - }), - (this.containsRange = function (range) { - return ( - 0 == this.comparePoint(range.start) && - 0 == this.comparePoint(range.end) - ); - }), - (this.intersects = function (range) { - let cmp = this.compareRange(range); - return -1 == cmp || 0 == cmp || 1 == cmp; - }), - (this.isEnd = function (row, column) { - return this.end.row == row && this.end.column == column; - }), - (this.isStart = function (row, column) { - return this.start.row == row && this.start.column == column; - }), - (this.setStart = function (row, column) { - 'object' === typeof row - ? ((this.start.column = row.column), (this.start.row = row.row)) - : ((this.start.row = row), (this.start.column = column)); - }), - (this.setEnd = function (row, column) { - 'object' === typeof row - ? ((this.end.column = row.column), (this.end.row = row.row)) - : ((this.end.row = row), (this.end.column = column)); - }), - (this.inside = function (row, column) { - return 0 == this.compare(row, column) - ? this.isEnd(row, column) || this.isStart(row, column) - ? !1 - : !0 - : !1; - }), - (this.insideStart = function (row, column) { - return 0 == this.compare(row, column) - ? this.isEnd(row, column) - ? !1 - : !0 - : !1; - }), - (this.insideEnd = function (row, column) { - return 0 == this.compare(row, column) - ? this.isStart(row, column) - ? !1 - : !0 - : !1; - }), - (this.compare = function (row, column) { - return this.isMultiLine() || row !== this.start.row - ? this.start.row > row - ? -1 - : row > this.end.row - ? 1 - : this.start.row === row - ? column >= this.start.column - ? 0 - : -1 - : this.end.row === row - ? this.end.column >= column - ? 0 - : 1 - : 0 - : this.start.column > column - ? -1 - : column > this.end.column - ? 1 - : 0; - }), - (this.compareStart = function (row, column) { - return this.start.row == row && this.start.column == column - ? -1 - : this.compare(row, column); - }), - (this.compareEnd = function (row, column) { - return this.end.row == row && this.end.column == column - ? 1 - : this.compare(row, column); - }), - (this.compareInside = function (row, column) { - return this.end.row == row && this.end.column == column - ? 1 - : this.start.row == row && this.start.column == column - ? -1 - : this.compare(row, column); - }), - (this.clipRows = function (firstRow, lastRow) { - if (this.end.row > lastRow) var end = { row: lastRow + 1, column: 0 }; - else if (firstRow > this.end.row) - {var end = { row: firstRow, column: 0 };} - if (this.start.row > lastRow) - {var start = { row: lastRow + 1, column: 0 };} - else if (firstRow > this.start.row) - {var start = { row: firstRow, column: 0 };} - return Range.fromPoints(start || this.start, end || this.end); - }), - (this.extend = function (row, column) { - let cmp = this.compare(row, column); - if (0 == cmp) return this; - if (-1 == cmp) var start = { row: row, column: column }; - else var end = { row: row, column: column }; - return Range.fromPoints(start || this.start, end || this.end); - }), - (this.isEmpty = function () { - return ( - this.start.row === this.end.row && - this.start.column === this.end.column - ); - }), - (this.isMultiLine = function () { - return this.start.row !== this.end.row; - }), - (this.clone = function () { - return Range.fromPoints(this.start, this.end); - }), - (this.collapseRows = function () { - return 0 == this.end.column - ? new Range( - this.start.row, - 0, - Math.max(this.start.row, this.end.row - 1), - 0 - ) - : new Range(this.start.row, 0, this.end.row, 0); - }), - (this.toScreenRange = function (session) { - let screenPosStart = session.documentToScreenPosition(this.start), - screenPosEnd = session.documentToScreenPosition(this.end); - return new Range( - screenPosStart.row, - screenPosStart.column, - screenPosEnd.row, - screenPosEnd.column - ); - }), - (this.moveBy = function (row, column) { - (this.start.row += row), - (this.start.column += column), - (this.end.row += row), - (this.end.column += column); - }); - }.call(Range.prototype), - (Range.fromPoints = function (start, end) { - return new Range(start.row, start.column, end.row, end.column); - }), - (Range.comparePoints = comparePoints), - (Range.comparePoints = function (p1, p2) { - return p1.row - p2.row || p1.column - p2.column; - }), - (exports.Range = Range)); -}), -ace.define('ace/apply_delta', ['require', 'exports', 'module'], function ( - acequire, - exports -) { - exports.applyDelta = function (docLines, delta) { - let row = delta.start.row, - startColumn = delta.start.column, - line = docLines[row] || ''; - switch (delta.action) { - case 'insert': - var lines = delta.lines; - if (1 === lines.length) - {docLines[row] = - line.substring(0, startColumn) + - delta.lines[0] + - line.substring(startColumn);} - else { - let args = [row, 1].concat(delta.lines); - docLines.splice.apply(docLines, args), - (docLines[row] = line.substring(0, startColumn) + docLines[row]), - (docLines[row + delta.lines.length - 1] += line.substring( - startColumn - )); - } - break; - case 'remove': - var endColumn = delta.end.column, - endRow = delta.end.row; - row === endRow - ? (docLines[row] = - line.substring(0, startColumn) + line.substring(endColumn)) - : docLines.splice( - row, - endRow - row + 1, - line.substring(0, startColumn) + - docLines[endRow].substring(endColumn) - ); - } - }; -}), -ace.define( - 'ace/lib/event_emitter', - ['require', 'exports', 'module'], - function (acequire, exports) { - let EventEmitter = {}, - stopPropagation = function () { - this.propagationStopped = !0; - }, - preventDefault = function () { - this.defaultPrevented = !0; - }; - (EventEmitter._emit = EventEmitter._dispatchEvent = function ( - eventName, - e - ) { - this._eventRegistry || (this._eventRegistry = {}), - this._defaultHandlers || (this._defaultHandlers = {}); - let listeners = this._eventRegistry[eventName] || [], - defaultHandler = this._defaultHandlers[eventName]; - if (listeners.length || defaultHandler) { - ('object' === typeof e && e) || (e = {}), - e.type || (e.type = eventName), - e.stopPropagation || (e.stopPropagation = stopPropagation), - e.preventDefault || (e.preventDefault = preventDefault), - (listeners = listeners.slice()); - for ( - let i = 0; - listeners.length > i && - (listeners[i](e, this), !e.propagationStopped); - i++ - ); - return defaultHandler && !e.defaultPrevented - ? defaultHandler(e, this) - : void 0; - } - }), - (EventEmitter._signal = function (eventName, e) { - let listeners = (this._eventRegistry || {})[eventName]; - if (listeners) { - listeners = listeners.slice(); - for (let i = 0; listeners.length > i; i++) listeners[i](e, this); - } - }), - (EventEmitter.once = function (eventName, callback) { - let _self = this; - callback && - this.addEventListener(eventName, function newCallback() { - _self.removeEventListener(eventName, newCallback), - callback.apply(null, arguments); - }); - }), - (EventEmitter.setDefaultHandler = function (eventName, callback) { - let handlers = this._defaultHandlers; - if ( - (handlers || - (handlers = this._defaultHandlers = { _disabled_: {} }), - handlers[eventName]) - ) { - let old = handlers[eventName], - disabled = handlers._disabled_[eventName]; - disabled || (handlers._disabled_[eventName] = disabled = []), - disabled.push(old); - let i = disabled.indexOf(callback); - -1 != i && disabled.splice(i, 1); - } - handlers[eventName] = callback; - }), - (EventEmitter.removeDefaultHandler = function (eventName, callback) { - let handlers = this._defaultHandlers; - if (handlers) { - let disabled = handlers._disabled_[eventName]; - if (handlers[eventName] == callback) - {handlers[eventName], - disabled && this.setDefaultHandler(eventName, disabled.pop());} - else if (disabled) { - let i = disabled.indexOf(callback); - -1 != i && disabled.splice(i, 1); - } - } - }), - (EventEmitter.on = EventEmitter.addEventListener = function ( - eventName, - callback, - capturing - ) { - this._eventRegistry = this._eventRegistry || {}; - let listeners = this._eventRegistry[eventName]; - return ( - listeners || (listeners = this._eventRegistry[eventName] = []), - -1 == listeners.indexOf(callback) && - listeners[capturing ? 'unshift' : 'push'](callback), - callback - ); - }), - (EventEmitter.off = EventEmitter.removeListener = EventEmitter.removeEventListener = function ( - eventName, - callback - ) { - this._eventRegistry = this._eventRegistry || {}; - let listeners = this._eventRegistry[eventName]; - if (listeners) { - let index = listeners.indexOf(callback); - -1 !== index && listeners.splice(index, 1); - } - }), - (EventEmitter.removeAllListeners = function (eventName) { - this._eventRegistry && (this._eventRegistry[eventName] = []); - }), - (exports.EventEmitter = EventEmitter); - } -), -ace.define( - 'ace/anchor', - ['require', 'exports', 'module', 'ace/lib/oop', 'ace/lib/event_emitter'], - function (acequire, exports) { - let oop = acequire('./lib/oop'), - EventEmitter = acequire('./lib/event_emitter').EventEmitter, - Anchor = (exports.Anchor = function (doc, row, column) { - (this.$onChange = this.onChange.bind(this)), - this.attach(doc), - column === void 0 - ? this.setPosition(row.row, row.column) - : this.setPosition(row, column); - }); - (function () { - function $pointsInOrder(point1, point2, equalPointsInOrder) { - let bColIsAfter = equalPointsInOrder - ? point1.column <= point2.column - : point1.column < point2.column; - return ( - point1.row < point2.row || (point1.row == point2.row && bColIsAfter) - ); - } - function $getTransformedPoint(delta, point, moveIfEqual) { - let deltaIsInsert = 'insert' == delta.action, - deltaRowShift = - (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row), - deltaColShift = - (deltaIsInsert ? 1 : -1) * - (delta.end.column - delta.start.column), - deltaStart = delta.start, - deltaEnd = deltaIsInsert ? deltaStart : delta.end; - return $pointsInOrder(point, deltaStart, moveIfEqual) - ? { row: point.row, column: point.column } - : $pointsInOrder(deltaEnd, point, !moveIfEqual) - ? { - row: point.row + deltaRowShift, - column: - point.column + - (point.row == deltaEnd.row ? deltaColShift : 0), - } - : { row: deltaStart.row, column: deltaStart.column }; - } - oop.implement(this, EventEmitter), - (this.getPosition = function () { - return this.$clipPositionToDocument(this.row, this.column); - }), - (this.getDocument = function () { - return this.document; - }), - (this.$insertRight = !1), - (this.onChange = function (delta) { - if ( - !( - (delta.start.row == delta.end.row && - delta.start.row != this.row) || - delta.start.row > this.row - ) - ) { - let point = $getTransformedPoint( - delta, - { row: this.row, column: this.column }, - this.$insertRight - ); - this.setPosition(point.row, point.column, !0); - } - }), - (this.setPosition = function (row, column, noClip) { - let pos; - if ( - ((pos = noClip - ? { row: row, column: column } - : this.$clipPositionToDocument(row, column)), - this.row != pos.row || this.column != pos.column) - ) { - let old = { row: this.row, column: this.column }; - (this.row = pos.row), - (this.column = pos.column), - this._signal('change', { old: old, value: pos }); - } - }), - (this.detach = function () { - this.document.removeEventListener('change', this.$onChange); - }), - (this.attach = function (doc) { - (this.document = doc || this.document), - this.document.on('change', this.$onChange); - }), - (this.$clipPositionToDocument = function (row, column) { - let pos = {}; - return ( - row >= this.document.getLength() - ? ((pos.row = Math.max(0, this.document.getLength() - 1)), - (pos.column = this.document.getLine(pos.row).length)) - : 0 > row - ? ((pos.row = 0), (pos.column = 0)) - : ((pos.row = row), - (pos.column = Math.min( - this.document.getLine(pos.row).length, - Math.max(0, column) - ))), - 0 > column && (pos.column = 0), - pos - ); - }); - }.call(Anchor.prototype)); - } -), -ace.define( - 'ace/document', - [ - 'require', - 'exports', - 'module', - 'ace/lib/oop', - 'ace/apply_delta', - 'ace/lib/event_emitter', - 'ace/range', - 'ace/anchor', - ], - function (acequire, exports) { - let oop = acequire('./lib/oop'), - applyDelta = acequire('./apply_delta').applyDelta, - EventEmitter = acequire('./lib/event_emitter').EventEmitter, - Range = acequire('./range').Range, - Anchor = acequire('./anchor').Anchor, - Document = function (textOrLines) { - (this.$lines = ['']), - 0 === textOrLines.length - ? (this.$lines = ['']) - : Array.isArray(textOrLines) - ? this.insertMergedLines({ row: 0, column: 0 }, textOrLines) - : this.insert({ row: 0, column: 0 }, textOrLines); - }; - (function () { - oop.implement(this, EventEmitter), - (this.setValue = function (text) { - let len = this.getLength() - 1; - this.remove(new Range(0, 0, len, this.getLine(len).length)), - this.insert({ row: 0, column: 0 }, text); - }), - (this.getValue = function () { - return this.getAllLines().join(this.getNewLineCharacter()); - }), - (this.createAnchor = function (row, column) { - return new Anchor(this, row, column); - }), - (this.$split = - 0 === 'aaa'.split(/a/).length - ? function (text) { - return text.replace(/\r\n|\r/g, '\n').split('\n'); - } - : function (text) { - return text.split(/\r\n|\r|\n/); - }), - (this.$detectNewLine = function (text) { - let match = text.match(/^.*?(\r\n|\r|\n)/m); - (this.$autoNewLine = match ? match[1] : '\n'), - this._signal('changeNewLineMode'); - }), - (this.getNewLineCharacter = function () { - switch (this.$newLineMode) { - case 'windows': - return '\r\n'; - case 'unix': - return '\n'; - default: - return this.$autoNewLine || '\n'; - } - }), - (this.$autoNewLine = ''), - (this.$newLineMode = 'auto'), - (this.setNewLineMode = function (newLineMode) { - this.$newLineMode !== newLineMode && - ((this.$newLineMode = newLineMode), - this._signal('changeNewLineMode')); - }), - (this.getNewLineMode = function () { - return this.$newLineMode; - }), - (this.isNewLine = function (text) { - return '\r\n' == text || '\r' == text || '\n' == text; - }), - (this.getLine = function (row) { - return this.$lines[row] || ''; - }), - (this.getLines = function (firstRow, lastRow) { - return this.$lines.slice(firstRow, lastRow + 1); - }), - (this.getAllLines = function () { - return this.getLines(0, this.getLength()); - }), - (this.getLength = function () { - return this.$lines.length; - }), - (this.getTextRange = function (range) { - return this.getLinesForRange(range).join( - this.getNewLineCharacter() - ); - }), - (this.getLinesForRange = function (range) { - let lines; - if (range.start.row === range.end.row) - {lines = [ - this.getLine(range.start.row).substring( - range.start.column, - range.end.column - ), - ];} - else { - (lines = this.getLines(range.start.row, range.end.row)), - (lines[0] = (lines[0] || '').substring(range.start.column)); - let l = lines.length - 1; - range.end.row - range.start.row == l && - (lines[l] = lines[l].substring(0, range.end.column)); - } - return lines; - }), - (this.insertLines = function (row, lines) { - return ( - console.warn( - 'Use of document.insertLines is deprecated. Use the insertFullLines method instead.' - ), - this.insertFullLines(row, lines) - ); - }), - (this.removeLines = function (firstRow, lastRow) { - return ( - console.warn( - 'Use of document.removeLines is deprecated. Use the removeFullLines method instead.' - ), - this.removeFullLines(firstRow, lastRow) - ); - }), - (this.insertNewLine = function (position) { - return ( - console.warn( - 'Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead.' - ), - this.insertMergedLines(position, ['', '']) - ); - }), - (this.insert = function (position, text) { - return ( - 1 >= this.getLength() && this.$detectNewLine(text), - this.insertMergedLines(position, this.$split(text)) - ); - }), - (this.insertInLine = function (position, text) { - let start = this.clippedPos(position.row, position.column), - end = this.pos(position.row, position.column + text.length); - return ( - this.applyDelta( - { start: start, end: end, action: 'insert', lines: [text] }, - !0 - ), - this.clonePos(end) - ); - }), - (this.clippedPos = function (row, column) { - let length = this.getLength(); - void 0 === row - ? (row = length) - : 0 > row - ? (row = 0) - : row >= length && ((row = length - 1), (column = void 0)); - let line = this.getLine(row); - return ( - void 0 == column && (column = line.length), - (column = Math.min(Math.max(column, 0), line.length)), - { row: row, column: column } - ); - }), - (this.clonePos = function (pos) { - return { row: pos.row, column: pos.column }; - }), - (this.pos = function (row, column) { - return { row: row, column: column }; - }), - (this.$clipPosition = function (position) { - let length = this.getLength(); - return ( - position.row >= length - ? ((position.row = Math.max(0, length - 1)), - (position.column = this.getLine(length - 1).length)) - : ((position.row = Math.max(0, position.row)), - (position.column = Math.min( - Math.max(position.column, 0), - this.getLine(position.row).length - ))), - position - ); - }), - (this.insertFullLines = function (row, lines) { - row = Math.min(Math.max(row, 0), this.getLength()); - let column = 0; - this.getLength() > row - ? ((lines = lines.concat([''])), (column = 0)) - : ((lines = [''].concat(lines)), - row--, - (column = this.$lines[row].length)), - this.insertMergedLines({ row: row, column: column }, lines); - }), - (this.insertMergedLines = function (position, lines) { - let start = this.clippedPos(position.row, position.column), - end = { - row: start.row + lines.length - 1, - column: - (1 == lines.length ? start.column : 0) + - lines[lines.length - 1].length, - }; - return ( - this.applyDelta({ - start: start, - end: end, - action: 'insert', - lines: lines, - }), - this.clonePos(end) - ); - }), - (this.remove = function (range) { - let start = this.clippedPos(range.start.row, range.start.column), - end = this.clippedPos(range.end.row, range.end.column); - return ( - this.applyDelta({ - start: start, - end: end, - action: 'remove', - lines: this.getLinesForRange({ start: start, end: end }), - }), - this.clonePos(start) - ); - }), - (this.removeInLine = function (row, startColumn, endColumn) { - let start = this.clippedPos(row, startColumn), - end = this.clippedPos(row, endColumn); - return ( - this.applyDelta( - { - start: start, - end: end, - action: 'remove', - lines: this.getLinesForRange({ start: start, end: end }), - }, - !0 - ), - this.clonePos(start) - ); - }), - (this.removeFullLines = function (firstRow, lastRow) { - (firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1)), - (lastRow = Math.min(Math.max(0, lastRow), this.getLength() - 1)); - let deleteFirstNewLine = - lastRow == this.getLength() - 1 && firstRow > 0, - deleteLastNewLine = this.getLength() - 1 > lastRow, - startRow = deleteFirstNewLine ? firstRow - 1 : firstRow, - startCol = deleteFirstNewLine ? this.getLine(startRow).length : 0, - endRow = deleteLastNewLine ? lastRow + 1 : lastRow, - endCol = deleteLastNewLine ? 0 : this.getLine(endRow).length, - range = new Range(startRow, startCol, endRow, endCol), - deletedLines = this.$lines.slice(firstRow, lastRow + 1); - return ( - this.applyDelta({ - start: range.start, - end: range.end, - action: 'remove', - lines: this.getLinesForRange(range), - }), - deletedLines - ); - }), - (this.removeNewLine = function (row) { - this.getLength() - 1 > row && - row >= 0 && - this.applyDelta({ - start: this.pos(row, this.getLine(row).length), - end: this.pos(row + 1, 0), - action: 'remove', - lines: ['', ''], - }); - }), - (this.replace = function (range, text) { - if ( - (range instanceof Range || - (range = Range.fromPoints(range.start, range.end)), - 0 === text.length && range.isEmpty()) - ) - {return range.start;} - if (text == this.getTextRange(range)) return range.end; - this.remove(range); - let end; - return (end = text ? this.insert(range.start, text) : range.start); - }), - (this.applyDeltas = function (deltas) { - for (let i = 0; deltas.length > i; i++) this.applyDelta(deltas[i]); - }), - (this.revertDeltas = function (deltas) { - for (let i = deltas.length - 1; i >= 0; i--) - {this.revertDelta(deltas[i]);} - }), - (this.applyDelta = function (delta, doNotValidate) { - let isInsert = 'insert' == delta.action; - (isInsert - ? 1 >= delta.lines.length && !delta.lines[0] - : !Range.comparePoints(delta.start, delta.end)) || - (isInsert && - delta.lines.length > 2e4 && - this.$splitAndapplyLargeDelta(delta, 2e4), - applyDelta(this.$lines, delta, doNotValidate), - this._signal('change', delta)); - }), - (this.$splitAndapplyLargeDelta = function (delta, MAX) { - for ( - let lines = delta.lines, - l = lines.length, - row = delta.start.row, - column = delta.start.column, - from = 0, - to = 0; - ; - - ) { - (from = to), (to += MAX - 1); - let chunk = lines.slice(from, to); - if (to > l) { - (delta.lines = chunk), - (delta.start.row = row + from), - (delta.start.column = column); - break; - } - chunk.push(''), - this.applyDelta( - { - start: this.pos(row + from, column), - end: this.pos(row + to, (column = 0)), - action: delta.action, - lines: chunk, - }, - !0 - ); - } - }), - (this.revertDelta = function (delta) { - this.applyDelta({ - start: this.clonePos(delta.start), - end: this.clonePos(delta.end), - action: 'insert' == delta.action ? 'remove' : 'insert', - lines: delta.lines.slice(), - }); - }), - (this.indexToPosition = function (index, startRow) { - for ( - var lines = this.$lines || this.getAllLines(), - newlineLength = this.getNewLineCharacter().length, - i = startRow || 0, - l = lines.length; - l > i; - i++ - ) - {if (((index -= lines[i].length + newlineLength), 0 > index)) - return { - row: i, - column: index + lines[i].length + newlineLength, - };} - return { row: l - 1, column: lines[l - 1].length }; - }), - (this.positionToIndex = function (pos, startRow) { - for ( - var lines = this.$lines || this.getAllLines(), - newlineLength = this.getNewLineCharacter().length, - index = 0, - row = Math.min(pos.row, lines.length), - i = startRow || 0; - row > i; - ++i - ) - {index += lines[i].length + newlineLength;} - return index + pos.column; - }); - }.call(Document.prototype), - (exports.Document = Document)); - } -), -ace.define('ace/lib/lang', ['require', 'exports', 'module'], function ( - acequire, - exports -) { - (exports.last = function (a) { - return a[a.length - 1]; - }), - (exports.stringReverse = function (string) { - return string - .split('') - .reverse() - .join(''); - }), - (exports.stringRepeat = function (string, count) { - for (var result = ''; count > 0;) - {1 & count && (result += string), (count >>= 1) && (string += string);} - return result; - }); - let trimBeginRegexp = /^\s\s*/, - trimEndRegexp = /\s\s*$/; - (exports.stringTrimLeft = function (string) { - return string.replace(trimBeginRegexp, ''); - }), - (exports.stringTrimRight = function (string) { - return string.replace(trimEndRegexp, ''); - }), - (exports.copyObject = function (obj) { - let copy = {}; - for (let key in obj) copy[key] = obj[key]; - return copy; - }), - (exports.copyArray = function (array) { - for (var copy = [], i = 0, l = array.length; l > i; i++) - {copy[i] = - array[i] && 'object' == typeof array[i] - ? this.copyObject(array[i]) - : array[i];} - return copy; - }), - (exports.deepCopy = function deepCopy(obj) { - if ('object' !== typeof obj || !obj) return obj; - let copy; - if (Array.isArray(obj)) { - copy = []; - for (var key = 0; obj.length > key; key++) - {copy[key] = deepCopy(obj[key]);} - return copy; - } - if ('[object Object]' !== Object.prototype.toString.call(obj)) - {return obj;} - copy = {}; - for (var key in obj) copy[key] = deepCopy(obj[key]); - return copy; - }), - (exports.arrayToMap = function (arr) { - for (var map = {}, i = 0; arr.length > i; i++) map[arr[i]] = 1; - return map; - }), - (exports.createMap = function (props) { - let map = Object.create(null); - for (let i in props) map[i] = props[i]; - return map; - }), - (exports.arrayRemove = function (array, value) { - for (let i = 0; array.length >= i; i++) - {value === array[i] && array.splice(i, 1);} - }), - (exports.escapeRegExp = function (str) { - return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); - }), - (exports.escapeHTML = function (str) { - return str - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(/ i; i += 2) { - if (Array.isArray(data[i + 1])) - var d = { - action: 'insert', - start: data[i], - lines: data[i + 1], - }; - else - var d = { - action: 'remove', - start: data[i], - end: data[i + 1], - }; - doc.applyDelta(d, !0); - }} - return _self.$timeout - ? deferredUpdate.schedule(_self.$timeout) - : (_self.onUpdate(), void 0); - }); - }); - (function () { - (this.$timeout = 500), - (this.setTimeout = function (timeout) { - this.$timeout = timeout; - }), - (this.setValue = function (value) { - this.doc.setValue(value), - this.deferredUpdate.schedule(this.$timeout); - }), - (this.getValue = function (callbackId) { - this.sender.callback(this.doc.getValue(), callbackId); - }), - (this.onUpdate = function () {}), - (this.isPending = function () { - return this.deferredUpdate.isPending(); - }); - }.call(Mirror.prototype)); - } -), -ace.define('ace/lib/es5-shim', ['require', 'exports', 'module'], function () { - function Empty() {} - function doesDefinePropertyWork(object) { - try { - return ( - Object.defineProperty(object, 'sentinel', {}), 'sentinel' in object - ); - } catch (exception) {} - } - function toInteger(n) { - return ( - (n = +n), - n !== n - ? (n = 0) - : 0 !== n && - n !== 1 / 0 && - n !== -(1 / 0) && - (n = (n > 0 || -1) * Math.floor(Math.abs(n))), - n - ); - } - Function.prototype.bind || - (Function.prototype.bind = function (that) { - let target = this; - if ('function' !== typeof target) - {throw new TypeError( - 'Function.prototype.bind called on incompatible ' + target - );} - var args = slice.call(arguments, 1), - bound = function () { - if (this instanceof bound) { - let result = target.apply( - this, - args.concat(slice.call(arguments)) - ); - return Object(result) === result ? result : this; - } - return target.apply(that, args.concat(slice.call(arguments))); - }; - return ( - target.prototype && - ((Empty.prototype = target.prototype), - (bound.prototype = new Empty()), - (Empty.prototype = null)), - bound - ); - }); - var defineGetter, - defineSetter, - lookupGetter, - lookupSetter, - supportsAccessors, - call = Function.prototype.call, - prototypeOfArray = Array.prototype, - prototypeOfObject = Object.prototype, - slice = prototypeOfArray.slice, - _toString = call.bind(prototypeOfObject.toString), - owns = call.bind(prototypeOfObject.hasOwnProperty); - if ( - ((supportsAccessors = owns(prototypeOfObject, '__defineGetter__')) && - ((defineGetter = call.bind(prototypeOfObject.__defineGetter__)), - (defineSetter = call.bind(prototypeOfObject.__defineSetter__)), - (lookupGetter = call.bind(prototypeOfObject.__lookupGetter__)), - (lookupSetter = call.bind(prototypeOfObject.__lookupSetter__))), - 2 != [1, 2].splice(0).length) - ) - {if ( - (function() { - function makeArray(l) { - var a = Array(l + 2); - return (a[0] = a[1] = 0), a; - } - var lengthBefore, - array = []; - return ( - array.splice.apply(array, makeArray(20)), - array.splice.apply(array, makeArray(26)), - (lengthBefore = array.length), - array.splice(5, 0, 'XXX'), - lengthBefore + 1 == array.length, - lengthBefore + 1 == array.length ? !0 : void 0 - ); - })() - ) { - var array_splice = Array.prototype.splice; - Array.prototype.splice = function(start, deleteCount) { - return arguments.length - ? array_splice.apply( - this, - [ - void 0 === start ? 0 : start, - void 0 === deleteCount ? this.length - start : deleteCount, - ].concat(slice.call(arguments, 2)) - ) - : []; - }; - } else - Array.prototype.splice = function(pos, removeCount) { - var length = this.length; - pos > 0 - ? pos > length && (pos = length) - : void 0 == pos - ? (pos = 0) - : 0 > pos && (pos = Math.max(length + pos, 0)), - length > pos + removeCount || (removeCount = length - pos); - var removed = this.slice(pos, pos + removeCount), - insert = slice.call(arguments, 2), - add = insert.length; - if (pos === length) add && this.push.apply(this, insert); - else { - var remove = Math.min(removeCount, length - pos), - tailOldPos = pos + remove, - tailNewPos = tailOldPos + add - remove, - tailCount = length - tailOldPos, - lengthAfterRemove = length - remove; - if (tailOldPos > tailNewPos) - for (var i = 0; tailCount > i; ++i) - this[tailNewPos + i] = this[tailOldPos + i]; - else if (tailNewPos > tailOldPos) - for (i = tailCount; i--; ) - this[tailNewPos + i] = this[tailOldPos + i]; - if (add && pos === lengthAfterRemove) - (this.length = lengthAfterRemove), this.push.apply(this, insert); - else - for (this.length = lengthAfterRemove + add, i = 0; add > i; ++i) - this[pos + i] = insert[i]; - } - return removed; - };} - Array.isArray || - (Array.isArray = function (obj) { - return '[object Array]' == _toString(obj); - }); - let boxedString = Object('a'), - splitString = 'a' != boxedString[0] || !(0 in boxedString); - if ( - (Array.prototype.forEach || - (Array.prototype.forEach = function (fun) { - let object = toObject(this), - self = - splitString && '[object String]' == _toString(this) - ? this.split('') - : object, - thisp = arguments[1], - i = -1, - length = self.length >>> 0; - if ('[object Function]' != _toString(fun)) throw new TypeError(); - for (; length > ++i;) - {i in self && fun.call(thisp, self[i], i, object);} - }), - Array.prototype.map || - (Array.prototype.map = function (fun) { - let object = toObject(this), - self = - splitString && '[object String]' == _toString(this) - ? this.split('') - : object, - length = self.length >>> 0, - result = Array(length), - thisp = arguments[1]; - if ('[object Function]' != _toString(fun)) - {throw new TypeError(fun + ' is not a function');} - for (let i = 0; length > i; i++) - {i in self && (result[i] = fun.call(thisp, self[i], i, object));} - return result; - }), - Array.prototype.filter || - (Array.prototype.filter = function (fun) { - let value, - object = toObject(this), - self = - splitString && '[object String]' == _toString(this) - ? this.split('') - : object, - length = self.length >>> 0, - result = [], - thisp = arguments[1]; - if ('[object Function]' != _toString(fun)) - {throw new TypeError(fun + ' is not a function');} - for (let i = 0; length > i; i++) - {i in self && - ((value = self[i]), - fun.call(thisp, value, i, object) && result.push(value));} - return result; - }), - Array.prototype.every || - (Array.prototype.every = function (fun) { - let object = toObject(this), - self = - splitString && '[object String]' == _toString(this) - ? this.split('') - : object, - length = self.length >>> 0, - thisp = arguments[1]; - if ('[object Function]' != _toString(fun)) - {throw new TypeError(fun + ' is not a function');} - for (let i = 0; length > i; i++) - {if (i in self && !fun.call(thisp, self[i], i, object)) return !1;} - return !0; - }), - Array.prototype.some || - (Array.prototype.some = function (fun) { - let object = toObject(this), - self = - splitString && '[object String]' == _toString(this) - ? this.split('') - : object, - length = self.length >>> 0, - thisp = arguments[1]; - if ('[object Function]' != _toString(fun)) - {throw new TypeError(fun + ' is not a function');} - for (let i = 0; length > i; i++) - {if (i in self && fun.call(thisp, self[i], i, object)) return !0;} - return !1; - }), - Array.prototype.reduce || - (Array.prototype.reduce = function (fun) { - let object = toObject(this), - self = - splitString && '[object String]' == _toString(this) - ? this.split('') - : object, - length = self.length >>> 0; - if ('[object Function]' != _toString(fun)) - {throw new TypeError(fun + ' is not a function');} - if (!length && 1 == arguments.length) - {throw new TypeError('reduce of empty array with no initial value');} - let result, - i = 0; - if (arguments.length >= 2) result = arguments[1]; - else - {for (;;) { - if (i in self) { - result = self[i++]; - break; - } - if (++i >= length) - throw new TypeError( - 'reduce of empty array with no initial value' - ); - }} - for (; length > i; i++) - {i in self && - (result = fun.call(void 0, result, self[i], i, object));} - return result; - }), - Array.prototype.reduceRight || - (Array.prototype.reduceRight = function (fun) { - let object = toObject(this), - self = - splitString && '[object String]' == _toString(this) - ? this.split('') - : object, - length = self.length >>> 0; - if ('[object Function]' != _toString(fun)) - {throw new TypeError(fun + ' is not a function');} - if (!length && 1 == arguments.length) - {throw new TypeError( - 'reduceRight of empty array with no initial value' - );} - let result, - i = length - 1; - if (arguments.length >= 2) result = arguments[1]; - else - {for (;;) { - if (i in self) { - result = self[i--]; - break; - } - if (0 > --i) - throw new TypeError( - 'reduceRight of empty array with no initial value' - ); - }} - do - {i in this && - (result = fun.call(void 0, result, self[i], i, object));} - while (i--); - return result; - }), - (Array.prototype.indexOf && -1 == [0, 1].indexOf(1, 2)) || - (Array.prototype.indexOf = function (sought) { - let self = - splitString && '[object String]' == _toString(this) - ? this.split('') - : toObject(this), - length = self.length >>> 0; - if (!length) return -1; - let i = 0; - for ( - arguments.length > 1 && (i = toInteger(arguments[1])), - i = i >= 0 ? i : Math.max(0, length + i); - length > i; - i++ - ) - {if (i in self && self[i] === sought) return i;} - return -1; - }), - (Array.prototype.lastIndexOf && -1 == [0, 1].lastIndexOf(0, -3)) || - (Array.prototype.lastIndexOf = function (sought) { - let self = - splitString && '[object String]' == _toString(this) - ? this.split('') - : toObject(this), - length = self.length >>> 0; - if (!length) return -1; - let i = length - 1; - for ( - arguments.length > 1 && (i = Math.min(i, toInteger(arguments[1]))), - i = i >= 0 ? i : length - Math.abs(i); - i >= 0; - i-- - ) - {if (i in self && sought === self[i]) return i;} - return -1; - }), - Object.getPrototypeOf || - (Object.getPrototypeOf = function (object) { - return ( - object.__proto__ || - (object.constructor - ? object.constructor.prototype - : prototypeOfObject) - ); - }), - !Object.getOwnPropertyDescriptor) - ) { - let ERR_NON_OBJECT = - 'Object.getOwnPropertyDescriptor called on a non-object: '; - Object.getOwnPropertyDescriptor = function (object, property) { - if ( - ('object' !== typeof object && 'function' !== typeof object) || - null === object - ) - {throw new TypeError(ERR_NON_OBJECT + object);} - if (owns(object, property)) { - var descriptor, getter, setter; - if ( - ((descriptor = { enumerable: !0, configurable: !0 }), - supportsAccessors) - ) { - let prototype = object.__proto__; - object.__proto__ = prototypeOfObject; - var getter = lookupGetter(object, property), - setter = lookupSetter(object, property); - if (((object.__proto__ = prototype), getter || setter)) - {return ( - getter && (descriptor.get = getter), - setter && (descriptor.set = setter), - descriptor - );} - } - return (descriptor.value = object[property]), descriptor; - } - }; - } - if ( - (Object.getOwnPropertyNames || - (Object.getOwnPropertyNames = function (object) { - return Object.keys(object); - }), - !Object.create) - ) { - let createEmpty; - (createEmpty = - null === Object.prototype.__proto__ - ? function () { - return { __proto__: null }; - } - : function () { - let empty = {}; - for (let i in empty) empty[i] = null; - return ( - (empty.constructor = empty.hasOwnProperty = empty.propertyIsEnumerable = empty.isPrototypeOf = empty.toLocaleString = empty.toString = empty.valueOf = empty.__proto__ = null), - empty - ); - }), - (Object.create = function (prototype, properties) { - let object; - if (null === prototype) object = createEmpty(); - else { - if ('object' !== typeof prototype) - {throw new TypeError( - 'typeof prototype[' + typeof prototype + "] != 'object'" - );} - let Type = function () {}; - (Type.prototype = prototype), - (object = new Type()), - (object.__proto__ = prototype); - } - return ( - void 0 !== properties && - Object.defineProperties(object, properties), - object - ); - }); - } - if (Object.defineProperty) { - let definePropertyWorksOnObject = doesDefinePropertyWork({}), - definePropertyWorksOnDom = - 'undefined' === typeof document || - doesDefinePropertyWork(document.createElement('div')); - if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) - {var definePropertyFallback = Object.defineProperty;} - } - if (!Object.defineProperty || definePropertyFallback) { - let ERR_NON_OBJECT_DESCRIPTOR = - 'Property description must be an object: ', - ERR_NON_OBJECT_TARGET = 'Object.defineProperty called on non-object: ', - ERR_ACCESSORS_NOT_SUPPORTED = - 'getters & setters can not be defined on this javascript engine'; - Object.defineProperty = function (object, property, descriptor) { - if ( - ('object' !== typeof object && 'function' !== typeof object) || - null === object - ) - {throw new TypeError(ERR_NON_OBJECT_TARGET + object);} - if ( - ('object' !== typeof descriptor && 'function' !== typeof descriptor) || - null === descriptor - ) - {throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);} - if (definePropertyFallback) - {try { - return definePropertyFallback.call( - Object, - object, - property, - descriptor - ); - } catch (exception) {}} - if (owns(descriptor, 'value')) - {if ( - supportsAccessors && - (lookupGetter(object, property) || lookupSetter(object, property)) - ) { - var prototype = object.__proto__; - (object.__proto__ = prototypeOfObject), - delete object[property], - (object[property] = descriptor.value), - (object.__proto__ = prototype); - } else object[property] = descriptor.value;} - else { - if (!supportsAccessors) - {throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);} - owns(descriptor, 'get') && - defineGetter(object, property, descriptor.get), - owns(descriptor, 'set') && - defineSetter(object, property, descriptor.set); - } - return object; - }; - } - Object.defineProperties || - (Object.defineProperties = function (object, properties) { - for (let property in properties) - {owns(properties, property) && - Object.defineProperty(object, property, properties[property]);} - return object; - }), - Object.seal || - (Object.seal = function (object) { - return object; - }), - Object.freeze || - (Object.freeze = function (object) { - return object; - }); - try { - Object.freeze(function () {}); - } catch (exception) { - Object.freeze = (function (freezeObject) { - return function (object) { - return 'function' === typeof object ? object : freezeObject(object); - }; - }(Object.freeze)); - } - if ( - (Object.preventExtensions || - (Object.preventExtensions = function (object) { - return object; - }), - Object.isSealed || - (Object.isSealed = function () { - return !1; - }), - Object.isFrozen || - (Object.isFrozen = function () { - return !1; - }), - Object.isExtensible || - (Object.isExtensible = function (object) { - if (Object(object) === object) throw new TypeError(); - for (var name = ''; owns(object, name);) name += '?'; - object[name] = !0; - let returnValue = owns(object, name); - return delete object[name], returnValue; - }), - !Object.keys) - ) { - let hasDontEnumBug = !0, - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor', - ], - dontEnumsLength = dontEnums.length; - for (let key in { toString: null }) hasDontEnumBug = !1; - Object.keys = function (object) { - if ( - ('object' !== typeof object && 'function' !== typeof object) || - null === object - ) - {throw new TypeError('Object.keys called on a non-object');} - let keys = []; - for (let name in object) owns(object, name) && keys.push(name); - if (hasDontEnumBug) - {for (var i = 0, ii = dontEnumsLength; ii > i; i++) { - var dontEnum = dontEnums[i]; - owns(object, dontEnum) && keys.push(dontEnum); - }} - return keys; - }; - } - Date.now || - (Date.now = function () { - return new Date().getTime(); - }); - let ws = ' \nv\f\r   ᠎              \u2028\u2029'; - if (!String.prototype.trim || ws.trim()) { - ws = '[' + ws + ']'; - let trimBeginRegexp = RegExp('^' + ws + ws + '*'), - trimEndRegexp = RegExp(ws + ws + '*$'); - String.prototype.trim = function () { - return (this + '') - .replace(trimBeginRegexp, '') - .replace(trimEndRegexp, ''); - }; - } - var toObject = function (o) { - if (null == o) throw new TypeError('can\'t convert ' + o + ' to object'); - return Object(o); - }; -}); -ace.define( - 'sense_editor/mode/worker_parser', - ['require', 'exports', 'module'], - function () { - let at, // The index of the current character - ch, // The current character - annos, // annotations - escapee = { - '"': '"', - '\\': '\\', - '/': '/', - b: '\b', - f: '\f', - n: '\n', - r: '\r', - t: '\t', - }, - text, - annotate = function (type, text) { - annos.push({ type: type, text: text, at: at }); - }, - error = function (m) { - throw { - name: 'SyntaxError', - message: m, - at: at, - text: text, - }; - }, - reset = function (newAt) { - ch = text.charAt(newAt); - at = newAt + 1; - }, - next = function (c) { - if (c && c !== ch) { - error('Expected \'' + c + '\' instead of \'' + ch + '\''); - } - - ch = text.charAt(at); - at += 1; - return ch; - }, - nextUpTo = function (upTo, errorMessage) { - let currentAt = at, - i = text.indexOf(upTo, currentAt); - if (i < 0) { - error(errorMessage || 'Expected \'' + upTo + '\''); - } - reset(i + upTo.length); - return text.substring(currentAt, i); - }, - peek = function (offset) { - return text.charAt(at + offset); - }, - number = function () { - let number, - string = ''; - - if (ch === '-') { - string = '-'; - next('-'); - } - while (ch >= '0' && ch <= '9') { - string += ch; - next(); - } - if (ch === '.') { - string += '.'; - while (next() && ch >= '0' && ch <= '9') { - string += ch; - } - } - if (ch === 'e' || ch === 'E') { - string += ch; - next(); - if (ch === '-' || ch === '+') { - string += ch; - next(); - } - while (ch >= '0' && ch <= '9') { - string += ch; - next(); - } - } - number = +string; - if (isNaN(number)) { - error('Bad number'); - } else { - return number; - } - }, - string = function () { - let hex, - i, - string = '', - uffff; - - if (ch === '"') { - // If the current and the next characters are equal to "", empty string or start of triple quoted strings - if (peek(0) === '"' && peek(1) === '"') { - // literal - next('"'); - next('"'); - return nextUpTo('"""', 'failed to find closing \'"""\''); - } else { - while (next()) { - if (ch === '"') { - next(); - return string; - } else if (ch === '\\') { - next(); - if (ch === 'u') { - uffff = 0; - for (i = 0; i < 4; i += 1) { - hex = parseInt(next(), 16); - if (!isFinite(hex)) { - break; - } - uffff = uffff * 16 + hex; - } - string += String.fromCharCode(uffff); - } else if (typeof escapee[ch] === 'string') { - string += escapee[ch]; - } else { - break; - } - } else { - string += ch; - } - } - } - } - error('Bad string'); - }, - white = function () { - while (ch) { - // Skip whitespace. - while (ch && ch <= ' ') { - next(); - } - // if the current char in iteration is '#' or the char and the next char is equal to '//' - // we are on the single line comment - if (ch === '#' || ch === '/' && peek(0) === '/') { - // Until we are on the new line, skip to the next char - while (ch && ch !== '\n') { - next(); - } - } else if (ch === '/' && peek(0) === '*') { - // If the chars starts with '/*', we are on the multiline comment - next(); - next(); - while (ch && !(ch === '*' && peek(0) === '/')) { - // Until we have closing tags '*/', skip to the next char - next(); - } - if (ch) { - next(); - next(); - } - } else break; - } - }, - strictWhite = function () { - while (ch && (ch == ' ' || ch == '\t')) { - next(); - } - }, - newLine = function () { - if (ch == '\n') next(); - }, - word = function () { - switch (ch) { - case 't': - next('t'); - next('r'); - next('u'); - next('e'); - return true; - case 'f': - next('f'); - next('a'); - next('l'); - next('s'); - next('e'); - return false; - case 'n': - next('n'); - next('u'); - next('l'); - next('l'); - return null; - } - error('Unexpected \'' + ch + '\''); - }, - // parses and returns the method - method = function () { - switch (ch) { - case 'g': - next('g'); - next('e'); - next('t'); - return 'get'; - case 'G': - next('G'); - next('E'); - next('T'); - return 'GET'; - case 'h': - next('h'); - next('e'); - next('a'); - next('d'); - return 'head'; - case 'H': - next('H'); - next('E'); - next('A'); - next('D'); - return 'HEAD'; - case 'd': - next('d'); - next('e'); - next('l'); - next('e'); - next('t'); - next('e'); - return 'delete'; - case 'D': - next('D'); - next('E'); - next('L'); - next('E'); - next('T'); - next('E'); - return 'DELETE'; - case 'p': - next('p'); - switch (ch) { - case 'a': - next('a'); - next('t'); - next('c'); - next('h'); - return 'patch'; - case 'u': - next('u'); - next('t'); - return 'put'; - case 'o': - next('o'); - next('s'); - next('t'); - return 'post'; - default: - error('Unexpected \'' + ch + '\''); - } - break; - case 'P': - next('P'); - switch (ch) { - case 'A': - next('A'); - next('T'); - next('C'); - next('H'); - return 'PATCH'; - case 'U': - next('U'); - next('T'); - return 'PUT'; - case 'O': - next('O'); - next('S'); - next('T'); - return 'POST'; - default: - error('Unexpected \'' + ch + '\''); - } - break; - default: - error('Expected one of GET/POST/PUT/DELETE/HEAD/PATCH'); - } - }, - value, // Place holder for the value function. - array = function () { - const array = []; - - if (ch === '[') { - next('['); - white(); - if (ch === ']') { - next(']'); - return array; // empty array - } - while (ch) { - array.push(value()); - white(); - if (ch === ']') { - next(']'); - return array; - } - next(','); - white(); - } - } - error('Bad array'); - }, - object = function () { - let key, - object = {}; - - if (ch === '{') { - next('{'); - white(); - if (ch === '}') { - next('}'); - return object; // empty object - } - while (ch) { - key = string(); - white(); - next(':'); - if (Object.hasOwnProperty.call(object, key)) { - error('Duplicate key "' + key + '"'); - } - object[key] = value(); - white(); - if (ch === '}') { - next('}'); - return object; - } - next(','); - white(); - } - } - error('Bad object'); - }; - - value = function () { - white(); - switch (ch) { - case '{': - return object(); - case '[': - return array(); - case '"': - return string(); - case '-': - return number(); - default: - return ch >= '0' && ch <= '9' ? number() : word(); - } - }; - - let url = function () { - let url = ''; - while (ch && ch != '\n') { - url += ch; - next(); - } - if (url == '') { - error('Missing url'); - } - return url; - }, - request = function () { - white(); - method(); - strictWhite(); - url(); - strictWhite(); // advance to one new line - newLine(); - strictWhite(); - if (ch == '{') { - object(); - } - // multi doc request - strictWhite(); // advance to one new line - newLine(); - strictWhite(); - while (ch == '{') { - // another object - object(); - strictWhite(); - newLine(); - strictWhite(); - } - }, - comment = function () { - while (ch == '#') { - while (ch && ch !== '\n') { - next(); - } - white(); - } - }, - multi_request = function () { - while (ch && ch != '') { - white(); - if (!ch) { - continue; - } - try { - comment(); - white(); - if (!ch) { - continue; - } - request(); - white(); - } catch (e) { - annotate('error', e.message); - // snap - const substring = text.substr(at); - const nextMatch = substring.search(/^POST|HEAD|GET|PUT|DELETE|PATCH/m); - if (nextMatch < 1) return; - reset(at + nextMatch); - } - } - }; - - return function (source, reviver) { - let result; - - text = source; - at = 0; - annos = []; - next(); - multi_request(); - white(); - if (ch) { - annotate('error', 'Syntax error'); - } - - result = { annotations: annos }; - - return typeof reviver === 'function' - ? (function walk(holder, key) { - let k, - v, - value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - }({ '': result }, '')) - : result; - }; - } -); - -ace.define( - 'sense_editor/mode/worker', - [ - 'require', - 'exports', - 'module', - 'ace/lib/oop', - 'ace/worker/mirror', - 'sense_editor/mode/worker_parser', - ], - function (require, exports) { - const oop = require('ace/lib/oop'); - const Mirror = require('ace/worker/mirror').Mirror; - const parse = require('sense_editor/mode/worker_parser'); - - const SenseWorker = (exports.SenseWorker = function (sender) { - Mirror.call(this, sender); - this.setTimeout(200); - }); - - oop.inherits(SenseWorker, Mirror); - - (function () { - this.id = 'senseWorker'; - this.onUpdate = function () { - const value = this.doc.getValue(); - let pos, result; - try { - result = parse(value); - } catch (e) { - pos = this.charToDocumentPosition(e.at - 1); - this.sender.emit('error', { - row: pos.row, - column: pos.column, - text: e.message, - type: 'error', - }); - return; - } - for (let i = 0; i < result.annotations.length; i++) { - pos = this.charToDocumentPosition(result.annotations[i].at - 1); - result.annotations[i].row = pos.row; - result.annotations[i].column = pos.column; - } - this.sender.emit('ok', result.annotations); - }; - - this.charToDocumentPosition = function (charPos) { - let i = 0; - const len = this.doc.getLength(); - const nl = this.doc.getNewLineCharacter().length; - - if (!len) { - return { row: 0, column: 0 }; - } - - let lineStart = 0, - line; - while (i < len) { - line = this.doc.getLine(i); - const lineLength = line.length + nl; - if (lineStart + lineLength > charPos) { - return { - row: i, - column: charPos - lineStart, - }; - } - - lineStart += lineLength; - i += 1; - } - - return { - row: i - 1, - column: line.length, - }; - }; - }.call(SenseWorker.prototype)); - } -); diff --git a/src/plugins/console/public/application/models/legacy_core_editor/output_tokenization.test.js b/src/plugins/console/public/application/models/legacy_core_editor/output_tokenization.test.js deleted file mode 100644 index e09bf06e48246..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/output_tokenization.test.js +++ /dev/null @@ -1,91 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import './legacy_core_editor.test.mocks'; -import $ from 'jquery'; -import RowParser from '../../../lib/row_parser'; -import ace from 'brace'; -import { createReadOnlyAceEditor } from './create_readonly'; -let output; -const tokenIterator = ace.acequire('ace/token_iterator'); - -describe('Output Tokenization', () => { - beforeEach(() => { - output = createReadOnlyAceEditor(document.querySelector('#ConAppOutput')); - $(output.container).show(); - }); - - afterEach(() => { - $(output.container).hide(); - }); - - function tokensAsList() { - const iter = new tokenIterator.TokenIterator(output.getSession(), 0, 0); - const ret = []; - let t = iter.getCurrentToken(); - const parser = new RowParser(output); - if (parser.isEmptyToken(t)) { - t = parser.nextNonEmptyToken(iter); - } - while (t) { - ret.push({ value: t.value, type: t.type }); - t = parser.nextNonEmptyToken(iter); - } - - return ret; - } - - let testCount = 0; - - function tokenTest(tokenList, data) { - if (data && typeof data !== 'string') { - data = JSON.stringify(data, null, 3); - } - - test('Token test ' + testCount++, function (done) { - output.update(data, function () { - const tokens = tokensAsList(); - const normTokenList = []; - for (let i = 0; i < tokenList.length; i++) { - normTokenList.push({ type: tokenList[i++], value: tokenList[i] }); - } - - expect(tokens).toEqual(normTokenList); - done(); - }); - }); - } - - tokenTest( - ['warning', '#! warning', 'comment', '# GET url', 'paren.lparen', '{', 'paren.rparen', '}'], - '#! warning\n' + '# GET url\n' + '{}' - ); - - tokenTest( - [ - 'comment', - '# GET url', - 'paren.lparen', - '{', - 'variable', - '"f"', - 'punctuation.colon', - ':', - 'punctuation.start_triple_quote', - '"""', - 'multi_string', - 'raw', - 'punctuation.end_triple_quote', - '"""', - 'paren.rparen', - '}', - ], - '# GET url\n' + '{ "f": """raw""" }' - ); -}); diff --git a/src/plugins/console/public/application/models/legacy_core_editor/smart_resize.ts b/src/plugins/console/public/application/models/legacy_core_editor/smart_resize.ts deleted file mode 100644 index c238e8c6a5da7..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/smart_resize.ts +++ /dev/null @@ -1,27 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { get, throttle } from 'lodash'; -import type { Editor } from 'brace'; - -// eslint-disable-next-line import/no-default-export -export default function (editor: Editor) { - const resize = editor.resize; - - const throttledResize = throttle(() => { - resize.call(editor, false); - - // Keep current top line in view when resizing to avoid losing user context - const userRow = get(throttledResize, 'topRow', 0); - if (userRow !== 0) { - editor.renderer.scrollToLine(userRow, false, false, () => {}); - } - }, 35); - return throttledResize; -} diff --git a/src/plugins/console/public/application/models/legacy_core_editor/theme_sense_dark.js b/src/plugins/console/public/application/models/legacy_core_editor/theme_sense_dark.js deleted file mode 100644 index fd8e12bf1d703..0000000000000 --- a/src/plugins/console/public/application/models/legacy_core_editor/theme_sense_dark.js +++ /dev/null @@ -1,123 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ace from 'brace'; - -ace.define('ace/theme/sense-dark', ['require', 'exports', 'module'], function (require, exports) { - exports.isDark = true; - exports.cssClass = 'ace-sense-dark'; - exports.cssText = - '.ace-sense-dark .ace_gutter {\ -background: #2e3236;\ -color: #bbbfc2;\ -}\ -.ace-sense-dark .ace_print-margin {\ -width: 1px;\ -background: #555651\ -}\ -.ace-sense-dark .ace_scroller {\ -background-color: #202328;\ -}\ -.ace-sense-dark .ace_content {\ -}\ -.ace-sense-dark .ace_text-layer {\ -color: #F8F8F2\ -}\ -.ace-sense-dark .ace_cursor {\ -border-left: 2px solid #F8F8F0\ -}\ -.ace-sense-dark .ace_overwrite-cursors .ace_cursor {\ -border-left: 0px;\ -border-bottom: 1px solid #F8F8F0\ -}\ -.ace-sense-dark .ace_marker-layer .ace_selection {\ -background: #222\ -}\ -.ace-sense-dark.ace_multiselect .ace_selection.ace_start {\ -box-shadow: 0 0 3px 0px #272822;\ -border-radius: 2px\ -}\ -.ace-sense-dark .ace_marker-layer .ace_step {\ -background: rgb(102, 82, 0)\ -}\ -.ace-sense-dark .ace_marker-layer .ace_bracket {\ -margin: -1px 0 0 -1px;\ -border: 1px solid #49483E\ -}\ -.ace-sense-dark .ace_marker-layer .ace_active-line {\ -background: #202020\ -}\ -.ace-sense-dark .ace_gutter-active-line {\ -background-color: #272727\ -}\ -.ace-sense-dark .ace_marker-layer .ace_selected-word {\ -border: 1px solid #49483E\ -}\ -.ace-sense-dark .ace_invisible {\ -color: #49483E\ -}\ -.ace-sense-dark .ace_entity.ace_name.ace_tag,\ -.ace-sense-dark .ace_keyword,\ -.ace-sense-dark .ace_meta,\ -.ace-sense-dark .ace_storage {\ -color: #F92672\ -}\ -.ace-sense-dark .ace_constant.ace_character,\ -.ace-sense-dark .ace_constant.ace_language,\ -.ace-sense-dark .ace_constant.ace_numeric,\ -.ace-sense-dark .ace_constant.ace_other {\ -color: #AE81FF\ -}\ -.ace-sense-dark .ace_invalid {\ -color: #F8F8F0;\ -background-color: #F92672\ -}\ -.ace-sense-dark .ace_invalid.ace_deprecated {\ -color: #F8F8F0;\ -background-color: #AE81FF\ -}\ -.ace-sense-dark .ace_support.ace_constant,\ -.ace-sense-dark .ace_support.ace_function {\ -color: #66D9EF\ -}\ -.ace-sense-dark .ace_fold {\ -background-color: #A6E22E;\ -border-color: #F8F8F2\ -}\ -.ace-sense-dark .ace_storage.ace_type,\ -.ace-sense-dark .ace_support.ace_class,\ -.ace-sense-dark .ace_support.ace_type {\ -font-style: italic;\ -color: #66D9EF\ -}\ -.ace-sense-dark .ace_entity.ace_name.ace_function,\ -.ace-sense-dark .ace_entity.ace_other.ace_attribute-name,\ -.ace-sense-dark .ace_variable {\ -color: #A6E22E\ -}\ -.ace-sense-dark .ace_variable.ace_parameter {\ -font-style: italic;\ -color: #FD971F\ -}\ -.ace-sense-dark .ace_string {\ -color: #E6DB74\ -}\ -.ace-sense-dark .ace_comment {\ -color: #629755\ -}\ -.ace-sense-dark .ace_markup.ace_underline {\ -text-decoration: underline\ -}\ -.ace-sense-dark .ace_indent-guide {\ -background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNQ11D6z7Bq1ar/ABCKBG6g04U2AAAAAElFTkSuQmCC) right repeat-y\ -}'; - - const dom = require('ace/lib/dom'); - dom.importCssString(exports.cssText, exports.cssClass); -}); diff --git a/src/plugins/console/public/application/models/sense_editor/__fixtures__/editor_input1.txt b/src/plugins/console/public/application/models/sense_editor/__fixtures__/editor_input1.txt deleted file mode 100644 index 517f22bd8ad6a..0000000000000 --- a/src/plugins/console/public/application/models/sense_editor/__fixtures__/editor_input1.txt +++ /dev/null @@ -1,37 +0,0 @@ -GET _search -{ - "query": { "match_all": {} } -} - -#preceeding comment -GET _stats?level=shards - -#in between comment - -PUT index_1/type1/1 -{ - "f": 1 -} - -PUT index_1/type1/2 -{ - "f": 2 -} - -# comment - - -GET index_1/type1/1/_source?_source_include=f - -DELETE index_2 - - -POST /_sql?format=txt -{ - "query": "SELECT prenom FROM claude_index WHERE prenom = 'claude' ", - "fetch_size": 1 -} - -GET ,,/_search?pretty - -GET kbn:/api/spaces/space \ No newline at end of file diff --git a/src/plugins/console/public/application/models/sense_editor/create.ts b/src/plugins/console/public/application/models/sense_editor/create.ts deleted file mode 100644 index 9c6c3e38471d5..0000000000000 --- a/src/plugins/console/public/application/models/sense_editor/create.ts +++ /dev/null @@ -1,22 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SenseEditor } from './sense_editor'; -import * as core from '../legacy_core_editor'; - -export function create(element: HTMLElement) { - const coreEditor = core.create(element); - const senseEditor = new SenseEditor(coreEditor); - - /** - * Init the editor - */ - senseEditor.highlightCurrentRequestsAndUpdateActionBar(); - return senseEditor; -} diff --git a/src/plugins/console/public/application/models/sense_editor/curl.ts b/src/plugins/console/public/application/models/sense_editor/curl.ts deleted file mode 100644 index 9080610a0e8c5..0000000000000 --- a/src/plugins/console/public/application/models/sense_editor/curl.ts +++ /dev/null @@ -1,194 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -function detectCURLinLine(line: string) { - // returns true if text matches a curl request - return line.match(/^\s*?curl\s+(-X[A-Z]+)?\s*['"]?.*?['"]?(\s*$|\s+?-d\s*?['"])/); -} - -export function detectCURL(text: string) { - // returns true if text matches a curl request - if (!text) return false; - for (const line of text.split('\n')) { - if (detectCURLinLine(line)) { - return true; - } - } - return false; -} - -export function parseCURL(text: string) { - let state = 'NONE'; - const out = []; - let body: string[] = []; - let line = ''; - const lines = text.trim().split('\n'); - let matches; - - const EmptyLine = /^\s*$/; - const Comment = /^\s*(?:#|\/{2,})(.*)\n?$/; - const ExecutionComment = /^\s*#!/; - const ClosingSingleQuote = /^([^']*)'/; - const ClosingDoubleQuote = /^((?:[^\\"]|\\.)*)"/; - const EscapedQuotes = /^((?:[^\\"']|\\.)+)/; - - const LooksLikeCurl = /^\s*curl\s+/; - const CurlVerb = /-X ?(GET|HEAD|POST|PUT|DELETE|PATCH)/; - - const HasProtocol = /[\s"']https?:\/\//; - const CurlRequestWithProto = /[\s"']https?:\/\/[^\/ ]+\/+([^\s"']+)/; - const CurlRequestWithoutProto = /[\s"'][^\/ ]+\/+([^\s"']+)/; - const CurlData = /^.+\s(--data|-d)\s*/; - const SenseLine = /^\s*(GET|HEAD|POST|PUT|DELETE|PATCH)\s+\/?(.+)/; - - if (lines.length > 0 && ExecutionComment.test(lines[0])) { - lines.shift(); - } - - function nextLine() { - if (line.length > 0) { - return true; - } - if (lines.length === 0) { - return false; - } - line = lines.shift()!.replace(/[\r\n]+/g, '\n') + '\n'; - return true; - } - - function unescapeLastBodyEl() { - const str = body.pop()!.replace(/\\([\\"'])/g, '$1'); - body.push(str); - } - - // Is the next char a single or double quote? - // If so remove it - function detectQuote() { - if (line.substr(0, 1) === "'") { - line = line.substr(1); - state = 'SINGLE_QUOTE'; - } else if (line.substr(0, 1) === '"') { - line = line.substr(1); - state = 'DOUBLE_QUOTE'; - } else { - state = 'UNQUOTED'; - } - } - - // Body is finished - append to output with final LF - function addBodyToOut() { - if (body.length > 0) { - out.push(body.join('')); - body = []; - } - state = 'LF'; - out.push('\n'); - } - - // If the pattern matches, then the state is about to change, - // so add the capture to the body and detect the next state - // Otherwise add the whole line - function consumeMatching(pattern: string | RegExp) { - const result = line.match(pattern); - if (result) { - body.push(result[1]); - line = line.substr(result[0].length); - detectQuote(); - } else { - body.push(line); - line = ''; - } - } - - function parseCurlLine() { - let verb = 'GET'; - let request = ''; - let result; - if ((result = line.match(CurlVerb))) { - verb = result[1]; - } - - // JS regexen don't support possessive quantifiers, so - // we need two distinct patterns - const pattern = HasProtocol.test(line) ? CurlRequestWithProto : CurlRequestWithoutProto; - - if ((result = line.match(pattern))) { - request = result[1]; - } - - out.push(verb + ' /' + request + '\n'); - - if ((result = line.match(CurlData))) { - line = line.substr(result[0].length); - detectQuote(); - if (EmptyLine.test(line)) { - line = ''; - } - } else { - state = 'NONE'; - line = ''; - out.push(''); - } - } - - while (nextLine()) { - if (state === 'SINGLE_QUOTE') { - consumeMatching(ClosingSingleQuote); - } else if (state === 'DOUBLE_QUOTE') { - consumeMatching(ClosingDoubleQuote); - unescapeLastBodyEl(); - } else if (state === 'UNQUOTED') { - consumeMatching(EscapedQuotes); - if (body.length) { - unescapeLastBodyEl(); - } - if (state === 'UNQUOTED') { - addBodyToOut(); - line = ''; - } - } - - // the BODY state (used to match the body of a Sense request) - // can be terminated early if it encounters - // a comment or an empty line - else if (state === 'BODY') { - if (Comment.test(line) || EmptyLine.test(line)) { - addBodyToOut(); - } else { - body.push(line); - line = ''; - } - } else if (EmptyLine.test(line)) { - if (state !== 'LF') { - out.push('\n'); - state = 'LF'; - } - line = ''; - } else if ((matches = line.match(Comment))) { - out.push('#' + matches[1] + '\n'); - state = 'NONE'; - line = ''; - } else if (LooksLikeCurl.test(line)) { - parseCurlLine(); - } else if ((matches = line.match(SenseLine))) { - out.push(matches[1] + ' /' + matches[2] + '\n'); - line = ''; - state = 'BODY'; - } - - // Nothing else matches, so output with a prefix of ### for debugging purposes - else { - out.push('### ' + line); - line = ''; - } - } - - addBodyToOut(); - return out.join('').trim(); -} diff --git a/src/plugins/console/public/application/models/sense_editor/index.ts b/src/plugins/console/public/application/models/sense_editor/index.ts deleted file mode 100644 index 2bd44988dc02f..0000000000000 --- a/src/plugins/console/public/application/models/sense_editor/index.ts +++ /dev/null @@ -1,14 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './create'; -export * from '../legacy_core_editor/create_readonly'; -export { MODE } from '../../../lib/row_parser'; -export { SenseEditor } from './sense_editor'; -export { getEndpointFromPosition } from '../../../lib/autocomplete/get_endpoint_from_position'; diff --git a/src/plugins/console/public/application/models/sense_editor/integration.test.js b/src/plugins/console/public/application/models/sense_editor/integration.test.js deleted file mode 100644 index bed83293e31d6..0000000000000 --- a/src/plugins/console/public/application/models/sense_editor/integration.test.js +++ /dev/null @@ -1,1279 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import './sense_editor.test.mocks'; -import { create } from './create'; -import _ from 'lodash'; -import $ from 'jquery'; - -import * as kb from '../../../lib/kb/kb'; -import { AutocompleteInfo, setAutocompleteInfo } from '../../../services'; -import { httpServiceMock } from '@kbn/core-http-browser-mocks'; -import { StorageMock } from '../../../services/storage.mock'; -import { SettingsMock } from '../../../services/settings.mock'; - -describe('Integration', () => { - let senseEditor; - let autocompleteInfo; - - beforeEach(() => { - // Set up our document body - document.body.innerHTML = - '
    '; - - senseEditor = create(document.querySelector('#ConAppEditor')); - $(senseEditor.getCoreEditor().getContainer()).show(); - senseEditor.autocomplete._test.removeChangeListener(); - autocompleteInfo = new AutocompleteInfo(); - - const httpMock = httpServiceMock.createSetupContract(); - const storage = new StorageMock({}, 'test'); - const settingsMock = new SettingsMock(storage); - - settingsMock.getAutocomplete.mockReturnValue({ fields: true }); - - autocompleteInfo.mapping.setup(httpMock, settingsMock); - - setAutocompleteInfo(autocompleteInfo); - }); - afterEach(() => { - $(senseEditor.getCoreEditor().getContainer()).hide(); - senseEditor.autocomplete._test.addChangeListener(); - autocompleteInfo = null; - setAutocompleteInfo(null); - }); - - function processContextTest(data, mapping, kbSchemes, requestLine, testToRun) { - test(testToRun.name, function (done) { - let lineOffset = 0; // add one for the extra method line - let editorValue = data; - if (requestLine != null) { - if (data != null) { - editorValue = requestLine + '\n' + data; - lineOffset = 1; - } else { - editorValue = requestLine; - } - } - - testToRun.cursor.lineNumber += lineOffset; - - autocompleteInfo.clear(); - autocompleteInfo.mapping.loadMappings(mapping); - const json = {}; - json[test.name] = kbSchemes || {}; - const testApi = kb._test.loadApisFromJson(json); - if (kbSchemes) { - // if (kbSchemes.globals) { - // $.each(kbSchemes.globals, function (parent, rules) { - // testApi.addGlobalAutocompleteRules(parent, rules); - // }); - // } - if (kbSchemes.endpoints) { - $.each(kbSchemes.endpoints, function (endpoint, scheme) { - testApi.addEndpointDescription(endpoint, scheme); - }); - } - } - kb._test.setActiveApi(testApi); - const { cursor } = testToRun; - senseEditor.update(editorValue, true).then(() => { - senseEditor.getCoreEditor().moveCursorToPosition(cursor); - // allow ace rendering to move cursor so it will be seen during test - handy for debugging. - //setTimeout(function () { - senseEditor.completer = { - base: {}, - changeListener: function () {}, - }; // mimic auto complete - - senseEditor.autocomplete._test.getCompletions( - senseEditor, - null, - cursor, - '', - function (err, terms) { - if (testToRun.assertThrows) { - done(); - return; - } - - if (err) { - throw err; - } - - if (testToRun.no_context) { - expect(!terms || terms.length === 0).toBeTruthy(); - } else { - expect(terms).not.toBeNull(); - expect(terms.length).toBeGreaterThan(0); - } - - if (!terms || terms.length === 0) { - done(); - return; - } - - if (testToRun.autoCompleteSet) { - const expectedTerms = _.map(testToRun.autoCompleteSet, function (t) { - if (typeof t !== 'object') { - t = { name: t }; - } - return t; - }); - if (terms.length !== expectedTerms.length) { - expect(_.map(terms, 'name')).toEqual(_.map(expectedTerms, 'name')); - } else { - const filteredActualTerms = _.map(terms, function (actualTerm, i) { - const expectedTerm = expectedTerms[i]; - const filteredTerm = {}; - _.each(expectedTerm, function (v, p) { - filteredTerm[p] = actualTerm[p]; - }); - return filteredTerm; - }); - expect(filteredActualTerms).toEqual(expectedTerms); - } - } - - const context = terms[0].context; - const { - cursor: { lineNumber, column }, - } = testToRun; - senseEditor.autocomplete._test.addReplacementInfoToContext( - context, - { lineNumber, column }, - terms[0].value - ); - - function ac(prop, propTest) { - if (typeof testToRun[prop] !== 'undefined') { - if (propTest) { - propTest(context[prop], testToRun[prop], prop); - } else { - expect(context[prop]).toEqual(testToRun[prop]); - } - } - } - - function posCompare(actual, expected) { - expect(actual.lineNumber).toEqual(expected.lineNumber + lineOffset); - expect(actual.column).toEqual(expected.column); - } - - function rangeCompare(actual, expected, name) { - posCompare(actual.start, expected.start, name + '.start'); - posCompare(actual.end, expected.end, name + '.end'); - } - - ac('prefixToAdd'); - ac('suffixToAdd'); - ac('addTemplate'); - ac('textBoxPosition', posCompare); - ac('rangeToReplace', rangeCompare); - done(); - }, - { setAnnotation: () => {}, removeAnnotation: () => {} } - ); - }); - }); - } - - function contextTests(data, mapping, kbSchemes, requestLine, tests) { - if (data != null && typeof data !== 'string') { - data = JSON.stringify(data, null, 3); - } - for (let t = 0; t < tests.length; t++) { - processContextTest(data, mapping, kbSchemes, requestLine, tests[t]); - } - } - - const SEARCH_KB = { - endpoints: { - _search: { - methods: ['GET', 'POST'], - patterns: ['{index}/_search', '_search'], - data_autocomplete_rules: { - query: { - match_all: {}, - term: { '{field}': { __template: { f: 1 } } }, - }, - size: {}, - facets: { - __template: { - FIELD: {}, - }, - '*': { terms: { field: '{field}' } }, - }, - }, - }, - }, - }; - - const MAPPING = { - index1: { - properties: { - 'field1.1.1': { type: 'string' }, - 'field1.1.2': { type: 'string' }, - }, - }, - index2: { - properties: { - 'field2.1.1': { type: 'string' }, - 'field2.1.2': { type: 'string' }, - }, - }, - }; - - contextTests({}, MAPPING, SEARCH_KB, 'POST _search', [ - { - name: 'Empty doc', - cursor: { lineNumber: 1, column: 2 }, - initialValue: '', - addTemplate: true, - prefixToAdd: '', - suffixToAdd: '', - rangeToReplace: { - start: { lineNumber: 1, column: 2 }, - end: { lineNumber: 1, column: 2 }, - }, - autoCompleteSet: ['facets', 'query', 'size'], - }, - ]); - - contextTests({}, MAPPING, SEARCH_KB, 'POST _no_context', [ - { - name: 'Missing KB', - cursor: { lineNumber: 1, column: 2 }, - no_context: true, - }, - ]); - - contextTests( - { - query: { - f: 1, - }, - }, - MAPPING, - { - globals: { - query: { - t1: 2, - }, - }, - endpoints: {}, - }, - 'POST _no_context', - [ - { - name: 'Missing KB - global auto complete', - cursor: { lineNumber: 3, column: 6 }, - autoCompleteSet: ['t1'], - }, - ] - ); - - contextTests( - { - query: { - field: 'something', - }, - facets: {}, - size: 20, - }, - MAPPING, - SEARCH_KB, - 'POST _search', - [ - { - name: 'existing dictionary key, no template', - cursor: { lineNumber: 2, column: 6 }, - initialValue: 'query', - addTemplate: false, - prefixToAdd: '', - suffixToAdd: '', - rangeToReplace: { - start: { lineNumber: 2, column: 4 }, - end: { lineNumber: 2, column: 11 }, - }, - autoCompleteSet: ['facets', 'query', 'size'], - }, - { - name: 'existing inner dictionary key', - cursor: { lineNumber: 3, column: 8 }, - initialValue: 'field', - addTemplate: false, - prefixToAdd: '', - suffixToAdd: '', - rangeToReplace: { - start: { lineNumber: 3, column: 7 }, - end: { lineNumber: 3, column: 14 }, - }, - autoCompleteSet: ['match_all', 'term'], - }, - { - name: 'existing dictionary key, yes template', - cursor: { lineNumber: 5, column: 8 }, - initialValue: 'facets', - addTemplate: true, - prefixToAdd: '', - suffixToAdd: '', - rangeToReplace: { - start: { lineNumber: 5, column: 4 }, - end: { lineNumber: 5, column: 16 }, - }, - autoCompleteSet: ['facets', 'query', 'size'], - }, - { - name: 'ignoring meta keys', - cursor: { lineNumber: 5, column: 15 }, - no_context: true, - }, - ] - ); - - contextTests( - '{\n' + - ' "query": {\n' + - ' "field": "something"\n' + - ' },\n' + - ' "facets": {},\n' + - ' "size": 20\n' + - '}', - MAPPING, - SEARCH_KB, - 'POST _search', - [ - { - name: 'trailing comma, end of line', - cursor: { lineNumber: 5, column: 17 }, - initialValue: '', - addTemplate: true, - prefixToAdd: '', - suffixToAdd: ', ', - rangeToReplace: { - start: { lineNumber: 5, column: 17 }, - end: { lineNumber: 5, column: 17 }, - }, - autoCompleteSet: ['facets', 'query', 'size'], - }, - { - name: 'trailing comma, beginning of line', - cursor: { lineNumber: 6, column: 2 }, - initialValue: '', - addTemplate: true, - prefixToAdd: '', - suffixToAdd: ', ', - rangeToReplace: { - start: { lineNumber: 6, column: 2 }, - end: { lineNumber: 6, column: 2 }, - }, - autoCompleteSet: ['facets', 'query', 'size'], - }, - { - name: 'prefix comma, end of line', - cursor: { lineNumber: 7, column: 1 }, - initialValue: '', - addTemplate: true, - prefixToAdd: ',\n', - suffixToAdd: '', - rangeToReplace: { - start: { lineNumber: 6, column: 14 }, - end: { lineNumber: 7, column: 1 }, - }, - autoCompleteSet: ['facets', 'query', 'size'], - }, - ] - ); - - contextTests( - { - object: 1, - array: 1, - value_one_of: 1, - value: 2, - something_else: 5, - }, - MAPPING, - { - endpoints: { - _test: { - patterns: ['_test'], - data_autocomplete_rules: { - object: { bla: 1 }, - array: [1], - value_one_of: { __one_of: [1, 2] }, - value: 3, - '*': { __one_of: [4, 5] }, - }, - }, - }, - }, - 'GET _test', - [ - { - name: 'not matching object when { is not opened', - cursor: { lineNumber: 2, column: 13 }, - initialValue: '', - autoCompleteSet: ['{'], - }, - { - name: 'not matching array when [ is not opened', - cursor: { lineNumber: 3, column: 13 }, - initialValue: '', - autoCompleteSet: ['['], - }, - { - name: 'matching value with one_of', - cursor: { lineNumber: 4, column: 20 }, - initialValue: '', - autoCompleteSet: [1, 2], - }, - { - name: 'matching value', - cursor: { lineNumber: 5, column: 13 }, - initialValue: '', - autoCompleteSet: [3], - }, - { - name: 'matching any value with one_of', - cursor: { lineNumber: 6, column: 22 }, - initialValue: '', - autoCompleteSet: [4, 5], - }, - ] - ); - - contextTests( - { - query: { - field: 'something', - }, - facets: { - name: {}, - }, - size: 20, - }, - MAPPING, - SEARCH_KB, - 'GET _search', - [ - { - name: '* matching everything', - cursor: { lineNumber: 6, column: 16 }, - initialValue: '', - addTemplate: true, - prefixToAdd: '', - suffixToAdd: '', - rangeToReplace: { - start: { lineNumber: 6, column: 16 }, - end: { lineNumber: 6, column: 16 }, - }, - autoCompleteSet: [{ name: 'terms', meta: 'API' }], - }, - ] - ); - - contextTests( - { - index: '123', - }, - MAPPING, - { - endpoints: { - _test: { - patterns: ['_test'], - data_autocomplete_rules: { - index: '{index}', - }, - }, - }, - }, - 'GET _test', - [ - { - name: '{index} matching', - cursor: { lineNumber: 2, column: 16 }, - autoCompleteSet: [ - { name: 'index1', meta: 'index' }, - { name: 'index2', meta: 'index' }, - ], - }, - ] - ); - - function tt(term, template, meta) { - term = { name: term, template: template }; - if (meta) { - term.meta = meta; - } - return term; - } - - contextTests( - { - array: ['a'], - oneof: '1', - }, - MAPPING, - { - endpoints: { - _endpoint: { - patterns: ['_endpoint'], - data_autocomplete_rules: { - array: ['a', 'b'], - number: 1, - object: {}, - fixed: { __template: { a: 1 } }, - oneof: { __one_of: ['o1', 'o2'] }, - }, - }, - }, - }, - 'GET _endpoint', - [ - { - name: 'Templates 1', - cursor: { lineNumber: 2, column: 1 }, - autoCompleteSet: [ - tt('array', []), - tt('fixed', { a: 1 }), - tt('number', 1), - tt('object', {}), - tt('oneof', 'o1'), - ], - }, - { - name: 'Templates - one off', - cursor: { lineNumber: 5, column: 13 }, - autoCompleteSet: [tt('o1'), tt('o2')], - }, - ] - ); - - contextTests( - { - string: 'value', - context: {}, - }, - MAPPING, - { - endpoints: { - _endpoint: { - patterns: ['_endpoint'], - data_autocomplete_rules: { - context: { - __one_of: [ - { - __condition: { - lines_regex: 'value', - }, - match: {}, - }, - { - __condition: { - lines_regex: 'other', - }, - no_match: {}, - }, - { always: {} }, - ], - }, - }, - }, - }, - }, - 'GET _endpoint', - [ - { - name: 'Conditionals', - cursor: { lineNumber: 3, column: 16 }, - autoCompleteSet: [tt('always', {}), tt('match', {})], - }, - ] - ); - - contextTests( - { - any_of_numbers: [1], - any_of_obj: [ - { - a: 1, - }, - ], - any_of_mixed: [ - { - a: 1, - }, - 2, - ], - }, - MAPPING, - { - endpoints: { - _endpoint: { - patterns: ['_endpoint'], - data_autocomplete_rules: { - any_of_numbers: { __template: [1, 2], __any_of: [1, 2, 3] }, - any_of_obj: { - __template: [{ c: 1 }], - __any_of: [{ a: 1, b: 2 }, { c: 1 }], - }, - any_of_mixed: { - __any_of: [{ a: 1 }, 3], - }, - }, - }, - }, - }, - 'GET _endpoint', - [ - { - name: 'Any of - templates', - cursor: { lineNumber: 2, column: 1 }, - autoCompleteSet: [ - tt('any_of_mixed', []), - tt('any_of_numbers', [1, 2]), - tt('any_of_obj', [{ c: 1 }]), - ], - }, - { - name: 'Any of - numbers', - cursor: { lineNumber: 3, column: 3 }, - autoCompleteSet: [1, 2, 3], - }, - { - name: 'Any of - object', - cursor: { lineNumber: 7, column: 3 }, - autoCompleteSet: [tt('a', 1), tt('b', 2), tt('c', 1)], - }, - { - name: 'Any of - mixed - obj', - cursor: { lineNumber: 12, column: 3 }, - autoCompleteSet: [tt('a', 1)], - }, - { - name: 'Any of - mixed - both', - cursor: { lineNumber: 14, column: 3 }, - autoCompleteSet: [tt(3), tt('{')], - }, - ] - ); - - contextTests( - {}, - MAPPING, - { - endpoints: { - _endpoint: { - patterns: ['_endpoint'], - data_autocomplete_rules: { - query: '', - }, - }, - }, - }, - 'GET _endpoint', - [ - { - name: 'Empty string as default', - cursor: { lineNumber: 1, column: 2 }, - autoCompleteSet: [tt('query', '')], - }, - ] - ); - - // NOTE: This test emits "error while getting completion terms Error: failed to resolve link - // [GLOBAL.broken]: Error: failed to resolve global components for ['broken']". but that's - // expected. - contextTests( - { - a: { - b: {}, - c: {}, - d: { - t1a: {}, - }, - e: {}, - f: [{}], - g: {}, - h: {}, - }, - }, - MAPPING, - { - globals: { - gtarget: { - t1: 2, - t1a: { - __scope_link: '.', - }, - }, - }, - endpoints: { - _current: { - patterns: ['_current'], - data_autocomplete_rules: { - a: { - b: { - __scope_link: '.a', - }, - c: { - __scope_link: 'ext.target', - }, - d: { - __scope_link: 'GLOBAL.gtarget', - }, - e: { - __scope_link: 'ext', - }, - f: [ - { - __scope_link: 'ext.target', - }, - ], - g: { - __scope_link: function () { - return { - a: 1, - b: 2, - }; - }, - }, - h: { - __scope_link: 'GLOBAL.broken', - }, - }, - }, - }, - ext: { - patterns: ['ext'], - data_autocomplete_rules: { - target: { - t2: 1, - }, - }, - }, - }, - }, - 'GET _current', - [ - { - name: 'Relative scope link test', - cursor: { lineNumber: 3, column: 13 }, - autoCompleteSet: [ - tt('b', {}), - tt('c', {}), - tt('d', {}), - tt('e', {}), - tt('f', [{}]), - tt('g', {}), - tt('h', {}), - ], - }, - { - name: 'External scope link test', - cursor: { lineNumber: 4, column: 13 }, - autoCompleteSet: [tt('t2', 1)], - }, - { - name: 'Global scope link test', - cursor: { lineNumber: 5, column: 13 }, - autoCompleteSet: [tt('t1', 2), tt('t1a', {})], - }, - { - name: 'Global scope link with an internal scope link', - cursor: { lineNumber: 6, column: 18 }, - autoCompleteSet: [tt('t1', 2), tt('t1a', {})], - }, - { - name: 'Entire endpoint scope link test', - cursor: { lineNumber: 8, column: 13 }, - autoCompleteSet: [tt('target', {})], - }, - { - name: 'A scope link within an array', - cursor: { lineNumber: 10, column: 11 }, - autoCompleteSet: [tt('t2', 1)], - }, - { - name: 'A function based scope link', - cursor: { lineNumber: 12, column: 13 }, - autoCompleteSet: [tt('a', 1), tt('b', 2)], - }, - { - name: 'A global scope link with wrong link', - cursor: { lineNumber: 13, column: 13 }, - assertThrows: /broken/, - }, - ] - ); - - contextTests( - {}, - MAPPING, - { - globals: { - gtarget: { - t1: 2, - }, - }, - endpoints: { - _current: { - patterns: ['_current'], - id: 'GET _current', - data_autocomplete_rules: { - __scope_link: 'GLOBAL.gtarget', - }, - }, - }, - }, - 'GET _current', - [ - { - name: 'Top level scope link', - cursor: { lineNumber: 1, column: 2 }, - autoCompleteSet: [tt('t1', 2)], - }, - ] - ); - - contextTests( - { - a: {}, - }, - MAPPING, - { - endpoints: { - _endpoint: { - patterns: ['_endpoint'], - data_autocomplete_rules: { - a: {}, - b: {}, - }, - }, - }, - }, - 'GET _endpoint', - [ - { - name: 'Path after empty object', - cursor: { lineNumber: 2, column: 11 }, - autoCompleteSet: ['a', 'b'], - }, - ] - ); - - contextTests( - { - '': {}, - }, - MAPPING, - SEARCH_KB, - 'POST _search', - [ - { - name: 'Replace an empty string', - cursor: { lineNumber: 2, column: 5 }, - rangeToReplace: { - start: { lineNumber: 2, column: 4 }, - end: { lineNumber: 2, column: 10 }, - }, - }, - ] - ); - - contextTests( - { - a: [ - { - c: {}, - }, - ], - }, - MAPPING, - { - endpoints: { - _endpoint: { - patterns: ['_endpoint'], - data_autocomplete_rules: { - a: [{ b: 1 }], - }, - }, - }, - }, - 'GET _endpoint', - [ - { - name: 'List of objects - internal autocomplete', - cursor: { lineNumber: 4, column: 11 }, - autoCompleteSet: ['b'], - }, - { - name: 'List of objects - external template', - cursor: { lineNumber: 1, column: 2 }, - autoCompleteSet: [tt('a', [{}])], - }, - ] - ); - - contextTests( - { - query: { - term: { - field: 'something', - }, - }, - facets: { - test: { - terms: { - field: 'test', - }, - }, - }, - size: 20, - }, - MAPPING, - SEARCH_KB, - 'POST index1/_search', - [ - { - name: 'Field completion as scope', - cursor: { lineNumber: 4, column: 11 }, - autoCompleteSet: [ - tt('field1.1.1', { f: 1 }, 'string'), - tt('field1.1.2', { f: 1 }, 'string'), - ], - }, - { - name: 'Field completion as value', - cursor: { lineNumber: 10, column: 24 }, - autoCompleteSet: [ - { name: 'field1.1.1', meta: 'string' }, - { name: 'field1.1.2', meta: 'string' }, - ], - }, - ] - ); - - // NOTE: This test emits "Can't extract a valid url token path", but that's expected. - contextTests('POST _search\n', MAPPING, SEARCH_KB, null, [ - { - name: 'initial doc start', - cursor: { lineNumber: 2, column: 1 }, - autoCompleteSet: ['{'], - prefixToAdd: '', - suffixToAdd: '', - }, - ]); - - contextTests( - '{\n' + ' "query": {} \n' + '}\n' + '\n' + '\n', - MAPPING, - SEARCH_KB, - 'POST _search', - [ - { - name: 'Cursor rows after request end', - cursor: { lineNumber: 5, column: 1 }, - autoCompleteSet: ['GET', 'PUT', 'POST', 'DELETE', 'HEAD', 'PATCH'], - prefixToAdd: '', - suffixToAdd: ' ', - }, - { - name: 'Cursor just after request end', - cursor: { lineNumber: 3, column: 2 }, - no_context: true, - }, - ] - ); - - const CLUSTER_KB = { - endpoints: { - _search: { - patterns: ['_search', '{index}/_search'], - url_params: { - search_type: ['count', 'query_then_fetch'], - scroll: '10m', - }, - methods: ['GET'], - data_autocomplete_rules: {}, - }, - '_cluster/stats': { - patterns: ['_cluster/stats'], - indices_mode: 'none', - data_autocomplete_rules: {}, - methods: ['GET'], - }, - '_cluster/nodes/stats': { - patterns: ['_cluster/nodes/stats'], - data_autocomplete_rules: {}, - methods: ['GET'], - }, - }, - }; - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster', [ - { - name: 'Endpoints with slashes - no slash', - cursor: { lineNumber: 1, column: 9 }, - autoCompleteSet: ['_cluster/nodes/stats', '_cluster/stats', '_search', 'index1', 'index2'], - prefixToAdd: '', - suffixToAdd: '', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster/', [ - { - name: 'Endpoints with slashes - before slash', - cursor: { lineNumber: 1, column: 8 }, - autoCompleteSet: ['_cluster/nodes/stats', '_cluster/stats', '_search', 'index1', 'index2'], - prefixToAdd: '', - suffixToAdd: '', - }, - { - name: 'Endpoints with slashes - on slash', - cursor: { lineNumber: 1, column: 13 }, - autoCompleteSet: ['_cluster/nodes/stats', '_cluster/stats', '_search', 'index1', 'index2'], - prefixToAdd: '', - suffixToAdd: '', - }, - { - name: 'Endpoints with slashes - after slash', - cursor: { lineNumber: 1, column: 14 }, - autoCompleteSet: ['nodes/stats', 'stats'], - prefixToAdd: '', - suffixToAdd: '', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster/no', [ - { - name: 'Endpoints with slashes - after slash', - cursor: { lineNumber: 1, column: 15 }, - autoCompleteSet: [ - { name: 'nodes/stats', meta: 'endpoint' }, - { name: 'stats', meta: 'endpoint' }, - ], - prefixToAdd: '', - suffixToAdd: '', - initialValue: 'no', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster/nodes/st', [ - { - name: 'Endpoints with two slashes', - cursor: { lineNumber: 1, column: 21 }, - autoCompleteSet: ['stats'], - prefixToAdd: '', - suffixToAdd: '', - initialValue: 'st', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET ', [ - { - name: 'Immediately after space + method', - cursor: { lineNumber: 1, column: 5 }, - autoCompleteSet: [ - { name: '_cluster/nodes/stats', meta: 'endpoint' }, - { name: '_cluster/stats', meta: 'endpoint' }, - { name: '_search', meta: 'endpoint' }, - { name: 'index1', meta: 'index' }, - { name: 'index2', meta: 'index' }, - ], - prefixToAdd: '', - suffixToAdd: '', - initialValue: '', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET cl', [ - { - name: 'Endpoints by subpart GET', - cursor: { lineNumber: 1, column: 7 }, - autoCompleteSet: [ - { name: '_cluster/nodes/stats', meta: 'endpoint' }, - { name: '_cluster/stats', meta: 'endpoint' }, - { name: '_search', meta: 'endpoint' }, - { name: 'index1', meta: 'index' }, - { name: 'index2', meta: 'index' }, - ], - prefixToAdd: '', - suffixToAdd: '', - initialValue: 'cl', - method: 'GET', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'POST cl', [ - { - name: 'Endpoints by subpart POST', - cursor: { lineNumber: 1, column: 8 }, - no_context: true, - prefixToAdd: '', - suffixToAdd: '', - initialValue: 'cl', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?', [ - { - name: 'Params just after ?', - cursor: { lineNumber: 1, column: 13 }, - autoCompleteSet: [ - { name: 'filter_path', meta: 'param', insertValue: 'filter_path=' }, - { name: 'format', meta: 'param', insertValue: 'format=' }, - { name: 'pretty', meta: 'flag' }, - { name: 'scroll', meta: 'param', insertValue: 'scroll=' }, - { name: 'search_type', meta: 'param', insertValue: 'search_type=' }, - ], - prefixToAdd: '', - suffixToAdd: '', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=', [ - { - name: 'Params values', - cursor: { lineNumber: 1, column: 20 }, - autoCompleteSet: [ - { name: 'json', meta: 'format' }, - { name: 'yaml', meta: 'format' }, - ], - prefixToAdd: '', - suffixToAdd: '', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=yaml&', [ - { - name: 'Params after amp', - cursor: { lineNumber: 1, column: 25 }, - autoCompleteSet: [ - { name: 'filter_path', meta: 'param', insertValue: 'filter_path=' }, - { name: 'format', meta: 'param', insertValue: 'format=' }, - { name: 'pretty', meta: 'flag' }, - { name: 'scroll', meta: 'param', insertValue: 'scroll=' }, - { name: 'search_type', meta: 'param', insertValue: 'search_type=' }, - ], - prefixToAdd: '', - suffixToAdd: '', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=yaml&search', [ - { - name: 'Params on existing param', - cursor: { lineNumber: 1, column: 27 }, - rangeToReplace: { - start: { lineNumber: 1, column: 25 }, - end: { lineNumber: 1, column: 31 }, - }, - autoCompleteSet: [ - { name: 'filter_path', meta: 'param', insertValue: 'filter_path=' }, - { name: 'format', meta: 'param', insertValue: 'format=' }, - { name: 'pretty', meta: 'flag' }, - { name: 'scroll', meta: 'param', insertValue: 'scroll=' }, - { name: 'search_type', meta: 'param', insertValue: 'search_type=' }, - ], - prefixToAdd: '', - suffixToAdd: '', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=yaml&search_type=cou', [ - { - name: 'Params on existing value', - cursor: { lineNumber: 1, column: 38 }, - rangeToReplace: { - start: { lineNumber: 1, column: 37 }, - end: { lineNumber: 1, column: 40 }, - }, - autoCompleteSet: [ - { name: 'count', meta: 'search_type' }, - { name: 'query_then_fetch', meta: 'search_type' }, - ], - prefixToAdd: '', - suffixToAdd: '', - }, - ]); - - contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=yaml&search_type=cou', [ - { - name: 'Params on just after = with existing value', - cursor: { lineNumber: 1, column: 37 }, - rangeToReplace: { - start: { lineNumber: 1, column: 37 }, - end: { lineNumber: 1, column: 37 }, - }, - autoCompleteSet: [ - { name: 'count', meta: 'search_type' }, - { name: 'query_then_fetch', meta: 'search_type' }, - ], - prefixToAdd: '', - suffixToAdd: '', - }, - ]); - - contextTests( - { - query: { - field: 'something', - }, - facets: {}, - size: 20, - }, - MAPPING, - SEARCH_KB, - 'POST http://somehost/_search', - [ - { - name: 'fullurl - existing dictionary key, no template', - cursor: { lineNumber: 2, column: 7 }, - initialValue: 'query', - addTemplate: false, - prefixToAdd: '', - suffixToAdd: '', - rangeToReplace: { - start: { lineNumber: 2, column: 4 }, - end: { lineNumber: 2, column: 11 }, - }, - autoCompleteSet: ['facets', 'query', 'size'], - }, - { - name: 'fullurl - existing inner dictionary key', - cursor: { lineNumber: 3, column: 8 }, - initialValue: 'field', - addTemplate: false, - prefixToAdd: '', - suffixToAdd: '', - rangeToReplace: { - start: { lineNumber: 3, column: 7 }, - end: { lineNumber: 3, column: 14 }, - }, - autoCompleteSet: ['match_all', 'term'], - }, - { - name: 'fullurl - existing dictionary key, yes template', - cursor: { lineNumber: 5, column: 8 }, - initialValue: 'facets', - addTemplate: true, - prefixToAdd: '', - suffixToAdd: '', - rangeToReplace: { - start: { lineNumber: 5, column: 4 }, - end: { lineNumber: 5, column: 16 }, - }, - autoCompleteSet: ['facets', 'query', 'size'], - }, - ] - ); -}); diff --git a/src/plugins/console/public/application/models/sense_editor/sense_editor.test.js b/src/plugins/console/public/application/models/sense_editor/sense_editor.test.js deleted file mode 100644 index 19d782f1b8e87..0000000000000 --- a/src/plugins/console/public/application/models/sense_editor/sense_editor.test.js +++ /dev/null @@ -1,641 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import './sense_editor.test.mocks'; - -import $ from 'jquery'; -import _ from 'lodash'; -import { URL } from 'url'; - -import { create } from './create'; -import { XJson } from '@kbn/es-ui-shared-plugin/public'; -import editorInput1 from './__fixtures__/editor_input1.txt'; -import { setStorage, createStorage } from '../../../services'; - -const { collapseLiteralStrings } = XJson; - -describe('Editor', () => { - let input; - let oldUrl; - let olldWindow; - let storage; - - beforeEach(function () { - // Set up our document body - document.body.innerHTML = `
    -
    -
    -
    -
    `; - - input = create(document.querySelector('#ConAppEditor')); - $(input.getCoreEditor().getContainer()).show(); - input.autocomplete._test.removeChangeListener(); - oldUrl = global.URL; - olldWindow = { ...global.window }; - global.URL = URL; - Object.defineProperty(global, 'window', { - value: Object.create(window), - writable: true, - }); - Object.defineProperty(window, 'location', { - value: { - origin: 'http://localhost:5620', - }, - }); - storage = createStorage({ - engine: global.window.localStorage, - prefix: 'console_test', - }); - setStorage(storage); - }); - afterEach(function () { - global.URL = oldUrl; - global.window = olldWindow; - $(input.getCoreEditor().getContainer()).hide(); - input.autocomplete._test.addChangeListener(); - setStorage(null); - }); - - let testCount = 0; - - const callWithEditorMethod = (editorMethod, fn) => async (done) => { - const results = await input[editorMethod](); - fn(results, done); - }; - - function utilsTest(name, prefix, data, testToRun) { - const id = testCount++; - if (typeof data === 'function') { - testToRun = data; - data = null; - } - if (data && typeof data !== 'string') { - data = JSON.stringify(data, null, 3); - } - if (data) { - if (prefix) { - data = prefix + '\n' + data; - } - } else { - data = prefix; - } - - test('Utils test ' + id + ' : ' + name, function (done) { - input.update(data, true).then(() => { - testToRun(done); - }); - }); - } - - function compareRequest(requests, expected) { - if (!Array.isArray(requests)) { - requests = [requests]; - expected = [expected]; - } - - _.each(requests, function (r) { - delete r.range; - }); - expect(requests).toEqual(expected); - } - - const simpleRequest = { - prefix: 'POST _search', - data: ['{', ' "query": { "match_all": {} }', '}'].join('\n'), - }; - - const singleLineRequest = { - prefix: 'POST _search', - data: '{ "query": { "match_all": {} } }', - }; - - const getRequestNoData = { - prefix: 'GET _stats', - }; - - const multiDocRequest = { - prefix: 'POST _bulk', - data_as_array: ['{ "index": { "_index": "index", "_type":"type" } }', '{ "field": 1 }'], - }; - multiDocRequest.data = multiDocRequest.data_as_array.join('\n'); - - utilsTest( - 'simple request range', - simpleRequest.prefix, - simpleRequest.data, - callWithEditorMethod('getRequestRange', (range, done) => { - compareRequest(range, { - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 4, column: 2 }, - }); - done(); - }) - ); - - utilsTest( - 'simple request data', - simpleRequest.prefix, - simpleRequest.data, - callWithEditorMethod('getRequest', (request, done) => { - const expected = { - method: 'POST', - url: '_search', - data: [simpleRequest.data], - }; - compareRequest(request, expected); - done(); - }) - ); - - utilsTest( - 'simple request range, prefixed with spaces', - ' ' + simpleRequest.prefix, - simpleRequest.data, - callWithEditorMethod('getRequestRange', (range, done) => { - expect(range).toEqual({ - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 4, column: 2 }, - }); - done(); - }) - ); - - utilsTest( - 'simple request data, prefixed with spaces', - ' ' + simpleRequest.prefix, - simpleRequest.data, - callWithEditorMethod('getRequest', (request, done) => { - const expected = { - method: 'POST', - url: '_search', - data: [simpleRequest.data], - }; - - compareRequest(request, expected); - done(); - }) - ); - - utilsTest( - 'simple request range, suffixed with spaces', - simpleRequest.prefix + ' ', - simpleRequest.data + ' ', - callWithEditorMethod('getRequestRange', (range, done) => { - compareRequest(range, { - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 4, column: 2 }, - }); - done(); - }) - ); - - utilsTest( - 'simple request data, suffixed with spaces', - simpleRequest.prefix + ' ', - simpleRequest.data + ' ', - callWithEditorMethod('getRequest', (request, done) => { - const expected = { - method: 'POST', - url: '_search', - data: [simpleRequest.data], - }; - - compareRequest(request, expected); - done(); - }) - ); - - utilsTest( - 'single line request range', - singleLineRequest.prefix, - singleLineRequest.data, - callWithEditorMethod('getRequestRange', (range, done) => { - compareRequest(range, { - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 2, column: 33 }, - }); - done(); - }) - ); - - utilsTest( - 'full url: single line request data', - 'POST https://somehost/_search', - singleLineRequest.data, - callWithEditorMethod('getRequest', (request, done) => { - const expected = { - method: 'POST', - url: 'https://somehost/_search', - data: [singleLineRequest.data], - }; - compareRequest(request, expected); - done(); - }) - ); - - utilsTest( - 'request with no data followed by a new line', - getRequestNoData.prefix, - '\n', - callWithEditorMethod('getRequestRange', (range, done) => { - compareRequest(range, { - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 1, column: 11 }, - }); - done(); - }) - ); - - utilsTest( - 'request with no data followed by a new line (data)', - getRequestNoData.prefix, - '\n', - callWithEditorMethod('getRequest', (request, done) => { - const expected = { - method: 'GET', - url: '_stats', - data: [], - }; - compareRequest(request, expected); - done(); - }) - ); - - utilsTest( - 'request with no data', - getRequestNoData.prefix, - getRequestNoData.data, - callWithEditorMethod('getRequestRange', (range, done) => { - expect(range).toEqual({ - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 1, column: 11 }, - }); - done(); - }) - ); - - utilsTest( - 'request with no data (data)', - getRequestNoData.prefix, - getRequestNoData.data, - callWithEditorMethod('getRequest', (request, done) => { - const expected = { - method: 'GET', - url: '_stats', - data: [], - }; - compareRequest(request, expected); - done(); - }) - ); - - utilsTest( - 'multi doc request range', - multiDocRequest.prefix, - multiDocRequest.data, - callWithEditorMethod('getRequestRange', (range, done) => { - expect(range).toEqual({ - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 3, column: 15 }, - }); - done(); - }) - ); - - utilsTest( - 'multi doc request data', - multiDocRequest.prefix, - multiDocRequest.data, - callWithEditorMethod('getRequest', (request, done) => { - const expected = { - method: 'POST', - url: '_bulk', - data: multiDocRequest.data_as_array, - }; - compareRequest(request, expected); - done(); - }) - ); - - const scriptRequest = { - prefix: 'POST _search', - data: ['{', ' "query": { "script": """', ' some script ', ' """}', '}'].join('\n'), - }; - - utilsTest( - 'script request range', - scriptRequest.prefix, - scriptRequest.data, - callWithEditorMethod('getRequestRange', (range, done) => { - compareRequest(range, { - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 6, column: 2 }, - }); - done(); - }) - ); - - utilsTest( - 'simple request data', - simpleRequest.prefix, - simpleRequest.data, - callWithEditorMethod('getRequest', (request, done) => { - const expected = { - method: 'POST', - url: '_search', - data: [collapseLiteralStrings(simpleRequest.data)], - }; - - compareRequest(request, expected); - done(); - }) - ); - - function multiReqTest(name, editorInput, range, expected) { - utilsTest('multi request select - ' + name, editorInput, async function (done) { - const requests = await input.getRequestsInRange(range, false); - // convert to format returned by request. - _.each(expected, function (req) { - req.data = req.data == null ? [] : [JSON.stringify(req.data, null, 2)]; - }); - - compareRequest(requests, expected); - done(); - }); - } - - multiReqTest( - 'mid body to mid body', - editorInput1, - { start: { lineNumber: 13 }, end: { lineNumber: 18 } }, - [ - { - method: 'PUT', - url: 'index_1/type1/1', - data: { - f: 1, - }, - }, - { - method: 'PUT', - url: 'index_1/type1/2', - data: { - f: 2, - }, - }, - ] - ); - - multiReqTest( - 'single request start to end', - editorInput1, - { start: { lineNumber: 11 }, end: { lineNumber: 14 } }, - [ - { - method: 'PUT', - url: 'index_1/type1/1', - data: { - f: 1, - }, - }, - ] - ); - - multiReqTest( - 'start to end, with comment', - editorInput1, - { start: { lineNumber: 7 }, end: { lineNumber: 14 } }, - [ - { - method: 'GET', - url: '_stats?level=shards', - data: null, - }, - { - method: 'PUT', - url: 'index_1/type1/1', - data: { - f: 1, - }, - }, - ] - ); - - multiReqTest( - 'before start to after end, with comments', - editorInput1, - { start: { lineNumber: 5 }, end: { lineNumber: 15 } }, - [ - { - method: 'GET', - url: '_stats?level=shards', - data: null, - }, - { - method: 'PUT', - url: 'index_1/type1/1', - data: { - f: 1, - }, - }, - ] - ); - - multiReqTest( - 'between requests', - editorInput1, - { start: { lineNumber: 22 }, end: { lineNumber: 23 } }, - [] - ); - - multiReqTest( - 'between requests - with comment', - editorInput1, - { start: { lineNumber: 21 }, end: { lineNumber: 23 } }, - [] - ); - - multiReqTest( - 'between requests - before comment', - editorInput1, - { start: { lineNumber: 20 }, end: { lineNumber: 23 } }, - [] - ); - - function multiReqCopyAsCurlTest(name, editorInput, range, expected) { - utilsTest('multi request copy as curl - ' + name, editorInput, async function (done) { - const curl = await input.getRequestsAsCURL('http://localhost:9200', range); - expect(curl).toEqual(expected); - done(); - }); - } - - multiReqCopyAsCurlTest( - 'start to end, with comment', - editorInput1, - { start: { lineNumber: 7 }, end: { lineNumber: 14 } }, - ` -curl -XGET "http://localhost:9200/_stats?level=shards" -H "kbn-xsrf: reporting" - -#in between comment - -curl -XPUT "http://localhost:9200/index_1/type1/1" -H "kbn-xsrf: reporting" -H "Content-Type: application/json" -d' -{ - "f": 1 -}'`.trim() - ); - - multiReqCopyAsCurlTest( - 'with single quotes', - editorInput1, - { start: { lineNumber: 29 }, end: { lineNumber: 33 } }, - ` -curl -XPOST "http://localhost:9200/_sql?format=txt" -H "kbn-xsrf: reporting" -H "Content-Type: application/json" -d' -{ - "query": "SELECT prenom FROM claude_index WHERE prenom = '\\''claude'\\'' ", - "fetch_size": 1 -}'`.trim() - ); - - multiReqCopyAsCurlTest( - 'with date math index', - editorInput1, - { start: { lineNumber: 35 }, end: { lineNumber: 35 } }, - ` - curl -XGET "http://localhost:9200/%3Cindex_1-%7Bnow%2Fd-2d%7D%3E%2C%3Cindex_1-%7Bnow%2Fd-1d%7D%3E%2C%3Cindex_1-%7Bnow%2Fd%7D%3E%2F_search?pretty" -H "kbn-xsrf: reporting"`.trim() - ); - - multiReqCopyAsCurlTest( - 'with Kibana API request', - editorInput1, - { start: { lineNumber: 37 }, end: { lineNumber: 37 } }, - ` -curl -XGET "http://localhost:5620/api/spaces/space" -H \"kbn-xsrf: reporting\"`.trim() - ); - - describe('getRequestsAsCURL', () => { - it('should return empty string if no requests', async () => { - input?.getCoreEditor().setValue('', false); - const curl = await input.getRequestsAsCURL('http://localhost:9200', { - start: { lineNumber: 1 }, - end: { lineNumber: 1 }, - }); - expect(curl).toEqual(''); - }); - - it('should replace variables in the URL', async () => { - storage.set('variables', [{ name: 'exampleVariableA', value: 'valueA' }]); - input?.getCoreEditor().setValue('GET ${exampleVariableA}', false); - const curl = await input.getRequestsAsCURL('http://localhost:9200', { - start: { lineNumber: 1 }, - end: { lineNumber: 1 }, - }); - expect(curl).toContain('valueA'); - }); - - it('should replace variables in the body', async () => { - storage.set('variables', [{ name: 'exampleVariableB', value: 'valueB' }]); - console.log(storage.get('variables')); - input - ?.getCoreEditor() - .setValue('GET _search\n{\t\t"query": {\n\t\t\t"${exampleVariableB}": ""\n\t}\n}', false); - const curl = await input.getRequestsAsCURL('http://localhost:9200', { - start: { lineNumber: 1 }, - end: { lineNumber: 6 }, - }); - expect(curl).toContain('valueB'); - }); - - it('should strip comments in the URL', async () => { - input?.getCoreEditor().setValue('GET _search // comment', false); - const curl = await input.getRequestsAsCURL('http://localhost:9200', { - start: { lineNumber: 1 }, - end: { lineNumber: 6 }, - }); - expect(curl).not.toContain('comment'); - }); - - it('should strip comments in the body', async () => { - input - ?.getCoreEditor() - .setValue('{\n\t"query": {\n\t\t"match_all": {} // comment \n\t}\n}', false); - const curl = await input.getRequestsAsCURL('http://localhost:9200', { - start: { lineNumber: 1 }, - end: { lineNumber: 8 }, - }); - console.log('curl', curl); - expect(curl).not.toContain('comment'); - }); - - it('should strip multi-line comments in the body', async () => { - input - ?.getCoreEditor() - .setValue('{\n\t"query": {\n\t\t"match_all": {} /* comment */\n\t}\n}', false); - const curl = await input.getRequestsAsCURL('http://localhost:9200', { - start: { lineNumber: 1 }, - end: { lineNumber: 8 }, - }); - console.log('curl', curl); - expect(curl).not.toContain('comment'); - }); - - it('should replace multiple variables in the URL', async () => { - storage.set('variables', [ - { name: 'exampleVariableA', value: 'valueA' }, - { name: 'exampleVariableB', value: 'valueB' }, - ]); - input?.getCoreEditor().setValue('GET ${exampleVariableA}/${exampleVariableB}', false); - const curl = await input.getRequestsAsCURL('http://localhost:9200', { - start: { lineNumber: 1 }, - end: { lineNumber: 1 }, - }); - expect(curl).toContain('valueA'); - expect(curl).toContain('valueB'); - }); - - it('should replace multiple variables in the body', async () => { - storage.set('variables', [ - { name: 'exampleVariableA', value: 'valueA' }, - { name: 'exampleVariableB', value: 'valueB' }, - ]); - input - ?.getCoreEditor() - .setValue( - 'GET _search\n{\t\t"query": {\n\t\t\t"${exampleVariableA}": "${exampleVariableB}"\n\t}\n}', - false - ); - const curl = await input.getRequestsAsCURL('http://localhost:9200', { - start: { lineNumber: 1 }, - end: { lineNumber: 6 }, - }); - expect(curl).toContain('valueA'); - expect(curl).toContain('valueB'); - }); - - it('should replace variables in bulk request', async () => { - storage.set('variables', [ - { name: 'exampleVariableA', value: 'valueA' }, - { name: 'exampleVariableB', value: 'valueB' }, - ]); - input - ?.getCoreEditor() - .setValue( - 'POST _bulk\n{"index": {"_id": "0"}}\n{"field" : "${exampleVariableA}"}\n{"index": {"_id": "1"}}\n{"field" : "${exampleVariableB}"}\n', - false - ); - const curl = await input.getRequestsAsCURL('http://localhost:9200', { - start: { lineNumber: 1 }, - end: { lineNumber: 4 }, - }); - expect(curl).toContain('valueA'); - expect(curl).toContain('valueB'); - }); - }); -}); diff --git a/src/plugins/console/public/application/models/sense_editor/sense_editor.test.mocks.ts b/src/plugins/console/public/application/models/sense_editor/sense_editor.test.mocks.ts deleted file mode 100644 index f0ec279fb4ffe..0000000000000 --- a/src/plugins/console/public/application/models/sense_editor/sense_editor.test.mocks.ts +++ /dev/null @@ -1,20 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint no-undef: 0 */ - -import '../legacy_core_editor/legacy_core_editor.test.mocks'; - -import jQuery from 'jquery'; -jest.spyOn(jQuery, 'ajax').mockImplementation( - () => - new Promise(() => { - // never resolve - }) as any -); diff --git a/src/plugins/console/public/application/models/sense_editor/sense_editor.ts b/src/plugins/console/public/application/models/sense_editor/sense_editor.ts deleted file mode 100644 index f6b0439cb283e..0000000000000 --- a/src/plugins/console/public/application/models/sense_editor/sense_editor.ts +++ /dev/null @@ -1,534 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import _ from 'lodash'; -import { parse } from 'hjson'; -import { XJson } from '@kbn/es-ui-shared-plugin/public'; - -import RowParser from '../../../lib/row_parser'; -import * as utils from '../../../lib/utils'; -import { constructUrl } from '../../../lib/es/es'; - -import { CoreEditor, Position, Range } from '../../../types'; -import { createTokenIterator } from '../../factories'; -import createAutocompleter from '../../../lib/autocomplete/autocomplete'; -import { getStorage, StorageKeys } from '../../../services'; -import { DEFAULT_VARIABLES } from '../../../../common/constants'; - -const { collapseLiteralStrings } = XJson; - -export class SenseEditor { - currentReqRange: (Range & { markerRef: unknown }) | null; - parser: RowParser; - - private readonly autocomplete: ReturnType; - - constructor(private readonly coreEditor: CoreEditor) { - this.currentReqRange = null; - this.parser = new RowParser(this.coreEditor); - this.autocomplete = createAutocompleter({ - coreEditor, - parser: this.parser, - }); - this.coreEditor.registerAutocompleter(this.autocomplete.getCompletions); - this.coreEditor.on( - 'tokenizerUpdate', - this.highlightCurrentRequestsAndUpdateActionBar.bind(this) - ); - this.coreEditor.on('changeCursor', this.highlightCurrentRequestsAndUpdateActionBar.bind(this)); - this.coreEditor.on('changeScrollTop', this.updateActionsBar.bind(this)); - } - - prevRequestStart = (rowOrPos?: number | Position): Position => { - let curRow: number; - - if (rowOrPos == null) { - curRow = this.coreEditor.getCurrentPosition().lineNumber; - } else if (_.isObject(rowOrPos)) { - curRow = (rowOrPos as Position).lineNumber; - } else { - curRow = rowOrPos as number; - } - - while (curRow > 0 && !this.parser.isStartRequestRow(curRow, this.coreEditor)) curRow--; - - return { - lineNumber: curRow, - column: 1, - }; - }; - - nextRequestStart = (rowOrPos?: number | Position) => { - let curRow: number; - if (rowOrPos == null) { - curRow = this.coreEditor.getCurrentPosition().lineNumber; - } else if (_.isObject(rowOrPos)) { - curRow = (rowOrPos as Position).lineNumber; - } else { - curRow = rowOrPos as number; - } - const maxLines = this.coreEditor.getLineCount(); - for (; curRow < maxLines - 1; curRow++) { - if (this.parser.isStartRequestRow(curRow, this.coreEditor)) { - break; - } - } - return { - row: curRow, - column: 0, - }; - }; - - autoIndent = _.debounce(async () => { - await this.coreEditor.waitForLatestTokens(); - const reqRange = await this.getRequestRange(); - if (!reqRange) { - return; - } - const parsedReq = await this.getRequest(); - - if (!parsedReq) { - return; - } - - if (parsedReq.data.some((doc) => utils.hasComments(doc))) { - /** - * Comments require different approach for indentation and do not have condensed format - * We need to delegate indentation logic to coreEditor since it has access to session and other methods used for formatting and indenting the comments - */ - this.coreEditor.autoIndent(parsedReq.range); - return; - } - - if (parsedReq.data && parsedReq.data.length > 0) { - let indent = parsedReq.data.length === 1; // unindent multi docs by default - let formattedData = utils.formatRequestBodyDoc(parsedReq.data, indent); - if (!formattedData.changed) { - // toggle. - indent = !indent; - formattedData = utils.formatRequestBodyDoc(parsedReq.data, indent); - } - parsedReq.data = formattedData.data; - - this.replaceRequestRange(parsedReq, reqRange); - } - }, 25); - - update = async (data: string, reTokenizeAll = false) => { - return this.coreEditor.setValue(data, reTokenizeAll); - }; - - replaceRequestRange = ( - newRequest: { method: string; url: string; data: string | string[] }, - requestRange: Range - ) => { - const text = utils.textFromRequest(newRequest); - if (requestRange) { - this.coreEditor.replaceRange(requestRange, text); - } else { - // just insert where we are - this.coreEditor.insert(this.coreEditor.getCurrentPosition(), text); - } - }; - - getRequestRange = async (lineNumber?: number): Promise => { - await this.coreEditor.waitForLatestTokens(); - - if (this.parser.isInBetweenRequestsRow(lineNumber)) { - return null; - } - - const reqStart = this.prevRequestStart(lineNumber); - const reqEnd = this.nextRequestEnd(reqStart); - - return { - start: { - ...reqStart, - }, - end: { - ...reqEnd, - }, - }; - }; - - expandRangeToRequestEdges = async ( - range = this.coreEditor.getSelectionRange() - ): Promise => { - await this.coreEditor.waitForLatestTokens(); - - let startLineNumber = range.start.lineNumber; - let endLineNumber = range.end.lineNumber; - const maxLine = Math.max(1, this.coreEditor.getLineCount()); - - if (this.parser.isInBetweenRequestsRow(startLineNumber)) { - /* Do nothing... */ - } else { - for (; startLineNumber >= 1; startLineNumber--) { - if (this.parser.isStartRequestRow(startLineNumber)) { - break; - } - } - } - - if (startLineNumber < 1 || startLineNumber > endLineNumber) { - return null; - } - // move end row to the previous request end if between requests, otherwise walk forward - if (this.parser.isInBetweenRequestsRow(endLineNumber)) { - for (; endLineNumber >= startLineNumber; endLineNumber--) { - if (this.parser.isEndRequestRow(endLineNumber)) { - break; - } - } - } else { - for (; endLineNumber <= maxLine; endLineNumber++) { - if (this.parser.isEndRequestRow(endLineNumber)) { - break; - } - } - } - - if (endLineNumber < startLineNumber || endLineNumber > maxLine) { - return null; - } - - const endColumn = - (this.coreEditor.getLineValue(endLineNumber) || '').replace(/\s+$/, '').length + 1; - return { - start: { - lineNumber: startLineNumber, - column: 1, - }, - end: { - lineNumber: endLineNumber, - column: endColumn, - }, - }; - }; - - getRequestInRange = async (range?: Range) => { - await this.coreEditor.waitForLatestTokens(); - if (!range) { - return null; - } - const request: { - method: string; - data: string[]; - url: string; - range: Range; - } = { - method: '', - data: [], - url: '', - range, - }; - - const pos = range.start; - const tokenIter = createTokenIterator({ editor: this.coreEditor, position: pos }); - let t = tokenIter.getCurrentToken(); - if (this.parser.isEmptyToken(t)) { - // if the row starts with some spaces, skip them. - t = this.parser.nextNonEmptyToken(tokenIter); - } - if (t == null) { - return null; - } - - request.method = t.value; - t = this.parser.nextNonEmptyToken(tokenIter); - - if (!t || t.type === 'method') { - return null; - } - - request.url = ''; - - while (t && t.type && (t.type.indexOf('url') === 0 || t.type === 'variable.template')) { - request.url += t.value; - t = tokenIter.stepForward(); - } - if (this.parser.isEmptyToken(t)) { - // if the url row ends with some spaces, skip them. - t = this.parser.nextNonEmptyToken(tokenIter); - } - - // If the url row ends with a comment, skip it - while (this.parser.isCommentToken(t)) { - t = tokenIter.stepForward(); - } - - let bodyStartLineNumber = (t ? 0 : 1) + tokenIter.getCurrentPosition().lineNumber; // artificially increase end of docs. - let dataEndPos: Position; - while ( - bodyStartLineNumber < range.end.lineNumber || - (bodyStartLineNumber === range.end.lineNumber && 1 < range.end.column) - ) { - dataEndPos = this.nextDataDocEnd({ - lineNumber: bodyStartLineNumber, - column: 1, - }); - const bodyRange: Range = { - start: { - lineNumber: bodyStartLineNumber, - column: 1, - }, - end: dataEndPos, - }; - const data = this.coreEditor.getValueInRange(bodyRange)!; - request.data.push(data.trim()); - bodyStartLineNumber = dataEndPos.lineNumber + 1; - } - - return request; - }; - - getRequestsInRange = async ( - range = this.coreEditor.getSelectionRange(), - includeNonRequestBlocks = false - ): Promise => { - await this.coreEditor.waitForLatestTokens(); - if (!range) { - return []; - } - - const expandedRange = await this.expandRangeToRequestEdges(range); - if (!expandedRange) { - return []; - } - - const requests: unknown[] = []; - - let rangeStartCursor = expandedRange.start.lineNumber; - const endLineNumber = expandedRange.end.lineNumber; - - // move to the next request start (during the second iterations this may not be exactly on a request - let currentLineNumber = expandedRange.start.lineNumber; - - const flushNonRequestBlock = () => { - if (includeNonRequestBlocks) { - const nonRequestPrefixBlock = this.coreEditor - .getLines(rangeStartCursor, currentLineNumber - 1) - .join('\n'); - if (nonRequestPrefixBlock) { - requests.push(nonRequestPrefixBlock); - } - } - }; - - while (currentLineNumber <= endLineNumber) { - if (this.parser.isStartRequestRow(currentLineNumber)) { - flushNonRequestBlock(); - const request = await this.getRequest(currentLineNumber); - if (!request) { - // Something has probably gone wrong. - return requests; - } else { - requests.push(request); - rangeStartCursor = currentLineNumber = request.range.end.lineNumber + 1; - } - } else { - ++currentLineNumber; - } - } - - flushNonRequestBlock(); - - return requests; - }; - - getRequest = async (row?: number) => { - await this.coreEditor.waitForLatestTokens(); - if (this.parser.isInBetweenRequestsRow(row)) { - return null; - } - - const range = await this.getRequestRange(row); - return this.getRequestInRange(range!); - }; - - moveToPreviousRequestEdge = async () => { - await this.coreEditor.waitForLatestTokens(); - const pos = this.coreEditor.getCurrentPosition(); - for ( - pos.lineNumber--; - pos.lineNumber > 1 && !this.parser.isRequestEdge(pos.lineNumber); - pos.lineNumber-- - ) { - // loop for side effects - } - this.coreEditor.moveCursorToPosition({ - lineNumber: pos.lineNumber, - column: 1, - }); - }; - - moveToNextRequestEdge = async (moveOnlyIfNotOnEdge: boolean) => { - await this.coreEditor.waitForLatestTokens(); - const pos = this.coreEditor.getCurrentPosition(); - const maxRow = this.coreEditor.getLineCount(); - if (!moveOnlyIfNotOnEdge) { - pos.lineNumber++; - } - for ( - ; - pos.lineNumber < maxRow && !this.parser.isRequestEdge(pos.lineNumber); - pos.lineNumber++ - ) { - // loop for side effects - } - this.coreEditor.moveCursorToPosition({ - lineNumber: pos.lineNumber, - column: 1, - }); - }; - - nextRequestEnd = (pos: Position): Position => { - pos = pos || this.coreEditor.getCurrentPosition(); - const maxLines = this.coreEditor.getLineCount(); - let curLineNumber = pos.lineNumber; - for (; curLineNumber <= maxLines; ++curLineNumber) { - const curRowMode = this.parser.getRowParseMode(curLineNumber); - // eslint-disable-next-line no-bitwise - if ((curRowMode & this.parser.MODE.REQUEST_END) > 0) { - break; - } - // eslint-disable-next-line no-bitwise - if (curLineNumber !== pos.lineNumber && (curRowMode & this.parser.MODE.REQUEST_START) > 0) { - break; - } - } - - const column = - (this.coreEditor.getLineValue(curLineNumber) || '').replace(/\s+$/, '').length + 1; - - return { - lineNumber: curLineNumber, - column, - }; - }; - - nextDataDocEnd = (pos: Position): Position => { - pos = pos || this.coreEditor.getCurrentPosition(); - let curLineNumber = pos.lineNumber; - const maxLines = this.coreEditor.getLineCount(); - for (; curLineNumber < maxLines; curLineNumber++) { - const curRowMode = this.parser.getRowParseMode(curLineNumber); - // eslint-disable-next-line no-bitwise - if ((curRowMode & this.parser.MODE.REQUEST_END) > 0) { - break; - } - // eslint-disable-next-line no-bitwise - if ((curRowMode & this.parser.MODE.MULTI_DOC_CUR_DOC_END) > 0) { - break; - } - // eslint-disable-next-line no-bitwise - if (curLineNumber !== pos.lineNumber && (curRowMode & this.parser.MODE.REQUEST_START) > 0) { - break; - } - } - - const column = - (this.coreEditor.getLineValue(curLineNumber) || '').length + - 1; /* Range goes to 1 after last char */ - - return { - lineNumber: curLineNumber, - column, - }; - }; - - highlightCurrentRequestsAndUpdateActionBar = _.debounce(async () => { - await this.coreEditor.waitForLatestTokens(); - const expandedRange = await this.expandRangeToRequestEdges(); - if (expandedRange === null && this.currentReqRange === null) { - return; - } - if ( - expandedRange !== null && - this.currentReqRange !== null && - expandedRange.start.lineNumber === this.currentReqRange.start.lineNumber && - expandedRange.end.lineNumber === this.currentReqRange.end.lineNumber - ) { - // same request, now see if we are on the first line and update the action bar - const cursorLineNumber = this.coreEditor.getCurrentPosition().lineNumber; - if (cursorLineNumber === this.currentReqRange.start.lineNumber) { - this.updateActionsBar(); - } - return; // nothing to do.. - } - - if (this.currentReqRange) { - this.coreEditor.removeMarker(this.currentReqRange.markerRef); - } - - this.currentReqRange = expandedRange as any; - if (this.currentReqRange) { - this.currentReqRange.markerRef = this.coreEditor.addMarker(this.currentReqRange); - } - this.updateActionsBar(); - }, 25); - - getRequestsAsCURL = async (elasticsearchBaseUrl: string, range?: Range): Promise => { - const variables = getStorage().get(StorageKeys.VARIABLES, DEFAULT_VARIABLES); - let requests = await this.getRequestsInRange(range, true); - requests = utils.replaceVariables(requests, variables); - const result = _.map(requests, (req) => { - if (typeof req === 'string') { - // no request block - return req; - } - - const path = req.url; - const method = req.method; - const data = req.data; - - // this is the first url defined in elasticsearch.hosts - const url = constructUrl(elasticsearchBaseUrl, path); - - // Append 'kbn-xsrf' header to bypass (XSRF/CSRF) protections - let ret = `curl -X${method.toUpperCase()} "${url}" -H "kbn-xsrf: reporting"`; - - if (data && data.length) { - const joinedData = data.join('\n'); - let dataAsString: string; - - try { - ret += ` -H "Content-Type: application/json" -d'\n`; - - if (utils.hasComments(joinedData)) { - // if there are comments in the data, we need to strip them out - const dataWithoutComments = parse(joinedData); - dataAsString = collapseLiteralStrings(JSON.stringify(dataWithoutComments, null, 2)); - } else { - dataAsString = collapseLiteralStrings(joinedData); - } - // We escape single quoted strings that are wrapped in single quoted strings - ret += dataAsString.replace(/'/g, "'\\''"); - if (data.length > 1) { - ret += '\n'; - } // end with a new line - ret += "'"; - } catch (e) { - throw new Error(`Error parsing data: ${e.message}`); - } - } - return ret; - }); - - return result.join('\n'); - }; - - updateActionsBar = () => { - return this.coreEditor.legacyUpdateUI(this.currentReqRange); - }; - - getCoreEditor() { - return this.coreEditor; - } -} diff --git a/src/plugins/console/public/application/stores/editor.ts b/src/plugins/console/public/application/stores/editor.ts index 556f4f64337e6..8ae24e5a422b7 100644 --- a/src/plugins/console/public/application/stores/editor.ts +++ b/src/plugins/console/public/application/stores/editor.ts @@ -12,7 +12,6 @@ import { produce } from 'immer'; import { identity } from 'fp-ts/lib/function'; import { DevToolsSettings, DEFAULT_SETTINGS } from '../../services'; import { TextObject } from '../../../common/text_object'; -import { SenseEditor } from '../models'; import { SHELL_TAB_ID } from '../containers/main/constants'; import { MonacoEditorActionsProvider } from '../containers/editor/monaco_editor_actions_provider'; import { RequestToRestore } from '../../types'; @@ -39,7 +38,7 @@ export const initialValue: Store = produce( ); export type Action = - | { type: 'setInputEditor'; payload: SenseEditor | MonacoEditorActionsProvider } + | { type: 'setInputEditor'; payload: MonacoEditorActionsProvider } | { type: 'setCurrentTextObject'; payload: TextObject } | { type: 'updateSettings'; payload: DevToolsSettings } | { type: 'setCurrentView'; payload: string } diff --git a/src/plugins/console/public/lib/ace_token_provider/index.ts b/src/plugins/console/public/lib/ace_token_provider/index.ts deleted file mode 100644 index 8819ac19a1262..0000000000000 --- a/src/plugins/console/public/lib/ace_token_provider/index.ts +++ /dev/null @@ -1,10 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './token_provider'; diff --git a/src/plugins/console/public/lib/ace_token_provider/token_provider.test.ts b/src/plugins/console/public/lib/ace_token_provider/token_provider.test.ts deleted file mode 100644 index b36d9855414bd..0000000000000 --- a/src/plugins/console/public/lib/ace_token_provider/token_provider.test.ts +++ /dev/null @@ -1,223 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import '../../application/models/sense_editor/sense_editor.test.mocks'; - -import $ from 'jquery'; - -// TODO: -// We import from application models as a convenient way to bootstrap loading up of an editor using -// this lib. We also need to import application specific mocks which is not ideal. -// In this situation, the token provider lib knows about app models in tests, which it really shouldn't. Should create -// a better sandbox in future. -import { create, SenseEditor } from '../../application/models/sense_editor'; - -import { Position, Token, TokensProvider } from '../../types'; - -interface RunTestArgs { - input: string; - done?: () => void; -} - -describe('Ace (legacy) token provider', () => { - let senseEditor: SenseEditor; - let tokenProvider: TokensProvider; - beforeEach(() => { - // Set up our document body - document.body.innerHTML = `
    -
    -
    -
    -
    `; - - senseEditor = create(document.querySelector('#ConAppEditor')!); - - $(senseEditor.getCoreEditor().getContainer())!.show(); - - (senseEditor as any).autocomplete._test.removeChangeListener(); - tokenProvider = senseEditor.getCoreEditor().getTokenProvider(); - }); - - afterEach(async () => { - $(senseEditor.getCoreEditor().getContainer())!.hide(); - (senseEditor as any).autocomplete._test.addChangeListener(); - await senseEditor.update('', true); - }); - - describe('#getTokens', () => { - const runTest = ({ - input, - expectedTokens, - done, - lineNumber = 1, - }: RunTestArgs & { expectedTokens: Token[] | null; lineNumber?: number }) => { - senseEditor.update(input, true).then(() => { - const tokens = tokenProvider.getTokens(lineNumber); - expect(tokens).toEqual(expectedTokens); - if (done) done(); - }); - }; - - describe('base cases', () => { - test('case 1 - only url', (done) => { - runTest({ - input: `GET http://somehost/_search`, - expectedTokens: [ - { type: 'method', value: 'GET', position: { lineNumber: 1, column: 1 } }, - { type: 'whitespace', value: ' ', position: { lineNumber: 1, column: 4 } }, - { - type: 'url.protocol_host', - value: 'http://somehost', - position: { lineNumber: 1, column: 5 }, - }, - { type: 'url.slash', value: '/', position: { lineNumber: 1, column: 20 } }, - { type: 'url.part', value: '_search', position: { lineNumber: 1, column: 21 } }, - ], - done, - }); - }); - - test('case 2 - basic auth in host name', (done) => { - runTest({ - input: `GET http://test:user@somehost/`, - expectedTokens: [ - { type: 'method', value: 'GET', position: { lineNumber: 1, column: 1 } }, - { type: 'whitespace', value: ' ', position: { lineNumber: 1, column: 4 } }, - { - type: 'url.protocol_host', - value: 'http://test:user@somehost', - position: { lineNumber: 1, column: 5 }, - }, - { type: 'url.slash', value: '/', position: { lineNumber: 1, column: 30 } }, - ], - done, - }); - }); - - test('case 3 - handles empty lines', (done) => { - runTest({ - input: `POST abc - - -{ -`, - expectedTokens: [ - { type: 'method', value: 'POST', position: { lineNumber: 1, column: 1 } }, - { type: 'whitespace', value: ' ', position: { lineNumber: 1, column: 5 } }, - { type: 'url.part', value: 'abc', position: { lineNumber: 1, column: 6 } }, - ], - done, - lineNumber: 1, - }); - }); - }); - - describe('with newlines', () => { - test('case 1 - newlines base case', (done) => { - runTest({ - input: `GET http://test:user@somehost/ -{ - "wudup": "!" -}`, - expectedTokens: [ - { type: 'whitespace', value: ' ', position: { lineNumber: 3, column: 1 } }, - { type: 'variable', value: '"wudup"', position: { lineNumber: 3, column: 3 } }, - { type: 'punctuation.colon', value: ':', position: { lineNumber: 3, column: 10 } }, - { type: 'whitespace', value: ' ', position: { lineNumber: 3, column: 11 } }, - { type: 'string', value: '"!"', position: { lineNumber: 3, column: 12 } }, - ], - done, - lineNumber: 3, - }); - }); - }); - - describe('edge cases', () => { - test('case 1 - getting token outside of document', (done) => { - runTest({ - input: `GET http://test:user@somehost/ -{ - "wudup": "!" -}`, - expectedTokens: null, - done, - lineNumber: 100, - }); - }); - - test('case 2 - empty lines', (done) => { - runTest({ - input: `GET http://test:user@somehost/ - - - - -{ - "wudup": "!" -}`, - expectedTokens: [], - done, - lineNumber: 5, - }); - }); - }); - }); - - describe('#getTokenAt', () => { - const runTest = ({ - input, - expectedToken, - done, - position, - }: RunTestArgs & { expectedToken: Token | null; position: Position }) => { - senseEditor.update(input, true).then(() => { - const tokens = tokenProvider.getTokenAt(position); - expect(tokens).toEqual(expectedToken); - if (done) done(); - }); - }; - - describe('base cases', () => { - it('case 1 - gets a token from the url', (done) => { - const input = `GET http://test:user@somehost/`; - runTest({ - input, - expectedToken: { - position: { lineNumber: 1, column: 4 }, - type: 'whitespace', - value: ' ', - }, - position: { lineNumber: 1, column: 5 }, - }); - - runTest({ - input, - expectedToken: { - position: { lineNumber: 1, column: 5 }, - type: 'url.protocol_host', - value: 'http://test:user@somehost', - }, - position: { lineNumber: 1, column: input.length }, - done, - }); - }); - }); - - describe('special cases', () => { - it('case 1 - handles input outside of range', (done) => { - runTest({ - input: `GET abc`, - expectedToken: null, - done, - position: { lineNumber: 1, column: 99 }, - }); - }); - }); - }); -}); diff --git a/src/plugins/console/public/lib/ace_token_provider/token_provider.ts b/src/plugins/console/public/lib/ace_token_provider/token_provider.ts deleted file mode 100644 index 9e61771946771..0000000000000 --- a/src/plugins/console/public/lib/ace_token_provider/token_provider.ts +++ /dev/null @@ -1,84 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { IEditSession, TokenInfo as BraceTokenInfo } from 'brace'; -import { TokensProvider, Token, Position } from '../../types'; - -// Brace's token information types are not accurate. -interface TokenInfo extends BraceTokenInfo { - type: string; -} - -const toToken = (lineNumber: number, column: number, token: TokenInfo): Token => ({ - type: token.type, - value: token.value, - position: { - lineNumber, - column, - }, -}); - -const toTokens = (lineNumber: number, tokens: TokenInfo[]): Token[] => { - let acc = ''; - return tokens.map((token) => { - const column = acc.length + 1; - acc += token.value; - return toToken(lineNumber, column, token); - }); -}; - -const extractTokenFromAceTokenRow = ( - lineNumber: number, - column: number, - aceTokens: TokenInfo[] -) => { - let acc = ''; - for (const token of aceTokens) { - const start = acc.length + 1; - acc += token.value; - const end = acc.length; - if (column < start) continue; - if (column > end + 1) continue; - return toToken(lineNumber, start, token); - } - return null; -}; - -export class AceTokensProvider implements TokensProvider { - constructor(private readonly session: IEditSession) {} - - getTokens(lineNumber: number): Token[] | null { - if (lineNumber < 1) return null; - - // Important: must use a .session.getLength because this is a cached value. - // Calculating line length here will lead to performance issues because this function - // may be called inside of tight loops. - const lineCount = this.session.getLength(); - if (lineNumber > lineCount) { - return null; - } - - const tokens = this.session.getTokens(lineNumber - 1) as unknown as TokenInfo[]; - if (!tokens || !tokens.length) { - // We are inside of the document but have no tokens for this line. Return an empty - // array to represent this empty line. - return []; - } - - return toTokens(lineNumber, tokens); - } - - getTokenAt(pos: Position): Token | null { - const tokens = this.session.getTokens(pos.lineNumber - 1) as unknown as TokenInfo[]; - if (tokens) { - return extractTokenFromAceTokenRow(pos.lineNumber, pos.column, tokens); - } - return null; - } -} diff --git a/src/plugins/console/public/lib/autocomplete/autocomplete.ts b/src/plugins/console/public/lib/autocomplete/autocomplete.ts deleted file mode 100644 index 73ef1981cfc0b..0000000000000 --- a/src/plugins/console/public/lib/autocomplete/autocomplete.ts +++ /dev/null @@ -1,1316 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import _ from 'lodash'; -import { i18n } from '@kbn/i18n'; - -// TODO: All of these imports need to be moved to the core editor so that it can inject components from there. -import { - getEndpointBodyCompleteComponents, - getGlobalAutocompleteComponents, - getTopLevelUrlCompleteComponents, - getUnmatchedEndpointComponents, -} from '../kb/kb'; - -import { createTokenIterator } from '../../application/factories'; -import type { CoreEditor, Position, Range, Token } from '../../types'; -import type RowParser from '../row_parser'; - -import * as utils from '../utils'; - -import { populateContext } from './engine'; -import type { AutoCompleteContext, DataAutoCompleteRulesOneOf, ResultTerm } from './types'; -import { URL_PATH_END_MARKER, ConstantComponent } from './components'; -import { looksLikeTypingIn } from './looks_like_typing_in'; - -let lastEvaluatedToken: Token | null = null; - -function isUrlParamsToken(token: { type: string } | null) { - switch ((token || {}).type) { - case 'url.param': - case 'url.equal': - case 'url.value': - case 'url.questionmark': - case 'url.amp': - return true; - default: - return false; - } -} - -/* Logs the provided arguments to the console if the `window.autocomplete_trace` flag is set to true. - * This function checks if the `autocomplete_trace` flag is enabled on the `window` object. This is - * only used when executing functional tests. - * If the flag is enabled, it logs each argument to the console. - * If an argument is an object, it is stringified before logging. - */ -const tracer = (...args: any[]) => { - // @ts-ignore - if (window.autocomplete_trace) { - // eslint-disable-next-line no-console - console.log.call( - console, - ..._.map(args, (arg) => { - return typeof arg === 'object' ? JSON.stringify(arg) : arg; - }) - ); - } -}; - -/** - * Get the method and token paths for a specific position in the current editor buffer. - * - * This function can be used for getting autocomplete information or for getting more information - * about the endpoint associated with autocomplete. In future, these concerns should be better - * separated. - * - */ -export function getCurrentMethodAndTokenPaths( - editor: CoreEditor, - pos: Position, - parser: RowParser, - forceEndOfUrl?: boolean /* Flag for indicating whether we want to avoid early escape optimization. */ -) { - const tokenIter = createTokenIterator({ - editor, - position: pos, - }); - const startPos = pos; - let bodyTokenPath: string[] | null = []; - const ret: AutoCompleteContext = {}; - - const STATES = { - looking_for_key: 0, // looking for a key but without jumping over anything but white space and colon. - looking_for_scope_start: 1, // skip everything until scope start - start: 3, - }; - let state = STATES.start; - - // initialization problems - - let t = tokenIter.getCurrentToken(); - if (t) { - if (startPos.column === 1) { - // if we are at the beginning of the line, the current token is the one after cursor, not before which - // deviates from the standard. - t = tokenIter.stepBackward(); - state = STATES.looking_for_scope_start; - } - } else { - if (startPos.column === 1) { - // empty lines do no have tokens, move one back - t = tokenIter.stepBackward(); - state = STATES.start; - } - } - - let walkedSomeBody = false; - - // climb one scope at a time and get the scope key - for (; t && t.type.indexOf('url') === -1 && t.type !== 'method'; t = tokenIter.stepBackward()) { - if (t.type !== 'whitespace') { - walkedSomeBody = true; - } // marks we saw something - - switch (t.type) { - case 'variable': - if (state === STATES.looking_for_key) { - bodyTokenPath.unshift(t.value.trim().replace(/"/g, '')); - } - state = STATES.looking_for_scope_start; // skip everything until the beginning of this scope - break; - - case 'paren.lparen': - bodyTokenPath.unshift(t.value); - if (state === STATES.looking_for_scope_start) { - // found it. go look for the relevant key - state = STATES.looking_for_key; - } - break; - case 'paren.rparen': - // reset he search for key - state = STATES.looking_for_scope_start; - // and ignore this sub scope.. - let parenCount = 1; - t = tokenIter.stepBackward(); - while (t && parenCount > 0) { - switch (t.type) { - case 'paren.lparen': - parenCount--; - break; - case 'paren.rparen': - parenCount++; - break; - } - if (parenCount > 0) { - t = tokenIter.stepBackward(); - } - } - if (!t) { - tracer(`paren.rparen: oops we run out.. we don't know what's up return null`); - return {}; - } - continue; - case 'punctuation.end_triple_quote': - // reset the search for key - state = STATES.looking_for_scope_start; - for (t = tokenIter.stepBackward(); t; t = tokenIter.stepBackward()) { - if (t.type === 'punctuation.start_triple_quote') { - t = tokenIter.stepBackward(); - break; - } - } - if (!t) { - tracer(`paren.rparen: oops we run out.. we don't know what's up return null`); - return {}; - } - continue; - case 'punctuation.start_triple_quote': - if (state === STATES.start) { - state = STATES.looking_for_key; - } else if (state === STATES.looking_for_key) { - state = STATES.looking_for_scope_start; - } - bodyTokenPath.unshift('"""'); - continue; - case 'string': - case 'constant.numeric': - case 'constant.language.boolean': - case 'text': - if (state === STATES.start) { - state = STATES.looking_for_key; - } else if (state === STATES.looking_for_key) { - state = STATES.looking_for_scope_start; - } - - break; - case 'punctuation.comma': - if (state === STATES.start) { - state = STATES.looking_for_scope_start; - } - break; - case 'punctuation.colon': - case 'whitespace': - if (state === STATES.start) { - state = STATES.looking_for_key; - } - break; // skip white space - } - } - - if (walkedSomeBody && (!bodyTokenPath || bodyTokenPath.length === 0) && !forceEndOfUrl) { - tracer( - 'we had some content and still no path', - '-> the cursor is position after a closed body', - '-> no auto complete' - ); - return {}; - } - - ret.urlTokenPath = []; - if (tokenIter.getCurrentPosition().lineNumber === startPos.lineNumber) { - if (t && (t.type === 'url.part' || t.type === 'url.param' || t.type === 'url.value')) { - // we are forcing the end of the url for the purposes of determining an endpoint - if (forceEndOfUrl && t.type === 'url.part') { - ret.urlTokenPath.push(t.value); - ret.urlTokenPath.push(URL_PATH_END_MARKER); - } - // we are on the same line as cursor and dealing with a url. Current token is not part of the context - t = tokenIter.stepBackward(); - // This will force method parsing - while (t!.type === 'whitespace') { - t = tokenIter.stepBackward(); - } - } - bodyTokenPath = null; // no not on a body line. - } - - ret.bodyTokenPath = bodyTokenPath; - - ret.urlParamsTokenPath = null; - ret.requestStartRow = tokenIter.getCurrentPosition().lineNumber; - let curUrlPart: - | null - | string - | Array> - | undefined - | Record; - - while (t && isUrlParamsToken(t)) { - switch (t.type) { - case 'url.value': - if (Array.isArray(curUrlPart)) { - curUrlPart.unshift(t.value); - } else if (curUrlPart) { - curUrlPart = [t.value, curUrlPart]; - } else { - curUrlPart = t.value; - } - break; - case 'url.comma': - if (!curUrlPart) { - curUrlPart = []; - } else if (!Array.isArray(curUrlPart)) { - curUrlPart = [curUrlPart]; - } - break; - case 'url.param': - const v = curUrlPart; - curUrlPart = {}; - curUrlPart[t.value] = v; - break; - case 'url.amp': - case 'url.questionmark': - if (!ret.urlParamsTokenPath) { - ret.urlParamsTokenPath = []; - } - ret.urlParamsTokenPath.unshift((curUrlPart as Record) || {}); - curUrlPart = null; - break; - } - t = tokenIter.stepBackward(); - } - - curUrlPart = null; - while (t && t.type.indexOf('url') !== -1) { - switch (t.type) { - case 'url.part': - if (Array.isArray(curUrlPart)) { - curUrlPart.unshift(t.value); - } else if (curUrlPart) { - curUrlPart = [t.value, curUrlPart]; - } else { - curUrlPart = t.value; - } - break; - case 'url.comma': - if (!curUrlPart) { - curUrlPart = []; - } else if (!Array.isArray(curUrlPart)) { - curUrlPart = [curUrlPart]; - } - break; - case 'url.slash': - if (curUrlPart) { - ret.urlTokenPath.unshift(curUrlPart as string); - curUrlPart = null; - } - break; - } - t = parser.prevNonEmptyToken(tokenIter); - } - - if (curUrlPart) { - ret.urlTokenPath.unshift(curUrlPart as string); - } - - if (!ret.bodyTokenPath && !ret.urlParamsTokenPath) { - if (ret.urlTokenPath.length > 0) { - // // started on the url, first token is current token - ret.otherTokenValues = ret.urlTokenPath[0]; - } - } else { - // mark the url as completed. - ret.urlTokenPath.push(URL_PATH_END_MARKER); - } - - if (t && t.type === 'method') { - ret.method = t.value; - } - return ret; -} - -// eslint-disable-next-line import/no-default-export -export default function ({ - coreEditor: editor, - parser, -}: { - coreEditor: CoreEditor; - parser: RowParser; -}) { - function isUrlPathToken(token: Token | null) { - switch ((token || ({} as Token)).type) { - case 'url.slash': - case 'url.comma': - case 'url.part': - return true; - default: - return false; - } - } - - function addMetaToTermsList(list: ResultTerm[], meta: string, template?: string): ResultTerm[] { - return _.map(list, function (t) { - if (typeof t !== 'object') { - t = { name: t }; - } - return _.defaults(t, { meta, template }); - }); - } - - function replaceLinesWithPrefixPieces(prefixPieces: string[], startLineNumber: number) { - const middlePiecesCount = prefixPieces.length - 1; - prefixPieces.forEach((piece, index) => { - if (index >= middlePiecesCount) { - return; - } - const line = startLineNumber + index + 1; - const column = editor.getLineValue(line).length - 1; - const start = { lineNumber: line, column: 0 }; - const end = { lineNumber: line, column }; - editor.replace({ start, end }, piece); - }); - } - - /** - * Get a different set of templates based on the value configured in the request. - * For example, when creating a snapshot repository of different types (`fs`, `url` etc), - * different properties are inserted in the textarea based on the type. - * E.g. https://github.com/elastic/kibana/blob/main/src/plugins/console/server/lib/spec_definitions/json/overrides/snapshot.create_repository.json - */ - function getConditionalTemplate( - name: string, - autocompleteRules: Record | null | undefined - ) { - const obj = autocompleteRules && autocompleteRules[name]; - - if (obj) { - const currentLineNumber = editor.getCurrentPosition().lineNumber; - - if (hasOneOfIn(obj)) { - // Get the line number of value that should provide different templates based on that - const startLine = getStartLineNumber(currentLineNumber, obj.__one_of); - // Join line values from start to current line - const lines = editor.getLines(startLine, currentLineNumber).join('\n'); - // Get the correct template by comparing the autocomplete rules against the lines - const prop = getProperty(lines, obj.__one_of); - if (prop && prop.__template) { - return prop.__template; - } - } - } - } - - /** - * Check if object has a property of '__one_of' - */ - function hasOneOfIn(value: unknown): value is { __one_of: DataAutoCompleteRulesOneOf[] } { - return typeof value === 'object' && value !== null && '__one_of' in value; - } - - /** - * Get the start line of value that matches the autocomplete rules condition - */ - function getStartLineNumber(currentLine: number, rules: DataAutoCompleteRulesOneOf[]): number { - if (currentLine === 1) { - return currentLine; - } - const value = editor.getLineValue(currentLine); - const prop = getProperty(value, rules); - if (prop) { - return currentLine; - } - return getStartLineNumber(currentLine - 1, rules); - } - - /** - * Get the matching property based on the given condition - */ - function getProperty(condition: string, rules: DataAutoCompleteRulesOneOf[]) { - return rules.find((rule) => { - if (rule.__condition && rule.__condition.lines_regex) { - return new RegExp(rule.__condition.lines_regex, 'm').test(condition); - } - return false; - }); - } - - function applyTerm(term: ResultTerm) { - const context = term.context!; - - if (context?.endpoint && term.value) { - const { data_autocomplete_rules: autocompleteRules } = context.endpoint; - const template = getConditionalTemplate(term.value, autocompleteRules); - if (template) { - term.template = template; - } - } - // make sure we get up to date replacement info. - addReplacementInfoToContext(context, editor.getCurrentPosition(), term.insertValue); - - let termAsString; - if (context.autoCompleteType === 'body') { - termAsString = - typeof term.insertValue === 'string' ? '"' + term.insertValue + '"' : term.insertValue + ''; - if (term.insertValue === '[' || term.insertValue === '{') { - termAsString = ''; - } - } else { - termAsString = term.insertValue + ''; - } - - let valueToInsert = termAsString; - let templateInserted = false; - if (context.addTemplate && !_.isUndefined(term.template) && !_.isNull(term.template)) { - let indentedTemplateLines; - // In order to allow triple quoted strings in template completion we check the `__raw_` - // attribute to determine whether this template should go through JSON formatting. - if (term.template.__raw && term.template.value) { - indentedTemplateLines = term.template.value.split('\n'); - } else { - indentedTemplateLines = utils.jsonToString(term.template, true).split('\n'); - } - let currentIndentation = editor.getLineValue(context.rangeToReplace!.start.lineNumber); - currentIndentation = currentIndentation.match(/^\s*/)![0]; - for ( - let i = 1; - i < indentedTemplateLines.length; - i++ // skip first line - ) { - indentedTemplateLines[i] = currentIndentation + indentedTemplateLines[i]; - } - - valueToInsert += ': ' + indentedTemplateLines.join('\n'); - templateInserted = true; - } else { - templateInserted = true; - if (term.value === '[') { - valueToInsert += '[]'; - } else if (term.value === '{') { - valueToInsert += '{}'; - } else { - templateInserted = false; - } - } - const linesToMoveDown = (context.prefixToAdd ?? '').match(/\n|\r/g)?.length ?? 0; - - let prefix = context.prefixToAdd ?? ''; - - // disable listening to the changes we are making. - editor.off('changeSelection', editorChangeListener); - - // if should add chars on the previous not empty line - if (linesToMoveDown) { - const [firstPart = '', ...prefixPieces] = context.prefixToAdd?.split(/\n|\r/g) ?? []; - const lastPart = _.last(prefixPieces) ?? ''; - const { start } = context.rangeToReplace!; - const end = { ...start, column: start.column + firstPart.length }; - - // adding only the content of prefix before newlines - editor.replace({ start, end }, firstPart); - - // replacing prefix pieces without the last one, which is handled separately - if (prefixPieces.length - 1 > 0) { - replaceLinesWithPrefixPieces(prefixPieces, start.lineNumber); - } - - // and the last prefix line, keeping the editor's own newlines. - prefix = lastPart; - context.rangeToReplace!.start.lineNumber = context.rangeToReplace!.end.lineNumber; - context.rangeToReplace!.start.column = 0; - } - - valueToInsert = prefix + valueToInsert + context.suffixToAdd; - - if (context.rangeToReplace!.start.column !== context.rangeToReplace!.end.column) { - editor.replace(context.rangeToReplace!, valueToInsert); - } else { - editor.insert(valueToInsert); - } - - editor.clearSelection(); // for some reason the above changes selection - - // go back to see whether we have one of ( : { & [ do not require a comma. All the rest do. - let newPos = { - lineNumber: context.rangeToReplace!.start.lineNumber, - column: - context.rangeToReplace!.start.column + - termAsString.length + - prefix.length + - (templateInserted ? 0 : context.suffixToAdd!.length), - }; - - const tokenIter = createTokenIterator({ - editor, - position: newPos, - }); - - if (context.autoCompleteType === 'body') { - // look for the next place stand, just after a comma, { - let nonEmptyToken = parser.nextNonEmptyToken(tokenIter); - switch (nonEmptyToken ? nonEmptyToken.type : 'NOTOKEN') { - case 'paren.rparen': - newPos = tokenIter.getCurrentPosition(); - break; - case 'punctuation.colon': - nonEmptyToken = parser.nextNonEmptyToken(tokenIter); - if ((nonEmptyToken || ({} as Token)).type === 'paren.lparen') { - nonEmptyToken = parser.nextNonEmptyToken(tokenIter); - newPos = tokenIter.getCurrentPosition(); - if (nonEmptyToken && nonEmptyToken.value.indexOf('"') === 0) { - newPos.column++; - } // don't stand on " - } - break; - case 'paren.lparen': - case 'punctuation.comma': - tokenIter.stepForward(); - newPos = tokenIter.getCurrentPosition(); - break; - } - editor.moveCursorToPosition(newPos); - } - - // re-enable listening to typing - editor.on('changeSelection', editorChangeListener); - } - - function getAutoCompleteContext(ctxEditor: CoreEditor, pos: Position) { - // deduces all the parameters need to position and insert the auto complete - const context: AutoCompleteContext = { - autoCompleteSet: null, // instructions for what can be here - endpoint: null, - urlPath: null, - method: null, - activeScheme: null, - editor: ctxEditor, - }; - - // context.updatedForToken = session.getTokenAt(pos.row, pos.column); - // - // if (!context.updatedForToken) - // context.updatedForToken = { value: "", start: pos.column }; // empty line - // - // context.updatedForToken.row = pos.row; // extend - - context.autoCompleteType = getAutoCompleteType(pos); - switch (context.autoCompleteType) { - case 'path': - addPathAutoCompleteSetToContext(context, pos); - break; - case 'url_params': - addUrlParamsAutoCompleteSetToContext(context, pos); - break; - case 'method': - addMethodAutoCompleteSetToContext(context); - break; - case 'body': - addBodyAutoCompleteSetToContext(context, pos); - break; - default: - return null; - } - - const isMappingsFetchingInProgress = - context.autoCompleteType === 'body' && !!context.asyncResultsState?.isLoading; - - if (!context.autoCompleteSet && !isMappingsFetchingInProgress) { - tracer('nothing to do..', context); - return null; - } - - addReplacementInfoToContext(context, pos); - - context.createdWithToken = _.clone(context.updatedForToken); - - return context; - } - - function getAutoCompleteType(pos: Position) { - // return "method", "path" or "body" to determine auto complete type. - - let rowMode = parser.getRowParseMode(); - - // eslint-disable-next-line no-bitwise - if (rowMode & parser.MODE.IN_REQUEST) { - return 'body'; - } - // eslint-disable-next-line no-bitwise - if (rowMode & parser.MODE.REQUEST_START) { - // on url path, url params or method. - const tokenIter = createTokenIterator({ - editor, - position: pos, - }); - let t = tokenIter.getCurrentToken(); - - while (t!.type === 'url.comma') { - t = tokenIter.stepBackward(); - } - switch (t!.type) { - case 'method': - return 'method'; - case 'whitespace': - t = parser.prevNonEmptyToken(tokenIter); - - switch ((t || ({} as Token)).type) { - case 'method': - // we moved one back - return 'path'; - break; - default: - if (isUrlPathToken(t)) { - return 'path'; - } - if (isUrlParamsToken(t)) { - return 'url_params'; - } - return null; - } - break; - default: - if (isUrlPathToken(t)) { - return 'path'; - } - if (isUrlParamsToken(t)) { - return 'url_params'; - } - return null; - } - } - - // after start to avoid single line url only requests - // eslint-disable-next-line no-bitwise - if (rowMode & parser.MODE.REQUEST_END) { - return 'body'; - } - - // in between request on an empty - if (editor.getLineValue(pos.lineNumber).trim() === '') { - // check if the previous line is a single line beginning of a new request - rowMode = parser.getRowParseMode(pos.lineNumber - 1); - if ( - // eslint-disable-next-line no-bitwise - rowMode & parser.MODE.REQUEST_START && - // eslint-disable-next-line no-bitwise - rowMode & parser.MODE.REQUEST_END - ) { - return 'body'; - } - // o.w suggest a method - return 'method'; - } - - return null; - } - - function addReplacementInfoToContext( - context: AutoCompleteContext, - pos: Position, - replacingTerm?: unknown - ) { - // extract the initial value, rangeToReplace & textBoxPosition - - // Scenarios for current token: - // - Nice token { "bla|" - // - Broken text token { bla| - // - No token : { | - // - Broken scenario { , bla| - // - Nice token, broken before: {, "bla" - - context.updatedForToken = _.clone( - editor.getTokenAt({ lineNumber: pos.lineNumber, column: pos.column }) - ); - if (!context.updatedForToken) { - context.updatedForToken = { - value: '', - type: '', - position: { column: pos.column, lineNumber: pos.lineNumber }, - }; - } // empty line - - let anchorToken = context.createdWithToken; - if (!anchorToken) { - anchorToken = context.updatedForToken; - } - - switch (context.updatedForToken.type) { - case 'variable': - case 'string': - case 'text': - case 'constant.numeric': - case 'constant.language.boolean': - case 'method': - case 'url.index': - case 'url.type': - case 'url.id': - case 'url.method': - case 'url.endpoint': - case 'url.part': - case 'url.param': - case 'url.value': - context.rangeToReplace = { - start: { lineNumber: pos.lineNumber, column: anchorToken.position.column }, - end: { - lineNumber: pos.lineNumber, - column: context.updatedForToken.position.column + context.updatedForToken.value.length, - }, - } as Range; - context.replacingToken = true; - break; - default: - if (replacingTerm && context.updatedForToken.value === replacingTerm) { - context.rangeToReplace = { - start: { lineNumber: pos.lineNumber, column: anchorToken.position.column }, - end: { - lineNumber: pos.lineNumber, - column: - context.updatedForToken.position.column + context.updatedForToken.value.length, - }, - } as Range; - context.replacingToken = true; - } else { - // standing on white space, quotes or another punctuation - no replacing - context.rangeToReplace = { - start: { lineNumber: pos.lineNumber, column: pos.column }, - end: { lineNumber: pos.lineNumber, column: pos.column }, - } as Range; - context.replacingToken = false; - } - break; - } - - context.textBoxPosition = { - lineNumber: context.rangeToReplace.start.lineNumber, - column: context.rangeToReplace.start.column, - }; - - switch (context.autoCompleteType) { - case 'path': - addPathPrefixSuffixToContext(context); - break; - case 'url_params': - addUrlParamsPrefixSuffixToContext(context); - break; - case 'method': - addMethodPrefixSuffixToContext(context); - break; - case 'body': - addBodyPrefixSuffixToContext(context); - break; - } - } - - function addCommaToPrefixOnAutocomplete( - nonEmptyToken: Token | null, - context: AutoCompleteContext, - charsToSkipOnSameLine: number = 1 - ) { - if (nonEmptyToken && nonEmptyToken.type.indexOf('url') < 0) { - const { position } = nonEmptyToken; - // if not on the first line - if (context.rangeToReplace && context.rangeToReplace.start?.lineNumber > 1) { - const prevTokenLineNumber = position.lineNumber; - const editorFromContext = context.editor as CoreEditor | undefined; - const line = editorFromContext?.getLineValue(prevTokenLineNumber) ?? ''; - const prevLineLength = line.length; - const linesToEnter = context.rangeToReplace.end.lineNumber - prevTokenLineNumber; - - const isTheSameLine = linesToEnter === 0; - let startColumn = prevLineLength + 1; - let spaces = context.rangeToReplace.start.column - 1; - - if (isTheSameLine) { - // prevent last char line from replacing - startColumn = position.column + charsToSkipOnSameLine; - // one char for pasted " and one for , - spaces = context.rangeToReplace.end.column - startColumn - 2; - } - - // go back to the end of the previous line - context.rangeToReplace = { - start: { lineNumber: prevTokenLineNumber, column: startColumn }, - end: { ...context.rangeToReplace.end }, - }; - - spaces = spaces >= 0 ? spaces : 0; - const spacesToEnter = isTheSameLine ? (spaces === 0 ? 1 : spaces) : spaces; - const newLineChars = `\n`.repeat(linesToEnter >= 0 ? linesToEnter : 0); - const whitespaceChars = ' '.repeat(spacesToEnter); - // add a comma at the end of the previous line, a new line and indentation - context.prefixToAdd = `,${newLineChars}${whitespaceChars}`; - } - } - } - - function addBodyPrefixSuffixToContext(context: AutoCompleteContext) { - // Figure out what happens next to the token to see whether it needs trailing commas etc. - - // Templates will be used if not destroying existing structure. - // -> token : {} or token ]/} or token , but not token : SOMETHING ELSE - - context.prefixToAdd = ''; - context.suffixToAdd = ''; - - let tokenIter = createTokenIterator({ - editor, - position: editor.getCurrentPosition()!, - }); - let nonEmptyToken = parser.nextNonEmptyToken(tokenIter); - switch (nonEmptyToken ? nonEmptyToken.type : 'NOTOKEN') { - case 'NOTOKEN': - case 'paren.lparen': - case 'paren.rparen': - case 'punctuation.comma': - context.addTemplate = true; - break; - case 'punctuation.colon': - // test if there is an empty object - if so we replace it - context.addTemplate = false; - - nonEmptyToken = parser.nextNonEmptyToken(tokenIter); - if (!(nonEmptyToken && nonEmptyToken.value === '{')) { - break; - } - nonEmptyToken = parser.nextNonEmptyToken(tokenIter); - if (!(nonEmptyToken && nonEmptyToken.value === '}')) { - break; - } - context.addTemplate = true; - // extend range to replace to include all up to token - context.rangeToReplace!.end.lineNumber = tokenIter.getCurrentTokenLineNumber() as number; - context.rangeToReplace!.end.column = - (tokenIter.getCurrentTokenColumn() as number) + nonEmptyToken.value.length; - - // move one more time to check if we need a trailing comma - nonEmptyToken = parser.nextNonEmptyToken(tokenIter); - switch (nonEmptyToken ? nonEmptyToken.type : 'NOTOKEN') { - case 'NOTOKEN': - case 'paren.rparen': - case 'punctuation.comma': - case 'punctuation.colon': - break; - default: - context.suffixToAdd = ', '; - } - - break; - default: - context.addTemplate = true; - context.suffixToAdd = ', '; - break; // for now play safe and do nothing. May be made smarter. - } - - // go back to see whether we have one of ( : { & [ do not require a comma. All the rest do. - tokenIter = createTokenIterator({ editor, position: editor.getCurrentPosition() }); - nonEmptyToken = tokenIter.getCurrentToken(); - let insertingRelativeToToken; // -1 is before token, 0 middle, +1 after token - if (context.replacingToken) { - insertingRelativeToToken = 0; - } else { - const pos = editor.getCurrentPosition(); - if (pos.column === context.updatedForToken!.position.column) { - insertingRelativeToToken = -1; - } else if ( - pos.column < - context.updatedForToken!.position.column + context.updatedForToken!.value.length - ) { - insertingRelativeToToken = 0; - } else { - insertingRelativeToToken = 1; - } - } - // we should actually look at what's happening before this token - if (parser.isEmptyToken(nonEmptyToken) || insertingRelativeToToken <= 0) { - nonEmptyToken = parser.prevNonEmptyToken(tokenIter); - } - - switch (nonEmptyToken ? nonEmptyToken.type : 'NOTOKEN') { - case 'NOTOKEN': - case 'paren.lparen': - case 'punctuation.comma': - case 'punctuation.colon': - case 'punctuation.start_triple_quote': - case 'method': - break; - case 'text': - case 'string': - case 'constant.numeric': - case 'constant.language.boolean': - case 'punctuation.end_triple_quote': - addCommaToPrefixOnAutocomplete(nonEmptyToken, context, nonEmptyToken?.value.length); - break; - default: - addCommaToPrefixOnAutocomplete(nonEmptyToken, context); - break; - } - - return context; - } - - function addUrlParamsPrefixSuffixToContext(context: AutoCompleteContext) { - context.prefixToAdd = ''; - context.suffixToAdd = ''; - } - - function addMethodPrefixSuffixToContext(context: AutoCompleteContext) { - context.prefixToAdd = ''; - context.suffixToAdd = ''; - const tokenIter = createTokenIterator({ editor, position: editor.getCurrentPosition() }); - const lineNumber = tokenIter.getCurrentPosition().lineNumber; - const t = parser.nextNonEmptyToken(tokenIter); - - if (tokenIter.getCurrentPosition().lineNumber !== lineNumber || !t) { - // we still have nothing next to the method, add a space.. - context.suffixToAdd = ' '; - } - } - - function addPathPrefixSuffixToContext(context: AutoCompleteContext) { - context.prefixToAdd = ''; - context.suffixToAdd = ''; - } - - function addMethodAutoCompleteSetToContext(context: AutoCompleteContext) { - context.autoCompleteSet = ['GET', 'PUT', 'POST', 'DELETE', 'HEAD', 'PATCH'].map((m, i) => ({ - name: m, - score: -i, - meta: i18n.translate('console.autocomplete.addMethodMetaText', { defaultMessage: 'method' }), - })); - } - - function addPathAutoCompleteSetToContext(context: AutoCompleteContext, pos: Position) { - const ret = getCurrentMethodAndTokenPaths(editor, pos, parser); - context.method = ret.method?.toUpperCase(); - context.token = ret.token; - context.otherTokenValues = ret.otherTokenValues; - context.urlTokenPath = ret.urlTokenPath; - - const components = getTopLevelUrlCompleteComponents(context.method); - let urlTokenPath = context.urlTokenPath; - let predicate: (term: ResultTerm) => boolean = () => true; - - const tokenIter = createTokenIterator({ editor, position: pos }); - const currentTokenType = tokenIter.getCurrentToken()?.type; - const previousTokenType = tokenIter.stepBackward()?.type; - if (!Array.isArray(urlTokenPath)) { - // skip checks for url.comma - } else if (previousTokenType === 'url.comma' && currentTokenType === 'url.comma') { - predicate = () => false; // two consecutive commas empty the autocomplete - } else if ( - (previousTokenType === 'url.part' && currentTokenType === 'url.comma') || - (previousTokenType === 'url.slash' && currentTokenType === 'url.comma') || - (previousTokenType === 'url.comma' && currentTokenType === 'url.part') - ) { - const lastUrlTokenPath = _.last(urlTokenPath) || []; // ['c', 'd'] from 'GET /a/b/c,d,' - const constantComponents = _.filter(components, (c) => c instanceof ConstantComponent); - const constantComponentNames = _.map(constantComponents, 'name'); - - // check if neither 'c' nor 'd' is a constant component name such as '_search' - if (_.every(lastUrlTokenPath, (token) => !_.includes(constantComponentNames, token))) { - urlTokenPath = urlTokenPath.slice(0, -1); // drop the last 'c,d,' part from the url path - predicate = (term) => term.meta === 'index'; // limit the autocomplete to indices only - } - } - - populateContext(urlTokenPath, context, editor, true, components); - context.autoCompleteSet = _.filter( - addMetaToTermsList(context.autoCompleteSet!, 'endpoint'), - predicate - ); - } - - function addUrlParamsAutoCompleteSetToContext(context: AutoCompleteContext, pos: Position) { - const ret = getCurrentMethodAndTokenPaths(editor, pos, parser); - context.method = ret.method; - context.otherTokenValues = ret.otherTokenValues; - context.urlTokenPath = ret.urlTokenPath; - if (!ret.urlTokenPath) { - // zero length tokenPath is true - - return context; - } - - populateContext( - ret.urlTokenPath, - context, - editor, - false, - getTopLevelUrlCompleteComponents(context.method) - ); - - if (!context.endpoint) { - return context; - } - - if (!ret.urlParamsTokenPath) { - // zero length tokenPath is true - return context; - } - let tokenPath: string[] = []; - const currentParam = ret.urlParamsTokenPath.pop(); - if (currentParam) { - tokenPath = Object.keys(currentParam); // single key object - context.otherTokenValues = currentParam[tokenPath[0]]; - } - - populateContext( - tokenPath, - context, - editor, - true, - context.endpoint.paramsAutocomplete.getTopLevelComponents(context.method) - ); - return context; - } - - function addBodyAutoCompleteSetToContext(context: AutoCompleteContext, pos: Position) { - const ret = getCurrentMethodAndTokenPaths(editor, pos, parser); - context.method = ret.method; - context.otherTokenValues = ret.otherTokenValues; - context.urlTokenPath = ret.urlTokenPath; - context.requestStartRow = ret.requestStartRow; - if (!ret.urlTokenPath) { - // zero length tokenPath is true - return context; - } - - populateContext( - ret.urlTokenPath, - context, - editor, - false, - getTopLevelUrlCompleteComponents(context.method) - ); - - context.bodyTokenPath = ret.bodyTokenPath; - if (!ret.bodyTokenPath) { - // zero length tokenPath is true - - return context; - } - - const t = editor.getTokenAt(pos); - if (t && t.type === 'punctuation.end_triple_quote' && pos.column !== t.position.column + 3) { - // skip to populate context as the current position is not on the edge of end_triple_quote - return context; - } - - // needed for scope linking + global term resolving - context.endpointComponentResolver = getEndpointBodyCompleteComponents; - context.globalComponentResolver = getGlobalAutocompleteComponents; - let components: unknown; - if (context.endpoint) { - components = context.endpoint.bodyAutocompleteRootComponents; - } else { - components = getUnmatchedEndpointComponents(); - } - populateContext(ret.bodyTokenPath, context, editor, true, components); - - return context; - } - - const evaluateCurrentTokenAfterAChange = _.debounce(function evaluateCurrentTokenAfterAChange( - pos: Position - ) { - let currentToken = editor.getTokenAt(pos)!; - tracer('has started evaluating current token', currentToken); - - if (!currentToken) { - lastEvaluatedToken = null; - currentToken = { position: { column: 0, lineNumber: 0 }, value: '', type: '' }; // empty row - } - - currentToken.position.lineNumber = pos.lineNumber; // extend token with row. Ace doesn't supply it by default - if (parser.isEmptyToken(currentToken)) { - // empty token. check what's coming next - const nextToken = editor.getTokenAt({ ...pos, column: pos.column + 1 })!; - if (parser.isEmptyToken(nextToken)) { - // Empty line, or we're not on the edge of current token. Save the current position as base - currentToken.position.column = pos.column; - lastEvaluatedToken = currentToken; - } else { - nextToken.position.lineNumber = pos.lineNumber; - lastEvaluatedToken = nextToken; - } - tracer('not starting autocomplete due to empty current token'); - return; - } - - if (!lastEvaluatedToken) { - lastEvaluatedToken = currentToken; - tracer('not starting autocomplete due to invalid last evaluated token'); - return; // wait for the next typing. - } - - if (!looksLikeTypingIn(lastEvaluatedToken, currentToken, editor)) { - tracer('not starting autocomplete', lastEvaluatedToken, '->', currentToken); - // not on the same place or nothing changed, cache and wait for the next time - lastEvaluatedToken = currentToken; - return; - } - - // don't automatically open the auto complete if some just hit enter (new line) or open a parentheses - switch (currentToken.type || 'UNKNOWN') { - case 'paren.lparen': - case 'paren.rparen': - case 'punctuation.colon': - case 'punctuation.comma': - case 'comment.line': - case 'comment.punctuation': - case 'comment.block': - case 'UNKNOWN': - tracer('not starting autocomplete for current token type', currentToken.type); - return; - } - - tracer('starting autocomplete', lastEvaluatedToken, '->', currentToken); - lastEvaluatedToken = currentToken; - editor.execCommand('startAutocomplete'); - }, - 100); - - function editorChangeListener() { - const position = editor.getCurrentPosition(); - tracer('editor changed', position); - if (position && !editor.isCompleterActive()) { - tracer('will start evaluating current token'); - evaluateCurrentTokenAfterAChange(position); - } - } - - /** - * Extracts terms from the autocomplete set. - * @param context - */ - function getTerms(context: AutoCompleteContext, autoCompleteSet: ResultTerm[]) { - const terms = _.map( - autoCompleteSet.filter((term) => Boolean(term) && term.name != null), - function (term) { - if (typeof term !== 'object') { - term = { - name: term, - }; - } else { - term = _.clone(term); - } - const defaults: { - value?: string; - meta: string; - score: number; - context: AutoCompleteContext; - completer?: { insertMatch: (v: unknown) => void }; - } = { - value: term.name + '', - meta: 'API', - score: 0, - context, - }; - // we only need our custom insertMatch behavior for the body - if (context.autoCompleteType === 'body') { - defaults.completer = { - insertMatch() { - return applyTerm(term); - }, - }; - } - return _.defaults(term, defaults); - } - ); - - terms.sort(function ( - t1: { score: number; name?: string | boolean }, - t2: { score: number; name?: string | boolean } - ) { - /* score sorts from high to low */ - if (t1.score > t2.score) { - return -1; - } - if (t1.score < t2.score) { - return 1; - } - /* names sort from low to high */ - if (t1.name! < t2.name!) { - return -1; - } - if (t1.name === t2.name) { - return 0; - } - return 1; - }); - - return terms; - } - - function getSuggestions(terms: ResultTerm[]) { - return _.map(terms, function (t, i) { - t.insertValue = t.insertValue || t.value; - t.value = '' + t.value; // normalize to strings - t.score = -i; - return t; - }); - } - - function getCompletions( - position: Position, - prefix: string, - callback: (e: Error | null, result: ResultTerm[] | null) => void, - annotationControls: { - setAnnotation: (text: string) => void; - removeAnnotation: () => void; - } - ) { - try { - const context = getAutoCompleteContext(editor, position); - - if (!context) { - tracer('zero suggestions due to invalid autocomplete context'); - callback(null, []); - } else { - if (!context.asyncResultsState?.isLoading) { - const terms = getTerms(context, context.autoCompleteSet!); - const suggestions = getSuggestions(terms); - tracer(suggestions?.length ?? 0, 'suggestions'); - callback(null, suggestions); - } - - if (context.asyncResultsState) { - annotationControls.setAnnotation( - i18n.translate('console.autocomplete.fieldsFetchingAnnotation', { - defaultMessage: 'Fields fetching is in progress', - }) - ); - - context.asyncResultsState.results.then((r) => { - const asyncSuggestions = getSuggestions(getTerms(context, r)); - tracer(asyncSuggestions?.length ?? 0, 'async suggestions'); - callback(null, asyncSuggestions); - annotationControls.removeAnnotation(); - }); - } - } - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - callback(e, null); - } - } - - editor.on('changeSelection', editorChangeListener); - - return { - getCompletions, - // TODO: This needs to be cleaned up - _test: { - getCompletions: ( - _editor: unknown, - _editSession: unknown, - pos: Position, - prefix: string, - callback: (e: Error | null, result: ResultTerm[] | null) => void, - annotationControls: { - setAnnotation: (text: string) => void; - removeAnnotation: () => void; - } - ) => getCompletions(pos, prefix, callback, annotationControls), - addReplacementInfoToContext, - addChangeListener: () => editor.on('changeSelection', editorChangeListener), - removeChangeListener: () => editor.off('changeSelection', editorChangeListener), - }, - }; -} diff --git a/src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.ts b/src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.ts deleted file mode 100644 index b65e277e41723..0000000000000 --- a/src/plugins/console/public/lib/autocomplete/get_endpoint_from_position.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { CoreEditor, Position } from '../../types'; -import { getCurrentMethodAndTokenPaths } from './autocomplete'; -import type RowParser from '../row_parser'; - -import { getTopLevelUrlCompleteComponents } from '../kb/kb'; -import { populateContext } from './engine'; - -export function getEndpointFromPosition(editor: CoreEditor, pos: Position, parser: RowParser) { - const lineValue = editor.getLineValue(pos.lineNumber); - const context = { - ...getCurrentMethodAndTokenPaths( - editor, - { - column: lineValue.length + 1 /* Go to the very end of the line */, - lineNumber: pos.lineNumber, - }, - parser, - true - ), - }; - const components = getTopLevelUrlCompleteComponents(context.method); - populateContext(context.urlTokenPath, context, editor, true, components); - return context.endpoint; -} diff --git a/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.test.ts b/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.test.ts deleted file mode 100644 index 101fd96a79024..0000000000000 --- a/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.test.ts +++ /dev/null @@ -1,224 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import '../../application/models/sense_editor/sense_editor.test.mocks'; - -import { looksLikeTypingIn } from './looks_like_typing_in'; -import { create } from '../../application/models'; -import type { SenseEditor } from '../../application/models'; -import type { CoreEditor, Position, Token, TokensProvider } from '../../types'; - -describe('looksLikeTypingIn', () => { - let editor: SenseEditor; - let coreEditor: CoreEditor; - let tokenProvider: TokensProvider; - - beforeEach(() => { - document.body.innerHTML = `
    -
    -
    -
    -
    `; - editor = create(document.getElementById('ConAppEditor')!); - coreEditor = editor.getCoreEditor(); - tokenProvider = coreEditor.getTokenProvider(); - }); - - afterEach(async () => { - await editor.update('', true); - }); - - describe('general typing in', () => { - interface RunTestArgs { - preamble: string; - autocomplete?: string; - input: string; - } - - const runTest = async ({ preamble, autocomplete, input }: RunTestArgs) => { - const pos: Position = { lineNumber: 1, column: 1 }; - - await editor.update(preamble, true); - pos.column += preamble.length; - const lastEvaluatedToken = tokenProvider.getTokenAt(pos); - - if (autocomplete !== undefined) { - await editor.update(coreEditor.getValue() + autocomplete, true); - pos.column += autocomplete.length; - } - - await editor.update(coreEditor.getValue() + input, true); - pos.column += input.length; - const currentToken = tokenProvider.getTokenAt(pos); - - expect(lastEvaluatedToken).not.toBeNull(); - expect(currentToken).not.toBeNull(); - expect(looksLikeTypingIn(lastEvaluatedToken!, currentToken!, coreEditor)).toBe(true); - }; - - const cases: RunTestArgs[] = [ - { preamble: 'G', input: 'E' }, - { preamble: 'GET .kibana', input: '/' }, - { preamble: 'GET .kibana', input: ',' }, - { preamble: 'GET .kibana', input: '?' }, - { preamble: 'GET .kibana/', input: '_' }, - { preamble: 'GET .kibana/', input: '?' }, - { preamble: 'GET .kibana,', input: '.' }, - { preamble: 'GET .kibana,', input: '?' }, - { preamble: 'GET .kibana?', input: 'k' }, - { preamble: 'GET .kibana?k', input: '=' }, - { preamble: 'GET .kibana?k=', input: 'v' }, - { preamble: 'GET .kibana?k=v', input: '&' }, - { preamble: 'GET .kibana?k', input: '&' }, - { preamble: 'GET .kibana?k&', input: 'k' }, - { preamble: 'GET ', autocomplete: '.kibana', input: '/' }, - { preamble: 'GET ', autocomplete: '.kibana', input: ',' }, - { preamble: 'GET ', autocomplete: '.kibana', input: '?' }, - { preamble: 'GET .ki', autocomplete: 'bana', input: '/' }, - { preamble: 'GET .ki', autocomplete: 'bana', input: ',' }, - { preamble: 'GET .ki', autocomplete: 'bana', input: '?' }, - { preamble: 'GET _nodes/', autocomplete: 'stats', input: '/' }, - { preamble: 'GET _nodes/sta', autocomplete: 'ts', input: '/' }, - { preamble: 'GET _nodes/', autocomplete: 'jvm', input: ',' }, - { preamble: 'GET _nodes/j', autocomplete: 'vm', input: ',' }, - { preamble: 'GET _nodes/jvm,', autocomplete: 'os', input: ',' }, - { preamble: 'GET .kibana,', autocomplete: '.security', input: ',' }, - { preamble: 'GET .kibana,.sec', autocomplete: 'urity', input: ',' }, - { preamble: 'GET .kibana,', autocomplete: '.security', input: '/' }, - { preamble: 'GET .kibana,.sec', autocomplete: 'urity', input: '/' }, - { preamble: 'GET .kibana,', autocomplete: '.security', input: '?' }, - { preamble: 'GET .kibana,.sec', autocomplete: 'urity', input: '?' }, - { preamble: 'GET .kibana/', autocomplete: '_search', input: '?' }, - { preamble: 'GET .kibana/_se', autocomplete: 'arch', input: '?' }, - { preamble: 'GET .kibana/_search?', autocomplete: 'expand_wildcards', input: '=' }, - { preamble: 'GET .kibana/_search?exp', autocomplete: 'and_wildcards', input: '=' }, - { preamble: 'GET .kibana/_search?expand_wildcards=', autocomplete: 'all', input: '&' }, - { preamble: 'GET .kibana/_search?expand_wildcards=a', autocomplete: 'll', input: '&' }, - { preamble: 'GET _cat/indices?s=index&', autocomplete: 'expand_wildcards', input: '=' }, - { preamble: 'GET _cat/indices?s=index&exp', autocomplete: 'and_wildcards', input: '=' }, - { preamble: 'GET _cat/indices?v&', autocomplete: 'expand_wildcards', input: '=' }, - { preamble: 'GET _cat/indices?v&exp', autocomplete: 'and_wildcards', input: '=' }, - // autocomplete skips one iteration of token evaluation if user types in every letter - { preamble: 'GET .kibana', autocomplete: '/', input: '_' }, // token '/' may not be evaluated - { preamble: 'GET .kibana', autocomplete: ',', input: '.' }, // token ',' may not be evaluated - { preamble: 'GET .kibana', autocomplete: '?', input: 'k' }, // token '?' may not be evaluated - ]; - for (const c of cases) { - const name = - c.autocomplete === undefined - ? `'${c.preamble}' -> '${c.input}'` - : `'${c.preamble}' -> '${c.autocomplete}' (autocomplte) -> '${c.input}'`; - test(name, async () => runTest(c)); - } - }); - - describe('first typing in', () => { - test(`'' -> 'G'`, () => { - // this is based on an implementation within the evaluateCurrentTokenAfterAChange function - const lastEvaluatedToken = { position: { column: 0, lineNumber: 0 }, value: '', type: '' }; - lastEvaluatedToken.position.lineNumber = coreEditor.getCurrentPosition().lineNumber; - - const currentToken = { position: { column: 1, lineNumber: 1 }, value: 'G', type: 'method' }; - expect(looksLikeTypingIn(lastEvaluatedToken, currentToken, coreEditor)).toBe(true); - }); - }); - - const matrices = [ - ` -GET .kibana/ - - -` - .slice(1, -1) - .split('\n'), - ` - - POST test/_doc -{"message": "test"} - -GET /_cat/indices?v&s= - -DE -` - .slice(1, -1) - .split('\n'), - ` - -PUT test/_doc/1 -{"field": "value"} -` - .slice(1, -1) - .split('\n'), - ]; - - describe('navigating the editor via keyboard arrow keys', () => { - const runHorizontalZigzagWalkTest = async (matrix: string[]) => { - const width = matrix[0].length; - const height = matrix.length; - - await editor.update(matrix.join('\n'), true); - let lastEvaluatedToken = tokenProvider.getTokenAt(coreEditor.getCurrentPosition()); - let currentToken: Token | null; - - for (let i = 1; i < height * width * 2; i++) { - const pos = { - column: 1 + (i % width), - lineNumber: 1 + Math.floor(i / width), - }; - if (pos.lineNumber % 2 === 0) { - pos.column = width - pos.column + 1; - } - if (pos.lineNumber > height) { - pos.lineNumber = 2 * height - pos.lineNumber + 1; - } - - currentToken = tokenProvider.getTokenAt(pos); - expect(lastEvaluatedToken).not.toBeNull(); - expect(currentToken).not.toBeNull(); - expect(looksLikeTypingIn(lastEvaluatedToken!, currentToken!, coreEditor)).toBe(false); - lastEvaluatedToken = currentToken; - } - }; - - for (const matrix of matrices) { - test(`horizontal zigzag walk ${matrix[0].length}x${matrix.length} map`, () => - runHorizontalZigzagWalkTest(matrix)); - } - }); - - describe('clicking around the editor', () => { - const runRandomClickingTest = async (matrix: string[], attempts: number) => { - const width = matrix[0].length; - const height = matrix.length; - - await editor.update(matrix.join('\n'), true); - let lastEvaluatedToken = tokenProvider.getTokenAt(coreEditor.getCurrentPosition()); - let currentToken: Token | null; - - for (let i = 1; i < attempts; i++) { - const pos = { - column: Math.ceil(Math.random() * width), - lineNumber: Math.ceil(Math.random() * height), - }; - - currentToken = tokenProvider.getTokenAt(pos); - expect(lastEvaluatedToken).not.toBeNull(); - expect(currentToken).not.toBeNull(); - expect(looksLikeTypingIn(lastEvaluatedToken!, currentToken!, coreEditor)).toBe(false); - lastEvaluatedToken = currentToken; - } - }; - - for (const matrix of matrices) { - const attempts = 4 * matrix[0].length * matrix.length; - test(`random clicking ${matrix[0].length}x${matrix.length} map ${attempts} times`, () => - runRandomClickingTest(matrix, attempts)); - } - }); -}); diff --git a/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.ts b/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.ts deleted file mode 100644 index a22c985a943f6..0000000000000 --- a/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.ts +++ /dev/null @@ -1,109 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreEditor, Position, Token } from '../../types'; - -enum Move { - ForwardOneCharacter = 1, - ForwardOneToken, // the column position may jump to the next token by autocomplete - ForwardTwoTokens, // the column position could jump two tokens due to autocomplete -} - -const knownTypingInTokenTypes = new Map>>([ - [ - Move.ForwardOneCharacter, - new Map>([ - // a pair of the last evaluated token type and a set of the current token types - ['', new Set(['method'])], - ['url.amp', new Set(['url.param'])], - ['url.comma', new Set(['url.part', 'url.questionmark'])], - ['url.equal', new Set(['url.value'])], - ['url.param', new Set(['url.amp', 'url.equal'])], - ['url.questionmark', new Set(['url.param'])], - ['url.slash', new Set(['url.part', 'url.questionmark'])], - ['url.value', new Set(['url.amp'])], - ]), - ], - [ - Move.ForwardOneToken, - new Map>([ - ['method', new Set(['url.part'])], - ['url.amp', new Set(['url.amp', 'url.equal'])], - ['url.comma', new Set(['url.comma', 'url.questionmark', 'url.slash'])], - ['url.equal', new Set(['url.amp'])], - ['url.param', new Set(['url.equal'])], - ['url.part', new Set(['url.comma', 'url.questionmark', 'url.slash'])], - ['url.questionmark', new Set(['url.equal'])], - ['url.slash', new Set(['url.comma', 'url.questionmark', 'url.slash'])], - ['url.value', new Set(['url.amp'])], - ['whitespace', new Set(['url.comma', 'url.questionmark', 'url.slash'])], - ]), - ], - [ - Move.ForwardTwoTokens, - new Map>([['url.part', new Set(['url.param', 'url.part'])]]), - ], -]); - -const getOneCharacterNextOnTheRight = (pos: Position, coreEditor: CoreEditor): string => { - const range = { - start: { column: pos.column + 1, lineNumber: pos.lineNumber }, - end: { column: pos.column + 2, lineNumber: pos.lineNumber }, - }; - return coreEditor.getValueInRange(range); -}; - -/** - * Examines a change from the last evaluated to the current token and one - * character next to the current token position on the right. Returns true if - * the change looks like typing in, false otherwise. - * - * This function is supposed to filter out situations where autocomplete is not - * preferable, such as clicking around the editor, navigating the editor via - * keyboard arrow keys, etc. - */ -export const looksLikeTypingIn = ( - lastEvaluatedToken: Token, - currentToken: Token, - coreEditor: CoreEditor -): boolean => { - // if the column position moves to the right in the same line and the current - // token length is 1, then user is possibly typing in a character. - if ( - lastEvaluatedToken.position.column < currentToken.position.column && - lastEvaluatedToken.position.lineNumber === currentToken.position.lineNumber && - currentToken.value.length === 1 && - getOneCharacterNextOnTheRight(currentToken.position, coreEditor) === '' - ) { - const moves = - lastEvaluatedToken.position.column + 1 === currentToken.position.column - ? [Move.ForwardOneCharacter] - : [Move.ForwardOneToken, Move.ForwardTwoTokens]; - for (const move of moves) { - const tokenTypesPairs = knownTypingInTokenTypes.get(move) ?? new Map>(); - const currentTokenTypes = tokenTypesPairs.get(lastEvaluatedToken.type) ?? new Set(); - if (currentTokenTypes.has(currentToken.type)) { - return true; - } - } - } - - // if the column or the line number have changed for the last token or - // user did not provided a new value, then we should not show autocomplete - // this guards against triggering autocomplete when clicking around the editor - if ( - lastEvaluatedToken.position.column !== currentToken.position.column || - lastEvaluatedToken.position.lineNumber !== currentToken.position.lineNumber || - lastEvaluatedToken.value === currentToken.value - ) { - return false; - } - - return true; -}; diff --git a/src/plugins/console/public/lib/autocomplete_entities/autocomplete_entities.test.js b/src/plugins/console/public/lib/autocomplete_entities/autocomplete_entities.test.js index 5901c95b9a074..0cffb157abb4c 100644 --- a/src/plugins/console/public/lib/autocomplete_entities/autocomplete_entities.test.js +++ b/src/plugins/console/public/lib/autocomplete_entities/autocomplete_entities.test.js @@ -7,7 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import '../../application/models/sense_editor/sense_editor.test.mocks'; import { setAutocompleteInfo, AutocompleteInfo } from '../../services'; import { expandAliases } from './expand_aliases'; import { httpServiceMock } from '@kbn/core-http-browser-mocks'; diff --git a/src/plugins/console/public/lib/curl_parsing/__fixtures__/curl_parsing.txt b/src/plugins/console/public/lib/curl_parsing/__fixtures__/curl_parsing.txt deleted file mode 100644 index b6dd39479550d..0000000000000 --- a/src/plugins/console/public/lib/curl_parsing/__fixtures__/curl_parsing.txt +++ /dev/null @@ -1,146 +0,0 @@ -========== -Curl 1 -------------------------------------- -curl -XPUT 'http://localhost:9200/twitter/tweet/1' -d '{ - "user" : "kimchy", - "post_date" : "2009-11-15T14:12:12", - "message" : "trying out Elastic Search" -}' -------------------------------------- -PUT /twitter/tweet/1 -{ - "user" : "kimchy", - "post_date" : "2009-11-15T14:12:12", - "message" : "trying out Elastic Search" -} -========== -Curl 2 -------------------------------------- -curl -XGET "localhost/twitter/tweet/1?version=2" -d '{ - "message" : "elasticsearch now has versioning support, double cool!" -}' -------------------------------------- -GET /twitter/tweet/1?version=2 -{ - "message" : "elasticsearch now has versioning support, double cool!" -} -=========== -Curl 3 -------------------------------------- -curl -XPOST https://localhost/twitter/tweet/1?version=2 -d '{ - "message" : "elasticsearch now has versioning support, double cool!" -}' -------------------------------------- -POST /twitter/tweet/1?version=2 -{ - "message" : "elasticsearch now has versioning support, double cool!" -} -========= -Curl 4 -------------------------------------- -curl -XPOST https://localhost/twitter -------------------------------------- -POST /twitter -========== -Curl 5 -------------------------------------- -curl -X POST https://localhost/twitter/ -------------------------------------- -POST /twitter/ -============= -Curl 6 -------------------------------------- -curl -s -XPOST localhost:9200/missing-test -d' -{ - "mappings": { - } -}' -------------------------------------- -POST /missing-test -{ - "mappings": { - } -} -========================= -Curl 7 -------------------------------------- -curl 'localhost:9200/missing-test/doc/_search?pretty' -d' -{ - "query": { - }, -}' -------------------------------------- -GET /missing-test/doc/_search?pretty -{ - "query": { - }, -} -=========================== -Curl 8 -------------------------------------- -curl localhost:9200/ -d' -{ - "query": { - } -}' -------------------------------------- -GET / -{ - "query": { - } -} -==================================== -Curl Script -------------------------------------- -#!bin/sh - -// test something -curl 'localhost:9200/missing-test/doc/_search?pretty' -d' -{ - "query": { - }, -}' - - -curl -XPOST https://localhost/twitter - -#someother comments -curl localhost:9200/ -d' -{ - "query": { - } -}' - - -------------------- -# test something -GET /missing-test/doc/_search?pretty -{ - "query": { - }, -} - -POST /twitter - -#someother comments -GET / -{ - "query": { - } -} -==================================== -Curl with some text -------------------------------------- -This is what I meant: - -curl 'localhost:9200/missing-test/doc/_search?' - -This, however, does work: -curl 'localhost:9200/missing/doc/_search?' -------------------- -### This is what I meant: - -GET /missing-test/doc/_search? - -### This, however, does work: -GET /missing/doc/_search? diff --git a/src/plugins/console/public/lib/curl_parsing/curl.js b/src/plugins/console/public/lib/curl_parsing/curl.js deleted file mode 100644 index 4dd09d1b7d59b..0000000000000 --- a/src/plugins/console/public/lib/curl_parsing/curl.js +++ /dev/null @@ -1,194 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -function detectCURLinLine(line) { - // returns true if text matches a curl request - return line.match(/^\s*?curl\s+(-X[A-Z]+)?\s*['"]?.*?['"]?(\s*$|\s+?-d\s*?['"])/); -} - -export function detectCURL(text) { - // returns true if text matches a curl request - if (!text) return false; - for (const line of text.split('\n')) { - if (detectCURLinLine(line)) { - return true; - } - } - return false; -} - -export function parseCURL(text) { - let state = 'NONE'; - const out = []; - let body = []; - let line = ''; - const lines = text.trim().split('\n'); - let matches; - - const EmptyLine = /^\s*$/; - const Comment = /^\s*(?:#|\/{2,})(.*)\n?$/; - const ExecutionComment = /^\s*#!/; - const ClosingSingleQuote = /^([^']*)'/; - const ClosingDoubleQuote = /^((?:[^\\"]|\\.)*)"/; - const EscapedQuotes = /^((?:[^\\"']|\\.)+)/; - - const LooksLikeCurl = /^\s*curl\s+/; - const CurlVerb = /-X ?(GET|HEAD|POST|PUT|DELETE|PATCH)/; - - const HasProtocol = /[\s"']https?:\/\//; - const CurlRequestWithProto = /[\s"']https?:\/\/[^\/ ]+\/+([^\s"']+)/; - const CurlRequestWithoutProto = /[\s"'][^\/ ]+\/+([^\s"']+)/; - const CurlData = /^.+\s(--data|-d)\s*/; - const SenseLine = /^\s*(GET|HEAD|POST|PUT|DELETE|PATCH)\s+\/?(.+)/; - - if (lines.length > 0 && ExecutionComment.test(lines[0])) { - lines.shift(); - } - - function nextLine() { - if (line.length > 0) { - return true; - } - if (lines.length === 0) { - return false; - } - line = lines.shift().replace(/[\r\n]+/g, '\n') + '\n'; - return true; - } - - function unescapeLastBodyEl() { - const str = body.pop().replace(/\\([\\"'])/g, '$1'); - body.push(str); - } - - // Is the next char a single or double quote? - // If so remove it - function detectQuote() { - if (line.substr(0, 1) === "'") { - line = line.substr(1); - state = 'SINGLE_QUOTE'; - } else if (line.substr(0, 1) === '"') { - line = line.substr(1); - state = 'DOUBLE_QUOTE'; - } else { - state = 'UNQUOTED'; - } - } - - // Body is finished - append to output with final LF - function addBodyToOut() { - if (body.length > 0) { - out.push(body.join('')); - body = []; - } - state = 'LF'; - out.push('\n'); - } - - // If the pattern matches, then the state is about to change, - // so add the capture to the body and detect the next state - // Otherwise add the whole line - function consumeMatching(pattern) { - const matches = line.match(pattern); - if (matches) { - body.push(matches[1]); - line = line.substr(matches[0].length); - detectQuote(); - } else { - body.push(line); - line = ''; - } - } - - function parseCurlLine() { - let verb = 'GET'; - let request = ''; - let matches; - if ((matches = line.match(CurlVerb))) { - verb = matches[1]; - } - - // JS regexen don't support possessive quantifiers, so - // we need two distinct patterns - const pattern = HasProtocol.test(line) ? CurlRequestWithProto : CurlRequestWithoutProto; - - if ((matches = line.match(pattern))) { - request = matches[1]; - } - - out.push(verb + ' /' + request + '\n'); - - if ((matches = line.match(CurlData))) { - line = line.substr(matches[0].length); - detectQuote(); - if (EmptyLine.test(line)) { - line = ''; - } - } else { - state = 'NONE'; - line = ''; - out.push(''); - } - } - - while (nextLine()) { - if (state === 'SINGLE_QUOTE') { - consumeMatching(ClosingSingleQuote); - } else if (state === 'DOUBLE_QUOTE') { - consumeMatching(ClosingDoubleQuote); - unescapeLastBodyEl(); - } else if (state === 'UNQUOTED') { - consumeMatching(EscapedQuotes); - if (body.length) { - unescapeLastBodyEl(); - } - if (state === 'UNQUOTED') { - addBodyToOut(); - line = ''; - } - } - - // the BODY state (used to match the body of a Sense request) - // can be terminated early if it encounters - // a comment or an empty line - else if (state === 'BODY') { - if (Comment.test(line) || EmptyLine.test(line)) { - addBodyToOut(); - } else { - body.push(line); - line = ''; - } - } else if (EmptyLine.test(line)) { - if (state !== 'LF') { - out.push('\n'); - state = 'LF'; - } - line = ''; - } else if ((matches = line.match(Comment))) { - out.push('#' + matches[1] + '\n'); - state = 'NONE'; - line = ''; - } else if (LooksLikeCurl.test(line)) { - parseCurlLine(); - } else if ((matches = line.match(SenseLine))) { - out.push(matches[1] + ' /' + matches[2] + '\n'); - line = ''; - state = 'BODY'; - } - - // Nothing else matches, so output with a prefix of !!! for debugging purposes - else { - out.push('### ' + line); - line = ''; - } - } - - addBodyToOut(); - return out.join('').trim(); -} diff --git a/src/plugins/console/public/lib/curl_parsing/curl_parsing.test.js b/src/plugins/console/public/lib/curl_parsing/curl_parsing.test.js deleted file mode 100644 index 80a60cd259717..0000000000000 --- a/src/plugins/console/public/lib/curl_parsing/curl_parsing.test.js +++ /dev/null @@ -1,37 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import _ from 'lodash'; -import { detectCURL, parseCURL } from './curl'; -import curlTests from './__fixtures__/curl_parsing.txt'; - -describe('CURL', () => { - const notCURLS = ['sldhfsljfhs', 's;kdjfsldkfj curl -XDELETE ""', '{ "hello": 1 }']; - _.each(notCURLS, function (notCURL, i) { - test('cURL Detection - broken strings ' + i, function () { - expect(detectCURL(notCURL)).toEqual(false); - }); - }); - - curlTests.split(/^=+$/m).forEach(function (fixture) { - if (fixture.trim() === '') { - return; - } - fixture = fixture.split(/^-+$/m); - const name = fixture[0].trim(); - const curlText = fixture[1]; - const response = fixture[2].trim(); - - test('cURL Detection - ' + name, function () { - expect(detectCURL(curlText)).toBe(true); - const r = parseCURL(curlText); - expect(r).toEqual(response); - }); - }); -}); diff --git a/src/plugins/console/public/lib/kb/kb.test.js b/src/plugins/console/public/lib/kb/kb.test.js index 70ea0ef33ae86..7560789718e58 100644 --- a/src/plugins/console/public/lib/kb/kb.test.js +++ b/src/plugins/console/public/lib/kb/kb.test.js @@ -10,7 +10,6 @@ import _ from 'lodash'; import { populateContext } from '../autocomplete/engine'; -import '../../application/models/sense_editor/sense_editor.test.mocks'; import * as kb from '.'; import { AutocompleteInfo, setAutocompleteInfo } from '../../services'; diff --git a/src/plugins/console/public/lib/row_parser.test.ts b/src/plugins/console/public/lib/row_parser.test.ts deleted file mode 100644 index 869822b7bf055..0000000000000 --- a/src/plugins/console/public/lib/row_parser.test.ts +++ /dev/null @@ -1,107 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import '../application/models/legacy_core_editor/legacy_core_editor.test.mocks'; - -import RowParser from './row_parser'; -import { create, MODE } from '../application/models'; -import type { SenseEditor } from '../application/models'; -import type { CoreEditor } from '../types'; - -describe('RowParser', () => { - let editor: SenseEditor | null; - let parser: RowParser | null; - - beforeEach(function () { - // Set up our document body - document.body.innerHTML = `
    -
    -
    -
    -
    `; - editor = create(document.getElementById('ConAppEditor')!); - parser = new RowParser(editor.getCoreEditor() as CoreEditor); - }); - - afterEach(function () { - editor?.getCoreEditor().destroy(); - editor = null; - parser = null; - }); - - describe('getRowParseMode', () => { - const forceRetokenize = false; - - it('should return MODE.BETWEEN_REQUESTS if line is empty', () => { - editor?.getCoreEditor().setValue('', forceRetokenize); - expect(parser?.getRowParseMode()).toBe(MODE.BETWEEN_REQUESTS); - }); - - it('should return MODE.BETWEEN_REQUESTS if line is a comment', () => { - editor?.getCoreEditor().setValue('// comment', forceRetokenize); - expect(parser?.getRowParseMode()).toBe(MODE.BETWEEN_REQUESTS); - }); - - it('should return MODE.REQUEST_START | MODE.REQUEST_END if line is a single line request', () => { - editor?.getCoreEditor().setValue('GET _search', forceRetokenize); - // eslint-disable-next-line no-bitwise - expect(parser?.getRowParseMode()).toBe(MODE.REQUEST_START | MODE.REQUEST_END); - }); - - it('should return MODE.IN_REQUEST if line is a request with an opening curly brace', () => { - editor?.getCoreEditor().setValue('{', forceRetokenize); - expect(parser?.getRowParseMode()).toBe(MODE.IN_REQUEST); - }); - - it('should return MODE.MULTI_DOC_CUR_DOC_END | MODE.IN_REQUEST if line is a multi doc request with an opening curly brace', () => { - editor?.getCoreEditor().setValue('GET _msearch\n{}\n{', forceRetokenize); - const lineNumber = editor?.getCoreEditor().getLineCount()! - 1; - expect(parser?.getRowParseMode(lineNumber)).toBe( - // eslint-disable-next-line no-bitwise - MODE.MULTI_DOC_CUR_DOC_END | MODE.IN_REQUEST - ); - }); - - it('should return MODE.MULTI_DOC_CUR_DOC_END | MODE.REQUEST_END if line is a multi doc request with a closing curly brace', () => { - editor?.getCoreEditor().setValue('GET _msearch\n{}\n{"foo": 1}\n', forceRetokenize); - const lineNumber = editor?.getCoreEditor().getLineCount()! - 1; - expect(parser?.getRowParseMode(lineNumber)).toBe( - // eslint-disable-next-line no-bitwise - MODE.MULTI_DOC_CUR_DOC_END | MODE.REQUEST_END - ); - }); - - it('should return MODE.REQUEST_START | MODE.REQUEST_END if line is a request with variables', () => { - editor?.getCoreEditor().setValue('GET /${exampleVariable}', forceRetokenize); - // eslint-disable-next-line no-bitwise - expect(parser?.getRowParseMode()).toBe(MODE.REQUEST_START | MODE.REQUEST_END); - }); - - it('should return MODE.REQUEST_START | MODE.REQUEST_END if a single request line ends with a closing curly brace', () => { - editor?.getCoreEditor().setValue('DELETE /_bar/_baz%{test}', forceRetokenize); - // eslint-disable-next-line no-bitwise - expect(parser?.getRowParseMode()).toBe(MODE.REQUEST_START | MODE.REQUEST_END); - }); - - it('should return correct modes for multiple bulk requests', () => { - editor - ?.getCoreEditor() - .setValue('POST _bulk\n{"index": {"_index": "test"}}\n{"foo": "bar"}\n', forceRetokenize); - expect(parser?.getRowParseMode(0)).toBe(MODE.BETWEEN_REQUESTS); - editor - ?.getCoreEditor() - .setValue('POST _bulk\n{"index": {"_index": "test"}}\n{"foo": "bar"}\n', forceRetokenize); - const lineNumber = editor?.getCoreEditor().getLineCount()! - 1; - expect(parser?.getRowParseMode(lineNumber)).toBe( - // eslint-disable-next-line no-bitwise - MODE.REQUEST_END | MODE.MULTI_DOC_CUR_DOC_END - ); - }); - }); -}); diff --git a/src/plugins/console/public/lib/row_parser.ts b/src/plugins/console/public/lib/row_parser.ts deleted file mode 100644 index 7078bb857d95b..0000000000000 --- a/src/plugins/console/public/lib/row_parser.ts +++ /dev/null @@ -1,161 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { CoreEditor, Token } from '../types'; -import { TokenIterator } from './token_iterator'; - -export const MODE = { - REQUEST_START: 2, - IN_REQUEST: 4, - MULTI_DOC_CUR_DOC_END: 8, - REQUEST_END: 16, - BETWEEN_REQUESTS: 32, -}; - -// eslint-disable-next-line import/no-default-export -export default class RowParser { - constructor(private readonly editor: CoreEditor) {} - - MODE = MODE; - - getRowParseMode(lineNumber = this.editor.getCurrentPosition().lineNumber) { - const linesCount = this.editor.getLineCount(); - if (lineNumber > linesCount || lineNumber < 1) { - return MODE.BETWEEN_REQUESTS; - } - const mode = this.editor.getLineState(lineNumber); - - if (!mode) { - return MODE.BETWEEN_REQUESTS; - } // shouldn't really happen - // If another "start" mode is added here because we want to allow for new language highlighting - // please see https://github.com/elastic/kibana/pull/51446 for a discussion on why - // should consider a different approach. - if (mode !== 'start' && mode !== 'start-sql') { - return MODE.IN_REQUEST; - } - let line = (this.editor.getLineValue(lineNumber) || '').trim(); - - if (!line || line.startsWith('#') || line.startsWith('//') || line.startsWith('/*')) { - return MODE.BETWEEN_REQUESTS; - } // empty line or a comment waiting for a new req to start - - // Check for multi doc requests - if (line.endsWith('}') && !this.isRequestLine(line)) { - // check for a multi doc request must start a new json doc immediately after this one end. - lineNumber++; - if (lineNumber < linesCount + 1) { - line = (this.editor.getLineValue(lineNumber) || '').trim(); - if (line.indexOf('{') === 0) { - // next line is another doc in a multi doc - // eslint-disable-next-line no-bitwise - return MODE.MULTI_DOC_CUR_DOC_END | MODE.IN_REQUEST; - } - } - // eslint-disable-next-line no-bitwise - return MODE.REQUEST_END | MODE.MULTI_DOC_CUR_DOC_END; // end of request - } - - // check for single line requests - lineNumber++; - if (lineNumber >= linesCount + 1) { - // eslint-disable-next-line no-bitwise - return MODE.REQUEST_START | MODE.REQUEST_END; - } - line = (this.editor.getLineValue(lineNumber) || '').trim(); - if (line.indexOf('{') !== 0) { - // next line is another request - // eslint-disable-next-line no-bitwise - return MODE.REQUEST_START | MODE.REQUEST_END; - } - - return MODE.REQUEST_START; - } - - rowPredicate(lineNumber: number | undefined, editor: CoreEditor, value: number) { - const mode = this.getRowParseMode(lineNumber); - // eslint-disable-next-line no-bitwise - return (mode & value) > 0; - } - - isEndRequestRow(row?: number, _e?: CoreEditor) { - const editor = _e || this.editor; - return this.rowPredicate(row, editor, MODE.REQUEST_END); - } - - isRequestEdge(row?: number, _e?: CoreEditor) { - const editor = _e || this.editor; - // eslint-disable-next-line no-bitwise - return this.rowPredicate(row, editor, MODE.REQUEST_END | MODE.REQUEST_START); - } - - isStartRequestRow(row?: number, _e?: CoreEditor) { - const editor = _e || this.editor; - return this.rowPredicate(row, editor, MODE.REQUEST_START); - } - - isInBetweenRequestsRow(row?: number, _e?: CoreEditor) { - const editor = _e || this.editor; - return this.rowPredicate(row, editor, MODE.BETWEEN_REQUESTS); - } - - isInRequestsRow(row?: number, _e?: CoreEditor) { - const editor = _e || this.editor; - return this.rowPredicate(row, editor, MODE.IN_REQUEST); - } - - isMultiDocDocEndRow(row?: number, _e?: CoreEditor) { - const editor = _e || this.editor; - return this.rowPredicate(row, editor, MODE.MULTI_DOC_CUR_DOC_END); - } - - isEmptyToken(tokenOrTokenIter: TokenIterator | Token | null) { - const token = - tokenOrTokenIter && (tokenOrTokenIter as TokenIterator).getCurrentToken - ? (tokenOrTokenIter as TokenIterator).getCurrentToken() - : tokenOrTokenIter; - return !token || (token as Token).type === 'whitespace'; - } - - isUrlOrMethodToken(tokenOrTokenIter: TokenIterator | Token) { - const t = (tokenOrTokenIter as TokenIterator)?.getCurrentToken() ?? (tokenOrTokenIter as Token); - return t && t.type && (t.type === 'method' || t.type.indexOf('url') === 0); - } - - nextNonEmptyToken(tokenIter: TokenIterator) { - let t = tokenIter.stepForward(); - while (t && this.isEmptyToken(t)) { - t = tokenIter.stepForward(); - } - return t; - } - - prevNonEmptyToken(tokenIter: TokenIterator) { - let t = tokenIter.stepBackward(); - // empty rows return null token. - while ((t || tokenIter.getCurrentPosition().lineNumber > 1) && this.isEmptyToken(t)) - t = tokenIter.stepBackward(); - return t; - } - - isCommentToken(token: Token | null) { - return ( - token && - token.type && - (token.type === 'comment.punctuation' || - token.type === 'comment.line' || - token.type === 'comment.block') - ); - } - - isRequestLine(line: string) { - const methods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'PATCH', 'OPTIONS']; - return methods.some((m) => line.startsWith(m)); - } -} diff --git a/src/plugins/console/public/styles/_app.scss b/src/plugins/console/public/styles/_app.scss index 4c3ccb8b1cadc..0f0a671d920c3 100644 --- a/src/plugins/console/public/styles/_app.scss +++ b/src/plugins/console/public/styles/_app.scss @@ -36,8 +36,6 @@ width: 100%; display: flex; flex: 0 0 auto; - - // Required on IE11 to render ace editor correctly after first input. position: relative; &__spinner { @@ -55,46 +53,6 @@ height: 100%; display: flex; flex: 1 1 1px; - - .ace_badge { - font-family: $euiFontFamily; - font-size: $euiFontSizeXS; - font-weight: $euiFontWeightMedium; - line-height: $euiLineHeight; - padding: 0 $euiSizeS; - display: inline-block; - text-decoration: none; - border-radius: calc($euiBorderRadius / 2); - white-space: nowrap; - vertical-align: middle; - cursor: default; - max-width: 100%; - - &--success { - background-color: $euiColorVis0_behindText; - color: chooseLightOrDarkText($euiColorVis0_behindText); - } - - &--warning { - background-color: $euiColorVis5_behindText; - color: chooseLightOrDarkText($euiColorVis5_behindText); - } - - &--primary { - background-color: $euiColorVis1_behindText; - color: chooseLightOrDarkText($euiColorVis1_behindText); - } - - &--default { - background-color: $euiColorLightShade; - color: chooseLightOrDarkText($euiColorLightShade); - } - - &--danger { - background-color: $euiColorVis9_behindText; - color: chooseLightOrDarkText($euiColorVis9_behindText); - } - } } .conApp__editorContent, @@ -145,17 +103,6 @@ margin-inline: 0; } -// SASSTODO: This component seems to not be used anymore? -// Possibly replaced by the Ace version -.conApp__autoComplete { - position: absolute; - left: -1000px; - visibility: hidden; - /* by pass any other element in ace and resize bar, but not modal popups */ - z-index: $euiZLevel1 + 2; - margin-top: 22px; -} - .conApp__requestProgressBarContainer { position: relative; z-index: $euiZLevel2; diff --git a/src/plugins/console/public/types/core_editor.ts b/src/plugins/console/public/types/core_editor.ts index aa9bdf21c1c94..8d5ab2a582226 100644 --- a/src/plugins/console/public/types/core_editor.ts +++ b/src/plugins/console/public/types/core_editor.ts @@ -7,7 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { Editor } from 'brace'; import { ResultTerm } from '../lib/autocomplete/types'; import { TokensProvider } from './tokens_provider'; import { Token } from './token'; @@ -94,7 +93,7 @@ export enum LINE_MODE { /** * The CoreEditor is a component separate from the Editor implementation that provides Console * app specific business logic. The CoreEditor is an interface to the lower-level editor implementation - * being used which is usually vendor code such as Ace or Monaco. + * being used which is usually vendor code such as Monaco. */ export interface CoreEditor { /** @@ -260,7 +259,7 @@ export interface CoreEditor { */ registerKeyboardShortcut(opts: { keys: string | { win?: string; mac?: string }; - fn: (editor: Editor) => void; + fn: (editor: any) => void; name: string; }): void; diff --git a/src/plugins/console/tsconfig.json b/src/plugins/console/tsconfig.json index 2b0f6127cd4af..02e4e7a9b7689 100644 --- a/src/plugins/console/tsconfig.json +++ b/src/plugins/console/tsconfig.json @@ -18,10 +18,8 @@ "@kbn/i18n-react", "@kbn/shared-ux-utility", "@kbn/core-http-browser", - "@kbn/ace", "@kbn/config-schema", "@kbn/core-http-router-server-internal", - "@kbn/web-worker-stub", "@kbn/core-elasticsearch-server", "@kbn/core-http-browser-mocks", "@kbn/react-kibana-context-theme", diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index ea995a275449d..3b078d6bb8a90 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -320,8 +320,6 @@ "coloring.dynamicColoring.rangeType.label": "Type de valeur", "coloring.dynamicColoring.rangeType.number": "Numéro", "coloring.dynamicColoring.rangeType.percent": "Pourcent", - "console.autocomplete.addMethodMetaText": "méthode", - "console.autocomplete.fieldsFetchingAnnotation": "La récupération des champs est en cours", "console.autocompleteSuggestions.apiLabel": "API", "console.autocompleteSuggestions.endpointLabel": "point de terminaison", "console.autocompleteSuggestions.methodLabel": "méthode", @@ -362,10 +360,6 @@ "console.loadingError.title": "Impossible de charger la console", "console.notification.clearHistory": "Effacer l'historique", "console.notification.disableSavingToHistory": "Désactiver l'enregistrement", - "console.notification.error.couldNotSaveRequestTitle": "Impossible d'enregistrer la requête dans l'historique de la console.", - "console.notification.error.historyQuotaReachedMessage": "L'historique des requêtes est arrivé à saturation. Effacez l'historique de la console ou désactivez l'enregistrement de nouvelles requêtes.", - "console.notification.error.noRequestSelectedTitle": "Aucune requête sélectionnée. Sélectionnez une requête en positionnant le curseur dessus.", - "console.notification.error.unknownErrorTitle": "Erreur de requête inconnue", "console.pageHeading": "Console", "console.requestInProgressBadgeText": "Requête en cours", "console.requestOptions.autoIndentButtonLabel": "Appliquer les indentations", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2ec8bc11bc0c8..e579f87771b20 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -320,8 +320,6 @@ "coloring.dynamicColoring.rangeType.label": "値型", "coloring.dynamicColoring.rangeType.number": "Number", "coloring.dynamicColoring.rangeType.percent": "割合(%)", - "console.autocomplete.addMethodMetaText": "メソド", - "console.autocomplete.fieldsFetchingAnnotation": "フィールドの取得を実行しています", "console.autocompleteSuggestions.apiLabel": "API", "console.autocompleteSuggestions.endpointLabel": "エンドポイント", "console.autocompleteSuggestions.methodLabel": "メソド", @@ -362,10 +360,6 @@ "console.loadingError.title": "コンソールを読み込めません", "console.notification.clearHistory": "履歴を消去", "console.notification.disableSavingToHistory": "保存を無効にする", - "console.notification.error.couldNotSaveRequestTitle": "リクエストをコンソール履歴に保存できませんでした。", - "console.notification.error.historyQuotaReachedMessage": "リクエスト履歴が満杯です。コンソール履歴を消去するか、新しいリクエストの保存を無効にしてください。", - "console.notification.error.noRequestSelectedTitle": "リクエストを選択していません。リクエストの中にカーソルを置いて選択します。", - "console.notification.error.unknownErrorTitle": "不明なリクエストエラー", "console.pageHeading": "コンソール", "console.requestInProgressBadgeText": "リクエストが進行中", "console.requestOptions.autoIndentButtonLabel": "インデントを適用", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 12ee59bb6fc9c..09662465c4833 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -319,8 +319,6 @@ "coloring.dynamicColoring.rangeType.label": "值类型", "coloring.dynamicColoring.rangeType.number": "数字", "coloring.dynamicColoring.rangeType.percent": "百分比", - "console.autocomplete.addMethodMetaText": "方法", - "console.autocomplete.fieldsFetchingAnnotation": "正在提取字段", "console.autocompleteSuggestions.apiLabel": "API", "console.autocompleteSuggestions.endpointLabel": "终端", "console.autocompleteSuggestions.methodLabel": "方法", @@ -361,10 +359,6 @@ "console.loadingError.title": "无法加载控制台", "console.notification.clearHistory": "清除历史记录", "console.notification.disableSavingToHistory": "禁止保存", - "console.notification.error.couldNotSaveRequestTitle": "无法将请求保存到控制台历史记录。", - "console.notification.error.historyQuotaReachedMessage": "请求历史记录已满。请清除控制台历史记录或禁止保存新的请求。", - "console.notification.error.noRequestSelectedTitle": "未选择任何请求。将鼠标置于请求内即可选择。", - "console.notification.error.unknownErrorTitle": "未知请求错误", "console.pageHeading": "控制台", "console.requestInProgressBadgeText": "进行中的请求", "console.requestOptions.autoIndentButtonLabel": "应用行首缩进", From 7df36721923159f45bc4fdbd26f76b20ad84249a Mon Sep 17 00:00:00 2001 From: Garrett Spong Date: Wed, 9 Oct 2024 10:17:47 -0600 Subject: [PATCH 075/110] [Security Assistant] V2 Knowledge Base Settings feedback and fixes (#194354) ## Summary This PR is a follow up to #192665 and addresses a bunch of feedback and fixes including: - [X] Adds support for updating/editing entries - [X] Fixes initial loading experience of the KB Settings Setup/Table - [X] Fixes two bugs where `semantic_text` and `text` must be declared for `IndexEntries` to work - [X] Add new Settings Context Menu items for KB and Alerts - [X] Add support for `required` entries in initial prompt * See [this trace](https://smith.langchain.com/public/84a17a31-8ce8-4bd9-911e-38a854484dd8/r) for included knowledge. Note that the KnowledgeBaseRetrievalTool was not selected. * Note: All prompts were updated to include the `{knowledge_history}` placeholder, and _not behind the feature flag_, as this will just be the empty case until the feature flag is enabled. TODO (in this or follow-up PR): - [ ] Add suggestions to `index` and `fields` inputs - [ ] Adds URL deeplinking to securityAssistantManagement - [ ] Fix bug where updating entry does not re-create embeddings (see [comment](https://github.com/elastic/kibana/pull/194354#discussion_r1786475496)) - [ ] Fix loading indicators when adding/editing entries - [ ] API integration tests for update API (@e40pud) ### Checklist Delete any items that are not applicable to this PR. - [X] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials * Docs being tracked in https://github.com/elastic/security-docs/issues/5337 for when feature flag is enabled - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Patryk Kopycinski --- .../entries/common_attributes.gen.ts | 6 +- .../entries/common_attributes.schema.yaml | 6 + .../impl/assistant/assistant_header/index.tsx | 79 +------- .../assistant_header/translations.ts | 28 +++ .../alerts_settings}/alerts_settings.test.tsx | 4 +- .../alerts_settings}/alerts_settings.tsx | 6 +- .../alerts_settings_management.tsx | 15 +- .../assistant_settings_management.test.tsx | 6 + .../assistant_settings_management.tsx | 8 +- .../settings_context_menu.tsx | 186 ++++++++++++++++++ .../impl/knowledge_base/alerts_range.tsx | 2 +- .../knowledge_base_settings.tsx | 2 +- .../document_entry_editor.tsx | 1 - .../index.tsx | 106 ++++++++-- .../index_entry_editor.tsx | 47 ++++- .../translations.ts | 41 +++- .../use_knowledge_base_table.tsx | 8 +- .../kbn-elastic-assistant/tsconfig.json | 1 + .../create_knowledge_base_entry.ts | 108 +++++++++- .../knowledge_base/helpers.ts | 5 +- .../knowledge_base/index.ts | 53 ++++- .../knowledge_base/types.ts | 33 ++++ .../server/ai_assistant_service/index.ts | 8 +- .../graphs/default_assistant_graph/graph.ts | 2 +- .../nodes/run_agent.ts | 14 ++ .../nodes/translations.ts | 6 +- .../graphs/default_assistant_graph/prompts.ts | 2 + .../entries/bulk_actions_route.ts | 23 ++- .../knowledge_base/entries/create_route.ts | 2 +- .../knowledge_base/entries/find_route.ts | 4 +- .../management_settings.test.tsx | 5 + .../stack_management/management_settings.tsx | 12 +- 32 files changed, 686 insertions(+), 143 deletions(-) rename x-pack/packages/kbn-elastic-assistant/impl/{alerts/settings => assistant/settings/alerts_settings}/alerts_settings.test.tsx (89%) rename x-pack/packages/kbn-elastic-assistant/impl/{alerts/settings => assistant/settings/alerts_settings}/alerts_settings.tsx (92%) rename x-pack/packages/kbn-elastic-assistant/impl/{alerts/settings => assistant/settings/alerts_settings}/alerts_settings_management.tsx (68%) create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/settings_context_menu/settings_context_menu.tsx diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/entries/common_attributes.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/entries/common_attributes.gen.ts index 1af5c46b1c130..c32517fec0860 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/entries/common_attributes.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/entries/common_attributes.gen.ts @@ -106,7 +106,11 @@ export type BaseCreateProps = z.infer; export const BaseCreateProps = BaseRequiredFields.merge(BaseDefaultableFields); export type BaseUpdateProps = z.infer; -export const BaseUpdateProps = BaseCreateProps.partial(); +export const BaseUpdateProps = BaseCreateProps.partial().merge( + z.object({ + id: NonEmptyString, + }) +); export type BaseResponseProps = z.infer; export const BaseResponseProps = BaseRequiredFields.merge(BaseDefaultableFields.required()); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/entries/common_attributes.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/entries/common_attributes.schema.yaml index c1c551059f04b..af7f4dd8e4221 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/entries/common_attributes.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/entries/common_attributes.schema.yaml @@ -112,6 +112,12 @@ components: allOf: - $ref: "#/components/schemas/BaseCreateProps" x-modify: partial + - type: object + properties: + id: + $ref: "../../common_attributes.schema.yaml#/components/schemas/NonEmptyString" + required: + - id BaseResponseProps: x-inline: true diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/index.tsx index d81a56fb97eef..ef37506f2af17 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/index.tsx @@ -5,16 +5,13 @@ * 2.0. */ -import React, { useState, useMemo, useCallback } from 'react'; +import React, { useMemo, useCallback } from 'react'; import { QueryObserverResult, RefetchOptions, RefetchQueryFilters } from '@tanstack/react-query'; import { EuiFlexGroup, EuiFlexItem, - EuiPopover, - EuiContextMenu, EuiButtonIcon, EuiPanel, - EuiConfirmModal, EuiToolTip, EuiSkeletonTitle, } from '@elastic/eui'; @@ -29,6 +26,7 @@ import { FlyoutNavigation } from '../assistant_overlay/flyout_navigation'; import { AssistantSettingsButton } from '../settings/assistant_settings_button'; import * as i18n from './translations'; import { AIConnector } from '../../connectorland/connector_selector'; +import { SettingsContextMenu } from '../settings/settings_context_menu/settings_context_menu'; interface OwnProps { selectedConversation: Conversation | undefined; @@ -94,21 +92,6 @@ export const AssistantHeader: React.FC = ({ [selectedConversation?.apiConfig?.connectorId] ); - const [isPopoverOpen, setPopover] = useState(false); - - const onButtonClick = useCallback(() => { - setPopover(!isPopoverOpen); - }, [isPopoverOpen]); - - const closePopover = useCallback(() => { - setPopover(false); - }, []); - - const [isResetConversationModalVisible, setIsResetConversationModalVisible] = useState(false); - - const closeDestroyModal = useCallback(() => setIsResetConversationModalVisible(false), []); - const showDestroyModal = useCallback(() => setIsResetConversationModalVisible(true), []); - const onConversationChange = useCallback( (updatedConversation: Conversation) => { onConversationSelected({ @@ -119,32 +102,6 @@ export const AssistantHeader: React.FC = ({ [onConversationSelected] ); - const panels = useMemo( - () => [ - { - id: 0, - items: [ - { - name: i18n.RESET_CONVERSATION, - css: css` - color: ${euiThemeVars.euiColorDanger}; - `, - onClick: showDestroyModal, - icon: 'refresh', - 'data-test-subj': 'clear-chat', - }, - ], - }, - ], - [showDestroyModal] - ); - - const handleReset = useCallback(() => { - onChatCleared(); - closeDestroyModal(); - closePopover(); - }, [onChatCleared, closeDestroyModal, closePopover]); - return ( <> = ({ - - } - isOpen={isPopoverOpen} - closePopover={closePopover} - panelPaddingSize="none" - anchorPosition="downLeft" - > - - + - {isResetConversationModalVisible && ( - -

    {i18n.CLEAR_CHAT_CONFIRMATION}

    -
    - )} ); }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/translations.ts index 68c926d2aa14c..e4f23e0970eb0 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/translations.ts @@ -7,6 +7,34 @@ import { i18n } from '@kbn/i18n'; +export const AI_ASSISTANT_SETTINGS = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.aiAssistantSettings', + { + defaultMessage: 'AI Assistant settings', + } +); + +export const ANONYMIZATION = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.anonymization', + { + defaultMessage: 'Anonymization', + } +); + +export const KNOWLEDGE_BASE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBase', + { + defaultMessage: 'Knowledge Base', + } +); + +export const ALERTS_TO_ANALYZE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.alertsToAnalyze', + { + defaultMessage: 'Alerts to analyze', + } +); + export const RESET_CONVERSATION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.resetConversation', { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.test.tsx similarity index 89% rename from x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.test.tsx index 3e730451ba1d5..2a5cae76d5e77 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.test.tsx @@ -9,8 +9,8 @@ import { render, screen, fireEvent } from '@testing-library/react'; import React from 'react'; import { AlertsSettings } from './alerts_settings'; -import { KnowledgeBaseConfig } from '../../assistant/types'; -import { DEFAULT_LATEST_ALERTS } from '../../assistant_context/constants'; +import { KnowledgeBaseConfig } from '../../types'; +import { DEFAULT_LATEST_ALERTS } from '../../../assistant_context/constants'; describe('AlertsSettings', () => { beforeEach(() => { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.tsx similarity index 92% rename from x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.tsx index e73bfa15e66be..60078178a1771 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.tsx @@ -9,9 +9,9 @@ import { EuiFlexGroup, EuiFormRow, EuiFlexItem, EuiSpacer, EuiText } from '@elas import { css } from '@emotion/react'; import React from 'react'; -import { KnowledgeBaseConfig } from '../../assistant/types'; -import { AlertsRange } from '../../knowledge_base/alerts_range'; -import * as i18n from '../../knowledge_base/translations'; +import { KnowledgeBaseConfig } from '../../types'; +import { AlertsRange } from '../../../knowledge_base/alerts_range'; +import * as i18n from '../../../knowledge_base/translations'; export const MIN_LATEST_ALERTS = 10; export const MAX_LATEST_ALERTS = 100; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings_management.tsx similarity index 68% rename from x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings_management.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings_management.tsx index d103c1a8c03c2..1a6f826bd415f 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings_management.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings_management.tsx @@ -7,19 +7,24 @@ import { EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; import React from 'react'; -import { KnowledgeBaseConfig } from '../../assistant/types'; -import { AlertsRange } from '../../knowledge_base/alerts_range'; -import * as i18n from '../../knowledge_base/translations'; +import { KnowledgeBaseConfig } from '../../types'; +import { AlertsRange } from '../../../knowledge_base/alerts_range'; +import * as i18n from '../../../knowledge_base/translations'; interface Props { knowledgeBase: KnowledgeBaseConfig; setUpdatedKnowledgeBaseSettings: React.Dispatch>; + hasBorder?: boolean; } +/** + * Replaces the AlertsSettings component used in the existing settings modal. Once the modal is + * fully removed we can delete that component in favor of this one. + */ export const AlertsSettingsManagement: React.FC = React.memo( - ({ knowledgeBase, setUpdatedKnowledgeBaseSettings }) => { + ({ knowledgeBase, setUpdatedKnowledgeBaseSettings, hasBorder = true }) => { return ( - +

    {i18n.ALERTS_LABEL}

    diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.test.tsx index d8e207cbb23cd..dd472b3ee87ab 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.test.tsx @@ -25,6 +25,7 @@ import { SYSTEM_PROMPTS_TAB, } from './const'; import { mockSystemPrompts } from '../../mock/system_prompt'; +import { DataViewsContract } from '@kbn/data-views-plugin/public'; const mockConversations = { [alertConvo.title]: alertConvo, @@ -53,8 +54,13 @@ const mockContext = { }, }; +const mockDataViews = { + getIndices: jest.fn(), +} as unknown as DataViewsContract; + const testProps = { selectedConversation: welcomeConvo, + dataViews: mockDataViews, }; jest.mock('../../assistant_context'); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx index 89c00fbf88773..4c50d14a5662e 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx @@ -9,6 +9,7 @@ import React, { useEffect, useMemo } from 'react'; import { EuiAvatar, EuiPageTemplate, EuiTitle, useEuiShadow, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; +import { DataViewsContract } from '@kbn/data-views-plugin/public'; import { Conversation } from '../../..'; import * as i18n from './translations'; import { useAssistantContext } from '../../assistant_context'; @@ -33,6 +34,7 @@ import { KnowledgeBaseSettingsManagement } from '../../knowledge_base/knowledge_ import { EvaluationSettings } from '.'; interface Props { + dataViews: DataViewsContract; selectedConversation: Conversation; } @@ -41,7 +43,7 @@ interface Props { * anonymization, knowledge base, and evaluation via the `isModelEvaluationEnabled` feature flag. */ export const AssistantSettingsManagement: React.FC = React.memo( - ({ selectedConversation: defaultSelectedConversation }) => { + ({ dataViews, selectedConversation: defaultSelectedConversation }) => { const { assistantFeatures: { assistantModelEvaluation: modelEvaluatorEnabled }, http, @@ -158,7 +160,9 @@ export const AssistantSettingsManagement: React.FC = React.memo( )} {selectedSettingsTab === QUICK_PROMPTS_TAB && } {selectedSettingsTab === ANONYMIZATION_TAB && } - {selectedSettingsTab === KNOWLEDGE_BASE_TAB && } + {selectedSettingsTab === KNOWLEDGE_BASE_TAB && ( + + )} {selectedSettingsTab === EVALUATION_TAB && } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/settings_context_menu/settings_context_menu.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/settings_context_menu/settings_context_menu.tsx new file mode 100644 index 0000000000000..b7f33b9a6af5a --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/settings_context_menu/settings_context_menu.tsx @@ -0,0 +1,186 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ReactElement, useCallback, useMemo, useState } from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiContextMenuPanel, + EuiContextMenuItem, + EuiConfirmModal, + EuiNotificationBadge, + EuiPopover, + EuiButtonIcon, +} from '@elastic/eui'; +import { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { useAssistantContext } from '../../../..'; +import * as i18n from '../../assistant_header/translations'; + +interface Params { + isDisabled?: boolean; + onChatCleared?: () => void; +} + +export const SettingsContextMenu: React.FC = React.memo( + ({ isDisabled = false, onChatCleared }: Params) => { + const { + navigateToApp, + knowledgeBase, + assistantFeatures: { assistantKnowledgeBaseByDefault: enableKnowledgeBaseByDefault }, + } = useAssistantContext(); + + const [isPopoverOpen, setPopover] = useState(false); + + const [isResetConversationModalVisible, setIsResetConversationModalVisible] = useState(false); + const closeDestroyModal = useCallback(() => setIsResetConversationModalVisible(false), []); + + const onButtonClick = useCallback(() => { + setPopover(!isPopoverOpen); + }, [isPopoverOpen]); + + const closePopover = useCallback(() => { + setPopover(false); + }, []); + + const showDestroyModal = useCallback(() => { + closePopover?.(); + setIsResetConversationModalVisible(true); + }, [closePopover]); + + const handleNavigateToSettings = useCallback( + () => + navigateToApp('management', { + path: 'kibana/securityAiAssistantManagement', + }), + [navigateToApp] + ); + + const handleNavigateToKnowledgeBase = useCallback( + () => + navigateToApp('management', { + path: 'kibana/securityAiAssistantManagement', + }), + [navigateToApp] + ); + + // We are migrating away from the settings modal in favor of the new Stack Management UI + // Currently behind `assistantKnowledgeBaseByDefault` FF + const newItems: ReactElement[] = useMemo( + () => [ + + {i18n.AI_ASSISTANT_SETTINGS} + , + + {i18n.ANONYMIZATION} + , + + {i18n.KNOWLEDGE_BASE} + , + + + {i18n.ALERTS_TO_ANALYZE} + + + {knowledgeBase.latestAlerts} + + + + , + ], + [handleNavigateToKnowledgeBase, handleNavigateToSettings, knowledgeBase] + ); + + const items = useMemo( + () => [ + ...(enableKnowledgeBaseByDefault ? newItems : []), + + {i18n.RESET_CONVERSATION} + , + ], + + [enableKnowledgeBaseByDefault, newItems, showDestroyModal] + ); + + const handleReset = useCallback(() => { + onChatCleared?.(); + closeDestroyModal(); + closePopover?.(); + }, [onChatCleared, closeDestroyModal, closePopover]); + + return ( + <> + + } + isOpen={isPopoverOpen} + closePopover={closePopover} + panelPaddingSize="none" + anchorPosition="leftUp" + > + + + {isResetConversationModalVisible && ( + +

    {i18n.CLEAR_CHAT_CONFIRMATION}

    +
    + )} + + ); + } +); + +SettingsContextMenu.displayName = 'SettingsContextMenu'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_range.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_range.tsx index 152f0a91a7d04..63bd86121dcc1 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_range.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_range.tsx @@ -12,7 +12,7 @@ import { MAX_LATEST_ALERTS, MIN_LATEST_ALERTS, TICK_INTERVAL, -} from '../alerts/settings/alerts_settings'; +} from '../assistant/settings/alerts_settings/alerts_settings'; import { KnowledgeBaseConfig } from '../assistant/types'; import { ALERTS_RANGE } from './translations'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx index b56abafafd5db..aa873decdcd87 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx @@ -23,7 +23,7 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; -import { AlertsSettings } from '../alerts/settings/alerts_settings'; +import { AlertsSettings } from '../assistant/settings/alerts_settings/alerts_settings'; import { useAssistantContext } from '../assistant_context'; import type { KnowledgeBaseConfig } from '../assistant/types'; import * as i18n from './translations'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/document_entry_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/document_entry_editor.tsx index 016da27d2c051..b33f221bfde3b 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/document_entry_editor.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/document_entry_editor.tsx @@ -127,7 +127,6 @@ export const DocumentEntryEditor: React.FC = React.memo(({ entry, setEntr id="requiredKnowledge" onChange={onRequiredKnowledgeChanged} checked={entry?.required ?? false} - disabled={true} /> diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx index a2097177a2ca4..34e8601e37ce7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx @@ -6,8 +6,12 @@ */ import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, EuiInMemoryTable, EuiLink, + EuiLoadingSpinner, EuiPanel, EuiSearchBarProps, EuiSpacer, @@ -23,7 +27,9 @@ import { KnowledgeBaseEntryCreateProps, KnowledgeBaseEntryResponse, } from '@kbn/elastic-assistant-common'; -import { AlertsSettingsManagement } from '../../alerts/settings/alerts_settings_management'; +import { css } from '@emotion/react'; +import { DataViewsContract } from '@kbn/data-views-plugin/public'; +import { AlertsSettingsManagement } from '../../assistant/settings/alerts_settings/alerts_settings_management'; import { useKnowledgeBaseEntries } from '../../assistant/api/knowledge_base/entries/use_knowledge_base_entries'; import { useAssistantContext } from '../../assistant_context'; import { useKnowledgeBaseTable } from './use_knowledge_base_table'; @@ -40,7 +46,7 @@ import { useFlyoutModalVisibility } from '../../assistant/common/components/assi import { IndexEntryEditor } from './index_entry_editor'; import { DocumentEntryEditor } from './document_entry_editor'; import { KnowledgeBaseSettings } from '../knowledge_base_settings'; -import { SetupKnowledgeBaseButton } from '../setup_knowledge_base_button'; +import { ESQL_RESOURCE, SetupKnowledgeBaseButton } from '../setup_knowledge_base_button'; import { useDeleteKnowledgeBaseEntries } from '../../assistant/api/knowledge_base/entries/use_delete_knowledge_base_entries'; import { isSystemEntry, @@ -51,14 +57,24 @@ import { useCreateKnowledgeBaseEntry } from '../../assistant/api/knowledge_base/ import { useUpdateKnowledgeBaseEntries } from '../../assistant/api/knowledge_base/entries/use_update_knowledge_base_entries'; import { SETTINGS_UPDATED_TOAST_TITLE } from '../../assistant/settings/translations'; import { KnowledgeBaseConfig } from '../../assistant/types'; +import { + isKnowledgeBaseSetup, + useKnowledgeBaseStatus, +} from '../../assistant/api/knowledge_base/use_knowledge_base_status'; + +interface Params { + dataViews: DataViewsContract; +} -export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { +export const KnowledgeBaseSettingsManagement: React.FC = React.memo(({ dataViews }) => { const { assistantFeatures: { assistantKnowledgeBaseByDefault: enableKnowledgeBaseByDefault }, http, toasts, } = useAssistantContext(); const [hasPendingChanges, setHasPendingChanges] = useState(false); + const { data: kbStatus, isFetched } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); + const isKbSetup = isKnowledgeBaseSetup(kbStatus); // Only needed for legacy settings management const { knowledgeBase, setUpdatedKnowledgeBaseSettings, resetSettings, saveSettings } = @@ -123,12 +139,12 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { // Flyout Save/Cancel Actions const onSaveConfirmed = useCallback(() => { - if (isKnowledgeBaseEntryCreateProps(selectedEntry)) { - createEntry(selectedEntry); - closeFlyout(); - } else if (isKnowledgeBaseEntryResponse(selectedEntry)) { + if (isKnowledgeBaseEntryResponse(selectedEntry)) { updateEntries([selectedEntry]); closeFlyout(); + } else if (isKnowledgeBaseEntryCreateProps(selectedEntry)) { + createEntry(selectedEntry); + closeFlyout(); } }, [closeFlyout, selectedEntry, createEntry, updateEntries]); @@ -137,7 +153,11 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { closeFlyout(); }, [closeFlyout]); - const { data: entries } = useKnowledgeBaseEntries({ + const { + data: entries, + isFetching: isFetchingEntries, + refetch: refetchEntries, + } = useKnowledgeBaseEntries({ http, toasts, enabled: enableKnowledgeBaseByDefault, @@ -169,6 +189,9 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { [deleteEntry, entries.data, getColumns, openFlyout] ); + // Refresh button + const handleRefreshTable = useCallback(() => refetchEntries(), [refetchEntries]); + const onDocumentClicked = useCallback(() => { setSelectedEntry({ type: DocumentEntryType.value, kbResource: 'user', source: 'user' }); openFlyout(); @@ -182,7 +205,30 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { const search: EuiSearchBarProps = useMemo( () => ({ toolsRight: ( - + + + + + + + + + + ), box: { incremental: true, @@ -190,7 +236,7 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { }, filters: [], }), - [onDocumentClicked, onIndexClicked] + [isFetchingEntries, handleRefreshTable, onDocumentClicked, onIndexClicked] ); const flyoutTitle = useMemo(() => { @@ -247,15 +293,40 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { ), }} /> - - + + + {!isFetched ? ( + + ) : isKbSetup ? ( + + ) : ( + <> + + + + + + + + + + + + + + )} + +
    { ) : ( >> } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx index 19f8cfbbc52ba..f5dd2df3bcaac 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx @@ -17,14 +17,16 @@ import { } from '@elastic/eui'; import React, { useCallback } from 'react'; import { IndexEntry } from '@kbn/elastic-assistant-common'; +import { DataViewsContract } from '@kbn/data-views-plugin/public'; import * as i18n from './translations'; interface Props { + dataViews: DataViewsContract; entry?: IndexEntry; setEntry: React.Dispatch>>; } -export const IndexEntryEditor: React.FC = React.memo(({ entry, setEntry }) => { +export const IndexEntryEditor: React.FC = React.memo(({ dataViews, entry, setEntry }) => { // Name const setName = useCallback( (e: React.ChangeEvent) => @@ -74,9 +76,17 @@ export const IndexEntryEditor: React.FC = React.memo(({ entry, setEntry } entry?.users?.length === 0 ? sharingOptions[1].value : sharingOptions[0].value; // Index + // TODO: For index field autocomplete + // const indexOptions = useMemo(() => { + // const indices = await dataViews.getIndices({ + // pattern: e[0]?.value ?? '', + // isRollupIndex: () => false, + // }); + // }, [dataViews]); const setIndex = useCallback( - (e: Array>) => - setEntry((prevEntry) => ({ ...prevEntry, index: e[0].value })), + async (e: Array>) => { + setEntry((prevEntry) => ({ ...prevEntry, index: e[0]?.value })); + }, [setEntry] ); @@ -162,30 +172,51 @@ export const IndexEntryEditor: React.FC = React.memo(({ entry, setEntry } - + - + + + + ); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/translations.ts index ed4a3676975b8..0cc16089fdaae 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/translations.ts @@ -251,14 +251,44 @@ export const ENTRY_FIELD_INPUT_LABEL = i18n.translate( export const ENTRY_DESCRIPTION_INPUT_LABEL = i18n.translate( 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryDescriptionInputLabel', { - defaultMessage: 'Description', + defaultMessage: 'Data Description', + } +); + +export const ENTRY_DESCRIPTION_HELP_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryDescriptionHelpLabel', + { + defaultMessage: + 'A description of the type of data in this index and/or when the assistant should look for data here.', } ); export const ENTRY_QUERY_DESCRIPTION_INPUT_LABEL = i18n.translate( 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryQueryDescriptionInputLabel', { - defaultMessage: 'Query Description', + defaultMessage: 'Query Instruction', + } +); + +export const ENTRY_QUERY_DESCRIPTION_HELP_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryQueryDescriptionHelpLabel', + { + defaultMessage: 'Any instructions for extracting the search query from the user request.', + } +); + +export const ENTRY_OUTPUT_FIELDS_INPUT_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryOutputFieldsInputLabel', + { + defaultMessage: 'Output Fields', + } +); + +export const ENTRY_OUTPUT_FIELDS_HELP_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryOutputFieldsHelpLabel', + { + defaultMessage: + 'What fields should be sent to the LLM. Leave empty to send the entire document.', } ); @@ -269,6 +299,13 @@ export const ENTRY_INPUT_PLACEHOLDER = i18n.translate( } ); +export const ENTRY_FIELD_PLACEHOLDER = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryFieldPlaceholder', + { + defaultMessage: 'semantic_text', + } +); + export const KNOWLEDGE_BASE_DOCUMENTATION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.knowledgeBaseDocumentation', { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/use_knowledge_base_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/use_knowledge_base_table.tsx index 5af360a598205..d0038169cd597 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/use_knowledge_base_table.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/use_knowledge_base_table.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiAvatar, EuiBadge, EuiBasicTableColumn, EuiIcon, EuiLink, EuiText } from '@elastic/eui'; +import { EuiAvatar, EuiBadge, EuiBasicTableColumn, EuiIcon, EuiText } from '@elastic/eui'; import { css } from '@emotion/react'; import React, { useCallback } from 'react'; import { FormattedDate } from '@kbn/i18n-react'; @@ -32,7 +32,7 @@ export const useKnowledgeBaseTable = () => { if (['esql', 'security_labs'].includes(entry.kbResource)) { return 'logoElastic'; } - return 'visText'; + return 'document'; } else if (entry.type === IndexEntryType.value) { return 'index'; } @@ -61,9 +61,7 @@ export const useKnowledgeBaseTable = () => { }, { name: i18n.COLUMN_NAME, - render: (entry: KnowledgeBaseEntryResponse) => ( - onEntryNameClicked(entry)}>{entry.name} - ), + render: ({ name }: KnowledgeBaseEntryResponse) => name, sortable: ({ name }: KnowledgeBaseEntryResponse) => name, width: '30%', }, diff --git a/x-pack/packages/kbn-elastic-assistant/tsconfig.json b/x-pack/packages/kbn-elastic-assistant/tsconfig.json index ed2631b597bd6..8d19fa86f4d11 100644 --- a/x-pack/packages/kbn-elastic-assistant/tsconfig.json +++ b/x-pack/packages/kbn-elastic-assistant/tsconfig.json @@ -30,5 +30,6 @@ "@kbn/core-doc-links-browser", "@kbn/core", "@kbn/zod", + "@kbn/data-views-plugin", ] } diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts index 7dac58ddecc9b..aef66d406bf74 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts @@ -12,10 +12,11 @@ import { DocumentEntryCreateFields, KnowledgeBaseEntryCreateProps, KnowledgeBaseEntryResponse, + KnowledgeBaseEntryUpdateProps, Metadata, } from '@kbn/elastic-assistant-common'; import { getKnowledgeBaseEntry } from './get_knowledge_base_entry'; -import { CreateKnowledgeBaseEntrySchema } from './types'; +import { CreateKnowledgeBaseEntrySchema, UpdateKnowledgeBaseEntrySchema } from './types'; export interface CreateKnowledgeBaseEntryParams { esClient: ElasticsearchClient; @@ -77,6 +78,111 @@ export const createKnowledgeBaseEntry = async ({ } }; +interface TransformToUpdateSchemaProps { + user: AuthenticatedUser; + updatedAt: string; + entry: KnowledgeBaseEntryUpdateProps; + global?: boolean; +} + +export const transformToUpdateSchema = ({ + user, + updatedAt, + entry, + global = false, +}: TransformToUpdateSchemaProps): UpdateKnowledgeBaseEntrySchema => { + const base = { + id: entry.id, + updated_at: updatedAt, + updated_by: user.profile_uid ?? 'unknown', + name: entry.name, + type: entry.type, + users: global + ? [] + : [ + { + id: user.profile_uid, + name: user.username, + }, + ], + }; + + if (entry.type === 'index') { + const { inputSchema, outputFields, queryDescription, ...restEntry } = entry; + return { + ...base, + ...restEntry, + query_description: queryDescription, + input_schema: + entry.inputSchema?.map((schema) => ({ + field_name: schema.fieldName, + field_type: schema.fieldType, + description: schema.description, + })) ?? undefined, + output_fields: outputFields ?? undefined, + }; + } + return { + ...base, + kb_resource: entry.kbResource, + required: entry.required ?? false, + source: entry.source, + text: entry.text, + vector: undefined, + }; +}; + +export const getUpdateScript = ({ + entry, + isPatch, +}: { + entry: UpdateKnowledgeBaseEntrySchema; + isPatch?: boolean; +}) => { + return { + source: ` + if (params.assignEmpty == true || params.containsKey('name')) { + ctx._source.name = params.name; + } + if (params.assignEmpty == true || params.containsKey('type')) { + ctx._source.type = params.type; + } + if (params.assignEmpty == true || params.containsKey('users')) { + ctx._source.users = params.users; + } + if (params.assignEmpty == true || params.containsKey('query_description')) { + ctx._source.query_description = params.query_description; + } + if (params.assignEmpty == true || params.containsKey('input_schema')) { + ctx._source.input_schema = params.input_schema; + } + if (params.assignEmpty == true || params.containsKey('output_fields')) { + ctx._source.output_fields = params.output_fields; + } + if (params.assignEmpty == true || params.containsKey('kb_resource')) { + ctx._source.kb_resource = params.kb_resource; + } + if (params.assignEmpty == true || params.containsKey('required')) { + ctx._source.required = params.required; + } + if (params.assignEmpty == true || params.containsKey('source')) { + ctx._source.source = params.source; + } + if (params.assignEmpty == true || params.containsKey('text')) { + ctx._source.text = params.text; + } + ctx._source.updated_at = params.updated_at; + ctx._source.updated_by = params.updated_by; + `, + lang: 'painless', + params: { + ...entry, // when assigning undefined in painless, it will remove property and wil set it to null + // for patch we don't want to remove unspecified value in payload + assignEmpty: !(isPatch ?? true), + }, + }; +}; + interface TransformToCreateSchemaProps { createdAt: string; spaceId: string; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts index 8ff8de6cfb408..de76a38135f0b 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts @@ -6,6 +6,7 @@ */ import { z } from '@kbn/zod'; +import { get } from 'lodash'; import { DynamicStructuredTool } from '@langchain/core/tools'; import { errors } from '@elastic/elasticsearch'; import { QueryDslQueryContainer, SearchRequest } from '@elastic/elasticsearch/lib/api/types'; @@ -189,7 +190,7 @@ export const getStructuredToolForIndexEntry = ({ standard: { query: { nested: { - path: 'semantic_text.inference.chunks', + path: `${indexEntry.field}.inference.chunks`, query: { sparse_vector: { inference_id: elserId, @@ -220,7 +221,7 @@ export const getStructuredToolForIndexEntry = ({ }, {}); } return { - text: (hit._source as { text: string }).text, + text: get(hit._source, `${indexEntry.field}.inference.chunks[0].text`), }; }); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts index a81e18630138e..1906f59ab4b32 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts @@ -15,6 +15,7 @@ import { Document } from 'langchain/document'; import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { DocumentEntryType, + DocumentEntry, IndexEntry, KnowledgeBaseEntryCreateProps, KnowledgeBaseEntryResponse, @@ -431,7 +432,9 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { ); this.options.logger.debug( () => - `getKnowledgeBaseDocuments() - Similarity Search Results:\n ${JSON.stringify(results)}` + `getKnowledgeBaseDocuments() - Similarity Search returned [${JSON.stringify( + results.length + )}] results` ); return results; @@ -441,6 +444,47 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { } }; + /** + * Returns all global and current user's private `required` document entries. + */ + public getRequiredKnowledgeBaseDocumentEntries = async (): Promise => { + const user = this.options.currentUser; + if (user == null) { + throw new Error( + 'Authenticated user not found! Ensure kbDataClient was initialized from a request.' + ); + } + + try { + const userFilter = getKBUserFilter(user); + const results = await this.findDocuments({ + // Note: This is a magic number to set some upward bound as to not blow the context with too + // many historical KB entries. Ideally we'd query for all and token trim. + perPage: 100, + page: 1, + sortField: 'created_at', + sortOrder: 'asc', + filter: `${userFilter} AND type:document AND kb_resource:user AND required:true`, + }); + this.options.logger.debug( + `kbDataClient.getRequiredKnowledgeBaseDocumentEntries() - results:\n${JSON.stringify( + results + )}` + ); + + if (results) { + return transformESSearchToKnowledgeBaseEntry(results.data) as DocumentEntry[]; + } + } catch (e) { + this.options.logger.error( + `kbDataClient.getRequiredKnowledgeBaseDocumentEntries() - Failed to fetch DocumentEntries` + ); + return []; + } + + return []; + }; + /** * Creates a new Knowledge Base Entry. * @@ -479,7 +523,10 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { }; /** - * Returns AssistantTools for any 'relevant' KB IndexEntries that exist in the knowledge base + * Returns AssistantTools for any 'relevant' KB IndexEntries that exist in the knowledge base. + * + * Note: Accepts esClient so retrieval can be scoped to the current user as esClient on kbDataClient + * is scoped to system user. */ public getAssistantTools = async ({ assistantToolParams, @@ -507,7 +554,7 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { page: 1, sortField: 'created_at', sortOrder: 'asc', - filter: `${userFilter}${` AND type:index`}`, // TODO: Support global tools (no user filter), and filter by space as well + filter: `${userFilter} AND type:index`, }); this.options.logger.debug( `kbDataClient.getAssistantTools() - results:\n${JSON.stringify(results, null, 2)}` diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts index ecf9260e999d2..3de1a15d79b2a 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts @@ -82,6 +82,39 @@ export interface LegacyEsKnowledgeBaseEntrySchema { model_id: string; }; } +export interface UpdateKnowledgeBaseEntrySchema { + id: string; + created_at?: string; + created_by?: string; + updated_at?: string; + updated_by?: string; + users?: Array<{ + id?: string; + name?: string; + }>; + name?: string; + type?: string; + // Document Entry Fields + kb_resource?: string; + required?: boolean; + source?: string; + text?: string; + vector?: { + tokens: Record; + model_id: string; + }; + // Index Entry Fields + index?: string; + field?: string; + description?: string; + query_description?: string; + input_schema?: Array<{ + field_name: string; + field_type: string; + description: string; + }>; + output_fields?: string[]; +} export interface CreateKnowledgeBaseEntrySchema { '@timestamp'?: string; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts index 942f94c203873..08912f41a8bbc 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts @@ -84,6 +84,7 @@ export class AIAssistantService { private isKBSetupInProgress: boolean = false; // Temporary 'feature flag' to determine if we should initialize the new kb mappings, toggled when accessing kbDataClient private v2KnowledgeBaseEnabled: boolean = false; + private hasInitializedV2KnowledgeBase: boolean = false; constructor(private readonly options: AIAssistantServiceOpts) { this.initialized = false; @@ -363,8 +364,13 @@ export class AIAssistantService { // If either v2 KB or a modelIdOverride is provided, we need to reinitialize all persistence resources to make sure // they're using the correct model/mappings. Technically all existing KB data is stale since it was created // with a different model/mappings, but modelIdOverride is only intended for testing purposes at this time - if (opts.v2KnowledgeBaseEnabled || opts.modelIdOverride != null) { + // Added hasInitializedV2KnowledgeBase to prevent the console noise from re-init on each KB request + if ( + !this.hasInitializedV2KnowledgeBase && + (opts.v2KnowledgeBaseEnabled || opts.modelIdOverride != null) + ) { await this.initializeResources(); + this.hasInitializedV2KnowledgeBase = true; } const res = await this.checkResourcesInstallation(opts); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/graph.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/graph.ts index dba756b9f3c9e..4688caa176b56 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/graph.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/graph.ts @@ -137,7 +137,7 @@ export const getDefaultAssistantGraph = ({ }) ) .addNode(NodeType.AGENT, (state: AgentState) => - runAgent({ ...nodeParams, state, agentRunnable }) + runAgent({ ...nodeParams, state, agentRunnable, kbDataClient: dataClients?.kbDataClient }) ) .addNode(NodeType.TOOLS, (state: AgentState) => executeTools({ ...nodeParams, state, tools })) .addNode(NodeType.RESPOND, (state: AgentState) => diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/run_agent.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/run_agent.ts index 2d076f6bd1472..053254a1d99b3 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/run_agent.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/run_agent.ts @@ -10,15 +10,20 @@ import { AgentRunnableSequence } from 'langchain/dist/agents/agent'; import { formatLatestUserMessage } from '../prompts'; import { AgentState, NodeParamsBase } from '../types'; import { NodeType } from '../constants'; +import { AIAssistantKnowledgeBaseDataClient } from '../../../../../ai_assistant_data_clients/knowledge_base'; export interface RunAgentParams extends NodeParamsBase { state: AgentState; config?: RunnableConfig; agentRunnable: AgentRunnableSequence; + kbDataClient?: AIAssistantKnowledgeBaseDataClient; } export const AGENT_NODE_TAG = 'agent_run'; +const KNOWLEDGE_HISTORY_PREFIX = 'Knowledge History:'; +const NO_KNOWLEDGE_HISTORY = '[No existing knowledge history]'; + /** * Node to run the agent * @@ -26,18 +31,27 @@ export const AGENT_NODE_TAG = 'agent_run'; * @param state - The current state of the graph * @param config - Any configuration that may've been supplied * @param agentRunnable - The agent to run + * @param kbDataClient - Data client for accessing the Knowledge Base on behalf of the current user */ export async function runAgent({ logger, state, agentRunnable, config, + kbDataClient, }: RunAgentParams): Promise> { logger.debug(() => `${NodeType.AGENT}: Node state:\n${JSON.stringify(state, null, 2)}`); + const knowledgeHistory = await kbDataClient?.getRequiredKnowledgeBaseDocumentEntries(); + const agentOutcome = await agentRunnable.withConfig({ tags: [AGENT_NODE_TAG] }).invoke( { ...state, + knowledge_history: `${KNOWLEDGE_HISTORY_PREFIX}\n${ + knowledgeHistory?.length + ? JSON.stringify(knowledgeHistory.map((e) => e.text)) + : NO_KNOWLEDGE_HISTORY + }`, // prepend any user prompt (gemini) input: formatLatestUserMessage(state.input, state.llmType), chat_history: state.messages, // TODO: Message de-dupe with ...state spread diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/translations.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/translations.ts index e55e1081e6474..e5a1c14846e23 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/translations.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/translations.ts @@ -8,8 +8,10 @@ const YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT = 'You are a security analyst and expert in resolving security incidents. Your role is to assist by answering questions about Elastic Security.'; const IF_YOU_DONT_KNOW_THE_ANSWER = 'Do not answer questions unrelated to Elastic Security.'; +export const KNOWLEDGE_HISTORY = + 'If available, use the Knowledge History provided to try and answer the question. If not provided, you can try and query for additional knowledge via the KnowledgeBaseRetrievalTool.'; -export const DEFAULT_SYSTEM_PROMPT = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER}`; +export const DEFAULT_SYSTEM_PROMPT = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER} ${KNOWLEDGE_HISTORY}`; // system prompt from @afirstenberg const BASE_GEMINI_PROMPT = 'You are an assistant that is an expert at using tools and Elastic Security, doing your best to use these tools to answer questions or follow instructions. It is very important to use tools to answer the question or follow the instructions rather than coming up with your own answer. Tool calls are good. Sometimes you may need to make several tool calls to accomplish the task or get an answer to the question that was asked. Use as many tool calls as necessary.'; @@ -19,7 +21,7 @@ export const GEMINI_SYSTEM_PROMPT = `${BASE_GEMINI_PROMPT} ${KB_CATCH}`; export const BEDROCK_SYSTEM_PROMPT = `Use tools as often as possible, as they have access to the latest data and syntax. Always return value from ESQLKnowledgeBaseTool as is. Never return tags in the response, but make sure to include tags content in the response. Do not reflect on the quality of the returned search results in your response.`; export const GEMINI_USER_PROMPT = `Now, always using the tools at your disposal, step by step, come up with a response to this request:\n\n`; -export const STRUCTURED_SYSTEM_PROMPT = `Respond to the human as helpfully and accurately as possible. You have access to the following tools: +export const STRUCTURED_SYSTEM_PROMPT = `Respond to the human as helpfully and accurately as possible. ${KNOWLEDGE_HISTORY} You have access to the following tools: {tools} diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/prompts.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/prompts.ts index 883047ed7b9df..05cc8b50852f5 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/prompts.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/prompts.ts @@ -17,6 +17,7 @@ import { export const formatPrompt = (prompt: string, additionalPrompt?: string) => ChatPromptTemplate.fromMessages([ ['system', additionalPrompt ? `${prompt}\n\n${additionalPrompt}` : prompt], + ['placeholder', '{knowledge_history}'], ['placeholder', '{chat_history}'], ['human', '{input}'], ['placeholder', '{agent_scratchpad}'], @@ -39,6 +40,7 @@ export const geminiToolCallingAgentPrompt = formatPrompt(systemPrompts.gemini); export const formatPromptStructured = (prompt: string, additionalPrompt?: string) => ChatPromptTemplate.fromMessages([ ['system', additionalPrompt ? `${prompt}\n\n${additionalPrompt}` : prompt], + ['placeholder', '{knowledge_history}'], ['placeholder', '{chat_history}'], [ 'human', diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts index 96045b17e6171..ce3f0c8c92693 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts @@ -22,11 +22,18 @@ import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/ import { performChecks } from '../../helpers'; import { KNOWLEDGE_BASE_ENTRIES_TABLE_MAX_PAGE_SIZE } from '../../../../common/constants'; -import { EsKnowledgeBaseEntrySchema } from '../../../ai_assistant_data_clients/knowledge_base/types'; +import { + EsKnowledgeBaseEntrySchema, + UpdateKnowledgeBaseEntrySchema, +} from '../../../ai_assistant_data_clients/knowledge_base/types'; import { ElasticAssistantPluginRouter } from '../../../types'; import { buildResponse } from '../../utils'; import { transformESSearchToKnowledgeBaseEntry } from '../../../ai_assistant_data_clients/knowledge_base/transforms'; -import { transformToCreateSchema } from '../../../ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry'; +import { + getUpdateScript, + transformToCreateSchema, + transformToUpdateSchema, +} from '../../../ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry'; export interface BulkOperationError { message: string; @@ -210,7 +217,17 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug }) ), documentsToDelete: body.delete?.ids, - documentsToUpdate: [], // TODO: Support bulk update + documentsToUpdate: body.update?.map((entry) => + // TODO: KB-RBAC check, required when users != null as entry will either be created globally if empty + transformToUpdateSchema({ + user: authenticatedUser, + updatedAt: changedAt, + entry, + global: entry.users != null && entry.users.length === 0, + }) + ), + getUpdateScript: (entry: UpdateKnowledgeBaseEntrySchema) => + getUpdateScript({ entry, isPatch: true }), authenticatedUser, }); const created = diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts index 3dbb5a9cf930e..51e3d48505ec2 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts @@ -66,7 +66,7 @@ export const createKnowledgeBaseEntryRoute = (router: ElasticAssistantPluginRout logger.debug(() => `Creating KB Entry:\n${JSON.stringify(request.body)}`); const createResponse = await kbDataClient?.createKnowledgeBaseEntry({ knowledgeBaseEntry: request.body, - // TODO: KB-RBAC check, required when users != null as entry will either be created globally if empty, or for specific users (only admin API feature) + // TODO: KB-RBAC check, required when users != null as entry will either be created globally if empty global: request.body.users != null && request.body.users.length === 0, }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts index f10876c4be3ee..356d5d9150a67 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts @@ -74,7 +74,7 @@ export const findKnowledgeBaseEntriesRoute = (router: ElasticAssistantPluginRout }); const currentUser = ctx.elasticAssistant.getCurrentUser(); const userFilter = getKBUserFilter(currentUser); - const systemFilter = ` AND kb_resource:"user"`; + const systemFilter = ` AND (kb_resource:"user" OR type:"index")`; const additionalFilter = query.filter ? ` AND ${query.filter}` : ''; const result = await kbDataClient?.findDocuments({ @@ -160,7 +160,7 @@ export const findKnowledgeBaseEntriesRoute = (router: ElasticAssistantPluginRout body: { perPage: result.perPage, page: result.page, - total: result.total, + total: result.total + systemEntries.length, data: [...transformESSearchToKnowledgeBaseEntry(result.data), ...systemEntries], }, }); diff --git a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.test.tsx b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.test.tsx index 1c988d14e845f..65a0ab84d3412 100644 --- a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.test.tsx +++ b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.test.tsx @@ -77,6 +77,11 @@ describe('ManagementSettings', () => { securitySolutionAssistant: { 'ai-assistant': false }, }, }, + data: { + dataViews: { + getIndices: jest.fn(), + }, + }, security: { userProfiles: { getCurrent: jest.fn().mockResolvedValue({ data: { color: 'blue', initials: 'P' } }), diff --git a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx index 90e39398474ec..48d89e02dfc71 100644 --- a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx +++ b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx @@ -37,6 +37,7 @@ export const ManagementSettings = React.memo(() => { securitySolutionAssistant: { 'ai-assistant': securityAIAssistantEnabled }, }, }, + data: { dataViews }, security, } = useKibana().services; @@ -46,8 +47,8 @@ export const ManagementSettings = React.memo(() => { security?.userProfiles.getCurrent<{ avatar: UserAvatar }>({ dataPath: 'avatar', }), - select: (data) => { - return data.data.avatar; + select: (d) => { + return d.data.avatar; }, keepPreviousData: true, refetchOnWindowFocus: false, @@ -79,7 +80,12 @@ export const ManagementSettings = React.memo(() => { } if (conversations) { - return ; + return ( + + ); } return <>; From 2327681de7306c20bcca69fe77660c0a586c979d Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Oct 2024 18:31:42 +0200 Subject: [PATCH 076/110] [HTTP/OAS] Ability to exclude routes from introspection (#192675) --- .../src/http_resources_service.test.ts | 17 +++++ .../src/http_resources_service.ts | 1 + .../src/router.ts | 3 +- .../src/http_service.ts | 76 +++++++++++-------- .../http/core-http-server/src/router/route.ts | 11 ++- packages/kbn-router-to-openapispec/index.ts | 5 +- .../src/util.test.ts | 9 +++ .../kbn-router-to-openapispec/src/util.ts | 3 +- .../server/integration_tests/http/oas.test.ts | 4 +- 9 files changed, 91 insertions(+), 38 deletions(-) diff --git a/packages/core/http/core-http-resources-server-internal/src/http_resources_service.test.ts b/packages/core/http/core-http-resources-server-internal/src/http_resources_service.test.ts index efce905e6564f..1a7757d4e1eaa 100644 --- a/packages/core/http/core-http-resources-server-internal/src/http_resources_service.test.ts +++ b/packages/core/http/core-http-resources-server-internal/src/http_resources_service.test.ts @@ -69,6 +69,23 @@ describe('HttpResources service', () => { expect(registeredRouteConfig.options?.access).toBe('internal'); }); + it('registration defaults to excluded from OAS', () => { + register({ ...routeConfig, options: { access: 'internal' } }, async (ctx, req, res) => + res.ok() + ); + const [[registeredRouteConfig]] = router.get.mock.calls; + expect(registeredRouteConfig.options?.excludeFromOAS).toBe(true); + }); + + it('registration allows being included in OAS', () => { + register( + { ...routeConfig, options: { access: 'internal', excludeFromOAS: false } }, + async (ctx, req, res) => res.ok() + ); + const [[registeredRouteConfig]] = router.get.mock.calls; + expect(registeredRouteConfig.options?.excludeFromOAS).toBe(false); + }); + describe('renderCoreApp', () => { it('formats successful response', async () => { register(routeConfig, async (ctx, req, res) => { diff --git a/packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts b/packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts index d9e75d49e72cf..29114c0dffc07 100644 --- a/packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts +++ b/packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts @@ -89,6 +89,7 @@ export class HttpResourcesService implements CoreService !route.isVersioned); } - return [...this.routes]; + return this.routes; } public handleLegacyErrors = wrapErrors; diff --git a/packages/core/http/core-http-server-internal/src/http_service.ts b/packages/core/http/core-http-server-internal/src/http_service.ts index e5a82f0abefb0..3f803b06f15fd 100644 --- a/packages/core/http/core-http-server-internal/src/http_service.ts +++ b/packages/core/http/core-http-server-internal/src/http_service.ts @@ -9,9 +9,13 @@ import { Observable, Subscription, combineLatest, firstValueFrom, of, mergeMap } from 'rxjs'; import { map } from 'rxjs'; +import { schema, TypeOf } from '@kbn/config-schema'; import { pick, Semaphore } from '@kbn/std'; -import { generateOpenApiDocument } from '@kbn/router-to-openapispec'; +import { + generateOpenApiDocument, + type GenerateOpenApiDocumentOptionsFilters, +} from '@kbn/router-to-openapispec'; import { Logger } from '@kbn/logging'; import { Env } from '@kbn/config'; import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; @@ -254,49 +258,55 @@ export class HttpService const baseUrl = basePath.publicBaseUrl ?? `http://localhost:${config.port}${basePath.serverBasePath}`; + const stringOrStringArraySchema = schema.oneOf([ + schema.string(), + schema.arrayOf(schema.string()), + ]); + const querySchema = schema.object({ + access: schema.maybe(schema.oneOf([schema.literal('public'), schema.literal('internal')])), + excludePathsMatching: schema.maybe(stringOrStringArraySchema), + pathStartsWith: schema.maybe(stringOrStringArraySchema), + pluginId: schema.maybe(schema.string()), + version: schema.maybe(schema.string()), + }); + server.route({ path: '/api/oas', method: 'GET', handler: async (req, h) => { - const version = req.query?.version; - - let pathStartsWith: undefined | string[]; - if (typeof req.query?.pathStartsWith === 'string') { - pathStartsWith = [req.query.pathStartsWith]; - } else { - pathStartsWith = req.query?.pathStartsWith; - } - - let excludePathsMatching: undefined | string[]; - if (typeof req.query?.excludePathsMatching === 'string') { - excludePathsMatching = [req.query.excludePathsMatching]; - } else { - excludePathsMatching = req.query?.excludePathsMatching; + let filters: GenerateOpenApiDocumentOptionsFilters; + let query: TypeOf; + try { + query = querySchema.validate(req.query); + filters = { + ...query, + excludePathsMatching: + typeof query.excludePathsMatching === 'string' + ? [query.excludePathsMatching] + : query.excludePathsMatching, + pathStartsWith: + typeof query.pathStartsWith === 'string' + ? [query.pathStartsWith] + : query.pathStartsWith, + }; + } catch (e) { + return h.response({ message: e.message }).code(400); } - - const pluginId = req.query?.pluginId; - - const access = req.query?.access as 'public' | 'internal' | undefined; - if (access && !['public', 'internal'].some((a) => a === access)) { - return h - .response({ - message: 'Invalid access query parameter. Must be one of "public" or "internal".', - }) - .code(400); - } - return await firstValueFrom( of(1).pipe( HttpService.generateOasSemaphore.acquire(), mergeMap(async () => { try { // Potentially quite expensive - const result = generateOpenApiDocument(this.httpServer.getRouters({ pluginId }), { - baseUrl, - title: 'Kibana HTTP APIs', - version: '0.0.0', // TODO get a better version here - filters: { pathStartsWith, excludePathsMatching, access, version }, - }); + const result = generateOpenApiDocument( + this.httpServer.getRouters({ pluginId: query.pluginId }), + { + baseUrl, + title: 'Kibana HTTP APIs', + version: '0.0.0', // TODO get a better version here + filters, + } + ); return h.response(result); } catch (e) { this.log.error(e); diff --git a/packages/core/http/core-http-server/src/router/route.ts b/packages/core/http/core-http-server/src/router/route.ts index bdf4f9f03c784..194191e6f423f 100644 --- a/packages/core/http/core-http-server/src/router/route.ts +++ b/packages/core/http/core-http-server/src/router/route.ts @@ -215,7 +215,7 @@ export interface RouteConfigOptions { /** * Defines intended request origin of the route: * - public. The route is public, declared stable and intended for external access. - * In the future, may require an incomming request to contain a specified header. + * In the future, may require an incoming request to contain a specified header. * - internal. The route is internal and intended for internal access only. * * Defaults to 'internal' If not declared, @@ -284,6 +284,14 @@ export interface RouteConfigOptions { */ deprecated?: boolean; + /** + * Whether this route should be treated as "invisible" and excluded from router + * OAS introspection. + * + * @default false + */ + excludeFromOAS?: boolean; + /** * Release version or date that this route will be removed * Use with `deprecated: true` @@ -292,6 +300,7 @@ export interface RouteConfigOptions { * @example 9.0.0 */ discontinued?: string; + /** * Defines the security requirements for a route, including authorization and authentication. * diff --git a/packages/kbn-router-to-openapispec/index.ts b/packages/kbn-router-to-openapispec/index.ts index 17f8253348ab3..1869167db0323 100644 --- a/packages/kbn-router-to-openapispec/index.ts +++ b/packages/kbn-router-to-openapispec/index.ts @@ -7,4 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { generateOpenApiDocument } from './src/generate_oas'; +export { + generateOpenApiDocument, + type GenerateOpenApiDocumentOptionsFilters, +} from './src/generate_oas'; diff --git a/packages/kbn-router-to-openapispec/src/util.test.ts b/packages/kbn-router-to-openapispec/src/util.test.ts index 79b4ddf8eba84..abbb605df79e5 100644 --- a/packages/kbn-router-to-openapispec/src/util.test.ts +++ b/packages/kbn-router-to-openapispec/src/util.test.ts @@ -163,6 +163,15 @@ describe('prepareRoutes', () => { output: [{ path: '/api/foo', options: { access: pub } }], filters: { excludePathsMatching: ['/api/b'], access: pub }, }, + { + input: [ + { path: '/api/foo', options: { access: pub, excludeFromOAS: true } }, + { path: '/api/bar', options: { access: internal } }, + { path: '/api/baz', options: { access: pub } }, + ], + output: [{ path: '/api/baz', options: { access: pub } }], + filters: { excludePathsMatching: ['/api/bar'], access: pub }, + }, ])('returns the expected routes #%#', ({ input, output, filters }) => { expect(prepareRoutes(input, filters)).toEqual(output); }); diff --git a/packages/kbn-router-to-openapispec/src/util.ts b/packages/kbn-router-to-openapispec/src/util.ts index 1aa2a080ccc18..55f7348dc199a 100644 --- a/packages/kbn-router-to-openapispec/src/util.ts +++ b/packages/kbn-router-to-openapispec/src/util.ts @@ -105,13 +105,14 @@ export const getVersionedHeaderParam = ( }); export const prepareRoutes = < - R extends { path: string; options: { access?: 'public' | 'internal' } } + R extends { path: string; options: { access?: 'public' | 'internal'; excludeFromOAS?: boolean } } >( routes: R[], filters: GenerateOpenApiDocumentOptionsFilters = {} ): R[] => { if (Object.getOwnPropertyNames(filters).length === 0) return routes; return routes.filter((route) => { + if (route.options.excludeFromOAS) return false; if ( filters.excludePathsMatching && filters.excludePathsMatching.some((ex) => route.path.startsWith(ex)) diff --git a/src/core/server/integration_tests/http/oas.test.ts b/src/core/server/integration_tests/http/oas.test.ts index c6a1d4e308356..413b8b01754b5 100644 --- a/src/core/server/integration_tests/http/oas.test.ts +++ b/src/core/server/integration_tests/http/oas.test.ts @@ -193,7 +193,9 @@ it('only accepts "public" or "internal" for "access" query param', async () => { const server = await startService({ config: { server: { oas: { enabled: true } } } }); const result = await supertest(server.listener).get('/api/oas').query({ access: 'invalid' }); expect(result.body.message).toBe( - 'Invalid access query parameter. Must be one of "public" or "internal".' + `[access]: types that failed validation: +- [access.0]: expected value to equal [public] +- [access.1]: expected value to equal [internal]` ); expect(result.status).toBe(400); }); From 61251bfdaffdb621558fff96d78cc8b2260c0abe Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Oct 2024 18:33:54 +0200 Subject: [PATCH 077/110] [Http] Added version header to unversioned, public routes (#195464) --- .../src/router.test.ts | 50 ++++++++++-- .../src/router.ts | 26 +++++-- .../src/util.test.ts | 17 ++++- .../src/util.ts | 29 +++++++ .../versioned_router/core_versioned_route.ts | 13 +--- .../inject_response_headers.ts | 27 ------- .../integration_tests/http/router.test.ts | 76 +++++++++++++++++++ .../http/versioned_router.test.ts | 68 +++++++---------- 8 files changed, 214 insertions(+), 92 deletions(-) delete mode 100644 packages/core/http/core-http-router-server-internal/src/versioned_router/inject_response_headers.ts diff --git a/packages/core/http/core-http-router-server-internal/src/router.test.ts b/packages/core/http/core-http-router-server-internal/src/router.test.ts index 65f5b41f91fba..b506933574d4a 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.test.ts @@ -7,20 +7,22 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { Router, type RouterOptions } from './router'; +import type { ResponseToolkit, ResponseObject } from '@hapi/hapi'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { isConfigSchema, schema } from '@kbn/config-schema'; -import { createFooValidation } from './router.test.util'; import { createRequestMock } from '@kbn/hapi-mocks/src/request'; +import { createFooValidation } from './router.test.util'; +import { Router, type RouterOptions } from './router'; import type { RouteValidatorRequestAndResponses } from '@kbn/core-http-server'; -const mockResponse: any = { +const mockResponse = { code: jest.fn().mockImplementation(() => mockResponse), header: jest.fn().mockImplementation(() => mockResponse), -}; -const mockResponseToolkit: any = { +} as unknown as jest.Mocked; + +const mockResponseToolkit = { response: jest.fn().mockReturnValue(mockResponse), -}; +} as unknown as jest.Mocked; const logger = loggingSystemMock.create().get(); const enhanceWithContext = (fn: (...args: any[]) => any) => fn.bind(null, {}); @@ -132,6 +134,42 @@ describe('Router', () => { } ); + it('adds versioned header v2023-10-31 to public, unversioned routes', async () => { + const router = new Router('', logger, enhanceWithContext, routerOptions); + router.post( + { + path: '/public', + options: { + access: 'public', + }, + validate: false, + }, + (context, req, res) => res.ok({ headers: { AAAA: 'test' } }) // with some fake headers + ); + router.post( + { + path: '/internal', + options: { + access: 'internal', + }, + validate: false, + }, + (context, req, res) => res.ok() + ); + const [{ handler: publicHandler }, { handler: internalHandler }] = router.getRoutes(); + + await publicHandler(createRequestMock(), mockResponseToolkit); + expect(mockResponse.header).toHaveBeenCalledTimes(2); + const [first, second] = mockResponse.header.mock.calls + .concat() + .sort(([k1], [k2]) => k1.localeCompare(k2)); + expect(first).toEqual(['AAAA', 'test']); + expect(second).toEqual(['elastic-api-version', '2023-10-31']); + + await internalHandler(createRequestMock(), mockResponseToolkit); + expect(mockResponse.header).toHaveBeenCalledTimes(2); // no additional calls + }); + it('constructs lazily provided validations once (idempotency)', async () => { const router = new Router('', logger, enhanceWithContext, routerOptions); const { fooValidation } = testValidation; diff --git a/packages/core/http/core-http-router-server-internal/src/router.ts b/packages/core/http/core-http-router-server-internal/src/router.ts index 13715dc166395..1a74e27910c1a 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.ts @@ -33,13 +33,13 @@ import { validBodyOutput, getRequestValidation } from '@kbn/core-http-server'; import type { RouteSecurityGetter } from '@kbn/core-http-server'; import type { DeepPartial } from '@kbn/utility-types'; import { RouteValidator } from './validator'; -import { CoreVersionedRouter } from './versioned_router'; +import { ALLOWED_PUBLIC_VERSION, CoreVersionedRouter } from './versioned_router'; import { CoreKibanaRequest } from './request'; import { kibanaResponseFactory } from './response'; import { HapiResponseAdapter } from './response_adapter'; import { wrapErrors } from './error_wrapper'; import { Method } from './versioned_router/types'; -import { prepareRouteConfigValidation } from './util'; +import { getVersionHeader, injectVersionHeader, prepareRouteConfigValidation } from './util'; import { stripIllegalHttp2Headers } from './strip_illegal_http2_headers'; import { validRouteSecurity } from './security_route_config_validator'; import { InternalRouteConfig } from './route'; @@ -201,10 +201,11 @@ export class Router( route: InternalRouteConfig, handler: RequestHandler, - internalOptions: { isVersioned: boolean } = { isVersioned: false } + { isVersioned }: { isVersioned: boolean } = { isVersioned: false } ) => { route = prepareRouteConfigValidation(route); const routeSchemas = routeSchemasFromRouteConfig(route, method); + const isPublicUnversionedRoute = route.options?.access === 'public' && !isVersioned; this.routes.push({ handler: async (req, responseToolkit) => @@ -212,18 +213,19 @@ export class Router, route.options), /** Below is added for introspection */ validationSchemas: route.validate, - isVersioned: internalOptions.isVersioned, + isVersioned, }); }; @@ -267,10 +269,12 @@ export class Router { it('wraps only expected values in "once"', () => { @@ -49,3 +50,17 @@ describe('prepareResponseValidation', () => { expect(validation.response![500].body).toBeUndefined(); }); }); + +describe('injectResponseHeaders', () => { + it('injects an empty value as expected', () => { + const result = injectResponseHeaders({}, kibanaResponseFactory.ok()); + expect(result.options.headers).toEqual({}); + }); + it('merges values as expected', () => { + const result = injectResponseHeaders( + { foo: 'false', baz: 'true' }, + kibanaResponseFactory.ok({ headers: { foo: 'true', bar: 'false' } }) + ); + expect(result.options.headers).toEqual({ foo: 'false', bar: 'false', baz: 'true' }); + }); +}); diff --git a/packages/core/http/core-http-router-server-internal/src/util.ts b/packages/core/http/core-http-router-server-internal/src/util.ts index 0d1c8abb0e103..176d33b589880 100644 --- a/packages/core/http/core-http-router-server-internal/src/util.ts +++ b/packages/core/http/core-http-router-server-internal/src/util.ts @@ -14,6 +14,9 @@ import { type RouteMethod, type RouteValidator, } from '@kbn/core-http-server'; +import type { Mutable } from 'utility-types'; +import type { IKibanaResponse, ResponseHeaders } from '@kbn/core-http-server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import type { InternalRouteConfig } from './route'; function isStatusCode(key: string) { @@ -63,3 +66,29 @@ export function prepareRouteConfigValidation( } return config; } + +/** + * @note mutates the response object + * @internal + */ +export function injectResponseHeaders( + headers: ResponseHeaders, + response: IKibanaResponse +): IKibanaResponse { + const mutableResponse = response as Mutable; + mutableResponse.options.headers = { + ...mutableResponse.options.headers, + ...headers, + }; + return mutableResponse; +} + +export function getVersionHeader(version: string): ResponseHeaders { + return { + [ELASTIC_HTTP_VERSION_HEADER]: version, + }; +} + +export function injectVersionHeader(version: string, response: IKibanaResponse): IKibanaResponse { + return injectResponseHeaders(getVersionHeader(version), response); +} diff --git a/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.ts b/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.ts index 71ab30bbe8b80..e9a9e60de8193 100644 --- a/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.ts +++ b/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.ts @@ -38,7 +38,7 @@ import { readVersion, removeQueryVersion, } from './route_version_utils'; -import { injectResponseHeaders } from './inject_response_headers'; +import { getVersionHeader, injectVersionHeader } from '../util'; import { validRouteSecurity } from '../security_route_config_validator'; import { resolvers } from './handler_resolvers'; @@ -221,9 +221,7 @@ export class CoreVersionedRoute implements VersionedRoute { req.params = params; req.query = query; } catch (e) { - return res.badRequest({ - body: e.message, - }); + return res.badRequest({ body: e.message, headers: getVersionHeader(version) }); } } else { // Preserve behavior of not passing through unvalidated data @@ -252,12 +250,7 @@ export class CoreVersionedRoute implements VersionedRoute { } } - return injectResponseHeaders( - { - [ELASTIC_HTTP_VERSION_HEADER]: version, - }, - response - ); + return injectVersionHeader(version, response); }; private validateVersion(version: string) { diff --git a/packages/core/http/core-http-router-server-internal/src/versioned_router/inject_response_headers.ts b/packages/core/http/core-http-router-server-internal/src/versioned_router/inject_response_headers.ts deleted file mode 100644 index c27c92023f56e..0000000000000 --- a/packages/core/http/core-http-router-server-internal/src/versioned_router/inject_response_headers.ts +++ /dev/null @@ -1,27 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { Mutable } from 'utility-types'; -import type { IKibanaResponse } from '@kbn/core-http-server'; - -/** - * @note mutates the response object - * @internal - */ -export function injectResponseHeaders(headers: object, response: IKibanaResponse): IKibanaResponse { - const mutableResponse = response as Mutable; - mutableResponse.options = { - ...mutableResponse.options, - headers: { - ...mutableResponse.options.headers, - ...headers, - }, - }; - return mutableResponse; -} diff --git a/src/core/server/integration_tests/http/router.test.ts b/src/core/server/integration_tests/http/router.test.ts index 0b7bbb8ce55c3..c0a690e479e67 100644 --- a/src/core/server/integration_tests/http/router.test.ts +++ b/src/core/server/integration_tests/http/router.test.ts @@ -836,6 +836,82 @@ describe('Handler', () => { expect(body).toEqual(12); }); + + it('adds versioned header v2023-10-31 to public, unversioned routes', async () => { + const { server: innerServer, createRouter } = await server.setup(setupDeps); + const router = createRouter('/'); + + router.post( + { + path: '/public', + validate: { body: schema.object({ ok: schema.boolean() }) }, + options: { + access: 'public', + }, + }, + (context, req, res) => { + if (req.body.ok) { + return res.ok({ body: 'ok', headers: { test: 'this' } }); + } + return res.customError({ statusCode: 499, body: 'custom error' }); + } + ); + router.post( + { + path: '/internal', + validate: { body: schema.object({ ok: schema.boolean() }) }, + }, + (context, req, res) => { + return res.ok({ body: 'ok', headers: { test: 'this' } }); + } + ); + await server.start(); + + // Includes header if validation fails + { + const { headers } = await supertest(innerServer.listener) + .post('/public') + .send({ ok: null }) + .expect(400); + expect(headers).toMatchObject({ 'elastic-api-version': '2023-10-31' }); + } + + // Includes header if custom error + { + const { headers } = await supertest(innerServer.listener) + .post('/public') + .send({ ok: false }) + .expect(499); + expect(headers).toMatchObject({ 'elastic-api-version': '2023-10-31' }); + } + + // Includes header if OK + { + const { headers } = await supertest(innerServer.listener) + .post('/public') + .send({ ok: true }) + .expect(200); + expect(headers).toMatchObject({ 'elastic-api-version': '2023-10-31' }); + } + + // Internal unversioned routes do not include the header for OK + { + const { headers } = await supertest(innerServer.listener) + .post('/internal') + .send({ ok: true }) + .expect(200); + expect(headers).not.toMatchObject({ 'elastic-api-version': '2023-10-31' }); + } + + // Internal unversioned routes do not include the header for validation failures + { + const { headers } = await supertest(innerServer.listener) + .post('/internal') + .send({ ok: null }) + .expect(400); + expect(headers).not.toMatchObject({ 'elastic-api-version': '2023-10-31' }); + } + }); }); describe('handleLegacyErrors', () => { diff --git a/src/core/server/integration_tests/http/versioned_router.test.ts b/src/core/server/integration_tests/http/versioned_router.test.ts index 9f2b2625a6a7e..254337f82abcf 100644 --- a/src/core/server/integration_tests/http/versioned_router.test.ts +++ b/src/core/server/integration_tests/http/versioned_router.test.ts @@ -112,14 +112,12 @@ describe('Routing versioned requests', () => { await server.start(); - await expect(supertest.get('/my-path').expect(200)).resolves.toEqual( - expect.objectContaining({ - body: { v: '1' }, - header: expect.objectContaining({ - 'elastic-api-version': '2020-02-02', - }), - }) - ); + await expect(supertest.get('/my-path').expect(200)).resolves.toMatchObject({ + body: { v: '1' }, + header: expect.objectContaining({ + 'elastic-api-version': '2020-02-02', + }), + }); }); it('returns the expected output for badly formatted versions', async () => { @@ -137,11 +135,9 @@ describe('Routing versioned requests', () => { .set('Elastic-Api-Version', 'abc') .expect(400) .then(({ body }) => body) - ).resolves.toEqual( - expect.objectContaining({ - message: expect.stringMatching(/Invalid version/), - }) - ); + ).resolves.toMatchObject({ + message: expect.stringMatching(/Invalid version/), + }); }); it('returns the expected responses for failed validation', async () => { @@ -163,18 +159,14 @@ describe('Routing versioned requests', () => { await server.start(); await expect( - supertest - .post('/my-path') - .send({}) - .set('Elastic-Api-Version', '1') - .expect(400) - .then(({ body }) => body) - ).resolves.toEqual( - expect.objectContaining({ + supertest.post('/my-path').send({}).set('Elastic-Api-Version', '1').expect(400) + ).resolves.toMatchObject({ + body: { error: 'Bad Request', message: expect.stringMatching(/expected value of type/), - }) - ); + }, + headers: { 'elastic-api-version': '1' }, // includes version if validation failed + }); expect(captureErrorMock).not.toHaveBeenCalled(); }); @@ -193,7 +185,7 @@ describe('Routing versioned requests', () => { .set('Elastic-Api-Version', '2023-10-31') .expect(200) .then(({ header }) => header) - ).resolves.toEqual(expect.objectContaining({ 'elastic-api-version': '2023-10-31' })); + ).resolves.toMatchObject({ 'elastic-api-version': '2023-10-31' }); }); it('runs response validation when in dev', async () => { @@ -236,11 +228,9 @@ describe('Routing versioned requests', () => { .set('Elastic-Api-Version', '1') .expect(500) .then(({ body }) => body) - ).resolves.toEqual( - expect.objectContaining({ - message: expect.stringMatching(/Failed output validation/), - }) - ); + ).resolves.toMatchObject({ + message: expect.stringMatching(/Failed output validation/), + }); await expect( supertest @@ -248,11 +238,9 @@ describe('Routing versioned requests', () => { .set('Elastic-Api-Version', '2') .expect(500) .then(({ body }) => body) - ).resolves.toEqual( - expect.objectContaining({ - message: expect.stringMatching(/Failed output validation/), - }) - ); + ).resolves.toMatchObject({ + message: expect.stringMatching(/Failed output validation/), + }); // This should pass response validation await expect( @@ -261,11 +249,9 @@ describe('Routing versioned requests', () => { .set('Elastic-Api-Version', '3') .expect(200) .then(({ body }) => body) - ).resolves.toEqual( - expect.objectContaining({ - v: '3', - }) - ); + ).resolves.toMatchObject({ + v: '3', + }); expect(captureErrorMock).not.toHaveBeenCalled(); }); @@ -367,9 +353,7 @@ describe('Routing versioned requests', () => { .set('Elastic-Api-Version', '2020-02-02') .expect(500) .then(({ body }) => body) - ).resolves.toEqual( - expect.objectContaining({ message: expect.stringMatching(/No handlers registered/) }) - ); + ).resolves.toMatchObject({ message: expect.stringMatching(/No handlers registered/) }); expect(captureErrorMock).not.toHaveBeenCalled(); }); From a209fe8d7d7d1e27bb9b80475ea2821a9202e823 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Wed, 9 Oct 2024 18:46:31 +0200 Subject: [PATCH 078/110] [Lens][ES|QL] Do not refetch the attributes if the query hasn't changed (#195196) ## Summary When a user is creating a Lens ES|QL chart we run the suggestions api even if the query hasn't changed. This PR adds a guard to avoid refetching the attributes when the query hasn't changed at all. --- .../shared/edit_on_the_fly/lens_configuration_flyout.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx index ecc392a7e56b7..fd0407513f869 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx @@ -337,6 +337,7 @@ export function LensEditConfigurationFlyout({ setErrors([]); updateSuggestion?.(attrs); } + prevQuery.current = q; setIsVisualizationLoading(false); }, [ @@ -481,7 +482,6 @@ export function LensEditConfigurationFlyout({ query={query} onTextLangQueryChange={(q) => { setQuery(q); - prevQuery.current = q; }} detectedTimestamp={adHocDataViews?.[0]?.timeFieldName} hideTimeFilterInfo={hideTimeFilterInfo} @@ -497,7 +497,8 @@ export function LensEditConfigurationFlyout({ editorIsInline hideRunQueryText onTextLangQuerySubmit={async (q, a) => { - if (q) { + // do not run the suggestions if the query is the same as the previous one + if (q && !isEqual(q, prevQuery.current)) { setIsVisualizationLoading(true); await runQuery(q, a); } From 5ed13ee4a4b4325bae2f3e117a4fc400540fa542 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Wed, 9 Oct 2024 10:12:52 -0700 Subject: [PATCH 079/110] Update deprecations carried over from 8 (#195491) Fix https://github.com/elastic/kibana/issues/142915 ### Risk Matrix | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Third party plugin types throw type errors | Low | Low | type checks will error when using a deprecated type. Plugin authors should extend the supported types or define new ones inline | ### For maintainers - [X] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) (no breaking changes) --- .../core-application-browser/src/app_mount.ts | 2 +- .../src/contracts.ts | 2 +- .../src/plugin.ts | 4 +--- .../core/plugins/core-plugins-server/index.ts | 1 - .../plugins/core-plugins-server/src/index.ts | 1 - .../plugins/core-plugins-server/src/types.ts | 24 +------------------ src/core/server/index.ts | 1 - 7 files changed, 4 insertions(+), 31 deletions(-) diff --git a/packages/core/application/core-application-browser/src/app_mount.ts b/packages/core/application/core-application-browser/src/app_mount.ts index a34550bc98fcd..4fb38b10a3704 100644 --- a/packages/core/application/core-application-browser/src/app_mount.ts +++ b/packages/core/application/core-application-browser/src/app_mount.ts @@ -89,7 +89,7 @@ export interface AppMountParameters { * This string should not include the base path from HTTP. * * @deprecated Use {@link AppMountParameters.history} instead. - * @removeBy 8.8.0 + * remove after https://github.com/elastic/kibana/issues/132600 is done * * @example * diff --git a/packages/core/elasticsearch/core-elasticsearch-server/src/contracts.ts b/packages/core/elasticsearch/core-elasticsearch-server/src/contracts.ts index bc712a61a535e..4e0bd253eb8b4 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server/src/contracts.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server/src/contracts.ts @@ -81,7 +81,7 @@ export interface ElasticsearchServiceSetup { setUnauthorizedErrorHandler: (handler: UnauthorizedErrorHandler) => void; /** - * @deprecated + * @deprecated Can be removed when https://github.com/elastic/kibana/issues/119862 is done. */ legacy: { /** diff --git a/packages/core/plugins/core-plugins-server-internal/src/plugin.ts b/packages/core/plugins/core-plugins-server-internal/src/plugin.ts index 8837cb24083d6..cd330a647da66 100644 --- a/packages/core/plugins/core-plugins-server-internal/src/plugin.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugin.ts @@ -15,7 +15,6 @@ import { isConfigSchema } from '@kbn/config-schema'; import type { Logger } from '@kbn/logging'; import { type PluginOpaqueId, PluginType } from '@kbn/core-base-common'; import type { - AsyncPlugin, Plugin, PluginConfigDescriptor, PluginInitializer, @@ -58,8 +57,7 @@ export class PluginWrapper< private instance?: | Plugin - | PrebootPlugin - | AsyncPlugin; + | PrebootPlugin; private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart, TStart]>(); public readonly startDependencies = firstValueFrom(this.startDependencies$); diff --git a/packages/core/plugins/core-plugins-server/index.ts b/packages/core/plugins/core-plugins-server/index.ts index b2c6057c4a1ac..a5fd0fd2e2ec3 100644 --- a/packages/core/plugins/core-plugins-server/index.ts +++ b/packages/core/plugins/core-plugins-server/index.ts @@ -10,7 +10,6 @@ export type { PrebootPlugin, Plugin, - AsyncPlugin, PluginConfigDescriptor, PluginConfigSchema, PluginInitializer, diff --git a/packages/core/plugins/core-plugins-server/src/index.ts b/packages/core/plugins/core-plugins-server/src/index.ts index 35b1b7c11d422..e48d077389ece 100644 --- a/packages/core/plugins/core-plugins-server/src/index.ts +++ b/packages/core/plugins/core-plugins-server/src/index.ts @@ -10,7 +10,6 @@ export type { PrebootPlugin, Plugin, - AsyncPlugin, PluginConfigDescriptor, PluginConfigSchema, PluginInitializer, diff --git a/packages/core/plugins/core-plugins-server/src/types.ts b/packages/core/plugins/core-plugins-server/src/types.ts index 6da8b2727733e..7be2647ba48d2 100644 --- a/packages/core/plugins/core-plugins-server/src/types.ts +++ b/packages/core/plugins/core-plugins-server/src/types.ts @@ -301,26 +301,6 @@ export interface Plugin< stop?(): MaybePromise; } -/** - * A plugin with asynchronous lifecycle methods. - * - * @deprecated Asynchronous lifecycles are deprecated, and should be migrated to sync {@link Plugin | plugin} - * @removeBy 8.8.0 - * @public - */ -export interface AsyncPlugin< - TSetup = void, - TStart = void, - TPluginsSetup extends object = object, - TPluginsStart extends object = object -> { - setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; - - start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; - - stop?(): MaybePromise; -} - /** * @public */ @@ -478,7 +458,5 @@ export type PluginInitializer< > = ( core: PluginInitializerContext ) => Promise< - | Plugin - | PrebootPlugin - | AsyncPlugin + Plugin | PrebootPlugin >; diff --git a/src/core/server/index.ts b/src/core/server/index.ts index f4852bdc97fe3..1ac38b1d44157 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -267,7 +267,6 @@ export { PluginType } from '@kbn/core-base-common'; export type { PrebootPlugin, Plugin, - AsyncPlugin, PluginConfigDescriptor, PluginConfigSchema, PluginInitializer, From 7448376119aa1aad0888eb68449c1b15fd0852ac Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 9 Oct 2024 11:21:15 -0600 Subject: [PATCH 080/110] [dashboard] do not async import dashboard actions on plugin load (#195616) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of https://github.com/elastic/kibana/issues/194171 Notice in the screen shot below, how opening Kibana home page loads async dashboard chunks. Screenshot 2024-10-09 at 8 38 24 AM This PR replaces async import with a sync import. The page load bundle size increases but this is no different than the current behavior, just the import is now properly accounted for in page load stats. The next step is to resolve https://github.com/elastic/kibana/issues/191642 and reduce the page load impact of registering uiActions (but this is out of scope for this PR). --- src/plugins/dashboard/public/plugin.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index 0957bf9364524..b7a920eb08ce3 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -78,6 +78,7 @@ import { } from './dashboard_container/panel_placement'; import type { FindDashboardsService } from './services/dashboard_content_management_service/types'; import { setKibanaServices, untilPluginStartServicesReady } from './services/kibana_services'; +import { buildAllDashboardActions } from './dashboard_actions'; export interface DashboardFeatureFlagConfig { allowByValueEmbeddables: boolean; @@ -322,14 +323,12 @@ export class DashboardPlugin public start(core: CoreStart, plugins: DashboardStartDependencies): DashboardStart { setKibanaServices(core, plugins); - Promise.all([import('./dashboard_actions'), untilPluginStartServicesReady()]).then( - ([{ buildAllDashboardActions }]) => { - buildAllDashboardActions({ - plugins, - allowByValueEmbeddables: this.dashboardFeatureFlagConfig?.allowByValueEmbeddables, - }); - } - ); + untilPluginStartServicesReady().then(() => { + buildAllDashboardActions({ + plugins, + allowByValueEmbeddables: this.dashboardFeatureFlagConfig?.allowByValueEmbeddables, + }); + }); return { locator: this.locator, From 15bccdf233d847f34ee4cbcc30f8a8e775207c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 9 Oct 2024 19:21:52 +0200 Subject: [PATCH 081/110] [Logs Overview] Overview component (iteration 1) (#191899) This introduces a "Logs Overview" component for use in solution UIs behind a feature flag. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Co-authored-by: Elastic Machine --- .eslintrc.js | 1 + .github/CODEOWNERS | 1 + package.json | 5 + .../src/lib/entity.ts | 12 + .../src/lib/gaussian_events.ts | 74 +++++ .../src/lib/infra/host.ts | 10 +- .../src/lib/infra/index.ts | 3 +- .../src/lib/interval.ts | 18 +- .../src/lib/logs/index.ts | 21 ++ .../src/lib/poisson_events.test.ts | 53 ++++ .../src/lib/poisson_events.ts | 77 +++++ .../src/lib/timerange.ts | 27 +- .../distributed_unstructured_logs.ts | 197 ++++++++++++ .../scenarios/helpers/unstructured_logs.ts | 94 ++++++ packages/kbn-apm-synthtrace/tsconfig.json | 1 + .../settings/setting_ids/index.ts | 1 + .../src/worker/webpack.config.ts | 12 + packages/kbn-xstate-utils/kibana.jsonc | 2 +- .../kbn-xstate-utils/src/console_inspector.ts | 88 ++++++ packages/kbn-xstate-utils/src/index.ts | 1 + .../server/collectors/management/schema.ts | 6 + .../server/collectors/management/types.ts | 1 + src/plugins/telemetry/schema/oss_plugins.json | 6 + tsconfig.base.json | 2 + x-pack/.i18nrc.json | 3 + .../observability/logs_overview/README.md | 3 + .../observability/logs_overview/index.ts | 21 ++ .../logs_overview/jest.config.js | 12 + .../observability/logs_overview/kibana.jsonc | 5 + .../observability/logs_overview/package.json | 7 + .../discover_link/discover_link.tsx | 110 +++++++ .../src/components/discover_link/index.ts | 8 + .../src/components/log_categories/index.ts | 8 + .../log_categories/log_categories.tsx | 94 ++++++ .../log_categories_control_bar.tsx | 44 +++ .../log_categories_error_content.tsx | 44 +++ .../log_categories/log_categories_grid.tsx | 182 +++++++++++ .../log_categories_grid_cell.tsx | 99 ++++++ .../log_categories_grid_change_time_cell.tsx | 54 ++++ .../log_categories_grid_change_type_cell.tsx | 108 +++++++ .../log_categories_grid_count_cell.tsx | 32 ++ .../log_categories_grid_histogram_cell.tsx | 99 ++++++ .../log_categories_grid_pattern_cell.tsx | 60 ++++ .../log_categories_loading_content.tsx | 68 +++++ .../log_categories_result_content.tsx | 87 ++++++ .../src/components/logs_overview/index.ts | 10 + .../logs_overview/logs_overview.tsx | 64 ++++ .../logs_overview_error_content.tsx | 41 +++ .../logs_overview_loading_content.tsx | 23 ++ .../categorize_documents.ts | 282 ++++++++++++++++++ .../categorize_logs_service.ts | 250 ++++++++++++++++ .../count_documents.ts | 60 ++++ .../services/categorize_logs_service/index.ts | 8 + .../categorize_logs_service/queries.ts | 151 ++++++++++ .../services/categorize_logs_service/types.ts | 21 ++ .../observability/logs_overview/src/types.ts | 74 +++++ .../logs_overview/src/utils/logs_source.ts | 60 ++++ .../logs_overview/src/utils/xstate5_utils.ts | 13 + .../observability/logs_overview/tsconfig.json | 39 +++ .../components/app/service_logs/index.tsx | 171 ++++++++++- .../routing/service_detail/index.tsx | 2 +- .../apm/public/plugin.ts | 2 + .../components/tabs/logs/logs_tab_content.tsx | 94 ++++-- .../logs_shared/kibana.jsonc | 5 +- .../public/components/logs_overview/index.tsx | 8 + .../logs_overview/logs_overview.mock.tsx | 32 ++ .../logs_overview/logs_overview.tsx | 70 +++++ .../logs_shared/public/index.ts | 1 + .../logs_shared/public/mocks.tsx | 2 + .../logs_shared/public/plugin.ts | 23 +- .../logs_shared/public/types.ts | 12 +- .../logs_shared/server/feature_flags.ts | 33 ++ .../logs_shared/server/plugin.ts | 28 +- .../logs_shared/tsconfig.json | 4 + yarn.lock | 17 ++ 75 files changed, 3405 insertions(+), 56 deletions(-) create mode 100644 packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts create mode 100644 packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts create mode 100644 packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts create mode 100644 packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts create mode 100644 packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts create mode 100644 packages/kbn-xstate-utils/src/console_inspector.ts create mode 100644 x-pack/packages/observability/logs_overview/README.md create mode 100644 x-pack/packages/observability/logs_overview/index.ts create mode 100644 x-pack/packages/observability/logs_overview/jest.config.js create mode 100644 x-pack/packages/observability/logs_overview/kibana.jsonc create mode 100644 x-pack/packages/observability/logs_overview/package.json create mode 100644 x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts create mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts create mode 100644 x-pack/packages/observability/logs_overview/src/types.ts create mode 100644 x-pack/packages/observability/logs_overview/src/utils/logs_source.ts create mode 100644 x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts create mode 100644 x-pack/packages/observability/logs_overview/tsconfig.json create mode 100644 x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx create mode 100644 x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx create mode 100644 x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx create mode 100644 x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts diff --git a/.eslintrc.js b/.eslintrc.js index 797b84522df3f..c604844089ef4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -978,6 +978,7 @@ module.exports = { files: [ 'x-pack/plugins/observability_solution/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', 'src/plugins/ai_assistant_management/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/packages/observability/logs_overview/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', ], rules: { '@kbn/i18n/strings_should_be_translated_with_i18n': 'warn', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9b3c46d065fe1..974a7d39f63b3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -652,6 +652,7 @@ x-pack/packages/observability/alerting_test_data @elastic/obs-ux-management-team x-pack/test/cases_api_integration/common/plugins/observability @elastic/response-ops x-pack/packages/observability/get_padded_alert_time_range_util @elastic/obs-ux-management-team x-pack/plugins/observability_solution/observability_logs_explorer @elastic/obs-ux-logs-team +x-pack/packages/observability/logs_overview @elastic/obs-ux-logs-team x-pack/plugins/observability_solution/observability_onboarding/e2e @elastic/obs-ux-logs-team @elastic/obs-ux-onboarding-team x-pack/plugins/observability_solution/observability_onboarding @elastic/obs-ux-logs-team @elastic/obs-ux-onboarding-team x-pack/plugins/observability_solution/observability @elastic/obs-ux-management-team diff --git a/package.json b/package.json index 57b84f1c46dcb..58cd08773696f 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0", "@types/react": "~18.2.0", "@types/react-dom": "~18.2.0", + "@xstate5/react/**/xstate": "^5.18.1", "globby/fast-glob": "^3.2.11" }, "dependencies": { @@ -687,6 +688,7 @@ "@kbn/observability-fixtures-plugin": "link:x-pack/test/cases_api_integration/common/plugins/observability", "@kbn/observability-get-padded-alert-time-range-util": "link:x-pack/packages/observability/get_padded_alert_time_range_util", "@kbn/observability-logs-explorer-plugin": "link:x-pack/plugins/observability_solution/observability_logs_explorer", + "@kbn/observability-logs-overview": "link:x-pack/packages/observability/logs_overview", "@kbn/observability-onboarding-plugin": "link:x-pack/plugins/observability_solution/observability_onboarding", "@kbn/observability-plugin": "link:x-pack/plugins/observability_solution/observability", "@kbn/observability-shared-plugin": "link:x-pack/plugins/observability_solution/observability_shared", @@ -1050,6 +1052,7 @@ "@turf/helpers": "6.0.1", "@turf/length": "^6.0.2", "@xstate/react": "^3.2.2", + "@xstate5/react": "npm:@xstate/react@^4.1.2", "adm-zip": "^0.5.9", "ai": "^2.2.33", "ajv": "^8.12.0", @@ -1283,6 +1286,7 @@ "whatwg-fetch": "^3.0.0", "xml2js": "^0.5.0", "xstate": "^4.38.2", + "xstate5": "npm:xstate@^5.18.1", "xterm": "^5.1.0", "yauzl": "^2.10.0", "yazl": "^2.5.1", @@ -1304,6 +1308,7 @@ "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-env": "^7.24.7", diff --git a/packages/kbn-apm-synthtrace-client/src/lib/entity.ts b/packages/kbn-apm-synthtrace-client/src/lib/entity.ts index 4d522ef07ff0e..b26dbfc7ffb46 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/entity.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/entity.ts @@ -7,6 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +export type ObjectEntry = [keyof T, T[keyof T]]; + export type Fields | undefined = undefined> = { '@timestamp'?: number; } & (TMeta extends undefined ? {} : Partial<{ meta: TMeta }>); @@ -27,4 +29,14 @@ export class Entity { return this; } + + overrides(overrides: Partial) { + const overrideEntries = Object.entries(overrides) as Array>; + + overrideEntries.forEach(([fieldName, value]) => { + this.fields[fieldName] = value; + }); + + return this; + } } diff --git a/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts b/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts new file mode 100644 index 0000000000000..4f1db28017d29 --- /dev/null +++ b/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { castArray } from 'lodash'; +import { SynthtraceGenerator } from '../types'; +import { Fields } from './entity'; +import { Serializable } from './serializable'; + +export class GaussianEvents { + constructor( + private readonly from: Date, + private readonly to: Date, + private readonly mean: Date, + private readonly width: number, + private readonly totalPoints: number + ) {} + + *generator( + map: ( + timestamp: number, + index: number + ) => Serializable | Array> + ): SynthtraceGenerator { + if (this.totalPoints <= 0) { + return; + } + + const startTime = this.from.getTime(); + const endTime = this.to.getTime(); + const meanTime = this.mean.getTime(); + const densityInterval = 1 / (this.totalPoints - 1); + + for (let eventIndex = 0; eventIndex < this.totalPoints; eventIndex++) { + const quantile = eventIndex * densityInterval; + + const standardScore = Math.sqrt(2) * inverseError(2 * quantile - 1); + const timestamp = Math.round(meanTime + standardScore * this.width); + + if (timestamp >= startTime && timestamp <= endTime) { + yield* this.generateEvents(timestamp, eventIndex, map); + } + } + } + + private *generateEvents( + timestamp: number, + eventIndex: number, + map: ( + timestamp: number, + index: number + ) => Serializable | Array> + ): Generator> { + const events = castArray(map(timestamp, eventIndex)); + for (const event of events) { + yield event; + } + } +} + +function inverseError(x: number): number { + const a = 0.147; + const sign = x < 0 ? -1 : 1; + + const part1 = 2 / (Math.PI * a) + Math.log(1 - x * x) / 2; + const part2 = Math.log(1 - x * x) / a; + + return sign * Math.sqrt(Math.sqrt(part1 * part1 - part2) - part1); +} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts index 198949b482be3..30550d64c4df8 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts @@ -27,7 +27,7 @@ interface HostDocument extends Fields { 'cloud.provider'?: string; } -class Host extends Entity { +export class Host extends Entity { cpu({ cpuTotalValue }: { cpuTotalValue?: number } = {}) { return new HostMetrics({ ...this.fields, @@ -175,3 +175,11 @@ export function host(name: string): Host { 'cloud.provider': 'gcp', }); } + +export function minimalHost(name: string): Host { + return new Host({ + 'agent.id': 'synthtrace', + 'host.hostname': name, + 'host.name': name, + }); +} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts index 853a9549ce02c..2957605cffcd3 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts @@ -8,7 +8,7 @@ */ import { dockerContainer, DockerContainerMetricsDocument } from './docker_container'; -import { host, HostMetricsDocument } from './host'; +import { host, HostMetricsDocument, minimalHost } from './host'; import { k8sContainer, K8sContainerMetricsDocument } from './k8s_container'; import { pod, PodMetricsDocument } from './pod'; import { awsRds, AWSRdsMetricsDocument } from './aws/rds'; @@ -24,6 +24,7 @@ export type InfraDocument = export const infra = { host, + minimalHost, pod, dockerContainer, k8sContainer, diff --git a/packages/kbn-apm-synthtrace-client/src/lib/interval.ts b/packages/kbn-apm-synthtrace-client/src/lib/interval.ts index 1d56c42e1fe12..5a5ed3ab5fdbe 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/interval.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/interval.ts @@ -34,6 +34,10 @@ interface IntervalOptions { rate?: number; } +interface StepDetails { + stepMilliseconds: number; +} + export class Interval { private readonly intervalAmount: number; private readonly intervalUnit: unitOfTime.DurationConstructor; @@ -46,12 +50,16 @@ export class Interval { this._rate = options.rate || 1; } + private getIntervalMilliseconds(): number { + return moment.duration(this.intervalAmount, this.intervalUnit).asMilliseconds(); + } + private getTimestamps() { const from = this.options.from.getTime(); const to = this.options.to.getTime(); let time: number = from; - const diff = moment.duration(this.intervalAmount, this.intervalUnit).asMilliseconds(); + const diff = this.getIntervalMilliseconds(); const timestamps: number[] = []; @@ -68,15 +76,19 @@ export class Interval { *generator( map: ( timestamp: number, - index: number + index: number, + stepDetails: StepDetails ) => Serializable | Array> ): SynthtraceGenerator { const timestamps = this.getTimestamps(); + const stepDetails: StepDetails = { + stepMilliseconds: this.getIntervalMilliseconds(), + }; let index = 0; for (const timestamp of timestamps) { - const events = castArray(map(timestamp, index)); + const events = castArray(map(timestamp, index, stepDetails)); index++; for (const event of events) { yield event; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts index e19f0f6fd6565..2bbc59eb37e70 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts @@ -68,6 +68,7 @@ export type LogDocument = Fields & 'event.duration': number; 'event.start': Date; 'event.end': Date; + labels?: Record; test_field: string | string[]; date: Date; severity: string; @@ -156,6 +157,26 @@ function create(logsOptions: LogsOptions = defaultLogsOptions): Log { ).dataset('synth'); } +function createMinimal({ + dataset = 'synth', + namespace = 'default', +}: { + dataset?: string; + namespace?: string; +} = {}): Log { + return new Log( + { + 'input.type': 'logs', + 'data_stream.namespace': namespace, + 'data_stream.type': 'logs', + 'data_stream.dataset': dataset, + 'event.dataset': dataset, + }, + { isLogsDb: false } + ); +} + export const log = { create, + createMinimal, }; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts new file mode 100644 index 0000000000000..0741884550f32 --- /dev/null +++ b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { PoissonEvents } from './poisson_events'; +import { Serializable } from './serializable'; + +describe('poisson events', () => { + it('generates events within the given time range', () => { + const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 10); + + const events = Array.from( + poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp })) + ); + + expect(events.length).toBeGreaterThanOrEqual(1); + + for (const event of events) { + expect(event.fields['@timestamp']).toBeGreaterThanOrEqual(1000); + expect(event.fields['@timestamp']).toBeLessThanOrEqual(2000); + } + }); + + it('generates at least one event if the rate is greater than 0', () => { + const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 1); + + const events = Array.from( + poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp })) + ); + + expect(events.length).toBeGreaterThanOrEqual(1); + + for (const event of events) { + expect(event.fields['@timestamp']).toBeGreaterThanOrEqual(1000); + expect(event.fields['@timestamp']).toBeLessThanOrEqual(2000); + } + }); + + it('generates no event if the rate is 0', () => { + const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 0); + + const events = Array.from( + poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp })) + ); + + expect(events.length).toBe(0); + }); +}); diff --git a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts new file mode 100644 index 0000000000000..e7fd24b8323e7 --- /dev/null +++ b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { castArray } from 'lodash'; +import { SynthtraceGenerator } from '../types'; +import { Fields } from './entity'; +import { Serializable } from './serializable'; + +export class PoissonEvents { + constructor( + private readonly from: Date, + private readonly to: Date, + private readonly rate: number + ) {} + + private getTotalTimePeriod(): number { + return this.to.getTime() - this.from.getTime(); + } + + private getInterarrivalTime(): number { + const distribution = -Math.log(1 - Math.random()) / this.rate; + const totalTimePeriod = this.getTotalTimePeriod(); + return Math.floor(distribution * totalTimePeriod); + } + + *generator( + map: ( + timestamp: number, + index: number + ) => Serializable | Array> + ): SynthtraceGenerator { + if (this.rate <= 0) { + return; + } + + let currentTime = this.from.getTime(); + const endTime = this.to.getTime(); + let eventIndex = 0; + + while (currentTime < endTime) { + const interarrivalTime = this.getInterarrivalTime(); + currentTime += interarrivalTime; + + if (currentTime < endTime) { + yield* this.generateEvents(currentTime, eventIndex, map); + eventIndex++; + } + } + + // ensure at least one event has been emitted + if (this.rate > 0 && eventIndex === 0) { + const forcedEventTime = + this.from.getTime() + Math.floor(Math.random() * this.getTotalTimePeriod()); + yield* this.generateEvents(forcedEventTime, eventIndex, map); + } + } + + private *generateEvents( + timestamp: number, + eventIndex: number, + map: ( + timestamp: number, + index: number + ) => Serializable | Array> + ): Generator> { + const events = castArray(map(timestamp, eventIndex)); + for (const event of events) { + yield event; + } + } +} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts b/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts index ccdea4ee75197..1c6f12414a148 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts @@ -9,10 +9,12 @@ import datemath from '@kbn/datemath'; import type { Moment } from 'moment'; +import { GaussianEvents } from './gaussian_events'; import { Interval } from './interval'; +import { PoissonEvents } from './poisson_events'; export class Timerange { - constructor(private from: Date, private to: Date) {} + constructor(public readonly from: Date, public readonly to: Date) {} interval(interval: string) { return new Interval({ from: this.from, to: this.to, interval }); @@ -21,6 +23,29 @@ export class Timerange { ratePerMinute(rate: number) { return this.interval(`1m`).rate(rate); } + + poissonEvents(rate: number) { + return new PoissonEvents(this.from, this.to, rate); + } + + gaussianEvents(mean: Date, width: number, totalPoints: number) { + return new GaussianEvents(this.from, this.to, mean, width, totalPoints); + } + + splitInto(segmentCount: number): Timerange[] { + const duration = this.to.getTime() - this.from.getTime(); + const segmentDuration = duration / segmentCount; + + return Array.from({ length: segmentCount }, (_, i) => { + const from = new Date(this.from.getTime() + i * segmentDuration); + const to = new Date(from.getTime() + segmentDuration); + return new Timerange(from, to); + }); + } + + toString() { + return `Timerange(from=${this.from.toISOString()}, to=${this.to.toISOString()})`; + } } type DateLike = Date | number | Moment | string; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts new file mode 100644 index 0000000000000..83860635ae64a --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts @@ -0,0 +1,197 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { infra, LogDocument, log } from '@kbn/apm-synthtrace-client'; +import { fakerEN as faker } from '@faker-js/faker'; +import { z } from '@kbn/zod'; +import { Scenario } from '../cli/scenario'; +import { withClient } from '../lib/utils/with_client'; +import { + LogMessageGenerator, + generateUnstructuredLogMessage, + unstructuredLogMessageGenerators, +} from './helpers/unstructured_logs'; + +const scenarioOptsSchema = z.intersection( + z.object({ + randomSeed: z.number().default(0), + messageGroup: z + .enum([ + 'httpAccess', + 'userAuthentication', + 'networkEvent', + 'dbOperations', + 'taskOperations', + 'degradedOperations', + 'errorOperations', + ]) + .default('dbOperations'), + }), + z + .discriminatedUnion('distribution', [ + z.object({ + distribution: z.literal('uniform'), + rate: z.number().default(1), + }), + z.object({ + distribution: z.literal('poisson'), + rate: z.number().default(1), + }), + z.object({ + distribution: z.literal('gaussian'), + mean: z.coerce.date().describe('Time of the peak of the gaussian distribution'), + width: z.number().default(5000).describe('Width of the gaussian distribution in ms'), + totalPoints: z + .number() + .default(100) + .describe('Total number of points in the gaussian distribution'), + }), + ]) + .default({ distribution: 'uniform', rate: 1 }) +); + +type ScenarioOpts = z.output; + +const scenario: Scenario = async (runOptions) => { + return { + generate: ({ range, clients: { logsEsClient } }) => { + const { logger } = runOptions; + const scenarioOpts = scenarioOptsSchema.parse(runOptions.scenarioOpts ?? {}); + + faker.seed(scenarioOpts.randomSeed); + faker.setDefaultRefDate(range.from.toISOString()); + + logger.debug(`Generating ${scenarioOpts.distribution} logs...`); + + // Logs Data logic + const LOG_LEVELS = ['info', 'debug', 'error', 'warn', 'trace', 'fatal']; + + const clusterDefinions = [ + { + 'orchestrator.cluster.id': faker.string.nanoid(), + 'orchestrator.cluster.name': 'synth-cluster-1', + 'orchestrator.namespace': 'default', + 'cloud.provider': 'gcp', + 'cloud.region': 'eu-central-1', + 'cloud.availability_zone': 'eu-central-1a', + 'cloud.project.id': faker.string.nanoid(), + }, + { + 'orchestrator.cluster.id': faker.string.nanoid(), + 'orchestrator.cluster.name': 'synth-cluster-2', + 'orchestrator.namespace': 'production', + 'cloud.provider': 'aws', + 'cloud.region': 'us-east-1', + 'cloud.availability_zone': 'us-east-1a', + 'cloud.project.id': faker.string.nanoid(), + }, + { + 'orchestrator.cluster.id': faker.string.nanoid(), + 'orchestrator.cluster.name': 'synth-cluster-3', + 'orchestrator.namespace': 'kube', + 'cloud.provider': 'azure', + 'cloud.region': 'area-51', + 'cloud.availability_zone': 'area-51a', + 'cloud.project.id': faker.string.nanoid(), + }, + ]; + + const hostEntities = [ + { + 'host.name': 'host-1', + 'agent.id': 'synth-agent-1', + 'agent.name': 'nodejs', + 'cloud.instance.id': faker.string.nanoid(), + 'orchestrator.resource.id': faker.string.nanoid(), + ...clusterDefinions[0], + }, + { + 'host.name': 'host-2', + 'agent.id': 'synth-agent-2', + 'agent.name': 'custom', + 'cloud.instance.id': faker.string.nanoid(), + 'orchestrator.resource.id': faker.string.nanoid(), + ...clusterDefinions[1], + }, + { + 'host.name': 'host-3', + 'agent.id': 'synth-agent-3', + 'agent.name': 'python', + 'cloud.instance.id': faker.string.nanoid(), + 'orchestrator.resource.id': faker.string.nanoid(), + ...clusterDefinions[2], + }, + ].map((hostDefinition) => + infra.minimalHost(hostDefinition['host.name']).overrides(hostDefinition) + ); + + const serviceNames = Array(3) + .fill(null) + .map((_, idx) => `synth-service-${idx}`); + + const generatorFactory = + scenarioOpts.distribution === 'uniform' + ? range.interval('1s').rate(scenarioOpts.rate) + : scenarioOpts.distribution === 'poisson' + ? range.poissonEvents(scenarioOpts.rate) + : range.gaussianEvents(scenarioOpts.mean, scenarioOpts.width, scenarioOpts.totalPoints); + + const logs = generatorFactory.generator((timestamp) => { + const entity = faker.helpers.arrayElement(hostEntities); + const serviceName = faker.helpers.arrayElement(serviceNames); + const level = faker.helpers.arrayElement(LOG_LEVELS); + const messages = logMessageGenerators[scenarioOpts.messageGroup](faker); + + return messages.map((message) => + log + .createMinimal() + .message(message) + .logLevel(level) + .service(serviceName) + .overrides({ + ...entity.fields, + labels: { + scenario: 'rare', + population: scenarioOpts.distribution, + }, + }) + .timestamp(timestamp) + ); + }); + + return [ + withClient( + logsEsClient, + logger.perf('generating_logs', () => [logs]) + ), + ]; + }, + }; +}; + +export default scenario; + +const logMessageGenerators = { + httpAccess: generateUnstructuredLogMessage([unstructuredLogMessageGenerators.httpAccess]), + userAuthentication: generateUnstructuredLogMessage([ + unstructuredLogMessageGenerators.userAuthentication, + ]), + networkEvent: generateUnstructuredLogMessage([unstructuredLogMessageGenerators.networkEvent]), + dbOperations: generateUnstructuredLogMessage([unstructuredLogMessageGenerators.dbOperation]), + taskOperations: generateUnstructuredLogMessage([ + unstructuredLogMessageGenerators.taskStatusSuccess, + ]), + degradedOperations: generateUnstructuredLogMessage([ + unstructuredLogMessageGenerators.taskStatusFailure, + ]), + errorOperations: generateUnstructuredLogMessage([ + unstructuredLogMessageGenerators.error, + unstructuredLogMessageGenerators.restart, + ]), +} satisfies Record; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts new file mode 100644 index 0000000000000..490bd449e2b60 --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { Faker, faker } from '@faker-js/faker'; + +export type LogMessageGenerator = (f: Faker) => string[]; + +export const unstructuredLogMessageGenerators = { + httpAccess: (f: Faker) => [ + `${f.internet.ip()} - - [${f.date + .past() + .toISOString() + .replace('T', ' ') + .replace( + /\..+/, + '' + )}] "${f.internet.httpMethod()} ${f.internet.url()} HTTP/1.1" ${f.helpers.arrayElement([ + 200, 301, 404, 500, + ])} ${f.number.int({ min: 100, max: 5000 })}`, + ], + dbOperation: (f: Faker) => [ + `${f.database.engine()}: ${f.database.column()} ${f.helpers.arrayElement([ + 'created', + 'updated', + 'deleted', + 'inserted', + ])} successfully ${f.number.int({ max: 100000 })} times`, + ], + taskStatusSuccess: (f: Faker) => [ + `${f.hacker.noun()}: ${f.word.words()} ${f.helpers.arrayElement([ + 'triggered', + 'executed', + 'processed', + 'handled', + ])} successfully at ${f.date.recent().toISOString()}`, + ], + taskStatusFailure: (f: Faker) => [ + `${f.hacker.noun()}: ${f.helpers.arrayElement([ + 'triggering', + 'execution', + 'processing', + 'handling', + ])} of ${f.word.words()} failed at ${f.date.recent().toISOString()}`, + ], + error: (f: Faker) => [ + `${f.helpers.arrayElement([ + 'Error', + 'Exception', + 'Failure', + 'Crash', + 'Bug', + 'Issue', + ])}: ${f.hacker.phrase()}`, + `Stopping ${f.number.int(42)} background tasks...`, + 'Shutting down process...', + ], + restart: (f: Faker) => { + const service = f.database.engine(); + return [ + `Restarting ${service}...`, + `Waiting for queue to drain...`, + `Service ${service} restarted ${f.helpers.arrayElement([ + 'successfully', + 'with errors', + 'with warnings', + ])}`, + ]; + }, + userAuthentication: (f: Faker) => [ + `User ${f.internet.userName()} ${f.helpers.arrayElement([ + 'logged in', + 'logged out', + 'failed to login', + ])}`, + ], + networkEvent: (f: Faker) => [ + `Network ${f.helpers.arrayElement([ + 'connection', + 'disconnection', + 'data transfer', + ])} ${f.helpers.arrayElement(['from', 'to'])} ${f.internet.ip()}`, + ], +} satisfies Record; + +export const generateUnstructuredLogMessage = + (generators: LogMessageGenerator[] = Object.values(unstructuredLogMessageGenerators)) => + (f: Faker = faker) => + f.helpers.arrayElement(generators)(f); diff --git a/packages/kbn-apm-synthtrace/tsconfig.json b/packages/kbn-apm-synthtrace/tsconfig.json index d0f5c5801597a..db93e36421b83 100644 --- a/packages/kbn-apm-synthtrace/tsconfig.json +++ b/packages/kbn-apm-synthtrace/tsconfig.json @@ -10,6 +10,7 @@ "@kbn/apm-synthtrace-client", "@kbn/dev-utils", "@kbn/elastic-agent-utils", + "@kbn/zod", ], "exclude": [ "target/**/*", diff --git a/packages/kbn-management/settings/setting_ids/index.ts b/packages/kbn-management/settings/setting_ids/index.ts index 2b8c5de0b71df..e926007f77f25 100644 --- a/packages/kbn-management/settings/setting_ids/index.ts +++ b/packages/kbn-management/settings/setting_ids/index.ts @@ -142,6 +142,7 @@ export const OBSERVABILITY_APM_ENABLE_SERVICE_INVENTORY_TABLE_SEARCH_BAR = 'observability:apmEnableServiceInventoryTableSearchBar'; export const OBSERVABILITY_LOGS_EXPLORER_ALLOWED_DATA_VIEWS_ID = 'observability:logsExplorer:allowedDataViews'; +export const OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID = 'observability:newLogsOverview'; export const OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE = 'observability:entityCentricExperience'; export const OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID = 'observability:logSources'; export const OBSERVABILITY_ENABLE_LOGS_STREAM = 'observability:enableLogsStream'; diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 539d3098030e0..52a837724480d 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -247,6 +247,18 @@ export function getWebpackConfig( }, }, }, + { + test: /node_modules\/@?xstate5\/.*\.js$/, + use: { + loader: 'babel-loader', + options: { + babelrc: false, + envName: worker.dist ? 'production' : 'development', + presets: [BABEL_PRESET], + plugins: ['@babel/plugin-transform-logical-assignment-operators'], + }, + }, + }, { test: /\.(html|md|txt|tmpl)$/, use: { diff --git a/packages/kbn-xstate-utils/kibana.jsonc b/packages/kbn-xstate-utils/kibana.jsonc index cd1151a3f2103..1fb3507854b98 100644 --- a/packages/kbn-xstate-utils/kibana.jsonc +++ b/packages/kbn-xstate-utils/kibana.jsonc @@ -1,5 +1,5 @@ { - "type": "shared-common", + "type": "shared-browser", "id": "@kbn/xstate-utils", "owner": "@elastic/obs-ux-logs-team" } diff --git a/packages/kbn-xstate-utils/src/console_inspector.ts b/packages/kbn-xstate-utils/src/console_inspector.ts new file mode 100644 index 0000000000000..8792ab44f3c28 --- /dev/null +++ b/packages/kbn-xstate-utils/src/console_inspector.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { + ActorRefLike, + AnyActorRef, + InspectedActorEvent, + InspectedEventEvent, + InspectedSnapshotEvent, + InspectionEvent, +} from 'xstate5'; +import { isDevMode } from './dev_tools'; + +export const createConsoleInspector = () => { + if (!isDevMode()) { + return () => {}; + } + + // eslint-disable-next-line no-console + const log = console.info.bind(console); + + const logActorEvent = (actorEvent: InspectedActorEvent) => { + if (isActorRef(actorEvent.actorRef)) { + log( + '✨ %c%s%c is a new actor of type %c%s%c:', + ...styleAsActor(actorEvent.actorRef.id), + ...styleAsKeyword(actorEvent.type), + actorEvent.actorRef + ); + } else { + log('✨ New %c%s%c actor without id:', ...styleAsKeyword(actorEvent.type), actorEvent); + } + }; + + const logEventEvent = (eventEvent: InspectedEventEvent) => { + if (isActorRef(eventEvent.actorRef)) { + log( + '🔔 %c%s%c received event %c%s%c from %c%s%c:', + ...styleAsActor(eventEvent.actorRef.id), + ...styleAsKeyword(eventEvent.event.type), + ...styleAsKeyword(eventEvent.sourceRef?.id), + eventEvent + ); + } else { + log('🔔 Event', ...styleAsKeyword(eventEvent.event.type), ':', eventEvent); + } + }; + + const logSnapshotEvent = (snapshotEvent: InspectedSnapshotEvent) => { + if (isActorRef(snapshotEvent.actorRef)) { + log( + '📸 %c%s%c updated due to %c%s%c:', + ...styleAsActor(snapshotEvent.actorRef.id), + ...styleAsKeyword(snapshotEvent.event.type), + snapshotEvent.snapshot + ); + } else { + log('📸 Snapshot due to %c%s%c:', ...styleAsKeyword(snapshotEvent.event.type), snapshotEvent); + } + }; + + return (inspectionEvent: InspectionEvent) => { + if (inspectionEvent.type === '@xstate.actor') { + logActorEvent(inspectionEvent); + } else if (inspectionEvent.type === '@xstate.event') { + logEventEvent(inspectionEvent); + } else if (inspectionEvent.type === '@xstate.snapshot') { + logSnapshotEvent(inspectionEvent); + } else { + log(`❓ Received inspection event:`, inspectionEvent); + } + }; +}; + +const isActorRef = (actorRefLike: ActorRefLike): actorRefLike is AnyActorRef => + 'id' in actorRefLike; + +const keywordStyle = 'font-weight: bold'; +const styleAsKeyword = (value: any) => [keywordStyle, value, ''] as const; + +const actorStyle = 'font-weight: bold; text-decoration: underline'; +const styleAsActor = (value: any) => [actorStyle, value, ''] as const; diff --git a/packages/kbn-xstate-utils/src/index.ts b/packages/kbn-xstate-utils/src/index.ts index 107585ba2096f..3edf83e8a32c2 100644 --- a/packages/kbn-xstate-utils/src/index.ts +++ b/packages/kbn-xstate-utils/src/index.ts @@ -9,5 +9,6 @@ export * from './actions'; export * from './dev_tools'; +export * from './console_inspector'; export * from './notification_channel'; export * from './types'; diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index dc2d2ad2c5de2..e5ddfbe4dd037 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -705,4 +705,10 @@ export const stackManagementSchema: MakeSchemaFrom = { _meta: { description: 'Non-default value of setting.' }, }, }, + 'observability:newLogsOverview': { + type: 'boolean', + _meta: { + description: 'Enable the new logs overview component.', + }, + }, }; diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index ef20ab223dfb6..2acb487e7ed08 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -56,6 +56,7 @@ export interface UsageStats { 'observability:logsExplorer:allowedDataViews': string[]; 'observability:logSources': string[]; 'observability:enableLogsStream': boolean; + 'observability:newLogsOverview': boolean; 'observability:aiAssistantSimulatedFunctionCalling': boolean; 'observability:aiAssistantSearchConnectorIndexPattern': string; 'visualization:heatmap:maxBuckets': number; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 958280d9eba00..830cffc17cf1c 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -10768,6 +10768,12 @@ "description": "Non-default value of setting." } }, + "observability:newLogsOverview": { + "type": "boolean", + "_meta": { + "description": "Enable the new logs overview component." + } + }, "observability:searchExcludedDataTiers": { "type": "array", "items": { diff --git a/tsconfig.base.json b/tsconfig.base.json index 3df30d9cf8c30..4bc68d806f043 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1298,6 +1298,8 @@ "@kbn/observability-get-padded-alert-time-range-util/*": ["x-pack/packages/observability/get_padded_alert_time_range_util/*"], "@kbn/observability-logs-explorer-plugin": ["x-pack/plugins/observability_solution/observability_logs_explorer"], "@kbn/observability-logs-explorer-plugin/*": ["x-pack/plugins/observability_solution/observability_logs_explorer/*"], + "@kbn/observability-logs-overview": ["x-pack/packages/observability/logs_overview"], + "@kbn/observability-logs-overview/*": ["x-pack/packages/observability/logs_overview/*"], "@kbn/observability-onboarding-e2e": ["x-pack/plugins/observability_solution/observability_onboarding/e2e"], "@kbn/observability-onboarding-e2e/*": ["x-pack/plugins/observability_solution/observability_onboarding/e2e/*"], "@kbn/observability-onboarding-plugin": ["x-pack/plugins/observability_solution/observability_onboarding"], diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index a46e291093411..50f2b77b84ad7 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -95,6 +95,9 @@ "xpack.observabilityLogsExplorer": "plugins/observability_solution/observability_logs_explorer", "xpack.observability_onboarding": "plugins/observability_solution/observability_onboarding", "xpack.observabilityShared": "plugins/observability_solution/observability_shared", + "xpack.observabilityLogsOverview": [ + "packages/observability/logs_overview/src/components" + ], "xpack.osquery": ["plugins/osquery"], "xpack.painlessLab": "plugins/painless_lab", "xpack.profiling": ["plugins/observability_solution/profiling"], diff --git a/x-pack/packages/observability/logs_overview/README.md b/x-pack/packages/observability/logs_overview/README.md new file mode 100644 index 0000000000000..20d3f0f02b7df --- /dev/null +++ b/x-pack/packages/observability/logs_overview/README.md @@ -0,0 +1,3 @@ +# @kbn/observability-logs-overview + +Empty package generated by @kbn/generate diff --git a/x-pack/packages/observability/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/index.ts new file mode 100644 index 0000000000000..057d1d3acd152 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { + LogsOverview, + LogsOverviewErrorContent, + LogsOverviewLoadingContent, + type LogsOverviewDependencies, + type LogsOverviewErrorContentProps, + type LogsOverviewProps, +} from './src/components/logs_overview'; +export type { + DataViewLogsSourceConfiguration, + IndexNameLogsSourceConfiguration, + LogsSourceConfiguration, + SharedSettingLogsSourceConfiguration, +} from './src/utils/logs_source'; diff --git a/x-pack/packages/observability/logs_overview/jest.config.js b/x-pack/packages/observability/logs_overview/jest.config.js new file mode 100644 index 0000000000000..2ee88ee990253 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/jest.config.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/x-pack/packages/observability/logs_overview'], +}; diff --git a/x-pack/packages/observability/logs_overview/kibana.jsonc b/x-pack/packages/observability/logs_overview/kibana.jsonc new file mode 100644 index 0000000000000..90b3375086720 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/observability-logs-overview", + "owner": "@elastic/obs-ux-logs-team" +} diff --git a/x-pack/packages/observability/logs_overview/package.json b/x-pack/packages/observability/logs_overview/package.json new file mode 100644 index 0000000000000..77a529e7e59f7 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/observability-logs-overview", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0", + "sideEffects": false +} diff --git a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx new file mode 100644 index 0000000000000..fe108289985a9 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { EuiButton } from '@elastic/eui'; +import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common'; +import { FilterStateStore, buildCustomFilter } from '@kbn/es-query'; +import { i18n } from '@kbn/i18n'; +import { getRouterLinkProps } from '@kbn/router-utils'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import React, { useCallback, useMemo } from 'react'; +import type { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; + +export interface DiscoverLinkProps { + documentFilters?: QueryDslQueryContainer[]; + logsSource: IndexNameLogsSourceConfiguration; + timeRange: { + start: string; + end: string; + }; + dependencies: DiscoverLinkDependencies; +} + +export interface DiscoverLinkDependencies { + share: SharePluginStart; +} + +export const DiscoverLink = React.memo( + ({ dependencies: { share }, documentFilters, logsSource, timeRange }: DiscoverLinkProps) => { + const discoverLocatorParams = useMemo( + () => ({ + dataViewSpec: { + id: logsSource.indexName, + name: logsSource.indexName, + title: logsSource.indexName, + timeFieldName: logsSource.timestampField, + }, + timeRange: { + from: timeRange.start, + to: timeRange.end, + }, + filters: documentFilters?.map((filter) => + buildCustomFilter( + logsSource.indexName, + filter, + false, + false, + categorizedLogsFilterLabel, + FilterStateStore.APP_STATE + ) + ), + }), + [ + documentFilters, + logsSource.indexName, + logsSource.timestampField, + timeRange.end, + timeRange.start, + ] + ); + + const discoverLocator = useMemo( + () => share.url.locators.get('DISCOVER_APP_LOCATOR'), + [share.url.locators] + ); + + const discoverUrl = useMemo( + () => discoverLocator?.getRedirectUrl(discoverLocatorParams), + [discoverLocatorParams, discoverLocator] + ); + + const navigateToDiscover = useCallback(() => { + discoverLocator?.navigate(discoverLocatorParams); + }, [discoverLocatorParams, discoverLocator]); + + const discoverLinkProps = getRouterLinkProps({ + href: discoverUrl, + onClick: navigateToDiscover, + }); + + return ( + + {discoverLinkTitle} + + ); + } +); + +export const discoverLinkTitle = i18n.translate( + 'xpack.observabilityLogsOverview.discoverLinkTitle', + { + defaultMessage: 'Open in Discover', + } +); + +export const categorizedLogsFilterLabel = i18n.translate( + 'xpack.observabilityLogsOverview.categorizedLogsFilterLabel', + { + defaultMessage: 'Categorized log entries', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts b/x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts new file mode 100644 index 0000000000000..738bf51d4529d --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './discover_link'; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts b/x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts new file mode 100644 index 0000000000000..786475396237c --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './log_categories'; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx new file mode 100644 index 0000000000000..6204667827281 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { ISearchGeneric } from '@kbn/search-types'; +import { createConsoleInspector } from '@kbn/xstate-utils'; +import { useMachine } from '@xstate5/react'; +import React, { useCallback } from 'react'; +import { + categorizeLogsService, + createCategorizeLogsServiceImplementations, +} from '../../services/categorize_logs_service'; +import { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { LogCategoriesErrorContent } from './log_categories_error_content'; +import { LogCategoriesLoadingContent } from './log_categories_loading_content'; +import { + LogCategoriesResultContent, + LogCategoriesResultContentDependencies, +} from './log_categories_result_content'; + +export interface LogCategoriesProps { + dependencies: LogCategoriesDependencies; + documentFilters?: QueryDslQueryContainer[]; + logsSource: IndexNameLogsSourceConfiguration; + // The time range could be made optional if we want to support an internal + // time range picker + timeRange: { + start: string; + end: string; + }; +} + +export type LogCategoriesDependencies = LogCategoriesResultContentDependencies & { + search: ISearchGeneric; +}; + +export const LogCategories: React.FC = ({ + dependencies, + documentFilters = [], + logsSource, + timeRange, +}) => { + const [categorizeLogsServiceState, sendToCategorizeLogsService] = useMachine( + categorizeLogsService.provide( + createCategorizeLogsServiceImplementations({ search: dependencies.search }) + ), + { + inspect: consoleInspector, + input: { + index: logsSource.indexName, + startTimestamp: timeRange.start, + endTimestamp: timeRange.end, + timeField: logsSource.timestampField, + messageField: logsSource.messageField, + documentFilters, + }, + } + ); + + const cancelOperation = useCallback(() => { + sendToCategorizeLogsService({ + type: 'cancel', + }); + }, [sendToCategorizeLogsService]); + + if (categorizeLogsServiceState.matches('done')) { + return ( + + ); + } else if (categorizeLogsServiceState.matches('failed')) { + return ; + } else if (categorizeLogsServiceState.matches('countingDocuments')) { + return ; + } else if ( + categorizeLogsServiceState.matches('fetchingSampledCategories') || + categorizeLogsServiceState.matches('fetchingRemainingCategories') + ) { + return ; + } else { + return null; + } +}; + +const consoleInspector = createConsoleInspector(); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx new file mode 100644 index 0000000000000..4538b0ec2fd5d --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import React from 'react'; +import type { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { DiscoverLink } from '../discover_link'; + +export interface LogCategoriesControlBarProps { + documentFilters?: QueryDslQueryContainer[]; + logsSource: IndexNameLogsSourceConfiguration; + timeRange: { + start: string; + end: string; + }; + dependencies: LogCategoriesControlBarDependencies; +} + +export interface LogCategoriesControlBarDependencies { + share: SharePluginStart; +} + +export const LogCategoriesControlBar: React.FC = React.memo( + ({ dependencies, documentFilters, logsSource, timeRange }) => { + return ( + + + + + + ); + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx new file mode 100644 index 0000000000000..1a335e3265294 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiCodeBlock, EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export interface LogCategoriesErrorContentProps { + error?: Error; +} + +export const LogCategoriesErrorContent: React.FC = ({ error }) => { + return ( + {logsOverviewErrorTitle}} + body={ + +

    {error?.stack ?? error?.toString() ?? unknownErrorDescription}

    +
    + } + layout="vertical" + /> + ); +}; + +const logsOverviewErrorTitle = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.errorTitle', + { + defaultMessage: 'Failed to categorize logs', + } +); + +const unknownErrorDescription = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.unknownErrorDescription', + { + defaultMessage: 'An unspecified error occurred.', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx new file mode 100644 index 0000000000000..d9e960685de99 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx @@ -0,0 +1,182 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiDataGrid, + EuiDataGridColumnSortingConfig, + EuiDataGridPaginationProps, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { createConsoleInspector } from '@kbn/xstate-utils'; +import { useMachine } from '@xstate5/react'; +import _ from 'lodash'; +import React, { useMemo } from 'react'; +import { assign, setup } from 'xstate5'; +import { LogCategory } from '../../types'; +import { + LogCategoriesGridCellDependencies, + LogCategoriesGridColumnId, + createCellContext, + logCategoriesGridColumnIds, + logCategoriesGridColumns, + renderLogCategoriesGridCell, +} from './log_categories_grid_cell'; + +export interface LogCategoriesGridProps { + dependencies: LogCategoriesGridDependencies; + logCategories: LogCategory[]; +} + +export type LogCategoriesGridDependencies = LogCategoriesGridCellDependencies; + +export const LogCategoriesGrid: React.FC = ({ + dependencies, + logCategories, +}) => { + const [gridState, dispatchGridEvent] = useMachine(gridStateService, { + input: { + visibleColumns: logCategoriesGridColumns.map(({ id }) => id), + }, + inspect: consoleInspector, + }); + + const sortedLogCategories = useMemo(() => { + const sortingCriteria = gridState.context.sortingColumns.map( + ({ id, direction }): [(logCategory: LogCategory) => any, 'asc' | 'desc'] => { + switch (id) { + case 'count': + return [(logCategory: LogCategory) => logCategory.documentCount, direction]; + case 'change_type': + // TODO: use better sorting weight for change types + return [(logCategory: LogCategory) => logCategory.change.type, direction]; + case 'change_time': + return [ + (logCategory: LogCategory) => + 'timestamp' in logCategory.change ? logCategory.change.timestamp ?? '' : '', + direction, + ]; + default: + return [_.identity, direction]; + } + } + ); + return _.orderBy( + logCategories, + sortingCriteria.map(([accessor]) => accessor), + sortingCriteria.map(([, direction]) => direction) + ); + }, [gridState.context.sortingColumns, logCategories]); + + return ( + + dispatchGridEvent({ type: 'changeVisibleColumns', visibleColumns }), + }} + cellContext={createCellContext(sortedLogCategories, dependencies)} + pagination={{ + ...gridState.context.pagination, + onChangeItemsPerPage: (pageSize) => dispatchGridEvent({ type: 'changePageSize', pageSize }), + onChangePage: (pageIndex) => dispatchGridEvent({ type: 'changePageIndex', pageIndex }), + }} + renderCellValue={renderLogCategoriesGridCell} + rowCount={sortedLogCategories.length} + sorting={{ + columns: gridState.context.sortingColumns, + onSort: (sortingColumns) => + dispatchGridEvent({ type: 'changeSortingColumns', sortingColumns }), + }} + /> + ); +}; + +const gridStateService = setup({ + types: { + context: {} as { + visibleColumns: string[]; + pagination: Pick; + sortingColumns: LogCategoriesGridSortingConfig[]; + }, + events: {} as + | { + type: 'changePageSize'; + pageSize: number; + } + | { + type: 'changePageIndex'; + pageIndex: number; + } + | { + type: 'changeSortingColumns'; + sortingColumns: EuiDataGridColumnSortingConfig[]; + } + | { + type: 'changeVisibleColumns'; + visibleColumns: string[]; + }, + input: {} as { + visibleColumns: string[]; + }, + }, +}).createMachine({ + id: 'logCategoriesGridState', + context: ({ input }) => ({ + visibleColumns: input.visibleColumns, + pagination: { pageIndex: 0, pageSize: 20, pageSizeOptions: [10, 20, 50] }, + sortingColumns: [{ id: 'change_time', direction: 'desc' }], + }), + on: { + changePageSize: { + actions: assign(({ context, event }) => ({ + pagination: { + ...context.pagination, + pageIndex: 0, + pageSize: event.pageSize, + }, + })), + }, + changePageIndex: { + actions: assign(({ context, event }) => ({ + pagination: { + ...context.pagination, + pageIndex: event.pageIndex, + }, + })), + }, + changeSortingColumns: { + actions: assign(({ event }) => ({ + sortingColumns: event.sortingColumns.filter( + (sortingConfig): sortingConfig is LogCategoriesGridSortingConfig => + (logCategoriesGridColumnIds as string[]).includes(sortingConfig.id) + ), + })), + }, + changeVisibleColumns: { + actions: assign(({ event }) => ({ + visibleColumns: event.visibleColumns, + })), + }, + }, +}); + +const consoleInspector = createConsoleInspector(); + +const logCategoriesGridLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.euiDataGrid.logCategoriesLabel', + { defaultMessage: 'Log categories' } +); + +interface TypedEuiDataGridColumnSortingConfig + extends EuiDataGridColumnSortingConfig { + id: ColumnId; +} + +type LogCategoriesGridSortingConfig = + TypedEuiDataGridColumnSortingConfig; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx new file mode 100644 index 0000000000000..d6ab4969eaf7b --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiDataGridColumn, RenderCellValue } from '@elastic/eui'; +import React from 'react'; +import { LogCategory } from '../../types'; +import { + LogCategoriesGridChangeTimeCell, + LogCategoriesGridChangeTimeCellDependencies, + logCategoriesGridChangeTimeColumn, +} from './log_categories_grid_change_time_cell'; +import { + LogCategoriesGridChangeTypeCell, + logCategoriesGridChangeTypeColumn, +} from './log_categories_grid_change_type_cell'; +import { + LogCategoriesGridCountCell, + logCategoriesGridCountColumn, +} from './log_categories_grid_count_cell'; +import { + LogCategoriesGridHistogramCell, + LogCategoriesGridHistogramCellDependencies, + logCategoriesGridHistoryColumn, +} from './log_categories_grid_histogram_cell'; +import { + LogCategoriesGridPatternCell, + logCategoriesGridPatternColumn, +} from './log_categories_grid_pattern_cell'; + +export interface LogCategoriesGridCellContext { + dependencies: LogCategoriesGridCellDependencies; + logCategories: LogCategory[]; +} + +export type LogCategoriesGridCellDependencies = LogCategoriesGridHistogramCellDependencies & + LogCategoriesGridChangeTimeCellDependencies; + +export const renderLogCategoriesGridCell: RenderCellValue = ({ + rowIndex, + columnId, + isExpanded, + ...rest +}) => { + const { dependencies, logCategories } = getCellContext(rest); + + const logCategory = logCategories[rowIndex]; + + switch (columnId as LogCategoriesGridColumnId) { + case 'pattern': + return ; + case 'count': + return ; + case 'history': + return ( + + ); + case 'change_type': + return ; + case 'change_time': + return ( + + ); + default: + return <>-; + } +}; + +export const logCategoriesGridColumns = [ + logCategoriesGridPatternColumn, + logCategoriesGridCountColumn, + logCategoriesGridChangeTypeColumn, + logCategoriesGridChangeTimeColumn, + logCategoriesGridHistoryColumn, +] satisfies EuiDataGridColumn[]; + +export const logCategoriesGridColumnIds = logCategoriesGridColumns.map(({ id }) => id); + +export type LogCategoriesGridColumnId = (typeof logCategoriesGridColumns)[number]['id']; + +const cellContextKey = 'cellContext'; + +const getCellContext = (cellContext: object): LogCategoriesGridCellContext => + (cellContextKey in cellContext + ? cellContext[cellContextKey] + : {}) as LogCategoriesGridCellContext; + +export const createCellContext = ( + logCategories: LogCategory[], + dependencies: LogCategoriesGridCellDependencies +): { [cellContextKey]: LogCategoriesGridCellContext } => ({ + [cellContextKey]: { + dependencies, + logCategories, + }, +}); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx new file mode 100644 index 0000000000000..5ad8cbdd49346 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiDataGridColumn } from '@elastic/eui'; +import { SettingsStart } from '@kbn/core-ui-settings-browser'; +import { i18n } from '@kbn/i18n'; +import moment from 'moment'; +import React, { useMemo } from 'react'; +import { LogCategory } from '../../types'; + +export const logCategoriesGridChangeTimeColumn = { + id: 'change_time' as const, + display: i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.changeTimeColumnLabel', + { + defaultMessage: 'Change at', + } + ), + isSortable: true, + initialWidth: 220, + schema: 'datetime', +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridChangeTimeCellProps { + dependencies: LogCategoriesGridChangeTimeCellDependencies; + logCategory: LogCategory; +} + +export interface LogCategoriesGridChangeTimeCellDependencies { + uiSettings: SettingsStart; +} + +export const LogCategoriesGridChangeTimeCell: React.FC = ({ + dependencies, + logCategory, +}) => { + const dateFormat = useMemo( + () => dependencies.uiSettings.client.get('dateFormat'), + [dependencies.uiSettings.client] + ); + if (!('timestamp' in logCategory.change && logCategory.change.timestamp != null)) { + return null; + } + + if (dateFormat) { + return <>{moment(logCategory.change.timestamp).format(dateFormat)}; + } else { + return <>{logCategory.change.timestamp}; + } +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx new file mode 100644 index 0000000000000..af6349bd0e18c --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiBadge, EuiDataGridColumn } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { LogCategory } from '../../types'; + +export const logCategoriesGridChangeTypeColumn = { + id: 'change_type' as const, + display: i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.changeTypeColumnLabel', + { + defaultMessage: 'Change type', + } + ), + isSortable: true, + initialWidth: 110, +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridChangeTypeCellProps { + logCategory: LogCategory; +} + +export const LogCategoriesGridChangeTypeCell: React.FC = ({ + logCategory, +}) => { + switch (logCategory.change.type) { + case 'dip': + return {dipBadgeLabel}; + case 'spike': + return {spikeBadgeLabel}; + case 'step': + return {stepBadgeLabel}; + case 'distribution': + return {distributionBadgeLabel}; + case 'rare': + return {rareBadgeLabel}; + case 'trend': + return {trendBadgeLabel}; + case 'other': + return {otherBadgeLabel}; + case 'none': + return <>-; + default: + return {unknownBadgeLabel}; + } +}; + +const dipBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.dipChangeTypeBadgeLabel', + { + defaultMessage: 'Dip', + } +); + +const spikeBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.spikeChangeTypeBadgeLabel', + { + defaultMessage: 'Spike', + } +); + +const stepBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.spikeChangeTypeBadgeLabel', + { + defaultMessage: 'Step', + } +); + +const distributionBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.distributionChangeTypeBadgeLabel', + { + defaultMessage: 'Distribution', + } +); + +const trendBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.spikeChangeTypeBadgeLabel', + { + defaultMessage: 'Trend', + } +); + +const otherBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.otherChangeTypeBadgeLabel', + { + defaultMessage: 'Other', + } +); + +const unknownBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.unknownChangeTypeBadgeLabel', + { + defaultMessage: 'Unknown', + } +); + +const rareBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.rareChangeTypeBadgeLabel', + { + defaultMessage: 'Rare', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx new file mode 100644 index 0000000000000..f2247aab5212e --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiDataGridColumn } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedNumber } from '@kbn/i18n-react'; +import React from 'react'; +import { LogCategory } from '../../types'; + +export const logCategoriesGridCountColumn = { + id: 'count' as const, + display: i18n.translate('xpack.observabilityLogsOverview.logCategoriesGrid.countColumnLabel', { + defaultMessage: 'Events', + }), + isSortable: true, + schema: 'numeric', + initialWidth: 100, +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridCountCellProps { + logCategory: LogCategory; +} + +export const LogCategoriesGridCountCell: React.FC = ({ + logCategory, +}) => { + return ; +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx new file mode 100644 index 0000000000000..2fb50b0f2f3b4 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + BarSeries, + Chart, + LineAnnotation, + LineAnnotationStyle, + PartialTheme, + Settings, + Tooltip, + TooltipType, +} from '@elastic/charts'; +import { EuiDataGridColumn } from '@elastic/eui'; +import { ChartsPluginStart } from '@kbn/charts-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { RecursivePartial } from '@kbn/utility-types'; +import React from 'react'; +import { LogCategory, LogCategoryHistogramBucket } from '../../types'; + +export const logCategoriesGridHistoryColumn = { + id: 'history' as const, + display: i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.histogramColumnLabel', + { + defaultMessage: 'Timeline', + } + ), + isSortable: false, + initialWidth: 250, + isExpandable: false, +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridHistogramCellProps { + dependencies: LogCategoriesGridHistogramCellDependencies; + logCategory: LogCategory; +} + +export interface LogCategoriesGridHistogramCellDependencies { + charts: ChartsPluginStart; +} + +export const LogCategoriesGridHistogramCell: React.FC = ({ + dependencies: { charts }, + logCategory, +}) => { + const baseTheme = charts.theme.useChartsBaseTheme(); + const sparklineTheme = charts.theme.useSparklineOverrides(); + + return ( + + + + + {'timestamp' in logCategory.change && logCategory.change.timestamp != null ? ( + + ) : null} + + ); +}; + +const localThemeOverrides: PartialTheme = { + scales: { + histogramPadding: 0.1, + }, + background: { + color: 'transparent', + }, +}; + +const annotationStyle: RecursivePartial = { + line: { + strokeWidth: 2, + }, +}; + +const timestampAccessor = (histogram: LogCategoryHistogramBucket) => + new Date(histogram.timestamp).getTime(); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx new file mode 100644 index 0000000000000..d507487a99e3c --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiDataGridColumn, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; +import { LogCategory } from '../../types'; + +export const logCategoriesGridPatternColumn = { + id: 'pattern' as const, + display: i18n.translate('xpack.observabilityLogsOverview.logCategoriesGrid.patternColumnLabel', { + defaultMessage: 'Pattern', + }), + isSortable: false, + schema: 'string', +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridPatternCellProps { + logCategory: LogCategory; +} + +export const LogCategoriesGridPatternCell: React.FC = ({ + logCategory, +}) => { + const theme = useEuiTheme(); + const { euiTheme } = theme; + const termsList = useMemo(() => logCategory.terms.split(' '), [logCategory.terms]); + + const commonStyle = css` + display: inline-block; + font-family: ${euiTheme.font.familyCode}; + margin-right: ${euiTheme.size.xs}; + `; + + const termStyle = css` + ${commonStyle}; + `; + + const separatorStyle = css` + ${commonStyle}; + color: ${euiTheme.colors.successText}; + `; + + return ( +
    +      
    *
    + {termsList.map((term, index) => ( + +
    {term}
    +
    *
    +
    + ))} +
    + ); +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx new file mode 100644 index 0000000000000..0fde469fe717d --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; + +export interface LogCategoriesLoadingContentProps { + onCancel?: () => void; + stage: 'counting' | 'categorizing'; +} + +export const LogCategoriesLoadingContent: React.FC = ({ + onCancel, + stage, +}) => { + return ( + } + title={ +

    + {stage === 'counting' + ? logCategoriesLoadingStateCountingTitle + : logCategoriesLoadingStateCategorizingTitle} +

    + } + actions={ + onCancel != null + ? [ + { + onCancel(); + }} + > + {logCategoriesLoadingStateCancelButtonLabel} + , + ] + : [] + } + /> + ); +}; + +const logCategoriesLoadingStateCountingTitle = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.loadingStageCountingTitle', + { + defaultMessage: 'Estimating log volume', + } +); + +const logCategoriesLoadingStateCategorizingTitle = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.loadingStageCategorizingTitle', + { + defaultMessage: 'Categorizing logs', + } +); + +const logCategoriesLoadingStateCancelButtonLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.loadingStateCancelButtonLabel', + { + defaultMessage: 'Cancel', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx new file mode 100644 index 0000000000000..e16bdda7cb44a --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { LogCategory } from '../../types'; +import { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { + LogCategoriesControlBar, + LogCategoriesControlBarDependencies, +} from './log_categories_control_bar'; +import { LogCategoriesGrid, LogCategoriesGridDependencies } from './log_categories_grid'; + +export interface LogCategoriesResultContentProps { + dependencies: LogCategoriesResultContentDependencies; + documentFilters?: QueryDslQueryContainer[]; + logCategories: LogCategory[]; + logsSource: IndexNameLogsSourceConfiguration; + timeRange: { + start: string; + end: string; + }; +} + +export type LogCategoriesResultContentDependencies = LogCategoriesControlBarDependencies & + LogCategoriesGridDependencies; + +export const LogCategoriesResultContent: React.FC = ({ + dependencies, + documentFilters, + logCategories, + logsSource, + timeRange, +}) => { + if (logCategories.length === 0) { + return ; + } else { + return ( + + + + + + + + + ); + } +}; + +export const LogCategoriesEmptyResultContent: React.FC = () => { + return ( + {emptyResultContentDescription}

    } + color="subdued" + layout="horizontal" + title={

    {emptyResultContentTitle}

    } + titleSize="m" + /> + ); +}; + +const emptyResultContentTitle = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.emptyResultContentTitle', + { + defaultMessage: 'No log categories found', + } +); + +const emptyResultContentDescription = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.emptyResultContentDescription', + { + defaultMessage: + 'No suitable documents within the time range. Try searching for a longer time period.', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts new file mode 100644 index 0000000000000..878f634f078ad --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './logs_overview'; +export * from './logs_overview_error_content'; +export * from './logs_overview_loading_content'; diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx new file mode 100644 index 0000000000000..988656eb1571e --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { type LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; +import React from 'react'; +import useAsync from 'react-use/lib/useAsync'; +import { LogsSourceConfiguration, normalizeLogsSource } from '../../utils/logs_source'; +import { LogCategories, LogCategoriesDependencies } from '../log_categories'; +import { LogsOverviewErrorContent } from './logs_overview_error_content'; +import { LogsOverviewLoadingContent } from './logs_overview_loading_content'; + +export interface LogsOverviewProps { + dependencies: LogsOverviewDependencies; + documentFilters?: QueryDslQueryContainer[]; + logsSource?: LogsSourceConfiguration; + timeRange: { + start: string; + end: string; + }; +} + +export type LogsOverviewDependencies = LogCategoriesDependencies & { + logsDataAccess: LogsDataAccessPluginStart; +}; + +export const LogsOverview: React.FC = React.memo( + ({ + dependencies, + documentFilters = defaultDocumentFilters, + logsSource = defaultLogsSource, + timeRange, + }) => { + const normalizedLogsSource = useAsync( + () => normalizeLogsSource({ logsDataAccess: dependencies.logsDataAccess })(logsSource), + [dependencies.logsDataAccess, logsSource] + ); + + if (normalizedLogsSource.loading) { + return ; + } + + if (normalizedLogsSource.error != null || normalizedLogsSource.value == null) { + return ; + } + + return ( + + ); + } +); + +const defaultDocumentFilters: QueryDslQueryContainer[] = []; + +const defaultLogsSource: LogsSourceConfiguration = { type: 'shared_setting' }; diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx new file mode 100644 index 0000000000000..73586756bb908 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiCodeBlock, EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export interface LogsOverviewErrorContentProps { + error?: Error; +} + +export const LogsOverviewErrorContent: React.FC = ({ error }) => { + return ( + {logsOverviewErrorTitle}} + body={ + +

    {error?.stack ?? error?.toString() ?? unknownErrorDescription}

    +
    + } + layout="vertical" + /> + ); +}; + +const logsOverviewErrorTitle = i18n.translate('xpack.observabilityLogsOverview.errorTitle', { + defaultMessage: 'Error', +}); + +const unknownErrorDescription = i18n.translate( + 'xpack.observabilityLogsOverview.unknownErrorDescription', + { + defaultMessage: 'An unspecified error occurred.', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx new file mode 100644 index 0000000000000..7645fdb90f0ac --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export const LogsOverviewLoadingContent: React.FC = ({}) => { + return ( + } + title={

    {logsOverviewLoadingTitle}

    } + /> + ); +}; + +const logsOverviewLoadingTitle = i18n.translate('xpack.observabilityLogsOverview.loadingTitle', { + defaultMessage: 'Loading', +}); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts new file mode 100644 index 0000000000000..7260efe63d435 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts @@ -0,0 +1,282 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ISearchGeneric } from '@kbn/search-types'; +import { lastValueFrom } from 'rxjs'; +import { fromPromise } from 'xstate5'; +import { createRandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; +import { z } from '@kbn/zod'; +import { LogCategorizationParams } from './types'; +import { createCategorizationRequestParams } from './queries'; +import { LogCategory, LogCategoryChange } from '../../types'; + +// the fraction of a category's histogram below which the category is considered rare +const rarityThreshold = 0.2; +const maxCategoriesCount = 1000; + +export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => + fromPromise< + { + categories: LogCategory[]; + hasReachedLimit: boolean; + }, + LogCategorizationParams & { + samplingProbability: number; + ignoredCategoryTerms: string[]; + minDocsPerCategory: number; + } + >( + async ({ + input: { + index, + endTimestamp, + startTimestamp, + timeField, + messageField, + samplingProbability, + ignoredCategoryTerms, + documentFilters = [], + minDocsPerCategory, + }, + signal, + }) => { + const randomSampler = createRandomSamplerWrapper({ + probability: samplingProbability, + seed: 1, + }); + + const requestParams = createCategorizationRequestParams({ + index, + timeField, + messageField, + startTimestamp, + endTimestamp, + randomSampler, + additionalFilters: documentFilters, + ignoredCategoryTerms, + minDocsPerCategory, + maxCategoriesCount, + }); + + const { rawResponse } = await lastValueFrom( + search({ params: requestParams }, { abortSignal: signal }) + ); + + if (rawResponse.aggregations == null) { + throw new Error('No aggregations found in large categories response'); + } + + const logCategoriesAggResult = randomSampler.unwrap(rawResponse.aggregations); + + if (!('categories' in logCategoriesAggResult)) { + throw new Error('No categorization aggregation found in large categories response'); + } + + const logCategories = + (logCategoriesAggResult.categories.buckets as unknown[]).map(mapCategoryBucket) ?? []; + + return { + categories: logCategories, + hasReachedLimit: logCategories.length >= maxCategoriesCount, + }; + } + ); + +const mapCategoryBucket = (bucket: any): LogCategory => + esCategoryBucketSchema + .transform((parsedBucket) => ({ + change: mapChangePoint(parsedBucket), + documentCount: parsedBucket.doc_count, + histogram: parsedBucket.histogram, + terms: parsedBucket.key, + })) + .parse(bucket); + +const mapChangePoint = ({ change, histogram }: EsCategoryBucket): LogCategoryChange => { + switch (change.type) { + case 'stationary': + if (isRareInHistogram(histogram)) { + return { + type: 'rare', + timestamp: findFirstNonZeroBucket(histogram)?.timestamp ?? histogram[0].timestamp, + }; + } else { + return { + type: 'none', + }; + } + case 'dip': + case 'spike': + return { + type: change.type, + timestamp: change.bucket.key, + }; + case 'step_change': + return { + type: 'step', + timestamp: change.bucket.key, + }; + case 'distribution_change': + return { + type: 'distribution', + timestamp: change.bucket.key, + }; + case 'trend_change': + return { + type: 'trend', + timestamp: change.bucket.key, + correlationCoefficient: change.details.r_value, + }; + case 'unknown': + return { + type: 'unknown', + rawChange: change.rawChange, + }; + case 'non_stationary': + default: + return { + type: 'other', + }; + } +}; + +/** + * The official types are lacking the change_point aggregation + */ +const esChangePointBucketSchema = z.object({ + key: z.string().datetime(), + doc_count: z.number(), +}); + +const esChangePointDetailsSchema = z.object({ + p_value: z.number(), +}); + +const esChangePointCorrelationSchema = esChangePointDetailsSchema.extend({ + r_value: z.number(), +}); + +const esChangePointSchema = z.union([ + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + dip: esChangePointDetailsSchema, + }), + }) + .transform(({ bucket, type: { dip: details } }) => ({ + type: 'dip' as const, + bucket, + details, + })), + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + spike: esChangePointDetailsSchema, + }), + }) + .transform(({ bucket, type: { spike: details } }) => ({ + type: 'spike' as const, + bucket, + details, + })), + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + step_change: esChangePointDetailsSchema, + }), + }) + .transform(({ bucket, type: { step_change: details } }) => ({ + type: 'step_change' as const, + bucket, + details, + })), + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + trend_change: esChangePointCorrelationSchema, + }), + }) + .transform(({ bucket, type: { trend_change: details } }) => ({ + type: 'trend_change' as const, + bucket, + details, + })), + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + distribution_change: esChangePointDetailsSchema, + }), + }) + .transform(({ bucket, type: { distribution_change: details } }) => ({ + type: 'distribution_change' as const, + bucket, + details, + })), + z + .object({ + type: z.object({ + non_stationary: esChangePointCorrelationSchema.extend({ + trend: z.enum(['increasing', 'decreasing']), + }), + }), + }) + .transform(({ type: { non_stationary: details } }) => ({ + type: 'non_stationary' as const, + details, + })), + z + .object({ + type: z.object({ + stationary: z.object({}), + }), + }) + .transform(() => ({ type: 'stationary' as const })), + z + .object({ + type: z.object({}), + }) + .transform((value) => ({ type: 'unknown' as const, rawChange: JSON.stringify(value) })), +]); + +const esHistogramSchema = z + .object({ + buckets: z.array( + z + .object({ + key_as_string: z.string(), + doc_count: z.number(), + }) + .transform((bucket) => ({ + timestamp: bucket.key_as_string, + documentCount: bucket.doc_count, + })) + ), + }) + .transform(({ buckets }) => buckets); + +type EsHistogram = z.output; + +const esCategoryBucketSchema = z.object({ + key: z.string(), + doc_count: z.number(), + change: esChangePointSchema, + histogram: esHistogramSchema, +}); + +type EsCategoryBucket = z.output; + +const isRareInHistogram = (histogram: EsHistogram): boolean => + histogram.filter((bucket) => bucket.documentCount > 0).length < + histogram.length * rarityThreshold; + +const findFirstNonZeroBucket = (histogram: EsHistogram) => + histogram.find((bucket) => bucket.documentCount > 0); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts new file mode 100644 index 0000000000000..deeb758d2d737 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts @@ -0,0 +1,250 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MachineImplementationsFrom, assign, setup } from 'xstate5'; +import { LogCategory } from '../../types'; +import { getPlaceholderFor } from '../../utils/xstate5_utils'; +import { categorizeDocuments } from './categorize_documents'; +import { countDocuments } from './count_documents'; +import { CategorizeLogsServiceDependencies, LogCategorizationParams } from './types'; + +export const categorizeLogsService = setup({ + types: { + input: {} as LogCategorizationParams, + output: {} as { + categories: LogCategory[]; + documentCount: number; + hasReachedLimit: boolean; + samplingProbability: number; + }, + context: {} as { + categories: LogCategory[]; + documentCount: number; + error?: Error; + hasReachedLimit: boolean; + parameters: LogCategorizationParams; + samplingProbability: number; + }, + events: {} as { + type: 'cancel'; + }, + }, + actors: { + countDocuments: getPlaceholderFor(countDocuments), + categorizeDocuments: getPlaceholderFor(categorizeDocuments), + }, + actions: { + storeError: assign((_, params: { error: unknown }) => ({ + error: params.error instanceof Error ? params.error : new Error(String(params.error)), + })), + storeCategories: assign( + ({ context }, params: { categories: LogCategory[]; hasReachedLimit: boolean }) => ({ + categories: [...context.categories, ...params.categories], + hasReachedLimit: params.hasReachedLimit, + }) + ), + storeDocumentCount: assign( + (_, params: { documentCount: number; samplingProbability: number }) => ({ + documentCount: params.documentCount, + samplingProbability: params.samplingProbability, + }) + ), + }, + guards: { + hasTooFewDocuments: (_guardArgs, params: { documentCount: number }) => params.documentCount < 1, + requiresSampling: (_guardArgs, params: { samplingProbability: number }) => + params.samplingProbability < 1, + }, +}).createMachine({ + /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QBmMwA5KACy+AQFmob4AjABMwQBsADQgAJ6IkYEAnJkA7FmxZlERmQGxAL4liXJYeESk5FQ0DEws7Jw8fILCogYy1BhVirUqDerNWm26+vSScsb01iYRNkggDk4u9G6eCD7+QSFhftFxiSkIvgCsWZSxEVlRsbFZ52Zm515lFX0KNcr1ak2aVo6ARCERiKbSWRfapKOqqRoaFraPiTaZGUyWExRJb2RzOWabbx+QLBULhI7FE7eWL+F45GnRPIRZkfECVb6wob-RFjYH8MC4XB4Sh2AA2GAAZnguL15DDBn8EaMgSiDDMMVZLG5VvjXMstjsSftyTFKclEOdzgFKF5zukvA8zBFnl50udWez5b94SNAcjdPw0PRkGBRdZtXj1oTtsS9mTDqaEuaEBF8udKFkIr5fK6olkzOksgEPdCBt6JWB0MgABYaADKqC4YsgAGFS-g4B0wd0oXKBg2m6LW+24OHljqo-rEMzbpQos8-K7fC9CknTrF0rEbbb0oVMoWIgF3eU2e3OVQK1XaywB82IG2+x2BAKhbgReL0FLcDLPf3G3eH36J8x1xNYCSnFNmSuecXhzdJlydTcqQQLJfHSOc0PyLJN3SMxYiPEtH3PShLxret-yHe8RwEIMQzDLVx0jcDQC2GdoIXOCENXZDsyiOcAiiKJ0iiPDLi8V1CKA4jSOvKAACUwC4VBmA0QDvk7UEughHpfxqBSlJUlg1OqUcGNA3UNggrMs347IjzdaIvGQwSvECXI8k3Z43gEiJJI5BUSMrMiWH05T6FU6j+UFYUxUlaVZSksBQsMqBjIIUycRWJi9RY6dIn8KIAjsu1zkc5CAmiG1fBiaIzB8B0QmPT4iICmSNGS8KjMi2jQxArKwJyjw8pswriocqInOTLwIi3ASD1yQpswCd5WXobAIDgNxdPPCMBss3KEAAWjXRBDvTfcLsu9Jlr8r04WGAEkXGeBGL26MBOQzIt2ut4cwmirCt8W6yzhNqbwo4dH0216LOjTMIjnBdYhK1DYgdHjihtZbUIdWIXJuYGflBoLZI6iKoZe8zJwOw9KtGt1kbuTcsmQrwi0oeCQjzZ5blwt1Cek5TKN22GIIKZbAgKC45pyLyeLwtz4Kyabs1QgWAs0kXqaGhBxdcnzpaE2XXmch0MORmaBJeLwjbKMogA */ + id: 'categorizeLogs', + context: ({ input }) => ({ + categories: [], + documentCount: 0, + hasReachedLimit: false, + parameters: input, + samplingProbability: 1, + }), + initial: 'countingDocuments', + states: { + countingDocuments: { + invoke: { + src: 'countDocuments', + input: ({ context }) => context.parameters, + onDone: [ + { + target: 'done', + guard: { + type: 'hasTooFewDocuments', + params: ({ event }) => event.output, + }, + actions: [ + { + type: 'storeDocumentCount', + params: ({ event }) => event.output, + }, + ], + }, + { + target: 'fetchingSampledCategories', + guard: { + type: 'requiresSampling', + params: ({ event }) => event.output, + }, + actions: [ + { + type: 'storeDocumentCount', + params: ({ event }) => event.output, + }, + ], + }, + { + target: 'fetchingRemainingCategories', + actions: [ + { + type: 'storeDocumentCount', + params: ({ event }) => event.output, + }, + ], + }, + ], + onError: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: ({ event }) => ({ error: event.error }), + }, + ], + }, + }, + + on: { + cancel: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: () => ({ error: new Error('Counting cancelled') }), + }, + ], + }, + }, + }, + + fetchingSampledCategories: { + invoke: { + src: 'categorizeDocuments', + id: 'categorizeSampledCategories', + input: ({ context }) => ({ + ...context.parameters, + samplingProbability: context.samplingProbability, + ignoredCategoryTerms: [], + minDocsPerCategory: 10, + }), + onDone: { + target: 'fetchingRemainingCategories', + actions: [ + { + type: 'storeCategories', + params: ({ event }) => event.output, + }, + ], + }, + onError: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: ({ event }) => ({ error: event.error }), + }, + ], + }, + }, + + on: { + cancel: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: () => ({ error: new Error('Categorization cancelled') }), + }, + ], + }, + }, + }, + + fetchingRemainingCategories: { + invoke: { + src: 'categorizeDocuments', + id: 'categorizeRemainingCategories', + input: ({ context }) => ({ + ...context.parameters, + samplingProbability: 1, + ignoredCategoryTerms: context.categories.map((category) => category.terms), + minDocsPerCategory: 0, + }), + onDone: { + target: 'done', + actions: [ + { + type: 'storeCategories', + params: ({ event }) => event.output, + }, + ], + }, + onError: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: ({ event }) => ({ error: event.error }), + }, + ], + }, + }, + + on: { + cancel: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: () => ({ error: new Error('Categorization cancelled') }), + }, + ], + }, + }, + }, + + failed: { + type: 'final', + }, + + done: { + type: 'final', + }, + }, + output: ({ context }) => ({ + categories: context.categories, + documentCount: context.documentCount, + hasReachedLimit: context.hasReachedLimit, + samplingProbability: context.samplingProbability, + }), +}); + +export const createCategorizeLogsServiceImplementations = ({ + search, +}: CategorizeLogsServiceDependencies): MachineImplementationsFrom< + typeof categorizeLogsService +> => ({ + actors: { + categorizeDocuments: categorizeDocuments({ search }), + countDocuments: countDocuments({ search }), + }, +}); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts new file mode 100644 index 0000000000000..359f9ddac2bd8 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getSampleProbability } from '@kbn/ml-random-sampler-utils'; +import { ISearchGeneric } from '@kbn/search-types'; +import { lastValueFrom } from 'rxjs'; +import { fromPromise } from 'xstate5'; +import { LogCategorizationParams } from './types'; +import { createCategorizationQuery } from './queries'; + +export const countDocuments = ({ search }: { search: ISearchGeneric }) => + fromPromise< + { + documentCount: number; + samplingProbability: number; + }, + LogCategorizationParams + >( + async ({ + input: { index, endTimestamp, startTimestamp, timeField, messageField, documentFilters }, + signal, + }) => { + const { rawResponse: totalHitsResponse } = await lastValueFrom( + search( + { + params: { + index, + size: 0, + track_total_hits: true, + query: createCategorizationQuery({ + messageField, + timeField, + startTimestamp, + endTimestamp, + additionalFilters: documentFilters, + }), + }, + }, + { abortSignal: signal } + ) + ); + + const documentCount = + totalHitsResponse.hits.total == null + ? 0 + : typeof totalHitsResponse.hits.total === 'number' + ? totalHitsResponse.hits.total + : totalHitsResponse.hits.total.value; + const samplingProbability = getSampleProbability(documentCount); + + return { + documentCount, + samplingProbability, + }; + } + ); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts new file mode 100644 index 0000000000000..149359b7d2015 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './categorize_logs_service'; diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts new file mode 100644 index 0000000000000..aef12da303bcc --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { calculateAuto } from '@kbn/calculate-auto'; +import { RandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; +import moment from 'moment'; + +const isoTimestampFormat = "YYYY-MM-DD'T'HH:mm:ss.SSS'Z'"; + +export const createCategorizationQuery = ({ + messageField, + timeField, + startTimestamp, + endTimestamp, + additionalFilters = [], + ignoredCategoryTerms = [], +}: { + messageField: string; + timeField: string; + startTimestamp: string; + endTimestamp: string; + additionalFilters?: QueryDslQueryContainer[]; + ignoredCategoryTerms?: string[]; +}): QueryDslQueryContainer => { + return { + bool: { + filter: [ + { + exists: { + field: messageField, + }, + }, + { + range: { + [timeField]: { + gte: startTimestamp, + lte: endTimestamp, + format: 'strict_date_time', + }, + }, + }, + ...additionalFilters, + ], + must_not: ignoredCategoryTerms.map(createCategoryQuery(messageField)), + }, + }; +}; + +export const createCategorizationRequestParams = ({ + index, + timeField, + messageField, + startTimestamp, + endTimestamp, + randomSampler, + minDocsPerCategory = 0, + additionalFilters = [], + ignoredCategoryTerms = [], + maxCategoriesCount = 1000, +}: { + startTimestamp: string; + endTimestamp: string; + index: string; + timeField: string; + messageField: string; + randomSampler: RandomSamplerWrapper; + minDocsPerCategory?: number; + additionalFilters?: QueryDslQueryContainer[]; + ignoredCategoryTerms?: string[]; + maxCategoriesCount?: number; +}) => { + const startMoment = moment(startTimestamp, isoTimestampFormat); + const endMoment = moment(endTimestamp, isoTimestampFormat); + const fixedIntervalDuration = calculateAuto.atLeast( + 24, + moment.duration(endMoment.diff(startMoment)) + ); + const fixedIntervalSize = `${Math.ceil(fixedIntervalDuration?.asMinutes() ?? 1)}m`; + + return { + index, + size: 0, + track_total_hits: false, + query: createCategorizationQuery({ + messageField, + timeField, + startTimestamp, + endTimestamp, + additionalFilters, + ignoredCategoryTerms, + }), + aggs: randomSampler.wrap({ + histogram: { + date_histogram: { + field: timeField, + fixed_interval: fixedIntervalSize, + extended_bounds: { + min: startTimestamp, + max: endTimestamp, + }, + }, + }, + categories: { + categorize_text: { + field: messageField, + size: maxCategoriesCount, + categorization_analyzer: { + tokenizer: 'standard', + }, + ...(minDocsPerCategory > 0 ? { min_doc_count: minDocsPerCategory } : {}), + }, + aggs: { + histogram: { + date_histogram: { + field: timeField, + fixed_interval: fixedIntervalSize, + extended_bounds: { + min: startTimestamp, + max: endTimestamp, + }, + }, + }, + change: { + // @ts-expect-error the official types don't support the change_point aggregation + change_point: { + buckets_path: 'histogram>_count', + }, + }, + }, + }, + }), + }; +}; + +export const createCategoryQuery = + (messageField: string) => + (categoryTerms: string): QueryDslQueryContainer => ({ + match: { + [messageField]: { + query: categoryTerms, + operator: 'AND' as const, + fuzziness: 0, + auto_generate_synonyms_phrase_query: false, + }, + }, + }); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts new file mode 100644 index 0000000000000..e094317a98d62 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { ISearchGeneric } from '@kbn/search-types'; + +export interface CategorizeLogsServiceDependencies { + search: ISearchGeneric; +} + +export interface LogCategorizationParams { + documentFilters: QueryDslQueryContainer[]; + endTimestamp: string; + index: string; + messageField: string; + startTimestamp: string; + timeField: string; +} diff --git a/x-pack/packages/observability/logs_overview/src/types.ts b/x-pack/packages/observability/logs_overview/src/types.ts new file mode 100644 index 0000000000000..4c3d27eca7e7c --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/types.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface LogCategory { + change: LogCategoryChange; + documentCount: number; + histogram: LogCategoryHistogramBucket[]; + terms: string; +} + +export type LogCategoryChange = + | LogCategoryNoChange + | LogCategoryRareChange + | LogCategorySpikeChange + | LogCategoryDipChange + | LogCategoryStepChange + | LogCategoryDistributionChange + | LogCategoryTrendChange + | LogCategoryOtherChange + | LogCategoryUnknownChange; + +export interface LogCategoryNoChange { + type: 'none'; +} + +export interface LogCategoryRareChange { + type: 'rare'; + timestamp: string; +} + +export interface LogCategorySpikeChange { + type: 'spike'; + timestamp: string; +} + +export interface LogCategoryDipChange { + type: 'dip'; + timestamp: string; +} + +export interface LogCategoryStepChange { + type: 'step'; + timestamp: string; +} + +export interface LogCategoryTrendChange { + type: 'trend'; + timestamp: string; + correlationCoefficient: number; +} + +export interface LogCategoryDistributionChange { + type: 'distribution'; + timestamp: string; +} + +export interface LogCategoryOtherChange { + type: 'other'; + timestamp?: string; +} + +export interface LogCategoryUnknownChange { + type: 'unknown'; + rawChange: string; +} + +export interface LogCategoryHistogramBucket { + documentCount: number; + timestamp: string; +} diff --git a/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts b/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts new file mode 100644 index 0000000000000..0c8767c8702d4 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { type AbstractDataView } from '@kbn/data-views-plugin/common'; +import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; + +export type LogsSourceConfiguration = + | SharedSettingLogsSourceConfiguration + | IndexNameLogsSourceConfiguration + | DataViewLogsSourceConfiguration; + +export interface SharedSettingLogsSourceConfiguration { + type: 'shared_setting'; + timestampField?: string; + messageField?: string; +} + +export interface IndexNameLogsSourceConfiguration { + type: 'index_name'; + indexName: string; + timestampField: string; + messageField: string; +} + +export interface DataViewLogsSourceConfiguration { + type: 'data_view'; + dataView: AbstractDataView; + messageField?: string; +} + +export const normalizeLogsSource = + ({ logsDataAccess }: { logsDataAccess: LogsDataAccessPluginStart }) => + async (logsSource: LogsSourceConfiguration): Promise => { + switch (logsSource.type) { + case 'index_name': + return logsSource; + case 'shared_setting': + const logSourcesFromSharedSettings = + await logsDataAccess.services.logSourcesService.getLogSources(); + return { + type: 'index_name', + indexName: logSourcesFromSharedSettings + .map((logSource) => logSource.indexPattern) + .join(','), + timestampField: logsSource.timestampField ?? '@timestamp', + messageField: logsSource.messageField ?? 'message', + }; + case 'data_view': + return { + type: 'index_name', + indexName: logsSource.dataView.getIndexPattern(), + timestampField: logsSource.dataView.timeFieldName ?? '@timestamp', + messageField: logsSource.messageField ?? 'message', + }; + } + }; diff --git a/x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts b/x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts new file mode 100644 index 0000000000000..3df0bf4ea3988 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const getPlaceholderFor = any>( + implementationFactory: ImplementationFactory +): ReturnType => + (() => { + throw new Error('Not implemented'); + }) as ReturnType; diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json new file mode 100644 index 0000000000000..886062ae8855f --- /dev/null +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -0,0 +1,39 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react", + "@kbn/ambient-ui-types", + "@kbn/ambient-storybook-types", + "@emotion/react/types/css-prop" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/data-views-plugin", + "@kbn/i18n", + "@kbn/search-types", + "@kbn/xstate-utils", + "@kbn/core-ui-settings-browser", + "@kbn/i18n-react", + "@kbn/charts-plugin", + "@kbn/utility-types", + "@kbn/logs-data-access-plugin", + "@kbn/ml-random-sampler-utils", + "@kbn/zod", + "@kbn/calculate-auto", + "@kbn/discover-plugin", + "@kbn/es-query", + "@kbn/router-utils", + "@kbn/share-plugin", + ] +} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index 4df52758ceda3..a1dadbf186b91 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -5,19 +5,36 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import moment from 'moment'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { LogStream } from '@kbn/logs-shared-plugin/public'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; -import { useFetcher } from '../../../hooks/use_fetcher'; -import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; -import { APIReturnType } from '../../../services/rest/create_call_apm_api'; - import { CONTAINER_ID, SERVICE_ENVIRONMENT, SERVICE_NAME } from '../../../../common/es_fields/apm'; +import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; +import { useKibana } from '../../../context/kibana_context/use_kibana'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; +import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; +import { APIReturnType } from '../../../services/rest/create_call_apm_api'; export function ServiceLogs() { + const { + services: { + logsShared: { LogsOverview }, + }, + } = useKibana(); + + const isLogsOverviewEnabled = LogsOverview.useIsEnabled(); + + if (isLogsOverviewEnabled) { + return ; + } else { + return ; + } +} + +export function ClassicServiceLogsStream() { const { serviceName } = useApmServiceContext(); const { @@ -58,6 +75,54 @@ export function ServiceLogs() { ); } +export function ServiceLogsOverview() { + const { + services: { logsShared }, + } = useKibana(); + const { serviceName } = useApmServiceContext(); + const { + query: { environment, kuery, rangeFrom, rangeTo }, + } = useAnyOfApmParams('/services/{serviceName}/logs'); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const timeRange = useMemo(() => ({ start, end }), [start, end]); + + const { data: logFilters, status } = useFetcher( + async (callApmApi) => { + if (start == null || end == null) { + return; + } + + const { containerIds } = await callApmApi( + 'GET /internal/apm/services/{serviceName}/infrastructure_attributes', + { + params: { + path: { serviceName }, + query: { + environment, + kuery, + start, + end, + }, + }, + } + ); + + return [getInfrastructureFilter({ containerIds, environment, serviceName })]; + }, + [environment, kuery, serviceName, start, end] + ); + + if (status === FETCH_STATUS.SUCCESS) { + return ; + } else if (status === FETCH_STATUS.FAILURE) { + return ( + + ); + } else { + return ; + } +} + export function getInfrastructureKQLFilter({ data, serviceName, @@ -84,3 +149,99 @@ export function getInfrastructureKQLFilter({ return [serviceNameAndEnvironmentCorrelation, ...containerIdCorrelation].join(' or '); } + +export function getInfrastructureFilter({ + containerIds, + environment, + serviceName, +}: { + containerIds: string[]; + environment: string; + serviceName: string; +}): QueryDslQueryContainer { + return { + bool: { + should: [ + ...getServiceShouldClauses({ environment, serviceName }), + ...getContainerShouldClauses({ containerIds }), + ], + minimum_should_match: 1, + }, + }; +} + +export function getServiceShouldClauses({ + environment, + serviceName, +}: { + environment: string; + serviceName: string; +}): QueryDslQueryContainer[] { + const serviceNameFilter: QueryDslQueryContainer = { + term: { + [SERVICE_NAME]: serviceName, + }, + }; + + if (environment === ENVIRONMENT_ALL.value) { + return [serviceNameFilter]; + } else { + return [ + { + bool: { + filter: [ + serviceNameFilter, + { + term: { + [SERVICE_ENVIRONMENT]: environment, + }, + }, + ], + }, + }, + { + bool: { + filter: [serviceNameFilter], + must_not: [ + { + exists: { + field: SERVICE_ENVIRONMENT, + }, + }, + ], + }, + }, + ]; + } +} + +export function getContainerShouldClauses({ + containerIds = [], +}: { + containerIds: string[]; +}): QueryDslQueryContainer[] { + if (containerIds.length === 0) { + return []; + } + + return [ + { + bool: { + filter: [ + { + terms: { + [CONTAINER_ID]: containerIds, + }, + }, + ], + must_not: [ + { + term: { + [SERVICE_NAME]: '*', + }, + }, + ], + }, + }, + ]; +} diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx index d746e0464fd40..8a4a1c32877c5 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx @@ -330,7 +330,7 @@ export const serviceDetailRoute = { }), element: , searchBarOptions: { - showUnifiedSearchBar: false, + showQueryInput: false, }, }), '/services/{serviceName}/infrastructure': { diff --git a/x-pack/plugins/observability_solution/apm/public/plugin.ts b/x-pack/plugins/observability_solution/apm/public/plugin.ts index 9a9f45f42a39e..b21bdedac9ef8 100644 --- a/x-pack/plugins/observability_solution/apm/public/plugin.ts +++ b/x-pack/plugins/observability_solution/apm/public/plugin.ts @@ -69,6 +69,7 @@ import { from } from 'rxjs'; import { map } from 'rxjs'; import type { CloudSetup } from '@kbn/cloud-plugin/public'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import { LogsSharedClientStartExports } from '@kbn/logs-shared-plugin/public'; import type { ConfigSchema } from '.'; import { registerApmRuleTypes } from './components/alerting/rule_types/register_apm_rule_types'; import { registerEmbeddables } from './embeddable/register_embeddables'; @@ -142,6 +143,7 @@ export interface ApmPluginStartDeps { dashboard: DashboardStart; metricsDataAccess: MetricsDataPluginStart; uiSettings: IUiSettingsClient; + logsShared: LogsSharedClientStartExports; } const applicationsTitle = i18n.translate('xpack.apm.navigation.rootTitle', { diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx index 27344ccd1f108..78443c9a6ec81 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx @@ -5,21 +5,37 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { LogStream } from '@kbn/logs-shared-plugin/public'; -import { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; import { InfraLoadingPanel } from '../../../../../../components/loading'; +import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana'; +import { useLogViewReference } from '../../../../../../hooks/use_log_view_reference'; +import { buildCombinedAssetFilter } from '../../../../../../utils/filters/build'; import { useHostsViewContext } from '../../../hooks/use_hosts_view'; -import { useUnifiedSearchContext } from '../../../hooks/use_unified_search'; import { useLogsSearchUrlState } from '../../../hooks/use_logs_search_url_state'; +import { useUnifiedSearchContext } from '../../../hooks/use_unified_search'; import { LogsLinkToStream } from './logs_link_to_stream'; import { LogsSearchBar } from './logs_search_bar'; -import { buildCombinedAssetFilter } from '../../../../../../utils/filters/build'; -import { useLogViewReference } from '../../../../../../hooks/use_log_view_reference'; export const LogsTabContent = () => { + const { + services: { + logsShared: { LogsOverview }, + }, + } = useKibanaContextForPlugin(); + const isLogsOverviewEnabled = LogsOverview.useIsEnabled(); + if (isLogsOverviewEnabled) { + return ; + } else { + return ; + } +}; + +export const LogsTabLogStreamContent = () => { const [filterQuery] = useLogsSearchUrlState(); const { getDateRangeAsTimestamp } = useUnifiedSearchContext(); const { from, to } = useMemo(() => getDateRangeAsTimestamp(), [getDateRangeAsTimestamp]); @@ -53,22 +69,7 @@ export const LogsTabContent = () => { }, [filterQuery.query, hostNodes]); if (loading || logViewLoading || !logView) { - return ( - - - - } - /> - - - ); + return ; } return ( @@ -84,6 +85,7 @@ export const LogsTabContent = () => { query={logsLinkToStreamQuery} logView={logView} /> + ] @@ -112,3 +114,53 @@ const createHostsFilterQueryParam = (hostNodes: string[]): string => { return hostsQueryParam; }; + +const LogsTabLogsOverviewContent = () => { + const { + services: { + logsShared: { LogsOverview }, + }, + } = useKibanaContextForPlugin(); + + const { parsedDateRange } = useUnifiedSearchContext(); + const timeRange = useMemo( + () => ({ start: parsedDateRange.from, end: parsedDateRange.to }), + [parsedDateRange.from, parsedDateRange.to] + ); + + const { hostNodes, loading, error } = useHostsViewContext(); + const logFilters = useMemo( + () => [ + buildCombinedAssetFilter({ + field: 'host.name', + values: hostNodes.map((p) => p.name), + }).query as QueryDslQueryContainer, + ], + [hostNodes] + ); + + if (loading) { + return ; + } else if (error != null) { + return ; + } else { + return ; + } +}; + +const LogsTabLoadingContent = () => ( + + + + } + /> + + +); diff --git a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc index ea93fd326dac7..10c8fe32cfe9c 100644 --- a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc @@ -9,13 +9,14 @@ "browser": true, "configPath": ["xpack", "logs_shared"], "requiredPlugins": [ + "charts", "data", "dataViews", "discoverShared", - "usageCollection", + "logsDataAccess", "observabilityShared", "share", - "logsDataAccess" + "usageCollection", ], "optionalPlugins": [ "observabilityAIAssistant", diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx new file mode 100644 index 0000000000000..627cdc8447eea --- /dev/null +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './logs_overview'; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx new file mode 100644 index 0000000000000..435766bff793d --- /dev/null +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { + LogsOverviewProps, + SelfContainedLogsOverviewComponent, + SelfContainedLogsOverviewHelpers, +} from './logs_overview'; + +export const createLogsOverviewMock = () => { + const LogsOverviewMock = jest.fn(LogsOverviewMockImpl) as unknown as ILogsOverviewMock; + + LogsOverviewMock.useIsEnabled = jest.fn(() => true); + + LogsOverviewMock.ErrorContent = jest.fn(() =>
    ); + + LogsOverviewMock.LoadingContent = jest.fn(() =>
    ); + + return LogsOverviewMock; +}; + +const LogsOverviewMockImpl = (_props: LogsOverviewProps) => { + return
    ; +}; + +type ILogsOverviewMock = jest.Mocked & + jest.Mocked; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx new file mode 100644 index 0000000000000..7b60aee5be57c --- /dev/null +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID } from '@kbn/management-settings-ids'; +import type { + LogsOverviewProps as FullLogsOverviewProps, + LogsOverviewDependencies, + LogsOverviewErrorContentProps, +} from '@kbn/observability-logs-overview'; +import { dynamic } from '@kbn/shared-ux-utility'; +import React from 'react'; +import useObservable from 'react-use/lib/useObservable'; + +const LazyLogsOverview = dynamic(() => + import('@kbn/observability-logs-overview').then((mod) => ({ default: mod.LogsOverview })) +); + +const LazyLogsOverviewErrorContent = dynamic(() => + import('@kbn/observability-logs-overview').then((mod) => ({ + default: mod.LogsOverviewErrorContent, + })) +); + +const LazyLogsOverviewLoadingContent = dynamic(() => + import('@kbn/observability-logs-overview').then((mod) => ({ + default: mod.LogsOverviewLoadingContent, + })) +); + +export type LogsOverviewProps = Omit; + +export interface SelfContainedLogsOverviewHelpers { + useIsEnabled: () => boolean; + ErrorContent: React.ComponentType; + LoadingContent: React.ComponentType; +} + +export type SelfContainedLogsOverviewComponent = React.ComponentType; + +export type SelfContainedLogsOverview = SelfContainedLogsOverviewComponent & + SelfContainedLogsOverviewHelpers; + +export const createLogsOverview = ( + dependencies: LogsOverviewDependencies +): SelfContainedLogsOverview => { + const SelfContainedLogsOverview = (props: LogsOverviewProps) => { + return ; + }; + + const isEnabled$ = dependencies.uiSettings.client.get$( + OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID, + defaultIsEnabled + ); + + SelfContainedLogsOverview.useIsEnabled = (): boolean => { + return useObservable(isEnabled$, defaultIsEnabled); + }; + + SelfContainedLogsOverview.ErrorContent = LazyLogsOverviewErrorContent; + + SelfContainedLogsOverview.LoadingContent = LazyLogsOverviewLoadingContent; + + return SelfContainedLogsOverview; +}; + +const defaultIsEnabled = false; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/index.ts b/x-pack/plugins/observability_solution/logs_shared/public/index.ts index a602b25786116..3d601c9936f2d 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/index.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/index.ts @@ -50,6 +50,7 @@ export type { UpdatedDateRange, VisibleInterval, } from './components/logging/log_text_stream/scrollable_log_text_stream_view'; +export type { LogsOverviewProps } from './components/logs_overview'; export const WithSummary = dynamic(() => import('./containers/logs/log_summary/with_summary')); export const LogEntryFlyout = dynamic( diff --git a/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx b/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx index a9b0ebd6a6aa3..ffb867abbcc17 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx @@ -6,12 +6,14 @@ */ import { createLogAIAssistantMock } from './components/log_ai_assistant/log_ai_assistant.mock'; +import { createLogsOverviewMock } from './components/logs_overview/logs_overview.mock'; import { createLogViewsServiceStartMock } from './services/log_views/log_views_service.mock'; import { LogsSharedClientStartExports } from './types'; export const createLogsSharedPluginStartMock = (): jest.Mocked => ({ logViews: createLogViewsServiceStartMock(), LogAIAssistant: createLogAIAssistantMock(), + LogsOverview: createLogsOverviewMock(), }); export const _ensureTypeCompatibility = (): LogsSharedClientStartExports => diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts index d6f4ac81fe266..fc17e9b17cc82 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts @@ -12,6 +12,7 @@ import { TraceLogsLocatorDefinition, } from '../common/locators'; import { createLogAIAssistant, createLogsAIAssistantRenderer } from './components/log_ai_assistant'; +import { createLogsOverview } from './components/logs_overview'; import { LogViewsService } from './services/log_views'; import { LogsSharedClientCoreSetup, @@ -51,8 +52,16 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { } public start(core: CoreStart, plugins: LogsSharedClientStartDeps) { - const { http } = core; - const { data, dataViews, discoverShared, observabilityAIAssistant, logsDataAccess } = plugins; + const { http, settings } = core; + const { + charts, + data, + dataViews, + discoverShared, + logsDataAccess, + observabilityAIAssistant, + share, + } = plugins; const logViews = this.logViews.start({ http, @@ -61,9 +70,18 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { search: data.search, }); + const LogsOverview = createLogsOverview({ + charts, + logsDataAccess, + search: data.search.search, + uiSettings: settings, + share, + }); + if (!observabilityAIAssistant) { return { logViews, + LogsOverview, }; } @@ -77,6 +95,7 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { return { logViews, LogAIAssistant, + LogsOverview, }; } diff --git a/x-pack/plugins/observability_solution/logs_shared/public/types.ts b/x-pack/plugins/observability_solution/logs_shared/public/types.ts index 58b180ee8b6ef..4237c28c621b8 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/types.ts @@ -5,19 +5,19 @@ * 2.0. */ +import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { CoreSetup, CoreStart, Plugin as PluginClass } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; -import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; +import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; - -import { LogsSharedLocators } from '../common/locators'; +import type { LogsSharedLocators } from '../common/locators'; import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; -// import type { OsqueryPluginStart } from '../../osquery/public'; -import { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views'; +import type { SelfContainedLogsOverview } from './components/logs_overview'; +import type { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views'; // Our own setup and start contract values export interface LogsSharedClientSetupExports { @@ -28,6 +28,7 @@ export interface LogsSharedClientSetupExports { export interface LogsSharedClientStartExports { logViews: LogViewsServiceStart; LogAIAssistant?: (props: Omit) => JSX.Element; + LogsOverview: SelfContainedLogsOverview; } export interface LogsSharedClientSetupDeps { @@ -35,6 +36,7 @@ export interface LogsSharedClientSetupDeps { } export interface LogsSharedClientStartDeps { + charts: ChartsPluginStart; data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; discoverShared: DiscoverSharedPublicStart; diff --git a/x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts b/x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts new file mode 100644 index 0000000000000..0298416bd3f26 --- /dev/null +++ b/x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { UiSettingsParams } from '@kbn/core-ui-settings-common'; +import { i18n } from '@kbn/i18n'; +import { OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID } from '@kbn/management-settings-ids'; + +const technicalPreviewLabel = i18n.translate('xpack.logsShared.technicalPreviewSettingLabel', { + defaultMessage: 'Technical Preview', +}); + +export const featureFlagUiSettings: Record = { + [OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID]: { + category: ['observability'], + name: i18n.translate('xpack.logsShared.newLogsOverviewSettingName', { + defaultMessage: 'New logs overview', + }), + value: false, + description: i18n.translate('xpack.logsShared.newLogsOverviewSettingDescription', { + defaultMessage: '{technicalPreviewLabel} Enable the new logs overview experience.', + + values: { technicalPreviewLabel: `[${technicalPreviewLabel}]` }, + }), + type: 'boolean', + schema: schema.boolean(), + requiresPageReload: true, + }, +}; diff --git a/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts index 7c97e175ed64f..d1f6399104fc2 100644 --- a/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts @@ -5,8 +5,19 @@ * 2.0. */ -import { PluginInitializerContext, CoreStart, Plugin, Logger } from '@kbn/core/server'; - +import { CoreStart, Logger, Plugin, PluginInitializerContext } from '@kbn/core/server'; +import { defaultLogViewId } from '../common/log_views'; +import { LogsSharedConfig } from '../common/plugin_config'; +import { registerDeprecations } from './deprecations'; +import { featureFlagUiSettings } from './feature_flags'; +import { KibanaFramework } from './lib/adapters/framework/kibana_framework_adapter'; +import { LogsSharedKibanaLogEntriesAdapter } from './lib/adapters/log_entries/kibana_log_entries_adapter'; +import { LogsSharedLogEntriesDomain } from './lib/domains/log_entries_domain'; +import { LogsSharedBackendLibs, LogsSharedDomainLibs } from './lib/logs_shared_types'; +import { initLogsSharedServer } from './logs_shared_server'; +import { logViewSavedObjectType } from './saved_objects'; +import { LogEntriesService } from './services/log_entries'; +import { LogViewsService } from './services/log_views'; import { LogsSharedPluginCoreSetup, LogsSharedPluginSetup, @@ -15,17 +26,6 @@ import { LogsSharedServerPluginStartDeps, UsageCollector, } from './types'; -import { logViewSavedObjectType } from './saved_objects'; -import { initLogsSharedServer } from './logs_shared_server'; -import { LogViewsService } from './services/log_views'; -import { KibanaFramework } from './lib/adapters/framework/kibana_framework_adapter'; -import { LogsSharedBackendLibs, LogsSharedDomainLibs } from './lib/logs_shared_types'; -import { LogsSharedLogEntriesDomain } from './lib/domains/log_entries_domain'; -import { LogsSharedKibanaLogEntriesAdapter } from './lib/adapters/log_entries/kibana_log_entries_adapter'; -import { LogEntriesService } from './services/log_entries'; -import { LogsSharedConfig } from '../common/plugin_config'; -import { registerDeprecations } from './deprecations'; -import { defaultLogViewId } from '../common/log_views'; export class LogsSharedPlugin implements @@ -88,6 +88,8 @@ export class LogsSharedPlugin registerDeprecations({ core }); + core.uiSettings.register(featureFlagUiSettings); + return { ...domainLibs, logViews, diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index 38cbba7c252c0..788f55c9b6fc5 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -44,5 +44,9 @@ "@kbn/logs-data-access-plugin", "@kbn/core-deprecations-common", "@kbn/core-deprecations-server", + "@kbn/management-settings-ids", + "@kbn/observability-logs-overview", + "@kbn/charts-plugin", + "@kbn/core-ui-settings-common", ] } diff --git a/yarn.lock b/yarn.lock index 54a38b2c0e5d3..019de6121540e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5879,6 +5879,10 @@ version "0.0.0" uid "" +"@kbn/observability-logs-overview@link:x-pack/packages/observability/logs_overview": + version "0.0.0" + uid "" + "@kbn/observability-onboarding-e2e@link:x-pack/plugins/observability_solution/observability_onboarding/e2e": version "0.0.0" uid "" @@ -12105,6 +12109,14 @@ use-isomorphic-layout-effect "^1.1.2" use-sync-external-store "^1.0.0" +"@xstate5/react@npm:@xstate/react@^4.1.2": + version "4.1.2" + resolved "https://registry.yarnpkg.com/@xstate/react/-/react-4.1.2.tgz#4bfcdf2d9e9ef1eaea7388d1896649345e6679cd" + integrity sha512-orAidFrKCrU0ZwN5l/ABPlBfW2ziRDT2RrYoktRlZ0WRoLvA2E/uAC1JpZt43mCLtc8jrdwYCgJiqx1V8NvGTw== + dependencies: + use-isomorphic-layout-effect "^1.1.2" + use-sync-external-store "^1.2.0" + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -32800,6 +32812,11 @@ xpath@^0.0.33: resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.33.tgz#5136b6094227c5df92002e7c3a13516a5074eb07" integrity sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA== +"xstate5@npm:xstate@^5.18.1", xstate@^5.18.1: + version "5.18.1" + resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.18.1.tgz#c4d43ceaba6e6c31705d36bd96e285de4be4f7f4" + integrity sha512-m02IqcCQbaE/kBQLunwub/5i8epvkD2mFutnL17Oeg1eXTShe1sRF4D5mhv1dlaFO4vbW5gRGRhraeAD5c938g== + xstate@^4.38.2: version "4.38.2" resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.38.2.tgz#1b74544fc9c8c6c713ba77f81c6017e65aa89804" From 3f75a1d3d56e1d2c84ed0d4c5b18b3beb8357d3b Mon Sep 17 00:00:00 2001 From: Khristinin Nikita Date: Wed, 9 Oct 2024 19:23:46 +0200 Subject: [PATCH 082/110] Remove feature flag for manual rule run (#193833) ## Summary Remove feature flag for manual rule run --------- Co-authored-by: Elastic Machine --- .../common/experimental_features.ts | 5 -- .../execution_log_search_bar.test.tsx.snap | 14 +++++ .../execution_log_search_bar.tsx | 19 +++--- .../execution_log_table.tsx | 27 +++----- .../components/manual_rule_run/index.tsx | 4 +- .../components/rule_backfills_info/index.tsx | 25 +++----- .../bulk_actions/use_bulk_actions.tsx | 23 +++---- .../rules_table/use_rules_table_actions.tsx | 52 +++++++-------- .../use_execution_results.tsx | 11 +--- .../rule_actions_overflow/index.test.tsx | 19 ------ .../rules/rule_actions_overflow/index.tsx | 63 ++++++++----------- .../logic/bulk_actions/validations.ts | 5 -- .../config/ess/config.base.ts | 1 - .../configs/serverless.config.ts | 5 +- .../configs/serverless.config.ts | 1 - .../manual_rule_run.ts | 4 +- .../configs/serverless.config.ts | 3 - .../test/security_solution_cypress/config.ts | 5 +- .../detection_engine/rule_edit/preview.cy.ts | 4 +- .../rule_gaps/bulk_manual_rule_run.cy.ts | 4 +- .../rule_gaps/manual_rule_run.cy.ts | 4 +- .../rule_details/backfill_group.cy.ts | 9 +-- .../rule_details/execution_log.cy.ts | 7 --- .../serverless_config.ts | 5 +- 24 files changed, 104 insertions(+), 215 deletions(-) diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 67b9a57af1628..1ae20af759611 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -230,11 +230,6 @@ export const allowedExperimentalValues = Object.freeze({ */ valueListItemsModalEnabled: true, - /** - * Enables the manual rule run - */ - manualRuleRunEnabled: false, - /** * Adds a new option to filter descendants of a process for Management / Event Filters */ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/__snapshots__/execution_log_search_bar.test.tsx.snap b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/__snapshots__/execution_log_search_bar.test.tsx.snap index 009e6dcc58ace..4f5e9954cced0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/__snapshots__/execution_log_search_bar.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/__snapshots__/execution_log_search_bar.test.tsx.snap @@ -13,6 +13,20 @@ exports[`ExecutionLogSearchBar snapshots renders correctly against snapshot 1`] + + + diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_search_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_search_bar.tsx index db43b104ec713..3c70fa7c33c9c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_search_bar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_search_bar.tsx @@ -20,7 +20,6 @@ import { } from '../../../../../../common/detection_engine/rule_management/execution_log'; import { ExecutionStatusFilter, ExecutionRunTypeFilter } from '../../../../rule_monitoring'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import * as i18n from './translations'; export const EXECUTION_LOG_SCHEMA_MAPPING = { @@ -75,7 +74,6 @@ export const ExecutionLogSearchBar = React.memo( }, [onSearch] ); - const isManualRuleRunEnabled = useIsExperimentalFeatureEnabled('manualRuleRunEnabled'); return ( @@ -93,15 +91,14 @@ export const ExecutionLogSearchBar = React.memo( - {isManualRuleRunEnabled && ( - - - - )} + + + + = ({ timelines, telemetry, } = useKibana().services; - const isManualRuleRunEnabled = useIsExperimentalFeatureEnabled('manualRuleRunEnabled'); const { [RuleDetailTabs.executionResults]: { @@ -473,15 +470,10 @@ const ExecutionLogTableComponent: React.FC = ({ ); const executionLogColumns = useMemo(() => { - const columns = [...EXECUTION_LOG_COLUMNS].filter((item) => { - if ('field' in item) { - return item.field === 'type' ? isManualRuleRunEnabled : true; - } - return true; - }); + const columns = [...EXECUTION_LOG_COLUMNS]; let messageColumnWidth = 50; - if (showSourceEventTimeRange && isManualRuleRunEnabled) { + if (showSourceEventTimeRange) { columns.push(...getSourceEventTimeRangeColumns()); messageColumnWidth = 30; } @@ -506,7 +498,6 @@ const ExecutionLogTableComponent: React.FC = ({ return columns; }, [ - isManualRuleRunEnabled, actions, docLinks, showMetricColumns, @@ -583,14 +574,12 @@ const ExecutionLogTableComponent: React.FC = ({ updatedAt: dataUpdatedAt, })} - {isManualRuleRunEnabled && ( - - )} + {i18n.MANUAL_RULE_RUN_MODAL_TITLE} - + } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/index.tsx index 2bacc44b15a76..2a0981e2f5259 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/index.tsx @@ -25,9 +25,8 @@ import { hasUserCRUDPermission } from '../../../../common/utils/privileges'; import { useUserData } from '../../../../detections/components/user_info'; import { getBackfillRowsFromResponse } from './utils'; import { HeaderSection } from '../../../../common/components/header_section'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { TableHeaderTooltipCell } from '../../../rule_management_ui/components/rules_table/table_header_tooltip_cell'; -import { TECHNICAL_PREVIEW, TECHNICAL_PREVIEW_TOOLTIP } from '../../../../common/translations'; +import { BETA, BETA_TOOLTIP } from '../../../../common/translations'; import { useKibana } from '../../../../common/lib/kibana'; const DEFAULT_PAGE_SIZE = 10; @@ -143,26 +142,16 @@ const getBackfillsTableColumns = (hasCRUDPermissions: boolean) => { }; export const RuleBackfillsInfo = React.memo<{ ruleId: string }>(({ ruleId }) => { - const isManualRuleRunEnabled = useIsExperimentalFeatureEnabled('manualRuleRunEnabled'); const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE); const [{ canUserCRUD }] = useUserData(); const hasCRUDPermissions = hasUserCRUDPermission(canUserCRUD); const { timelines } = useKibana().services; - const { data, isLoading, isError, refetch, dataUpdatedAt } = useFindBackfillsForRules( - { - ruleIds: [ruleId], - page: pageIndex + 1, - perPage: pageSize, - }, - { - enabled: isManualRuleRunEnabled, - } - ); - - if (!isManualRuleRunEnabled) { - return null; - } + const { data, isLoading, isError, refetch, dataUpdatedAt } = useFindBackfillsForRules({ + ruleIds: [ruleId], + page: pageIndex + 1, + perPage: pageSize, + }); const backfills: BackfillRow[] = getBackfillRowsFromResponse(data?.data ?? []); @@ -197,7 +186,7 @@ export const RuleBackfillsInfo = React.memo<{ ruleId: string }>(({ ruleId }) => title={i18n.BACKFILL_TABLE_TITLE} subtitle={i18n.BACKFILL_TABLE_SUBTITLE} /> - + diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx index c2c176563ca48..68e58b4db073f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx @@ -16,7 +16,6 @@ import { MAX_MANUAL_RULE_RUN_BULK_SIZE } from '../../../../../../common/constant import type { TimeRange } from '../../../../rule_gaps/types'; import { useKibana } from '../../../../../common/lib/kibana'; import { convertRulesFilterToKQL } from '../../../../../../common/detection_engine/rule_management/rule_filtering'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { DuplicateOptions } from '../../../../../../common/detection_engine/rule_management/constants'; import type { BulkActionEditPayload, @@ -89,7 +88,6 @@ export const useBulkActions = ({ actions: { clearRulesSelection, setIsPreflightInProgress }, } = rulesTableContext; - const isManualRuleRunEnabled = useIsExperimentalFeatureEnabled('manualRuleRunEnabled'); const getBulkItemsPopoverContent = useCallback( (closePopover: () => void): EuiContextMenuPanelDescriptor[] => { const selectedRules = rules.filter(({ id }) => selectedRuleIds.includes(id)); @@ -448,18 +446,14 @@ export const useBulkActions = ({ onClick: handleExportAction, icon: undefined, }, - ...(isManualRuleRunEnabled - ? [ - { - key: i18n.BULK_ACTION_MANUAL_RULE_RUN, - name: i18n.BULK_ACTION_MANUAL_RULE_RUN, - 'data-test-subj': 'scheduleRuleRunBulk', - disabled: containsLoading || (!containsEnabled && !isAllSelected), - onClick: handleScheduleRuleRunAction, - icon: undefined, - }, - ] - : []), + { + key: i18n.BULK_ACTION_MANUAL_RULE_RUN, + name: i18n.BULK_ACTION_MANUAL_RULE_RUN, + 'data-test-subj': 'scheduleRuleRunBulk', + disabled: containsLoading || (!containsEnabled && !isAllSelected), + onClick: handleScheduleRuleRunAction, + icon: undefined, + }, { key: i18n.BULK_ACTION_DISABLE, name: i18n.BULK_ACTION_DISABLE, @@ -600,7 +594,6 @@ export const useBulkActions = ({ filterOptions, completeBulkEditForm, startServices, - isManualRuleRunEnabled, ] ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx index 984df06342a1a..4cc7a03426657 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx @@ -8,7 +8,6 @@ import type { DefaultItemAction } from '@elastic/eui'; import { EuiToolTip } from '@elastic/eui'; import React from 'react'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { DuplicateOptions } from '../../../../../common/detection_engine/rule_management/constants'; import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management'; import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions'; @@ -47,8 +46,6 @@ export const useRulesTableActions = ({ const downloadExportedRules = useDownloadExportedRules(); const { scheduleRuleRun } = useScheduleRuleRun(); - const isManualRuleRunEnabled = useIsExperimentalFeatureEnabled('manualRuleRunEnabled'); - return [ { type: 'icon', @@ -120,33 +117,28 @@ export const useRulesTableActions = ({ }, enabled: (rule: Rule) => !rule.immutable, }, - ...(isManualRuleRunEnabled - ? [ - { - type: 'icon', - 'data-test-subj': 'manualRuleRunAction', - description: (rule) => - !rule.enabled ? i18n.MANUAL_RULE_RUN_TOOLTIP : i18n.MANUAL_RULE_RUN, - icon: 'play', - name: i18n.MANUAL_RULE_RUN, - onClick: async (rule: Rule) => { - startTransaction({ name: SINGLE_RULE_ACTIONS.MANUAL_RULE_RUN }); - const modalManualRuleRunConfirmationResult = await showManualRuleRunConfirmation(); - telemetry.reportManualRuleRunOpenModal({ - type: 'single', - }); - if (modalManualRuleRunConfirmationResult === null) { - return; - } - await scheduleRuleRun({ - ruleIds: [rule.id], - timeRange: modalManualRuleRunConfirmationResult, - }); - }, - enabled: (rule: Rule) => rule.enabled, - } as DefaultItemAction, - ] - : []), + { + type: 'icon', + 'data-test-subj': 'manualRuleRunAction', + description: (rule) => (!rule.enabled ? i18n.MANUAL_RULE_RUN_TOOLTIP : i18n.MANUAL_RULE_RUN), + icon: 'play', + name: i18n.MANUAL_RULE_RUN, + onClick: async (rule: Rule) => { + startTransaction({ name: SINGLE_RULE_ACTIONS.MANUAL_RULE_RUN }); + const modalManualRuleRunConfirmationResult = await showManualRuleRunConfirmation(); + telemetry.reportManualRuleRunOpenModal({ + type: 'single', + }); + if (modalManualRuleRunConfirmationResult === null) { + return; + } + await scheduleRuleRun({ + ruleIds: [rule.id], + timeRange: modalManualRuleRunConfirmationResult, + }); + }, + enabled: (rule: Rule) => rule.enabled, + }, { type: 'icon', 'data-test-subj': 'deleteRuleAction', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.tsx index 8660139676351..e6ee5769ee822 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.tsx @@ -7,29 +7,20 @@ import { useQuery } from '@tanstack/react-query'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; - -import { RuleRunTypeEnum } from '../../../../../common/api/detection_engine/rule_monitoring'; import type { GetRuleExecutionResultsResponse } from '../../../../../common/api/detection_engine/rule_monitoring'; import type { FetchRuleExecutionResultsArgs } from '../../api'; import { api } from '../../api'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import * as i18n from './translations'; export type UseExecutionResultsArgs = Omit; export const useExecutionResults = (args: UseExecutionResultsArgs) => { const { addError } = useAppToasts(); - const isManualRuleRunEnabled = useIsExperimentalFeatureEnabled('manualRuleRunEnabled'); return useQuery( ['detectionEngine', 'ruleMonitoring', 'executionResults', args], ({ signal }) => { - let runTypeFilters = args.runTypeFilters; - - // if manual rule run is disabled, only show standard runs - if (!isManualRuleRunEnabled) { - runTypeFilters = [RuleRunTypeEnum.standard]; - } + const runTypeFilters = args.runTypeFilters; return api.fetchRuleExecutionResults({ ...args, runTypeFilters, signal }); }, diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx index 298ae1c503533..e1ff950bc5e32 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx @@ -274,25 +274,6 @@ describe('RuleActionsOverflow', () => { expect(getByTestId('rules-details-popover')).not.toHaveTextContent(/.+/); }); - test('it does not show "Manual run" action item when feature flag "manualRuleRunEnabled" is set to false', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(false); - - const { getByTestId } = render( - Promise.resolve(true)} - />, - { wrapper: TestProviders } - ); - fireEvent.click(getByTestId('rules-details-popover-button-icon')); - - expect(getByTestId('rules-details-menu-panel')).not.toHaveTextContent('Manual run'); - }); - test('it calls telemetry.reportManualRuleRunOpenModal when rules-details-manual-rule-run is clicked', async () => { const { getByTestId } = render( { navigateToApp(APP_UI_ID, { deepLinkId: SecurityPageName.rules, @@ -152,39 +149,32 @@ const RuleActionsOverflowComponent = ({ > {i18nActions.EXPORT_RULE} , - ...(isManualRuleRunEnabled - ? [ - { - startTransaction({ name: SINGLE_RULE_ACTIONS.MANUAL_RULE_RUN }); - closePopover(); - const modalManualRuleRunConfirmationResult = - await showManualRuleRunConfirmation(); - telemetry.reportManualRuleRunOpenModal({ - type: 'single', - }); - if (modalManualRuleRunConfirmationResult === null) { - return; - } - await scheduleRuleRun({ - ruleIds: [rule.id], - timeRange: modalManualRuleRunConfirmationResult, - }); - }} - > - {i18nActions.MANUAL_RULE_RUN} - , - ] - : []), + { + startTransaction({ name: SINGLE_RULE_ACTIONS.MANUAL_RULE_RUN }); + closePopover(); + const modalManualRuleRunConfirmationResult = await showManualRuleRunConfirmation(); + telemetry.reportManualRuleRunOpenModal({ + type: 'single', + }); + if (modalManualRuleRunConfirmationResult === null) { + return; + } + await scheduleRuleRun({ + ruleIds: [rule.id], + timeRange: modalManualRuleRunConfirmationResult, + }); + }} + > + {i18nActions.MANUAL_RULE_RUN} + , { // check whether "manual rule run" feature is enabled - await throwDryRunError( - () => - invariant(experimentalFeatures?.manualRuleRunEnabled, 'Manual rule run feature is disabled.'), - BulkActionsDryRunErrCode.MANUAL_RULE_RUN_FEATURE - ); await throwDryRunError( () => invariant(rule.enabled, 'Cannot schedule manual rule run for a disabled rule'), diff --git a/x-pack/test/security_solution_api_integration/config/ess/config.base.ts b/x-pack/test/security_solution_api_integration/config/ess/config.base.ts index 705c0b8686dd0..3ab6d5059fd07 100644 --- a/x-pack/test/security_solution_api_integration/config/ess/config.base.ts +++ b/x-pack/test/security_solution_api_integration/config/ess/config.base.ts @@ -85,7 +85,6 @@ export function createTestConfig(options: CreateTestConfigOptions, testFiles?: s 'loggingRequestsEnabled', 'riskScoringPersistence', 'riskScoringRoutesEnabled', - 'manualRuleRunEnabled', ])}`, '--xpack.task_manager.poll_interval=1000', `--xpack.actions.preconfigured=${JSON.stringify(PRECONFIGURED_ACTION_CONNECTORS)}`, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/configs/serverless.config.ts index 8f64a859b7002..ce949d5cc23fc 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/configs/serverless.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/configs/serverless.config.ts @@ -17,9 +17,6 @@ export default createTestConfig({ 'testing_ignored.constant', '/testing_regex*/', ])}`, // See tests within the file "ignore_fields.ts" which use these values in "alertIgnoreFields" - `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - 'manualRuleRunEnabled', - 'loggingRequestsEnabled', - ])}`, + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['loggingRequestsEnabled'])}`, ], }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/configs/serverless.config.ts index 783adb64f6c2e..43904f7c217f3 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/configs/serverless.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/configs/serverless.config.ts @@ -16,6 +16,5 @@ export default createTestConfig({ 'testing_ignored.constant', '/testing_regex*/', ])}`, // See tests within the file "ignore_fields.ts" which use these values in "alertIgnoreFields" - `--xpack.securitySolution.enableExperimental=${JSON.stringify(['manualRuleRunEnabled'])}`, ], }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/manual_rule_run.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/manual_rule_run.ts index 8a6167fc69301..153185456544d 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/manual_rule_run.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_gaps/trial_license_complete_tier/manual_rule_run.ts @@ -42,9 +42,7 @@ export default ({ getService }: FtrProviderContext) => { const log = getService('log'); const es = getService('es'); - // Currently FF are not supported on MKI environments, so this test should be skipped from MKI environments. - // Once `manualRuleRunEnabled` FF is removed, we can remove `@skipInServerlessMKI` as well - describe('@ess @serverless @skipInServerlessMKI manual_rule_run', () => { + describe('@ess @serverless manual_rule_run', () => { beforeEach(async () => { await createAlertsIndex(supertest, log); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_management/trial_license_complete_tier/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_management/trial_license_complete_tier/configs/serverless.config.ts index 52a1074c87904..ca9396db04661 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_management/trial_license_complete_tier/configs/serverless.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_management/trial_license_complete_tier/configs/serverless.config.ts @@ -12,7 +12,4 @@ export default createTestConfig({ reportName: 'Rules Management - Rule Management Integration Tests - Serverless Env - Complete Tier', }, - kbnTestServerArgs: [ - `--xpack.securitySolution.enableExperimental=${JSON.stringify(['manualRuleRunEnabled'])}`, - ], }); diff --git a/x-pack/test/security_solution_cypress/config.ts b/x-pack/test/security_solution_cypress/config.ts index 88752eb1b5f93..05bc2e381527a 100644 --- a/x-pack/test/security_solution_cypress/config.ts +++ b/x-pack/test/security_solution_cypress/config.ts @@ -44,10 +44,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { // See https://github.com/elastic/kibana/pull/125396 for details '--xpack.alerting.rules.minimumScheduleInterval.value=1s', '--xpack.ruleRegistry.unsafe.legacyMultiTenancy.enabled=true', - `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - 'manualRuleRunEnabled', - 'loggingRequestsEnabled', - ])}`, + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['loggingRequestsEnabled'])}`, // mock cloud to enable the guided onboarding tour in e2e tests '--xpack.cloud.id=test', `--home.disableWelcomeScreen=true`, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/preview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/preview.cy.ts index ce298bafbfea0..c2e41c9d4680c 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/preview.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/preview.cy.ts @@ -32,9 +32,7 @@ const expectedValidEsqlQuery = 'from auditbeat* METADATA _id'; describe( 'Detection rules, preview', { - // Currently FF are not supported on MKI environments, so this test should be skipped from MKI environments. - // Once `manualRuleRunEnabled` FF is removed, we can remove `@skipInServerlessMKI` as well - tags: ['@ess', '@serverless', '@skipInServerlessMKI'], + tags: ['@ess', '@serverless'], env: { kbnServerArgs: [ `--xpack.securitySolution.enableExperimental=${JSON.stringify(['loggingRequestsEnabled'])}`, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_gaps/bulk_manual_rule_run.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_gaps/bulk_manual_rule_run.cy.ts index 17cde9485a13c..5a66dcdc0de84 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_gaps/bulk_manual_rule_run.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_gaps/bulk_manual_rule_run.cy.ts @@ -19,9 +19,7 @@ import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { createRule } from '../../../../tasks/api_calls/rules'; import { login } from '../../../../tasks/login'; -// Currently FF are not supported on MKI environments, so this test should be skipped from MKI environments. -// Once `manualRuleRunEnabled` FF is removed, we can remove `@skipInServerlessMKI` as well -describe('Manual rule run', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { +describe('Manual rule run', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); deleteAlertsAndRules(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_gaps/manual_rule_run.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_gaps/manual_rule_run.cy.ts index 29e2379367c0b..f40f4284b84b5 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_gaps/manual_rule_run.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_gaps/manual_rule_run.cy.ts @@ -18,9 +18,7 @@ import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { createRule } from '../../../../tasks/api_calls/rules'; import { login } from '../../../../tasks/login'; -// Currently FF are not supported on MKI environments, so this test should be skipped from MKI environments. -// Once `manualRuleRunEnabled` FF is removed, we can remove `@skipInServerlessMKI` as well -describe('Manual rule run', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { +describe('Manual rule run', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); deleteAlertsAndRules(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/backfill_group.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/backfill_group.cy.ts index 2f97e2f3c0721..f747e6be43e5a 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/backfill_group.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/backfill_group.cy.ts @@ -34,14 +34,7 @@ import { describe( 'Backfill groups', { - tags: ['@ess', '@serverless', '@skipInServerlessMKI'], - env: { - ftrConfig: { - kbnServerArgs: [ - `--xpack.securitySolution.enableExperimental=${JSON.stringify(['manualRuleRunEnabled'])}`, - ], - }, - }, + tags: ['@ess', '@serverless'], }, function () { before(() => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/execution_log.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/execution_log.cy.ts index a34826d2c8cb4..dc9e3e5719d27 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/execution_log.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/execution_log.cy.ts @@ -27,13 +27,6 @@ describe.skip( 'Event log', { tags: ['@ess', '@serverless'], - env: { - ftrConfig: { - kbnServerArgs: [ - `--xpack.securitySolution.enableExperimental=${JSON.stringify(['manualRuleRunEnabled'])}`, - ], - }, - }, }, function () { before(() => { diff --git a/x-pack/test/security_solution_cypress/serverless_config.ts b/x-pack/test/security_solution_cypress/serverless_config.ts index 13877fcbf5af4..71a63b697187f 100644 --- a/x-pack/test/security_solution_cypress/serverless_config.ts +++ b/x-pack/test/security_solution_cypress/serverless_config.ts @@ -34,10 +34,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { { product_line: 'endpoint', product_tier: 'complete' }, { product_line: 'cloud', product_tier: 'complete' }, ])}`, - `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - 'manualRuleRunEnabled', - 'loggingRequestsEnabled', - ])}`, + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['loggingRequestsEnabled'])}`, '--csp.strict=false', '--csp.warnLegacyBrowsers=false', ], From 8e986a6dd945160d80d9b400f4acb7f9181d962a Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Wed, 9 Oct 2024 13:27:49 -0400 Subject: [PATCH 083/110] [Synthetics] Add warning if TLS config not set for Synthetics (#195395) ## Summary Recently while debugging a production issue where the Synthetics plugin was receiving 401 errors while trying to reach the Synthetics Service health endpoint, we isolated that there was an issue with the mTLS handshake between Kibana and the service. Unfortunately, we were unsure if there was some missing custom config (especially relevant in Serverless Kibana), or if the certificate values were not present in the first place. Adding this warning will help us make this determination better in the future when reviewing Kibana logs, as we will be assured if the config is not defined via this warning. --- .../server/synthetics_service/service_api_client.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.ts index 3d334f32e9407..73f286e40d310 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/service_api_client.ts @@ -143,6 +143,10 @@ export class ServiceAPIClient { cert: tlsConfig.certificate, key: tlsConfig.key, }); + } else if (!this.server.isDev) { + this.logger.warn( + 'TLS certificate and key are not provided. Falling back to default HTTPS agent.' + ); } return baseHttpsAgent; From 1bf3f2a0b0484d601f797a20ec7c81ae05c522bb Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Wed, 9 Oct 2024 11:35:45 -0600 Subject: [PATCH 084/110] [Security Assistant] Knowledge base conflict fix (#195659) ## Summary Fixes on merge fail https://buildkite.com/elastic/kibana-on-merge/builds/51840 --- .../use_knowledge_base_status.tsx | 17 +++++++++++++++++ .../index.tsx | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx index ba6317329d350..75e78f2a06948 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx @@ -78,3 +78,20 @@ export const useInvalidateKnowledgeBaseStatus = () => { }); }, [queryClient]); }; + +/** + * Helper for determining if Knowledge Base setup is complete. + * + * Note: Consider moving to API + * + * @param kbStatus ReadKnowledgeBaseResponse + */ +export const isKnowledgeBaseSetup = (kbStatus: ReadKnowledgeBaseResponse | undefined): boolean => { + return ( + (kbStatus?.elser_exists && + kbStatus?.security_labs_exists && + kbStatus?.index_exists && + kbStatus?.pipeline_exists) ?? + false + ); +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx index 34e8601e37ce7..5cf887ae3375d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx @@ -46,7 +46,7 @@ import { useFlyoutModalVisibility } from '../../assistant/common/components/assi import { IndexEntryEditor } from './index_entry_editor'; import { DocumentEntryEditor } from './document_entry_editor'; import { KnowledgeBaseSettings } from '../knowledge_base_settings'; -import { ESQL_RESOURCE, SetupKnowledgeBaseButton } from '../setup_knowledge_base_button'; +import { SetupKnowledgeBaseButton } from '../setup_knowledge_base_button'; import { useDeleteKnowledgeBaseEntries } from '../../assistant/api/knowledge_base/entries/use_delete_knowledge_base_entries'; import { isSystemEntry, @@ -73,7 +73,7 @@ export const KnowledgeBaseSettingsManagement: React.FC = React.memo(({ d toasts, } = useAssistantContext(); const [hasPendingChanges, setHasPendingChanges] = useState(false); - const { data: kbStatus, isFetched } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); + const { data: kbStatus, isFetched } = useKnowledgeBaseStatus({ http }); const isKbSetup = isKnowledgeBaseSetup(kbStatus); // Only needed for legacy settings management From ac2e0c81cf4b1b75a0fa05e6dc15022a4c3ba0fa Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Wed, 9 Oct 2024 13:01:21 -0500 Subject: [PATCH 085/110] Update `@elastic/charts` renovate config labels (#195642) --- renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index dccc37ef702a4..ff7ee4b0aaafa 100644 --- a/renovate.json +++ b/renovate.json @@ -58,7 +58,7 @@ "matchDepNames": ["@elastic/charts"], "reviewers": ["team:visualizations", "markov00", "nickofthyme"], "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:skip", "Team:Visualizations"], + "labels": ["release_note:skip", "backport:prev-minor", "Team:Visualizations"], "enabled": true }, { From d2644ffe49ea732e5f048957a51350efbc321687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:19:49 +0100 Subject: [PATCH 086/110] [Inventory] Fixing entity links (#195625) Regression from https://github.com/elastic/kibana/pull/195204 --- .../inventory/common/entities.ts | 9 +- .../entity_name/entity_name.test.tsx | 152 ++++++++++++++++++ .../entities_grid/entity_name/index.tsx | 16 +- 3 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts index 218e3d50905a9..40fae48cb9dc3 100644 --- a/x-pack/plugins/observability_solution/inventory/common/entities.ts +++ b/x-pack/plugins/observability_solution/inventory/common/entities.ts @@ -78,26 +78,27 @@ interface BaseEntity { [ENTITY_TYPE]: EntityType; [ENTITY_DISPLAY_NAME]: string; [ENTITY_DEFINITION_ID]: string; - [ENTITY_IDENTITY_FIELDS]: string[]; + [ENTITY_IDENTITY_FIELDS]: string | string[]; + [key: string]: any; } /** * These types are based on service, host and container from the built in definition. */ -interface ServiceEntity extends BaseEntity { +export interface ServiceEntity extends BaseEntity { [ENTITY_TYPE]: 'service'; [SERVICE_NAME]: string; [SERVICE_ENVIRONMENT]?: string | string[] | null; [AGENT_NAME]: string | string[] | null; } -interface HostEntity extends BaseEntity { +export interface HostEntity extends BaseEntity { [ENTITY_TYPE]: 'host'; [HOST_NAME]: string; [CLOUD_PROVIDER]: string | string[] | null; } -interface ContainerEntity extends BaseEntity { +export interface ContainerEntity extends BaseEntity { [ENTITY_TYPE]: 'container'; [CONTAINER_ID]: string; [CLOUD_PROVIDER]: string | string[] | null; diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx new file mode 100644 index 0000000000000..36aad3d8e3a97 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx @@ -0,0 +1,152 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { type KibanaReactContextValue } from '@kbn/kibana-react-plugin/public'; +import * as useKibana from '../../../hooks/use_kibana'; +import { EntityName } from '.'; +import { ContainerEntity, HostEntity, ServiceEntity } from '../../../../common/entities'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { ASSET_DETAILS_LOCATOR_ID } from '@kbn/observability-shared-plugin/common/locators/infra/asset_details_locator'; + +describe('EntityName', () => { + jest.spyOn(useKibana, 'useKibana').mockReturnValue({ + services: { + share: { + url: { + locators: { + get: (locatorId: string) => { + return { + getRedirectUrl: (params: { [key: string]: any }) => { + if (locatorId === ASSET_DETAILS_LOCATOR_ID) { + return `assets_url/${params.assetType}/${params.assetId}`; + } + return `services_url/${params.serviceName}?environment=${params.environment}`; + }, + }; + }, + }, + }, + }, + }, + } as unknown as KibanaReactContextValue); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('returns host link', () => { + const entity: HostEntity = { + 'entity.lastSeenTimestamp': 'foo', + 'entity.id': '1', + 'entity.type': 'host', + 'entity.displayName': 'foo', + 'entity.identityFields': 'host.name', + 'host.name': 'foo', + 'entity.definitionId': 'host', + 'cloud.provider': null, + }; + render(); + expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( + 'assets_url/host/foo' + ); + expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); + }); + + it('returns container link', () => { + const entity: ContainerEntity = { + 'entity.lastSeenTimestamp': 'foo', + 'entity.id': '1', + 'entity.type': 'container', + 'entity.displayName': 'foo', + 'entity.identityFields': 'container.id', + 'container.id': 'foo', + 'entity.definitionId': 'container', + 'cloud.provider': null, + }; + render(); + expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( + 'assets_url/container/foo' + ); + expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); + }); + + it('returns service link without environment', () => { + const entity: ServiceEntity = { + 'entity.lastSeenTimestamp': 'foo', + 'entity.id': '1', + 'entity.type': 'service', + 'entity.displayName': 'foo', + 'entity.identityFields': 'service.name', + 'service.name': 'foo', + 'entity.definitionId': 'service', + 'agent.name': 'bar', + }; + render(); + expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( + 'services_url/foo?environment=undefined' + ); + expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); + }); + + it('returns service link with environment', () => { + const entity: ServiceEntity = { + 'entity.lastSeenTimestamp': 'foo', + 'entity.id': '1', + 'entity.type': 'service', + 'entity.displayName': 'foo', + 'entity.identityFields': 'service.name', + 'service.name': 'foo', + 'entity.definitionId': 'service', + 'agent.name': 'bar', + 'service.environment': 'baz', + }; + render(); + expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( + 'services_url/foo?environment=baz' + ); + expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); + }); + + it('returns service link with first environment when it is an array', () => { + const entity: ServiceEntity = { + 'entity.lastSeenTimestamp': 'foo', + 'entity.id': '1', + 'entity.type': 'service', + 'entity.displayName': 'foo', + 'entity.identityFields': 'service.name', + 'service.name': 'foo', + 'entity.definitionId': 'service', + 'agent.name': 'bar', + 'service.environment': ['baz', 'bar', 'foo'], + }; + render(); + expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( + 'services_url/foo?environment=baz' + ); + expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); + }); + + it('returns service link identity fields is an array', () => { + const entity: ServiceEntity = { + 'entity.lastSeenTimestamp': 'foo', + 'entity.id': '1', + 'entity.type': 'service', + 'entity.displayName': 'foo', + 'entity.identityFields': ['service.name', 'service.environment'], + 'service.name': 'foo', + 'entity.definitionId': 'service', + 'agent.name': 'bar', + 'service.environment': 'baz', + }; + render(); + expect(screen.queryByTestId('entityNameLink')?.getAttribute('href')).toEqual( + 'services_url/foo?environment=baz' + ); + expect(screen.queryByTestId('entityNameDisplayName')?.textContent).toEqual('foo'); + }); +}); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx index debe91d52dec1..f3488dfddbc4e 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx @@ -36,33 +36,37 @@ export function EntityName({ entity }: EntityNameProps) { const getEntityRedirectUrl = useCallback(() => { const type = entity[ENTITY_TYPE]; // For service, host and container type there is only one identity field - const identityField = entity[ENTITY_IDENTITY_FIELDS][0]; + const identityField = Array.isArray(entity[ENTITY_IDENTITY_FIELDS]) + ? entity[ENTITY_IDENTITY_FIELDS][0] + : entity[ENTITY_IDENTITY_FIELDS]; + const identityValue = entity[identityField]; - // Any unrecognised types will always return undefined switch (type) { case 'host': case 'container': return assetDetailsLocator?.getRedirectUrl({ - assetId: identityField, + assetId: identityValue, assetType: type, }); case 'service': return serviceOverviewLocator?.getRedirectUrl({ - serviceName: identityField, + serviceName: identityValue, environment: [entity[SERVICE_ENVIRONMENT] || undefined].flat()[0], }); } }, [entity, assetDetailsLocator, serviceOverviewLocator]); return ( - + - {entity[ENTITY_DISPLAY_NAME]} + + {entity[ENTITY_DISPLAY_NAME]} + From a31b16e411974d0ecd29e5eb7b546bef6ae4502e Mon Sep 17 00:00:00 2001 From: Brad White Date: Wed, 9 Oct 2024 12:40:00 -0600 Subject: [PATCH 087/110] Revert "[Logs Overview] Overview component (iteration 1) (#191899)" This reverts commit 15bccdf233d847f34ee4cbcc30f8a8e775207c42. --- .eslintrc.js | 1 - .github/CODEOWNERS | 1 - package.json | 5 - .../src/lib/entity.ts | 12 - .../src/lib/gaussian_events.ts | 74 ----- .../src/lib/infra/host.ts | 10 +- .../src/lib/infra/index.ts | 3 +- .../src/lib/interval.ts | 18 +- .../src/lib/logs/index.ts | 21 -- .../src/lib/poisson_events.test.ts | 53 ---- .../src/lib/poisson_events.ts | 77 ----- .../src/lib/timerange.ts | 27 +- .../distributed_unstructured_logs.ts | 197 ------------ .../scenarios/helpers/unstructured_logs.ts | 94 ------ packages/kbn-apm-synthtrace/tsconfig.json | 1 - .../settings/setting_ids/index.ts | 1 - .../src/worker/webpack.config.ts | 12 - packages/kbn-xstate-utils/kibana.jsonc | 2 +- .../kbn-xstate-utils/src/console_inspector.ts | 88 ------ packages/kbn-xstate-utils/src/index.ts | 1 - .../server/collectors/management/schema.ts | 6 - .../server/collectors/management/types.ts | 1 - src/plugins/telemetry/schema/oss_plugins.json | 6 - tsconfig.base.json | 2 - x-pack/.i18nrc.json | 3 - .../observability/logs_overview/README.md | 3 - .../observability/logs_overview/index.ts | 21 -- .../logs_overview/jest.config.js | 12 - .../observability/logs_overview/kibana.jsonc | 5 - .../observability/logs_overview/package.json | 7 - .../discover_link/discover_link.tsx | 110 ------- .../src/components/discover_link/index.ts | 8 - .../src/components/log_categories/index.ts | 8 - .../log_categories/log_categories.tsx | 94 ------ .../log_categories_control_bar.tsx | 44 --- .../log_categories_error_content.tsx | 44 --- .../log_categories/log_categories_grid.tsx | 182 ----------- .../log_categories_grid_cell.tsx | 99 ------ .../log_categories_grid_change_time_cell.tsx | 54 ---- .../log_categories_grid_change_type_cell.tsx | 108 ------- .../log_categories_grid_count_cell.tsx | 32 -- .../log_categories_grid_histogram_cell.tsx | 99 ------ .../log_categories_grid_pattern_cell.tsx | 60 ---- .../log_categories_loading_content.tsx | 68 ----- .../log_categories_result_content.tsx | 87 ------ .../src/components/logs_overview/index.ts | 10 - .../logs_overview/logs_overview.tsx | 64 ---- .../logs_overview_error_content.tsx | 41 --- .../logs_overview_loading_content.tsx | 23 -- .../categorize_documents.ts | 282 ------------------ .../categorize_logs_service.ts | 250 ---------------- .../count_documents.ts | 60 ---- .../services/categorize_logs_service/index.ts | 8 - .../categorize_logs_service/queries.ts | 151 ---------- .../services/categorize_logs_service/types.ts | 21 -- .../observability/logs_overview/src/types.ts | 74 ----- .../logs_overview/src/utils/logs_source.ts | 60 ---- .../logs_overview/src/utils/xstate5_utils.ts | 13 - .../observability/logs_overview/tsconfig.json | 39 --- .../components/app/service_logs/index.tsx | 171 +---------- .../routing/service_detail/index.tsx | 2 +- .../apm/public/plugin.ts | 2 - .../components/tabs/logs/logs_tab_content.tsx | 94 ++---- .../logs_shared/kibana.jsonc | 5 +- .../public/components/logs_overview/index.tsx | 8 - .../logs_overview/logs_overview.mock.tsx | 32 -- .../logs_overview/logs_overview.tsx | 70 ----- .../logs_shared/public/index.ts | 1 - .../logs_shared/public/mocks.tsx | 2 - .../logs_shared/public/plugin.ts | 23 +- .../logs_shared/public/types.ts | 12 +- .../logs_shared/server/feature_flags.ts | 33 -- .../logs_shared/server/plugin.ts | 28 +- .../logs_shared/tsconfig.json | 4 - yarn.lock | 17 -- 75 files changed, 56 insertions(+), 3405 deletions(-) delete mode 100644 packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts delete mode 100644 packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts delete mode 100644 packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts delete mode 100644 packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts delete mode 100644 packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts delete mode 100644 packages/kbn-xstate-utils/src/console_inspector.ts delete mode 100644 x-pack/packages/observability/logs_overview/README.md delete mode 100644 x-pack/packages/observability/logs_overview/index.ts delete mode 100644 x-pack/packages/observability/logs_overview/jest.config.js delete mode 100644 x-pack/packages/observability/logs_overview/kibana.jsonc delete mode 100644 x-pack/packages/observability/logs_overview/package.json delete mode 100644 x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx delete mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/types.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/utils/logs_source.ts delete mode 100644 x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts delete mode 100644 x-pack/packages/observability/logs_overview/tsconfig.json delete mode 100644 x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx delete mode 100644 x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx delete mode 100644 x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx delete mode 100644 x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts diff --git a/.eslintrc.js b/.eslintrc.js index c604844089ef4..797b84522df3f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -978,7 +978,6 @@ module.exports = { files: [ 'x-pack/plugins/observability_solution/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', 'src/plugins/ai_assistant_management/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', - 'x-pack/packages/observability/logs_overview/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', ], rules: { '@kbn/i18n/strings_should_be_translated_with_i18n': 'warn', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 974a7d39f63b3..9b3c46d065fe1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -652,7 +652,6 @@ x-pack/packages/observability/alerting_test_data @elastic/obs-ux-management-team x-pack/test/cases_api_integration/common/plugins/observability @elastic/response-ops x-pack/packages/observability/get_padded_alert_time_range_util @elastic/obs-ux-management-team x-pack/plugins/observability_solution/observability_logs_explorer @elastic/obs-ux-logs-team -x-pack/packages/observability/logs_overview @elastic/obs-ux-logs-team x-pack/plugins/observability_solution/observability_onboarding/e2e @elastic/obs-ux-logs-team @elastic/obs-ux-onboarding-team x-pack/plugins/observability_solution/observability_onboarding @elastic/obs-ux-logs-team @elastic/obs-ux-onboarding-team x-pack/plugins/observability_solution/observability @elastic/obs-ux-management-team diff --git a/package.json b/package.json index 58cd08773696f..57b84f1c46dcb 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,6 @@ "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0", "@types/react": "~18.2.0", "@types/react-dom": "~18.2.0", - "@xstate5/react/**/xstate": "^5.18.1", "globby/fast-glob": "^3.2.11" }, "dependencies": { @@ -688,7 +687,6 @@ "@kbn/observability-fixtures-plugin": "link:x-pack/test/cases_api_integration/common/plugins/observability", "@kbn/observability-get-padded-alert-time-range-util": "link:x-pack/packages/observability/get_padded_alert_time_range_util", "@kbn/observability-logs-explorer-plugin": "link:x-pack/plugins/observability_solution/observability_logs_explorer", - "@kbn/observability-logs-overview": "link:x-pack/packages/observability/logs_overview", "@kbn/observability-onboarding-plugin": "link:x-pack/plugins/observability_solution/observability_onboarding", "@kbn/observability-plugin": "link:x-pack/plugins/observability_solution/observability", "@kbn/observability-shared-plugin": "link:x-pack/plugins/observability_solution/observability_shared", @@ -1052,7 +1050,6 @@ "@turf/helpers": "6.0.1", "@turf/length": "^6.0.2", "@xstate/react": "^3.2.2", - "@xstate5/react": "npm:@xstate/react@^4.1.2", "adm-zip": "^0.5.9", "ai": "^2.2.33", "ajv": "^8.12.0", @@ -1286,7 +1283,6 @@ "whatwg-fetch": "^3.0.0", "xml2js": "^0.5.0", "xstate": "^4.38.2", - "xstate5": "npm:xstate@^5.18.1", "xterm": "^5.1.0", "yauzl": "^2.10.0", "yazl": "^2.5.1", @@ -1308,7 +1304,6 @@ "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-transform-class-properties": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-env": "^7.24.7", diff --git a/packages/kbn-apm-synthtrace-client/src/lib/entity.ts b/packages/kbn-apm-synthtrace-client/src/lib/entity.ts index b26dbfc7ffb46..4d522ef07ff0e 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/entity.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/entity.ts @@ -7,8 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export type ObjectEntry = [keyof T, T[keyof T]]; - export type Fields | undefined = undefined> = { '@timestamp'?: number; } & (TMeta extends undefined ? {} : Partial<{ meta: TMeta }>); @@ -29,14 +27,4 @@ export class Entity { return this; } - - overrides(overrides: Partial) { - const overrideEntries = Object.entries(overrides) as Array>; - - overrideEntries.forEach(([fieldName, value]) => { - this.fields[fieldName] = value; - }); - - return this; - } } diff --git a/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts b/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts deleted file mode 100644 index 4f1db28017d29..0000000000000 --- a/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts +++ /dev/null @@ -1,74 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { castArray } from 'lodash'; -import { SynthtraceGenerator } from '../types'; -import { Fields } from './entity'; -import { Serializable } from './serializable'; - -export class GaussianEvents { - constructor( - private readonly from: Date, - private readonly to: Date, - private readonly mean: Date, - private readonly width: number, - private readonly totalPoints: number - ) {} - - *generator( - map: ( - timestamp: number, - index: number - ) => Serializable | Array> - ): SynthtraceGenerator { - if (this.totalPoints <= 0) { - return; - } - - const startTime = this.from.getTime(); - const endTime = this.to.getTime(); - const meanTime = this.mean.getTime(); - const densityInterval = 1 / (this.totalPoints - 1); - - for (let eventIndex = 0; eventIndex < this.totalPoints; eventIndex++) { - const quantile = eventIndex * densityInterval; - - const standardScore = Math.sqrt(2) * inverseError(2 * quantile - 1); - const timestamp = Math.round(meanTime + standardScore * this.width); - - if (timestamp >= startTime && timestamp <= endTime) { - yield* this.generateEvents(timestamp, eventIndex, map); - } - } - } - - private *generateEvents( - timestamp: number, - eventIndex: number, - map: ( - timestamp: number, - index: number - ) => Serializable | Array> - ): Generator> { - const events = castArray(map(timestamp, eventIndex)); - for (const event of events) { - yield event; - } - } -} - -function inverseError(x: number): number { - const a = 0.147; - const sign = x < 0 ? -1 : 1; - - const part1 = 2 / (Math.PI * a) + Math.log(1 - x * x) / 2; - const part2 = Math.log(1 - x * x) / a; - - return sign * Math.sqrt(Math.sqrt(part1 * part1 - part2) - part1); -} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts index 30550d64c4df8..198949b482be3 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts @@ -27,7 +27,7 @@ interface HostDocument extends Fields { 'cloud.provider'?: string; } -export class Host extends Entity { +class Host extends Entity { cpu({ cpuTotalValue }: { cpuTotalValue?: number } = {}) { return new HostMetrics({ ...this.fields, @@ -175,11 +175,3 @@ export function host(name: string): Host { 'cloud.provider': 'gcp', }); } - -export function minimalHost(name: string): Host { - return new Host({ - 'agent.id': 'synthtrace', - 'host.hostname': name, - 'host.name': name, - }); -} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts index 2957605cffcd3..853a9549ce02c 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts @@ -8,7 +8,7 @@ */ import { dockerContainer, DockerContainerMetricsDocument } from './docker_container'; -import { host, HostMetricsDocument, minimalHost } from './host'; +import { host, HostMetricsDocument } from './host'; import { k8sContainer, K8sContainerMetricsDocument } from './k8s_container'; import { pod, PodMetricsDocument } from './pod'; import { awsRds, AWSRdsMetricsDocument } from './aws/rds'; @@ -24,7 +24,6 @@ export type InfraDocument = export const infra = { host, - minimalHost, pod, dockerContainer, k8sContainer, diff --git a/packages/kbn-apm-synthtrace-client/src/lib/interval.ts b/packages/kbn-apm-synthtrace-client/src/lib/interval.ts index 5a5ed3ab5fdbe..1d56c42e1fe12 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/interval.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/interval.ts @@ -34,10 +34,6 @@ interface IntervalOptions { rate?: number; } -interface StepDetails { - stepMilliseconds: number; -} - export class Interval { private readonly intervalAmount: number; private readonly intervalUnit: unitOfTime.DurationConstructor; @@ -50,16 +46,12 @@ export class Interval { this._rate = options.rate || 1; } - private getIntervalMilliseconds(): number { - return moment.duration(this.intervalAmount, this.intervalUnit).asMilliseconds(); - } - private getTimestamps() { const from = this.options.from.getTime(); const to = this.options.to.getTime(); let time: number = from; - const diff = this.getIntervalMilliseconds(); + const diff = moment.duration(this.intervalAmount, this.intervalUnit).asMilliseconds(); const timestamps: number[] = []; @@ -76,19 +68,15 @@ export class Interval { *generator( map: ( timestamp: number, - index: number, - stepDetails: StepDetails + index: number ) => Serializable | Array> ): SynthtraceGenerator { const timestamps = this.getTimestamps(); - const stepDetails: StepDetails = { - stepMilliseconds: this.getIntervalMilliseconds(), - }; let index = 0; for (const timestamp of timestamps) { - const events = castArray(map(timestamp, index, stepDetails)); + const events = castArray(map(timestamp, index)); index++; for (const event of events) { yield event; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts index 2bbc59eb37e70..e19f0f6fd6565 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts @@ -68,7 +68,6 @@ export type LogDocument = Fields & 'event.duration': number; 'event.start': Date; 'event.end': Date; - labels?: Record; test_field: string | string[]; date: Date; severity: string; @@ -157,26 +156,6 @@ function create(logsOptions: LogsOptions = defaultLogsOptions): Log { ).dataset('synth'); } -function createMinimal({ - dataset = 'synth', - namespace = 'default', -}: { - dataset?: string; - namespace?: string; -} = {}): Log { - return new Log( - { - 'input.type': 'logs', - 'data_stream.namespace': namespace, - 'data_stream.type': 'logs', - 'data_stream.dataset': dataset, - 'event.dataset': dataset, - }, - { isLogsDb: false } - ); -} - export const log = { create, - createMinimal, }; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts deleted file mode 100644 index 0741884550f32..0000000000000 --- a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts +++ /dev/null @@ -1,53 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PoissonEvents } from './poisson_events'; -import { Serializable } from './serializable'; - -describe('poisson events', () => { - it('generates events within the given time range', () => { - const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 10); - - const events = Array.from( - poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp })) - ); - - expect(events.length).toBeGreaterThanOrEqual(1); - - for (const event of events) { - expect(event.fields['@timestamp']).toBeGreaterThanOrEqual(1000); - expect(event.fields['@timestamp']).toBeLessThanOrEqual(2000); - } - }); - - it('generates at least one event if the rate is greater than 0', () => { - const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 1); - - const events = Array.from( - poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp })) - ); - - expect(events.length).toBeGreaterThanOrEqual(1); - - for (const event of events) { - expect(event.fields['@timestamp']).toBeGreaterThanOrEqual(1000); - expect(event.fields['@timestamp']).toBeLessThanOrEqual(2000); - } - }); - - it('generates no event if the rate is 0', () => { - const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 0); - - const events = Array.from( - poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp })) - ); - - expect(events.length).toBe(0); - }); -}); diff --git a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts deleted file mode 100644 index e7fd24b8323e7..0000000000000 --- a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts +++ /dev/null @@ -1,77 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { castArray } from 'lodash'; -import { SynthtraceGenerator } from '../types'; -import { Fields } from './entity'; -import { Serializable } from './serializable'; - -export class PoissonEvents { - constructor( - private readonly from: Date, - private readonly to: Date, - private readonly rate: number - ) {} - - private getTotalTimePeriod(): number { - return this.to.getTime() - this.from.getTime(); - } - - private getInterarrivalTime(): number { - const distribution = -Math.log(1 - Math.random()) / this.rate; - const totalTimePeriod = this.getTotalTimePeriod(); - return Math.floor(distribution * totalTimePeriod); - } - - *generator( - map: ( - timestamp: number, - index: number - ) => Serializable | Array> - ): SynthtraceGenerator { - if (this.rate <= 0) { - return; - } - - let currentTime = this.from.getTime(); - const endTime = this.to.getTime(); - let eventIndex = 0; - - while (currentTime < endTime) { - const interarrivalTime = this.getInterarrivalTime(); - currentTime += interarrivalTime; - - if (currentTime < endTime) { - yield* this.generateEvents(currentTime, eventIndex, map); - eventIndex++; - } - } - - // ensure at least one event has been emitted - if (this.rate > 0 && eventIndex === 0) { - const forcedEventTime = - this.from.getTime() + Math.floor(Math.random() * this.getTotalTimePeriod()); - yield* this.generateEvents(forcedEventTime, eventIndex, map); - } - } - - private *generateEvents( - timestamp: number, - eventIndex: number, - map: ( - timestamp: number, - index: number - ) => Serializable | Array> - ): Generator> { - const events = castArray(map(timestamp, eventIndex)); - for (const event of events) { - yield event; - } - } -} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts b/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts index 1c6f12414a148..ccdea4ee75197 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts @@ -9,12 +9,10 @@ import datemath from '@kbn/datemath'; import type { Moment } from 'moment'; -import { GaussianEvents } from './gaussian_events'; import { Interval } from './interval'; -import { PoissonEvents } from './poisson_events'; export class Timerange { - constructor(public readonly from: Date, public readonly to: Date) {} + constructor(private from: Date, private to: Date) {} interval(interval: string) { return new Interval({ from: this.from, to: this.to, interval }); @@ -23,29 +21,6 @@ export class Timerange { ratePerMinute(rate: number) { return this.interval(`1m`).rate(rate); } - - poissonEvents(rate: number) { - return new PoissonEvents(this.from, this.to, rate); - } - - gaussianEvents(mean: Date, width: number, totalPoints: number) { - return new GaussianEvents(this.from, this.to, mean, width, totalPoints); - } - - splitInto(segmentCount: number): Timerange[] { - const duration = this.to.getTime() - this.from.getTime(); - const segmentDuration = duration / segmentCount; - - return Array.from({ length: segmentCount }, (_, i) => { - const from = new Date(this.from.getTime() + i * segmentDuration); - const to = new Date(from.getTime() + segmentDuration); - return new Timerange(from, to); - }); - } - - toString() { - return `Timerange(from=${this.from.toISOString()}, to=${this.to.toISOString()})`; - } } type DateLike = Date | number | Moment | string; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts deleted file mode 100644 index 83860635ae64a..0000000000000 --- a/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts +++ /dev/null @@ -1,197 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { infra, LogDocument, log } from '@kbn/apm-synthtrace-client'; -import { fakerEN as faker } from '@faker-js/faker'; -import { z } from '@kbn/zod'; -import { Scenario } from '../cli/scenario'; -import { withClient } from '../lib/utils/with_client'; -import { - LogMessageGenerator, - generateUnstructuredLogMessage, - unstructuredLogMessageGenerators, -} from './helpers/unstructured_logs'; - -const scenarioOptsSchema = z.intersection( - z.object({ - randomSeed: z.number().default(0), - messageGroup: z - .enum([ - 'httpAccess', - 'userAuthentication', - 'networkEvent', - 'dbOperations', - 'taskOperations', - 'degradedOperations', - 'errorOperations', - ]) - .default('dbOperations'), - }), - z - .discriminatedUnion('distribution', [ - z.object({ - distribution: z.literal('uniform'), - rate: z.number().default(1), - }), - z.object({ - distribution: z.literal('poisson'), - rate: z.number().default(1), - }), - z.object({ - distribution: z.literal('gaussian'), - mean: z.coerce.date().describe('Time of the peak of the gaussian distribution'), - width: z.number().default(5000).describe('Width of the gaussian distribution in ms'), - totalPoints: z - .number() - .default(100) - .describe('Total number of points in the gaussian distribution'), - }), - ]) - .default({ distribution: 'uniform', rate: 1 }) -); - -type ScenarioOpts = z.output; - -const scenario: Scenario = async (runOptions) => { - return { - generate: ({ range, clients: { logsEsClient } }) => { - const { logger } = runOptions; - const scenarioOpts = scenarioOptsSchema.parse(runOptions.scenarioOpts ?? {}); - - faker.seed(scenarioOpts.randomSeed); - faker.setDefaultRefDate(range.from.toISOString()); - - logger.debug(`Generating ${scenarioOpts.distribution} logs...`); - - // Logs Data logic - const LOG_LEVELS = ['info', 'debug', 'error', 'warn', 'trace', 'fatal']; - - const clusterDefinions = [ - { - 'orchestrator.cluster.id': faker.string.nanoid(), - 'orchestrator.cluster.name': 'synth-cluster-1', - 'orchestrator.namespace': 'default', - 'cloud.provider': 'gcp', - 'cloud.region': 'eu-central-1', - 'cloud.availability_zone': 'eu-central-1a', - 'cloud.project.id': faker.string.nanoid(), - }, - { - 'orchestrator.cluster.id': faker.string.nanoid(), - 'orchestrator.cluster.name': 'synth-cluster-2', - 'orchestrator.namespace': 'production', - 'cloud.provider': 'aws', - 'cloud.region': 'us-east-1', - 'cloud.availability_zone': 'us-east-1a', - 'cloud.project.id': faker.string.nanoid(), - }, - { - 'orchestrator.cluster.id': faker.string.nanoid(), - 'orchestrator.cluster.name': 'synth-cluster-3', - 'orchestrator.namespace': 'kube', - 'cloud.provider': 'azure', - 'cloud.region': 'area-51', - 'cloud.availability_zone': 'area-51a', - 'cloud.project.id': faker.string.nanoid(), - }, - ]; - - const hostEntities = [ - { - 'host.name': 'host-1', - 'agent.id': 'synth-agent-1', - 'agent.name': 'nodejs', - 'cloud.instance.id': faker.string.nanoid(), - 'orchestrator.resource.id': faker.string.nanoid(), - ...clusterDefinions[0], - }, - { - 'host.name': 'host-2', - 'agent.id': 'synth-agent-2', - 'agent.name': 'custom', - 'cloud.instance.id': faker.string.nanoid(), - 'orchestrator.resource.id': faker.string.nanoid(), - ...clusterDefinions[1], - }, - { - 'host.name': 'host-3', - 'agent.id': 'synth-agent-3', - 'agent.name': 'python', - 'cloud.instance.id': faker.string.nanoid(), - 'orchestrator.resource.id': faker.string.nanoid(), - ...clusterDefinions[2], - }, - ].map((hostDefinition) => - infra.minimalHost(hostDefinition['host.name']).overrides(hostDefinition) - ); - - const serviceNames = Array(3) - .fill(null) - .map((_, idx) => `synth-service-${idx}`); - - const generatorFactory = - scenarioOpts.distribution === 'uniform' - ? range.interval('1s').rate(scenarioOpts.rate) - : scenarioOpts.distribution === 'poisson' - ? range.poissonEvents(scenarioOpts.rate) - : range.gaussianEvents(scenarioOpts.mean, scenarioOpts.width, scenarioOpts.totalPoints); - - const logs = generatorFactory.generator((timestamp) => { - const entity = faker.helpers.arrayElement(hostEntities); - const serviceName = faker.helpers.arrayElement(serviceNames); - const level = faker.helpers.arrayElement(LOG_LEVELS); - const messages = logMessageGenerators[scenarioOpts.messageGroup](faker); - - return messages.map((message) => - log - .createMinimal() - .message(message) - .logLevel(level) - .service(serviceName) - .overrides({ - ...entity.fields, - labels: { - scenario: 'rare', - population: scenarioOpts.distribution, - }, - }) - .timestamp(timestamp) - ); - }); - - return [ - withClient( - logsEsClient, - logger.perf('generating_logs', () => [logs]) - ), - ]; - }, - }; -}; - -export default scenario; - -const logMessageGenerators = { - httpAccess: generateUnstructuredLogMessage([unstructuredLogMessageGenerators.httpAccess]), - userAuthentication: generateUnstructuredLogMessage([ - unstructuredLogMessageGenerators.userAuthentication, - ]), - networkEvent: generateUnstructuredLogMessage([unstructuredLogMessageGenerators.networkEvent]), - dbOperations: generateUnstructuredLogMessage([unstructuredLogMessageGenerators.dbOperation]), - taskOperations: generateUnstructuredLogMessage([ - unstructuredLogMessageGenerators.taskStatusSuccess, - ]), - degradedOperations: generateUnstructuredLogMessage([ - unstructuredLogMessageGenerators.taskStatusFailure, - ]), - errorOperations: generateUnstructuredLogMessage([ - unstructuredLogMessageGenerators.error, - unstructuredLogMessageGenerators.restart, - ]), -} satisfies Record; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts deleted file mode 100644 index 490bd449e2b60..0000000000000 --- a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts +++ /dev/null @@ -1,94 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { Faker, faker } from '@faker-js/faker'; - -export type LogMessageGenerator = (f: Faker) => string[]; - -export const unstructuredLogMessageGenerators = { - httpAccess: (f: Faker) => [ - `${f.internet.ip()} - - [${f.date - .past() - .toISOString() - .replace('T', ' ') - .replace( - /\..+/, - '' - )}] "${f.internet.httpMethod()} ${f.internet.url()} HTTP/1.1" ${f.helpers.arrayElement([ - 200, 301, 404, 500, - ])} ${f.number.int({ min: 100, max: 5000 })}`, - ], - dbOperation: (f: Faker) => [ - `${f.database.engine()}: ${f.database.column()} ${f.helpers.arrayElement([ - 'created', - 'updated', - 'deleted', - 'inserted', - ])} successfully ${f.number.int({ max: 100000 })} times`, - ], - taskStatusSuccess: (f: Faker) => [ - `${f.hacker.noun()}: ${f.word.words()} ${f.helpers.arrayElement([ - 'triggered', - 'executed', - 'processed', - 'handled', - ])} successfully at ${f.date.recent().toISOString()}`, - ], - taskStatusFailure: (f: Faker) => [ - `${f.hacker.noun()}: ${f.helpers.arrayElement([ - 'triggering', - 'execution', - 'processing', - 'handling', - ])} of ${f.word.words()} failed at ${f.date.recent().toISOString()}`, - ], - error: (f: Faker) => [ - `${f.helpers.arrayElement([ - 'Error', - 'Exception', - 'Failure', - 'Crash', - 'Bug', - 'Issue', - ])}: ${f.hacker.phrase()}`, - `Stopping ${f.number.int(42)} background tasks...`, - 'Shutting down process...', - ], - restart: (f: Faker) => { - const service = f.database.engine(); - return [ - `Restarting ${service}...`, - `Waiting for queue to drain...`, - `Service ${service} restarted ${f.helpers.arrayElement([ - 'successfully', - 'with errors', - 'with warnings', - ])}`, - ]; - }, - userAuthentication: (f: Faker) => [ - `User ${f.internet.userName()} ${f.helpers.arrayElement([ - 'logged in', - 'logged out', - 'failed to login', - ])}`, - ], - networkEvent: (f: Faker) => [ - `Network ${f.helpers.arrayElement([ - 'connection', - 'disconnection', - 'data transfer', - ])} ${f.helpers.arrayElement(['from', 'to'])} ${f.internet.ip()}`, - ], -} satisfies Record; - -export const generateUnstructuredLogMessage = - (generators: LogMessageGenerator[] = Object.values(unstructuredLogMessageGenerators)) => - (f: Faker = faker) => - f.helpers.arrayElement(generators)(f); diff --git a/packages/kbn-apm-synthtrace/tsconfig.json b/packages/kbn-apm-synthtrace/tsconfig.json index db93e36421b83..d0f5c5801597a 100644 --- a/packages/kbn-apm-synthtrace/tsconfig.json +++ b/packages/kbn-apm-synthtrace/tsconfig.json @@ -10,7 +10,6 @@ "@kbn/apm-synthtrace-client", "@kbn/dev-utils", "@kbn/elastic-agent-utils", - "@kbn/zod", ], "exclude": [ "target/**/*", diff --git a/packages/kbn-management/settings/setting_ids/index.ts b/packages/kbn-management/settings/setting_ids/index.ts index e926007f77f25..2b8c5de0b71df 100644 --- a/packages/kbn-management/settings/setting_ids/index.ts +++ b/packages/kbn-management/settings/setting_ids/index.ts @@ -142,7 +142,6 @@ export const OBSERVABILITY_APM_ENABLE_SERVICE_INVENTORY_TABLE_SEARCH_BAR = 'observability:apmEnableServiceInventoryTableSearchBar'; export const OBSERVABILITY_LOGS_EXPLORER_ALLOWED_DATA_VIEWS_ID = 'observability:logsExplorer:allowedDataViews'; -export const OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID = 'observability:newLogsOverview'; export const OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE = 'observability:entityCentricExperience'; export const OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID = 'observability:logSources'; export const OBSERVABILITY_ENABLE_LOGS_STREAM = 'observability:enableLogsStream'; diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 52a837724480d..539d3098030e0 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -247,18 +247,6 @@ export function getWebpackConfig( }, }, }, - { - test: /node_modules\/@?xstate5\/.*\.js$/, - use: { - loader: 'babel-loader', - options: { - babelrc: false, - envName: worker.dist ? 'production' : 'development', - presets: [BABEL_PRESET], - plugins: ['@babel/plugin-transform-logical-assignment-operators'], - }, - }, - }, { test: /\.(html|md|txt|tmpl)$/, use: { diff --git a/packages/kbn-xstate-utils/kibana.jsonc b/packages/kbn-xstate-utils/kibana.jsonc index 1fb3507854b98..cd1151a3f2103 100644 --- a/packages/kbn-xstate-utils/kibana.jsonc +++ b/packages/kbn-xstate-utils/kibana.jsonc @@ -1,5 +1,5 @@ { - "type": "shared-browser", + "type": "shared-common", "id": "@kbn/xstate-utils", "owner": "@elastic/obs-ux-logs-team" } diff --git a/packages/kbn-xstate-utils/src/console_inspector.ts b/packages/kbn-xstate-utils/src/console_inspector.ts deleted file mode 100644 index 8792ab44f3c28..0000000000000 --- a/packages/kbn-xstate-utils/src/console_inspector.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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - ActorRefLike, - AnyActorRef, - InspectedActorEvent, - InspectedEventEvent, - InspectedSnapshotEvent, - InspectionEvent, -} from 'xstate5'; -import { isDevMode } from './dev_tools'; - -export const createConsoleInspector = () => { - if (!isDevMode()) { - return () => {}; - } - - // eslint-disable-next-line no-console - const log = console.info.bind(console); - - const logActorEvent = (actorEvent: InspectedActorEvent) => { - if (isActorRef(actorEvent.actorRef)) { - log( - '✨ %c%s%c is a new actor of type %c%s%c:', - ...styleAsActor(actorEvent.actorRef.id), - ...styleAsKeyword(actorEvent.type), - actorEvent.actorRef - ); - } else { - log('✨ New %c%s%c actor without id:', ...styleAsKeyword(actorEvent.type), actorEvent); - } - }; - - const logEventEvent = (eventEvent: InspectedEventEvent) => { - if (isActorRef(eventEvent.actorRef)) { - log( - '🔔 %c%s%c received event %c%s%c from %c%s%c:', - ...styleAsActor(eventEvent.actorRef.id), - ...styleAsKeyword(eventEvent.event.type), - ...styleAsKeyword(eventEvent.sourceRef?.id), - eventEvent - ); - } else { - log('🔔 Event', ...styleAsKeyword(eventEvent.event.type), ':', eventEvent); - } - }; - - const logSnapshotEvent = (snapshotEvent: InspectedSnapshotEvent) => { - if (isActorRef(snapshotEvent.actorRef)) { - log( - '📸 %c%s%c updated due to %c%s%c:', - ...styleAsActor(snapshotEvent.actorRef.id), - ...styleAsKeyword(snapshotEvent.event.type), - snapshotEvent.snapshot - ); - } else { - log('📸 Snapshot due to %c%s%c:', ...styleAsKeyword(snapshotEvent.event.type), snapshotEvent); - } - }; - - return (inspectionEvent: InspectionEvent) => { - if (inspectionEvent.type === '@xstate.actor') { - logActorEvent(inspectionEvent); - } else if (inspectionEvent.type === '@xstate.event') { - logEventEvent(inspectionEvent); - } else if (inspectionEvent.type === '@xstate.snapshot') { - logSnapshotEvent(inspectionEvent); - } else { - log(`❓ Received inspection event:`, inspectionEvent); - } - }; -}; - -const isActorRef = (actorRefLike: ActorRefLike): actorRefLike is AnyActorRef => - 'id' in actorRefLike; - -const keywordStyle = 'font-weight: bold'; -const styleAsKeyword = (value: any) => [keywordStyle, value, ''] as const; - -const actorStyle = 'font-weight: bold; text-decoration: underline'; -const styleAsActor = (value: any) => [actorStyle, value, ''] as const; diff --git a/packages/kbn-xstate-utils/src/index.ts b/packages/kbn-xstate-utils/src/index.ts index 3edf83e8a32c2..107585ba2096f 100644 --- a/packages/kbn-xstate-utils/src/index.ts +++ b/packages/kbn-xstate-utils/src/index.ts @@ -9,6 +9,5 @@ export * from './actions'; export * from './dev_tools'; -export * from './console_inspector'; export * from './notification_channel'; export * from './types'; diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index e5ddfbe4dd037..dc2d2ad2c5de2 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -705,10 +705,4 @@ export const stackManagementSchema: MakeSchemaFrom = { _meta: { description: 'Non-default value of setting.' }, }, }, - 'observability:newLogsOverview': { - type: 'boolean', - _meta: { - description: 'Enable the new logs overview component.', - }, - }, }; diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 2acb487e7ed08..ef20ab223dfb6 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -56,7 +56,6 @@ export interface UsageStats { 'observability:logsExplorer:allowedDataViews': string[]; 'observability:logSources': string[]; 'observability:enableLogsStream': boolean; - 'observability:newLogsOverview': boolean; 'observability:aiAssistantSimulatedFunctionCalling': boolean; 'observability:aiAssistantSearchConnectorIndexPattern': string; 'visualization:heatmap:maxBuckets': number; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 830cffc17cf1c..958280d9eba00 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -10768,12 +10768,6 @@ "description": "Non-default value of setting." } }, - "observability:newLogsOverview": { - "type": "boolean", - "_meta": { - "description": "Enable the new logs overview component." - } - }, "observability:searchExcludedDataTiers": { "type": "array", "items": { diff --git a/tsconfig.base.json b/tsconfig.base.json index 4bc68d806f043..3df30d9cf8c30 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1298,8 +1298,6 @@ "@kbn/observability-get-padded-alert-time-range-util/*": ["x-pack/packages/observability/get_padded_alert_time_range_util/*"], "@kbn/observability-logs-explorer-plugin": ["x-pack/plugins/observability_solution/observability_logs_explorer"], "@kbn/observability-logs-explorer-plugin/*": ["x-pack/plugins/observability_solution/observability_logs_explorer/*"], - "@kbn/observability-logs-overview": ["x-pack/packages/observability/logs_overview"], - "@kbn/observability-logs-overview/*": ["x-pack/packages/observability/logs_overview/*"], "@kbn/observability-onboarding-e2e": ["x-pack/plugins/observability_solution/observability_onboarding/e2e"], "@kbn/observability-onboarding-e2e/*": ["x-pack/plugins/observability_solution/observability_onboarding/e2e/*"], "@kbn/observability-onboarding-plugin": ["x-pack/plugins/observability_solution/observability_onboarding"], diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 50f2b77b84ad7..a46e291093411 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -95,9 +95,6 @@ "xpack.observabilityLogsExplorer": "plugins/observability_solution/observability_logs_explorer", "xpack.observability_onboarding": "plugins/observability_solution/observability_onboarding", "xpack.observabilityShared": "plugins/observability_solution/observability_shared", - "xpack.observabilityLogsOverview": [ - "packages/observability/logs_overview/src/components" - ], "xpack.osquery": ["plugins/osquery"], "xpack.painlessLab": "plugins/painless_lab", "xpack.profiling": ["plugins/observability_solution/profiling"], diff --git a/x-pack/packages/observability/logs_overview/README.md b/x-pack/packages/observability/logs_overview/README.md deleted file mode 100644 index 20d3f0f02b7df..0000000000000 --- a/x-pack/packages/observability/logs_overview/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# @kbn/observability-logs-overview - -Empty package generated by @kbn/generate diff --git a/x-pack/packages/observability/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/index.ts deleted file mode 100644 index 057d1d3acd152..0000000000000 --- a/x-pack/packages/observability/logs_overview/index.ts +++ /dev/null @@ -1,21 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { - LogsOverview, - LogsOverviewErrorContent, - LogsOverviewLoadingContent, - type LogsOverviewDependencies, - type LogsOverviewErrorContentProps, - type LogsOverviewProps, -} from './src/components/logs_overview'; -export type { - DataViewLogsSourceConfiguration, - IndexNameLogsSourceConfiguration, - LogsSourceConfiguration, - SharedSettingLogsSourceConfiguration, -} from './src/utils/logs_source'; diff --git a/x-pack/packages/observability/logs_overview/jest.config.js b/x-pack/packages/observability/logs_overview/jest.config.js deleted file mode 100644 index 2ee88ee990253..0000000000000 --- a/x-pack/packages/observability/logs_overview/jest.config.js +++ /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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../../../..', - roots: ['/x-pack/packages/observability/logs_overview'], -}; diff --git a/x-pack/packages/observability/logs_overview/kibana.jsonc b/x-pack/packages/observability/logs_overview/kibana.jsonc deleted file mode 100644 index 90b3375086720..0000000000000 --- a/x-pack/packages/observability/logs_overview/kibana.jsonc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "shared-browser", - "id": "@kbn/observability-logs-overview", - "owner": "@elastic/obs-ux-logs-team" -} diff --git a/x-pack/packages/observability/logs_overview/package.json b/x-pack/packages/observability/logs_overview/package.json deleted file mode 100644 index 77a529e7e59f7..0000000000000 --- a/x-pack/packages/observability/logs_overview/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/observability-logs-overview", - "private": true, - "version": "1.0.0", - "license": "Elastic License 2.0", - "sideEffects": false -} diff --git a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx deleted file mode 100644 index fe108289985a9..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx +++ /dev/null @@ -1,110 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { EuiButton } from '@elastic/eui'; -import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common'; -import { FilterStateStore, buildCustomFilter } from '@kbn/es-query'; -import { i18n } from '@kbn/i18n'; -import { getRouterLinkProps } from '@kbn/router-utils'; -import type { SharePluginStart } from '@kbn/share-plugin/public'; -import React, { useCallback, useMemo } from 'react'; -import type { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; - -export interface DiscoverLinkProps { - documentFilters?: QueryDslQueryContainer[]; - logsSource: IndexNameLogsSourceConfiguration; - timeRange: { - start: string; - end: string; - }; - dependencies: DiscoverLinkDependencies; -} - -export interface DiscoverLinkDependencies { - share: SharePluginStart; -} - -export const DiscoverLink = React.memo( - ({ dependencies: { share }, documentFilters, logsSource, timeRange }: DiscoverLinkProps) => { - const discoverLocatorParams = useMemo( - () => ({ - dataViewSpec: { - id: logsSource.indexName, - name: logsSource.indexName, - title: logsSource.indexName, - timeFieldName: logsSource.timestampField, - }, - timeRange: { - from: timeRange.start, - to: timeRange.end, - }, - filters: documentFilters?.map((filter) => - buildCustomFilter( - logsSource.indexName, - filter, - false, - false, - categorizedLogsFilterLabel, - FilterStateStore.APP_STATE - ) - ), - }), - [ - documentFilters, - logsSource.indexName, - logsSource.timestampField, - timeRange.end, - timeRange.start, - ] - ); - - const discoverLocator = useMemo( - () => share.url.locators.get('DISCOVER_APP_LOCATOR'), - [share.url.locators] - ); - - const discoverUrl = useMemo( - () => discoverLocator?.getRedirectUrl(discoverLocatorParams), - [discoverLocatorParams, discoverLocator] - ); - - const navigateToDiscover = useCallback(() => { - discoverLocator?.navigate(discoverLocatorParams); - }, [discoverLocatorParams, discoverLocator]); - - const discoverLinkProps = getRouterLinkProps({ - href: discoverUrl, - onClick: navigateToDiscover, - }); - - return ( - - {discoverLinkTitle} - - ); - } -); - -export const discoverLinkTitle = i18n.translate( - 'xpack.observabilityLogsOverview.discoverLinkTitle', - { - defaultMessage: 'Open in Discover', - } -); - -export const categorizedLogsFilterLabel = i18n.translate( - 'xpack.observabilityLogsOverview.categorizedLogsFilterLabel', - { - defaultMessage: 'Categorized log entries', - } -); diff --git a/x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts b/x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts deleted file mode 100644 index 738bf51d4529d..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/discover_link/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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './discover_link'; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts b/x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts deleted file mode 100644 index 786475396237c..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './log_categories'; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx deleted file mode 100644 index 6204667827281..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx +++ /dev/null @@ -1,94 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { ISearchGeneric } from '@kbn/search-types'; -import { createConsoleInspector } from '@kbn/xstate-utils'; -import { useMachine } from '@xstate5/react'; -import React, { useCallback } from 'react'; -import { - categorizeLogsService, - createCategorizeLogsServiceImplementations, -} from '../../services/categorize_logs_service'; -import { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; -import { LogCategoriesErrorContent } from './log_categories_error_content'; -import { LogCategoriesLoadingContent } from './log_categories_loading_content'; -import { - LogCategoriesResultContent, - LogCategoriesResultContentDependencies, -} from './log_categories_result_content'; - -export interface LogCategoriesProps { - dependencies: LogCategoriesDependencies; - documentFilters?: QueryDslQueryContainer[]; - logsSource: IndexNameLogsSourceConfiguration; - // The time range could be made optional if we want to support an internal - // time range picker - timeRange: { - start: string; - end: string; - }; -} - -export type LogCategoriesDependencies = LogCategoriesResultContentDependencies & { - search: ISearchGeneric; -}; - -export const LogCategories: React.FC = ({ - dependencies, - documentFilters = [], - logsSource, - timeRange, -}) => { - const [categorizeLogsServiceState, sendToCategorizeLogsService] = useMachine( - categorizeLogsService.provide( - createCategorizeLogsServiceImplementations({ search: dependencies.search }) - ), - { - inspect: consoleInspector, - input: { - index: logsSource.indexName, - startTimestamp: timeRange.start, - endTimestamp: timeRange.end, - timeField: logsSource.timestampField, - messageField: logsSource.messageField, - documentFilters, - }, - } - ); - - const cancelOperation = useCallback(() => { - sendToCategorizeLogsService({ - type: 'cancel', - }); - }, [sendToCategorizeLogsService]); - - if (categorizeLogsServiceState.matches('done')) { - return ( - - ); - } else if (categorizeLogsServiceState.matches('failed')) { - return ; - } else if (categorizeLogsServiceState.matches('countingDocuments')) { - return ; - } else if ( - categorizeLogsServiceState.matches('fetchingSampledCategories') || - categorizeLogsServiceState.matches('fetchingRemainingCategories') - ) { - return ; - } else { - return null; - } -}; - -const consoleInspector = createConsoleInspector(); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx deleted file mode 100644 index 4538b0ec2fd5d..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx +++ /dev/null @@ -1,44 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import type { SharePluginStart } from '@kbn/share-plugin/public'; -import React from 'react'; -import type { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; -import { DiscoverLink } from '../discover_link'; - -export interface LogCategoriesControlBarProps { - documentFilters?: QueryDslQueryContainer[]; - logsSource: IndexNameLogsSourceConfiguration; - timeRange: { - start: string; - end: string; - }; - dependencies: LogCategoriesControlBarDependencies; -} - -export interface LogCategoriesControlBarDependencies { - share: SharePluginStart; -} - -export const LogCategoriesControlBar: React.FC = React.memo( - ({ dependencies, documentFilters, logsSource, timeRange }) => { - return ( - - - - - - ); - } -); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx deleted file mode 100644 index 1a335e3265294..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx +++ /dev/null @@ -1,44 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiCodeBlock, EuiEmptyPrompt } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; - -export interface LogCategoriesErrorContentProps { - error?: Error; -} - -export const LogCategoriesErrorContent: React.FC = ({ error }) => { - return ( - {logsOverviewErrorTitle}} - body={ - -

    {error?.stack ?? error?.toString() ?? unknownErrorDescription}

    -
    - } - layout="vertical" - /> - ); -}; - -const logsOverviewErrorTitle = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.errorTitle', - { - defaultMessage: 'Failed to categorize logs', - } -); - -const unknownErrorDescription = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.unknownErrorDescription', - { - defaultMessage: 'An unspecified error occurred.', - } -); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx deleted file mode 100644 index d9e960685de99..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx +++ /dev/null @@ -1,182 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiDataGrid, - EuiDataGridColumnSortingConfig, - EuiDataGridPaginationProps, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { createConsoleInspector } from '@kbn/xstate-utils'; -import { useMachine } from '@xstate5/react'; -import _ from 'lodash'; -import React, { useMemo } from 'react'; -import { assign, setup } from 'xstate5'; -import { LogCategory } from '../../types'; -import { - LogCategoriesGridCellDependencies, - LogCategoriesGridColumnId, - createCellContext, - logCategoriesGridColumnIds, - logCategoriesGridColumns, - renderLogCategoriesGridCell, -} from './log_categories_grid_cell'; - -export interface LogCategoriesGridProps { - dependencies: LogCategoriesGridDependencies; - logCategories: LogCategory[]; -} - -export type LogCategoriesGridDependencies = LogCategoriesGridCellDependencies; - -export const LogCategoriesGrid: React.FC = ({ - dependencies, - logCategories, -}) => { - const [gridState, dispatchGridEvent] = useMachine(gridStateService, { - input: { - visibleColumns: logCategoriesGridColumns.map(({ id }) => id), - }, - inspect: consoleInspector, - }); - - const sortedLogCategories = useMemo(() => { - const sortingCriteria = gridState.context.sortingColumns.map( - ({ id, direction }): [(logCategory: LogCategory) => any, 'asc' | 'desc'] => { - switch (id) { - case 'count': - return [(logCategory: LogCategory) => logCategory.documentCount, direction]; - case 'change_type': - // TODO: use better sorting weight for change types - return [(logCategory: LogCategory) => logCategory.change.type, direction]; - case 'change_time': - return [ - (logCategory: LogCategory) => - 'timestamp' in logCategory.change ? logCategory.change.timestamp ?? '' : '', - direction, - ]; - default: - return [_.identity, direction]; - } - } - ); - return _.orderBy( - logCategories, - sortingCriteria.map(([accessor]) => accessor), - sortingCriteria.map(([, direction]) => direction) - ); - }, [gridState.context.sortingColumns, logCategories]); - - return ( - - dispatchGridEvent({ type: 'changeVisibleColumns', visibleColumns }), - }} - cellContext={createCellContext(sortedLogCategories, dependencies)} - pagination={{ - ...gridState.context.pagination, - onChangeItemsPerPage: (pageSize) => dispatchGridEvent({ type: 'changePageSize', pageSize }), - onChangePage: (pageIndex) => dispatchGridEvent({ type: 'changePageIndex', pageIndex }), - }} - renderCellValue={renderLogCategoriesGridCell} - rowCount={sortedLogCategories.length} - sorting={{ - columns: gridState.context.sortingColumns, - onSort: (sortingColumns) => - dispatchGridEvent({ type: 'changeSortingColumns', sortingColumns }), - }} - /> - ); -}; - -const gridStateService = setup({ - types: { - context: {} as { - visibleColumns: string[]; - pagination: Pick; - sortingColumns: LogCategoriesGridSortingConfig[]; - }, - events: {} as - | { - type: 'changePageSize'; - pageSize: number; - } - | { - type: 'changePageIndex'; - pageIndex: number; - } - | { - type: 'changeSortingColumns'; - sortingColumns: EuiDataGridColumnSortingConfig[]; - } - | { - type: 'changeVisibleColumns'; - visibleColumns: string[]; - }, - input: {} as { - visibleColumns: string[]; - }, - }, -}).createMachine({ - id: 'logCategoriesGridState', - context: ({ input }) => ({ - visibleColumns: input.visibleColumns, - pagination: { pageIndex: 0, pageSize: 20, pageSizeOptions: [10, 20, 50] }, - sortingColumns: [{ id: 'change_time', direction: 'desc' }], - }), - on: { - changePageSize: { - actions: assign(({ context, event }) => ({ - pagination: { - ...context.pagination, - pageIndex: 0, - pageSize: event.pageSize, - }, - })), - }, - changePageIndex: { - actions: assign(({ context, event }) => ({ - pagination: { - ...context.pagination, - pageIndex: event.pageIndex, - }, - })), - }, - changeSortingColumns: { - actions: assign(({ event }) => ({ - sortingColumns: event.sortingColumns.filter( - (sortingConfig): sortingConfig is LogCategoriesGridSortingConfig => - (logCategoriesGridColumnIds as string[]).includes(sortingConfig.id) - ), - })), - }, - changeVisibleColumns: { - actions: assign(({ event }) => ({ - visibleColumns: event.visibleColumns, - })), - }, - }, -}); - -const consoleInspector = createConsoleInspector(); - -const logCategoriesGridLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategoriesGrid.euiDataGrid.logCategoriesLabel', - { defaultMessage: 'Log categories' } -); - -interface TypedEuiDataGridColumnSortingConfig - extends EuiDataGridColumnSortingConfig { - id: ColumnId; -} - -type LogCategoriesGridSortingConfig = - TypedEuiDataGridColumnSortingConfig; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx deleted file mode 100644 index d6ab4969eaf7b..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx +++ /dev/null @@ -1,99 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiDataGridColumn, RenderCellValue } from '@elastic/eui'; -import React from 'react'; -import { LogCategory } from '../../types'; -import { - LogCategoriesGridChangeTimeCell, - LogCategoriesGridChangeTimeCellDependencies, - logCategoriesGridChangeTimeColumn, -} from './log_categories_grid_change_time_cell'; -import { - LogCategoriesGridChangeTypeCell, - logCategoriesGridChangeTypeColumn, -} from './log_categories_grid_change_type_cell'; -import { - LogCategoriesGridCountCell, - logCategoriesGridCountColumn, -} from './log_categories_grid_count_cell'; -import { - LogCategoriesGridHistogramCell, - LogCategoriesGridHistogramCellDependencies, - logCategoriesGridHistoryColumn, -} from './log_categories_grid_histogram_cell'; -import { - LogCategoriesGridPatternCell, - logCategoriesGridPatternColumn, -} from './log_categories_grid_pattern_cell'; - -export interface LogCategoriesGridCellContext { - dependencies: LogCategoriesGridCellDependencies; - logCategories: LogCategory[]; -} - -export type LogCategoriesGridCellDependencies = LogCategoriesGridHistogramCellDependencies & - LogCategoriesGridChangeTimeCellDependencies; - -export const renderLogCategoriesGridCell: RenderCellValue = ({ - rowIndex, - columnId, - isExpanded, - ...rest -}) => { - const { dependencies, logCategories } = getCellContext(rest); - - const logCategory = logCategories[rowIndex]; - - switch (columnId as LogCategoriesGridColumnId) { - case 'pattern': - return ; - case 'count': - return ; - case 'history': - return ( - - ); - case 'change_type': - return ; - case 'change_time': - return ( - - ); - default: - return <>-; - } -}; - -export const logCategoriesGridColumns = [ - logCategoriesGridPatternColumn, - logCategoriesGridCountColumn, - logCategoriesGridChangeTypeColumn, - logCategoriesGridChangeTimeColumn, - logCategoriesGridHistoryColumn, -] satisfies EuiDataGridColumn[]; - -export const logCategoriesGridColumnIds = logCategoriesGridColumns.map(({ id }) => id); - -export type LogCategoriesGridColumnId = (typeof logCategoriesGridColumns)[number]['id']; - -const cellContextKey = 'cellContext'; - -const getCellContext = (cellContext: object): LogCategoriesGridCellContext => - (cellContextKey in cellContext - ? cellContext[cellContextKey] - : {}) as LogCategoriesGridCellContext; - -export const createCellContext = ( - logCategories: LogCategory[], - dependencies: LogCategoriesGridCellDependencies -): { [cellContextKey]: LogCategoriesGridCellContext } => ({ - [cellContextKey]: { - dependencies, - logCategories, - }, -}); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx deleted file mode 100644 index 5ad8cbdd49346..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx +++ /dev/null @@ -1,54 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiDataGridColumn } from '@elastic/eui'; -import { SettingsStart } from '@kbn/core-ui-settings-browser'; -import { i18n } from '@kbn/i18n'; -import moment from 'moment'; -import React, { useMemo } from 'react'; -import { LogCategory } from '../../types'; - -export const logCategoriesGridChangeTimeColumn = { - id: 'change_time' as const, - display: i18n.translate( - 'xpack.observabilityLogsOverview.logCategoriesGrid.changeTimeColumnLabel', - { - defaultMessage: 'Change at', - } - ), - isSortable: true, - initialWidth: 220, - schema: 'datetime', -} satisfies EuiDataGridColumn; - -export interface LogCategoriesGridChangeTimeCellProps { - dependencies: LogCategoriesGridChangeTimeCellDependencies; - logCategory: LogCategory; -} - -export interface LogCategoriesGridChangeTimeCellDependencies { - uiSettings: SettingsStart; -} - -export const LogCategoriesGridChangeTimeCell: React.FC = ({ - dependencies, - logCategory, -}) => { - const dateFormat = useMemo( - () => dependencies.uiSettings.client.get('dateFormat'), - [dependencies.uiSettings.client] - ); - if (!('timestamp' in logCategory.change && logCategory.change.timestamp != null)) { - return null; - } - - if (dateFormat) { - return <>{moment(logCategory.change.timestamp).format(dateFormat)}; - } else { - return <>{logCategory.change.timestamp}; - } -}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx deleted file mode 100644 index af6349bd0e18c..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx +++ /dev/null @@ -1,108 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiBadge, EuiDataGridColumn } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import { LogCategory } from '../../types'; - -export const logCategoriesGridChangeTypeColumn = { - id: 'change_type' as const, - display: i18n.translate( - 'xpack.observabilityLogsOverview.logCategoriesGrid.changeTypeColumnLabel', - { - defaultMessage: 'Change type', - } - ), - isSortable: true, - initialWidth: 110, -} satisfies EuiDataGridColumn; - -export interface LogCategoriesGridChangeTypeCellProps { - logCategory: LogCategory; -} - -export const LogCategoriesGridChangeTypeCell: React.FC = ({ - logCategory, -}) => { - switch (logCategory.change.type) { - case 'dip': - return {dipBadgeLabel}; - case 'spike': - return {spikeBadgeLabel}; - case 'step': - return {stepBadgeLabel}; - case 'distribution': - return {distributionBadgeLabel}; - case 'rare': - return {rareBadgeLabel}; - case 'trend': - return {trendBadgeLabel}; - case 'other': - return {otherBadgeLabel}; - case 'none': - return <>-; - default: - return {unknownBadgeLabel}; - } -}; - -const dipBadgeLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.dipChangeTypeBadgeLabel', - { - defaultMessage: 'Dip', - } -); - -const spikeBadgeLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.spikeChangeTypeBadgeLabel', - { - defaultMessage: 'Spike', - } -); - -const stepBadgeLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.spikeChangeTypeBadgeLabel', - { - defaultMessage: 'Step', - } -); - -const distributionBadgeLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.distributionChangeTypeBadgeLabel', - { - defaultMessage: 'Distribution', - } -); - -const trendBadgeLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.spikeChangeTypeBadgeLabel', - { - defaultMessage: 'Trend', - } -); - -const otherBadgeLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.otherChangeTypeBadgeLabel', - { - defaultMessage: 'Other', - } -); - -const unknownBadgeLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.unknownChangeTypeBadgeLabel', - { - defaultMessage: 'Unknown', - } -); - -const rareBadgeLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.rareChangeTypeBadgeLabel', - { - defaultMessage: 'Rare', - } -); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx deleted file mode 100644 index f2247aab5212e..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx +++ /dev/null @@ -1,32 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiDataGridColumn } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedNumber } from '@kbn/i18n-react'; -import React from 'react'; -import { LogCategory } from '../../types'; - -export const logCategoriesGridCountColumn = { - id: 'count' as const, - display: i18n.translate('xpack.observabilityLogsOverview.logCategoriesGrid.countColumnLabel', { - defaultMessage: 'Events', - }), - isSortable: true, - schema: 'numeric', - initialWidth: 100, -} satisfies EuiDataGridColumn; - -export interface LogCategoriesGridCountCellProps { - logCategory: LogCategory; -} - -export const LogCategoriesGridCountCell: React.FC = ({ - logCategory, -}) => { - return ; -}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx deleted file mode 100644 index 2fb50b0f2f3b4..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx +++ /dev/null @@ -1,99 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - BarSeries, - Chart, - LineAnnotation, - LineAnnotationStyle, - PartialTheme, - Settings, - Tooltip, - TooltipType, -} from '@elastic/charts'; -import { EuiDataGridColumn } from '@elastic/eui'; -import { ChartsPluginStart } from '@kbn/charts-plugin/public'; -import { i18n } from '@kbn/i18n'; -import { RecursivePartial } from '@kbn/utility-types'; -import React from 'react'; -import { LogCategory, LogCategoryHistogramBucket } from '../../types'; - -export const logCategoriesGridHistoryColumn = { - id: 'history' as const, - display: i18n.translate( - 'xpack.observabilityLogsOverview.logCategoriesGrid.histogramColumnLabel', - { - defaultMessage: 'Timeline', - } - ), - isSortable: false, - initialWidth: 250, - isExpandable: false, -} satisfies EuiDataGridColumn; - -export interface LogCategoriesGridHistogramCellProps { - dependencies: LogCategoriesGridHistogramCellDependencies; - logCategory: LogCategory; -} - -export interface LogCategoriesGridHistogramCellDependencies { - charts: ChartsPluginStart; -} - -export const LogCategoriesGridHistogramCell: React.FC = ({ - dependencies: { charts }, - logCategory, -}) => { - const baseTheme = charts.theme.useChartsBaseTheme(); - const sparklineTheme = charts.theme.useSparklineOverrides(); - - return ( - - - - - {'timestamp' in logCategory.change && logCategory.change.timestamp != null ? ( - - ) : null} - - ); -}; - -const localThemeOverrides: PartialTheme = { - scales: { - histogramPadding: 0.1, - }, - background: { - color: 'transparent', - }, -}; - -const annotationStyle: RecursivePartial = { - line: { - strokeWidth: 2, - }, -}; - -const timestampAccessor = (histogram: LogCategoryHistogramBucket) => - new Date(histogram.timestamp).getTime(); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx deleted file mode 100644 index d507487a99e3c..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx +++ /dev/null @@ -1,60 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiDataGridColumn, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; -import { i18n } from '@kbn/i18n'; -import React, { useMemo } from 'react'; -import { LogCategory } from '../../types'; - -export const logCategoriesGridPatternColumn = { - id: 'pattern' as const, - display: i18n.translate('xpack.observabilityLogsOverview.logCategoriesGrid.patternColumnLabel', { - defaultMessage: 'Pattern', - }), - isSortable: false, - schema: 'string', -} satisfies EuiDataGridColumn; - -export interface LogCategoriesGridPatternCellProps { - logCategory: LogCategory; -} - -export const LogCategoriesGridPatternCell: React.FC = ({ - logCategory, -}) => { - const theme = useEuiTheme(); - const { euiTheme } = theme; - const termsList = useMemo(() => logCategory.terms.split(' '), [logCategory.terms]); - - const commonStyle = css` - display: inline-block; - font-family: ${euiTheme.font.familyCode}; - margin-right: ${euiTheme.size.xs}; - `; - - const termStyle = css` - ${commonStyle}; - `; - - const separatorStyle = css` - ${commonStyle}; - color: ${euiTheme.colors.successText}; - `; - - return ( -
    -      
    *
    - {termsList.map((term, index) => ( - -
    {term}
    -
    *
    -
    - ))} -
    - ); -}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx deleted file mode 100644 index 0fde469fe717d..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx +++ /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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; -import React from 'react'; -import { i18n } from '@kbn/i18n'; - -export interface LogCategoriesLoadingContentProps { - onCancel?: () => void; - stage: 'counting' | 'categorizing'; -} - -export const LogCategoriesLoadingContent: React.FC = ({ - onCancel, - stage, -}) => { - return ( - } - title={ -

    - {stage === 'counting' - ? logCategoriesLoadingStateCountingTitle - : logCategoriesLoadingStateCategorizingTitle} -

    - } - actions={ - onCancel != null - ? [ - { - onCancel(); - }} - > - {logCategoriesLoadingStateCancelButtonLabel} - , - ] - : [] - } - /> - ); -}; - -const logCategoriesLoadingStateCountingTitle = i18n.translate( - 'xpack.observabilityLogsOverview.logCategoriesGrid.loadingStageCountingTitle', - { - defaultMessage: 'Estimating log volume', - } -); - -const logCategoriesLoadingStateCategorizingTitle = i18n.translate( - 'xpack.observabilityLogsOverview.logCategoriesGrid.loadingStageCategorizingTitle', - { - defaultMessage: 'Categorizing logs', - } -); - -const logCategoriesLoadingStateCancelButtonLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategoriesGrid.loadingStateCancelButtonLabel', - { - defaultMessage: 'Cancel', - } -); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx deleted file mode 100644 index e16bdda7cb44a..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx +++ /dev/null @@ -1,87 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import { LogCategory } from '../../types'; -import { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; -import { - LogCategoriesControlBar, - LogCategoriesControlBarDependencies, -} from './log_categories_control_bar'; -import { LogCategoriesGrid, LogCategoriesGridDependencies } from './log_categories_grid'; - -export interface LogCategoriesResultContentProps { - dependencies: LogCategoriesResultContentDependencies; - documentFilters?: QueryDslQueryContainer[]; - logCategories: LogCategory[]; - logsSource: IndexNameLogsSourceConfiguration; - timeRange: { - start: string; - end: string; - }; -} - -export type LogCategoriesResultContentDependencies = LogCategoriesControlBarDependencies & - LogCategoriesGridDependencies; - -export const LogCategoriesResultContent: React.FC = ({ - dependencies, - documentFilters, - logCategories, - logsSource, - timeRange, -}) => { - if (logCategories.length === 0) { - return ; - } else { - return ( - - - - - - - - - ); - } -}; - -export const LogCategoriesEmptyResultContent: React.FC = () => { - return ( - {emptyResultContentDescription}

    } - color="subdued" - layout="horizontal" - title={

    {emptyResultContentTitle}

    } - titleSize="m" - /> - ); -}; - -const emptyResultContentTitle = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.emptyResultContentTitle', - { - defaultMessage: 'No log categories found', - } -); - -const emptyResultContentDescription = i18n.translate( - 'xpack.observabilityLogsOverview.logCategories.emptyResultContentDescription', - { - defaultMessage: - 'No suitable documents within the time range. Try searching for a longer time period.', - } -); diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts deleted file mode 100644 index 878f634f078ad..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts +++ /dev/null @@ -1,10 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './logs_overview'; -export * from './logs_overview_error_content'; -export * from './logs_overview_loading_content'; diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx deleted file mode 100644 index 988656eb1571e..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx +++ /dev/null @@ -1,64 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { type LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; -import React from 'react'; -import useAsync from 'react-use/lib/useAsync'; -import { LogsSourceConfiguration, normalizeLogsSource } from '../../utils/logs_source'; -import { LogCategories, LogCategoriesDependencies } from '../log_categories'; -import { LogsOverviewErrorContent } from './logs_overview_error_content'; -import { LogsOverviewLoadingContent } from './logs_overview_loading_content'; - -export interface LogsOverviewProps { - dependencies: LogsOverviewDependencies; - documentFilters?: QueryDslQueryContainer[]; - logsSource?: LogsSourceConfiguration; - timeRange: { - start: string; - end: string; - }; -} - -export type LogsOverviewDependencies = LogCategoriesDependencies & { - logsDataAccess: LogsDataAccessPluginStart; -}; - -export const LogsOverview: React.FC = React.memo( - ({ - dependencies, - documentFilters = defaultDocumentFilters, - logsSource = defaultLogsSource, - timeRange, - }) => { - const normalizedLogsSource = useAsync( - () => normalizeLogsSource({ logsDataAccess: dependencies.logsDataAccess })(logsSource), - [dependencies.logsDataAccess, logsSource] - ); - - if (normalizedLogsSource.loading) { - return ; - } - - if (normalizedLogsSource.error != null || normalizedLogsSource.value == null) { - return ; - } - - return ( - - ); - } -); - -const defaultDocumentFilters: QueryDslQueryContainer[] = []; - -const defaultLogsSource: LogsSourceConfiguration = { type: 'shared_setting' }; diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx deleted file mode 100644 index 73586756bb908..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx +++ /dev/null @@ -1,41 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiCodeBlock, EuiEmptyPrompt } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; - -export interface LogsOverviewErrorContentProps { - error?: Error; -} - -export const LogsOverviewErrorContent: React.FC = ({ error }) => { - return ( - {logsOverviewErrorTitle}} - body={ - -

    {error?.stack ?? error?.toString() ?? unknownErrorDescription}

    -
    - } - layout="vertical" - /> - ); -}; - -const logsOverviewErrorTitle = i18n.translate('xpack.observabilityLogsOverview.errorTitle', { - defaultMessage: 'Error', -}); - -const unknownErrorDescription = i18n.translate( - 'xpack.observabilityLogsOverview.unknownErrorDescription', - { - defaultMessage: 'An unspecified error occurred.', - } -); diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx deleted file mode 100644 index 7645fdb90f0ac..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx +++ /dev/null @@ -1,23 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; - -export const LogsOverviewLoadingContent: React.FC = ({}) => { - return ( - } - title={

    {logsOverviewLoadingTitle}

    } - /> - ); -}; - -const logsOverviewLoadingTitle = i18n.translate('xpack.observabilityLogsOverview.loadingTitle', { - defaultMessage: 'Loading', -}); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts deleted file mode 100644 index 7260efe63d435..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts +++ /dev/null @@ -1,282 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ISearchGeneric } from '@kbn/search-types'; -import { lastValueFrom } from 'rxjs'; -import { fromPromise } from 'xstate5'; -import { createRandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; -import { z } from '@kbn/zod'; -import { LogCategorizationParams } from './types'; -import { createCategorizationRequestParams } from './queries'; -import { LogCategory, LogCategoryChange } from '../../types'; - -// the fraction of a category's histogram below which the category is considered rare -const rarityThreshold = 0.2; -const maxCategoriesCount = 1000; - -export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => - fromPromise< - { - categories: LogCategory[]; - hasReachedLimit: boolean; - }, - LogCategorizationParams & { - samplingProbability: number; - ignoredCategoryTerms: string[]; - minDocsPerCategory: number; - } - >( - async ({ - input: { - index, - endTimestamp, - startTimestamp, - timeField, - messageField, - samplingProbability, - ignoredCategoryTerms, - documentFilters = [], - minDocsPerCategory, - }, - signal, - }) => { - const randomSampler = createRandomSamplerWrapper({ - probability: samplingProbability, - seed: 1, - }); - - const requestParams = createCategorizationRequestParams({ - index, - timeField, - messageField, - startTimestamp, - endTimestamp, - randomSampler, - additionalFilters: documentFilters, - ignoredCategoryTerms, - minDocsPerCategory, - maxCategoriesCount, - }); - - const { rawResponse } = await lastValueFrom( - search({ params: requestParams }, { abortSignal: signal }) - ); - - if (rawResponse.aggregations == null) { - throw new Error('No aggregations found in large categories response'); - } - - const logCategoriesAggResult = randomSampler.unwrap(rawResponse.aggregations); - - if (!('categories' in logCategoriesAggResult)) { - throw new Error('No categorization aggregation found in large categories response'); - } - - const logCategories = - (logCategoriesAggResult.categories.buckets as unknown[]).map(mapCategoryBucket) ?? []; - - return { - categories: logCategories, - hasReachedLimit: logCategories.length >= maxCategoriesCount, - }; - } - ); - -const mapCategoryBucket = (bucket: any): LogCategory => - esCategoryBucketSchema - .transform((parsedBucket) => ({ - change: mapChangePoint(parsedBucket), - documentCount: parsedBucket.doc_count, - histogram: parsedBucket.histogram, - terms: parsedBucket.key, - })) - .parse(bucket); - -const mapChangePoint = ({ change, histogram }: EsCategoryBucket): LogCategoryChange => { - switch (change.type) { - case 'stationary': - if (isRareInHistogram(histogram)) { - return { - type: 'rare', - timestamp: findFirstNonZeroBucket(histogram)?.timestamp ?? histogram[0].timestamp, - }; - } else { - return { - type: 'none', - }; - } - case 'dip': - case 'spike': - return { - type: change.type, - timestamp: change.bucket.key, - }; - case 'step_change': - return { - type: 'step', - timestamp: change.bucket.key, - }; - case 'distribution_change': - return { - type: 'distribution', - timestamp: change.bucket.key, - }; - case 'trend_change': - return { - type: 'trend', - timestamp: change.bucket.key, - correlationCoefficient: change.details.r_value, - }; - case 'unknown': - return { - type: 'unknown', - rawChange: change.rawChange, - }; - case 'non_stationary': - default: - return { - type: 'other', - }; - } -}; - -/** - * The official types are lacking the change_point aggregation - */ -const esChangePointBucketSchema = z.object({ - key: z.string().datetime(), - doc_count: z.number(), -}); - -const esChangePointDetailsSchema = z.object({ - p_value: z.number(), -}); - -const esChangePointCorrelationSchema = esChangePointDetailsSchema.extend({ - r_value: z.number(), -}); - -const esChangePointSchema = z.union([ - z - .object({ - bucket: esChangePointBucketSchema, - type: z.object({ - dip: esChangePointDetailsSchema, - }), - }) - .transform(({ bucket, type: { dip: details } }) => ({ - type: 'dip' as const, - bucket, - details, - })), - z - .object({ - bucket: esChangePointBucketSchema, - type: z.object({ - spike: esChangePointDetailsSchema, - }), - }) - .transform(({ bucket, type: { spike: details } }) => ({ - type: 'spike' as const, - bucket, - details, - })), - z - .object({ - bucket: esChangePointBucketSchema, - type: z.object({ - step_change: esChangePointDetailsSchema, - }), - }) - .transform(({ bucket, type: { step_change: details } }) => ({ - type: 'step_change' as const, - bucket, - details, - })), - z - .object({ - bucket: esChangePointBucketSchema, - type: z.object({ - trend_change: esChangePointCorrelationSchema, - }), - }) - .transform(({ bucket, type: { trend_change: details } }) => ({ - type: 'trend_change' as const, - bucket, - details, - })), - z - .object({ - bucket: esChangePointBucketSchema, - type: z.object({ - distribution_change: esChangePointDetailsSchema, - }), - }) - .transform(({ bucket, type: { distribution_change: details } }) => ({ - type: 'distribution_change' as const, - bucket, - details, - })), - z - .object({ - type: z.object({ - non_stationary: esChangePointCorrelationSchema.extend({ - trend: z.enum(['increasing', 'decreasing']), - }), - }), - }) - .transform(({ type: { non_stationary: details } }) => ({ - type: 'non_stationary' as const, - details, - })), - z - .object({ - type: z.object({ - stationary: z.object({}), - }), - }) - .transform(() => ({ type: 'stationary' as const })), - z - .object({ - type: z.object({}), - }) - .transform((value) => ({ type: 'unknown' as const, rawChange: JSON.stringify(value) })), -]); - -const esHistogramSchema = z - .object({ - buckets: z.array( - z - .object({ - key_as_string: z.string(), - doc_count: z.number(), - }) - .transform((bucket) => ({ - timestamp: bucket.key_as_string, - documentCount: bucket.doc_count, - })) - ), - }) - .transform(({ buckets }) => buckets); - -type EsHistogram = z.output; - -const esCategoryBucketSchema = z.object({ - key: z.string(), - doc_count: z.number(), - change: esChangePointSchema, - histogram: esHistogramSchema, -}); - -type EsCategoryBucket = z.output; - -const isRareInHistogram = (histogram: EsHistogram): boolean => - histogram.filter((bucket) => bucket.documentCount > 0).length < - histogram.length * rarityThreshold; - -const findFirstNonZeroBucket = (histogram: EsHistogram) => - histogram.find((bucket) => bucket.documentCount > 0); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts deleted file mode 100644 index deeb758d2d737..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts +++ /dev/null @@ -1,250 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { MachineImplementationsFrom, assign, setup } from 'xstate5'; -import { LogCategory } from '../../types'; -import { getPlaceholderFor } from '../../utils/xstate5_utils'; -import { categorizeDocuments } from './categorize_documents'; -import { countDocuments } from './count_documents'; -import { CategorizeLogsServiceDependencies, LogCategorizationParams } from './types'; - -export const categorizeLogsService = setup({ - types: { - input: {} as LogCategorizationParams, - output: {} as { - categories: LogCategory[]; - documentCount: number; - hasReachedLimit: boolean; - samplingProbability: number; - }, - context: {} as { - categories: LogCategory[]; - documentCount: number; - error?: Error; - hasReachedLimit: boolean; - parameters: LogCategorizationParams; - samplingProbability: number; - }, - events: {} as { - type: 'cancel'; - }, - }, - actors: { - countDocuments: getPlaceholderFor(countDocuments), - categorizeDocuments: getPlaceholderFor(categorizeDocuments), - }, - actions: { - storeError: assign((_, params: { error: unknown }) => ({ - error: params.error instanceof Error ? params.error : new Error(String(params.error)), - })), - storeCategories: assign( - ({ context }, params: { categories: LogCategory[]; hasReachedLimit: boolean }) => ({ - categories: [...context.categories, ...params.categories], - hasReachedLimit: params.hasReachedLimit, - }) - ), - storeDocumentCount: assign( - (_, params: { documentCount: number; samplingProbability: number }) => ({ - documentCount: params.documentCount, - samplingProbability: params.samplingProbability, - }) - ), - }, - guards: { - hasTooFewDocuments: (_guardArgs, params: { documentCount: number }) => params.documentCount < 1, - requiresSampling: (_guardArgs, params: { samplingProbability: number }) => - params.samplingProbability < 1, - }, -}).createMachine({ - /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QBmMwA5KACy+AQFmob4AjABMwQBsADQgAJ6IkYEAnJkA7FmxZlERmQGxAL4liXJYeESk5FQ0DEws7Jw8fILCogYy1BhVirUqDerNWm26+vSScsb01iYRNkggDk4u9G6eCD7+QSFhftFxiSkIvgCsWZSxEVlRsbFZ52Zm515lFX0KNcr1ak2aVo6ARCERiKbSWRfapKOqqRoaFraPiTaZGUyWExRJb2RzOWabbx+QLBULhI7FE7eWL+F45GnRPIRZkfECVb6wob-RFjYH8MC4XB4Sh2AA2GAAZnguL15DDBn8EaMgSiDDMMVZLG5VvjXMstjsSftyTFKclEOdzgFKF5zukvA8zBFnl50udWez5b94SNAcjdPw0PRkGBRdZtXj1oTtsS9mTDqaEuaEBF8udKFkIr5fK6olkzOksgEPdCBt6JWB0MgABYaADKqC4YsgAGFS-g4B0wd0oXKBg2m6LW+24OHljqo-rEMzbpQos8-K7fC9CknTrF0rEbbb0oVMoWIgF3eU2e3OVQK1XaywB82IG2+x2BAKhbgReL0FLcDLPf3G3eH36J8x1xNYCSnFNmSuecXhzdJlydTcqQQLJfHSOc0PyLJN3SMxYiPEtH3PShLxret-yHe8RwEIMQzDLVx0jcDQC2GdoIXOCENXZDsyiOcAiiKJ0iiPDLi8V1CKA4jSOvKAACUwC4VBmA0QDvk7UEughHpfxqBSlJUlg1OqUcGNA3UNggrMs347IjzdaIvGQwSvECXI8k3Z43gEiJJI5BUSMrMiWH05T6FU6j+UFYUxUlaVZSksBQsMqBjIIUycRWJi9RY6dIn8KIAjsu1zkc5CAmiG1fBiaIzB8B0QmPT4iICmSNGS8KjMi2jQxArKwJyjw8pswriocqInOTLwIi3ASD1yQpswCd5WXobAIDgNxdPPCMBss3KEAAWjXRBDvTfcLsu9Jlr8r04WGAEkXGeBGL26MBOQzIt2ut4cwmirCt8W6yzhNqbwo4dH0216LOjTMIjnBdYhK1DYgdHjihtZbUIdWIXJuYGflBoLZI6iKoZe8zJwOw9KtGt1kbuTcsmQrwi0oeCQjzZ5blwt1Cek5TKN22GIIKZbAgKC45pyLyeLwtz4Kyabs1QgWAs0kXqaGhBxdcnzpaE2XXmch0MORmaBJeLwjbKMogA */ - id: 'categorizeLogs', - context: ({ input }) => ({ - categories: [], - documentCount: 0, - hasReachedLimit: false, - parameters: input, - samplingProbability: 1, - }), - initial: 'countingDocuments', - states: { - countingDocuments: { - invoke: { - src: 'countDocuments', - input: ({ context }) => context.parameters, - onDone: [ - { - target: 'done', - guard: { - type: 'hasTooFewDocuments', - params: ({ event }) => event.output, - }, - actions: [ - { - type: 'storeDocumentCount', - params: ({ event }) => event.output, - }, - ], - }, - { - target: 'fetchingSampledCategories', - guard: { - type: 'requiresSampling', - params: ({ event }) => event.output, - }, - actions: [ - { - type: 'storeDocumentCount', - params: ({ event }) => event.output, - }, - ], - }, - { - target: 'fetchingRemainingCategories', - actions: [ - { - type: 'storeDocumentCount', - params: ({ event }) => event.output, - }, - ], - }, - ], - onError: { - target: 'failed', - actions: [ - { - type: 'storeError', - params: ({ event }) => ({ error: event.error }), - }, - ], - }, - }, - - on: { - cancel: { - target: 'failed', - actions: [ - { - type: 'storeError', - params: () => ({ error: new Error('Counting cancelled') }), - }, - ], - }, - }, - }, - - fetchingSampledCategories: { - invoke: { - src: 'categorizeDocuments', - id: 'categorizeSampledCategories', - input: ({ context }) => ({ - ...context.parameters, - samplingProbability: context.samplingProbability, - ignoredCategoryTerms: [], - minDocsPerCategory: 10, - }), - onDone: { - target: 'fetchingRemainingCategories', - actions: [ - { - type: 'storeCategories', - params: ({ event }) => event.output, - }, - ], - }, - onError: { - target: 'failed', - actions: [ - { - type: 'storeError', - params: ({ event }) => ({ error: event.error }), - }, - ], - }, - }, - - on: { - cancel: { - target: 'failed', - actions: [ - { - type: 'storeError', - params: () => ({ error: new Error('Categorization cancelled') }), - }, - ], - }, - }, - }, - - fetchingRemainingCategories: { - invoke: { - src: 'categorizeDocuments', - id: 'categorizeRemainingCategories', - input: ({ context }) => ({ - ...context.parameters, - samplingProbability: 1, - ignoredCategoryTerms: context.categories.map((category) => category.terms), - minDocsPerCategory: 0, - }), - onDone: { - target: 'done', - actions: [ - { - type: 'storeCategories', - params: ({ event }) => event.output, - }, - ], - }, - onError: { - target: 'failed', - actions: [ - { - type: 'storeError', - params: ({ event }) => ({ error: event.error }), - }, - ], - }, - }, - - on: { - cancel: { - target: 'failed', - actions: [ - { - type: 'storeError', - params: () => ({ error: new Error('Categorization cancelled') }), - }, - ], - }, - }, - }, - - failed: { - type: 'final', - }, - - done: { - type: 'final', - }, - }, - output: ({ context }) => ({ - categories: context.categories, - documentCount: context.documentCount, - hasReachedLimit: context.hasReachedLimit, - samplingProbability: context.samplingProbability, - }), -}); - -export const createCategorizeLogsServiceImplementations = ({ - search, -}: CategorizeLogsServiceDependencies): MachineImplementationsFrom< - typeof categorizeLogsService -> => ({ - actors: { - categorizeDocuments: categorizeDocuments({ search }), - countDocuments: countDocuments({ search }), - }, -}); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts deleted file mode 100644 index 359f9ddac2bd8..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts +++ /dev/null @@ -1,60 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getSampleProbability } from '@kbn/ml-random-sampler-utils'; -import { ISearchGeneric } from '@kbn/search-types'; -import { lastValueFrom } from 'rxjs'; -import { fromPromise } from 'xstate5'; -import { LogCategorizationParams } from './types'; -import { createCategorizationQuery } from './queries'; - -export const countDocuments = ({ search }: { search: ISearchGeneric }) => - fromPromise< - { - documentCount: number; - samplingProbability: number; - }, - LogCategorizationParams - >( - async ({ - input: { index, endTimestamp, startTimestamp, timeField, messageField, documentFilters }, - signal, - }) => { - const { rawResponse: totalHitsResponse } = await lastValueFrom( - search( - { - params: { - index, - size: 0, - track_total_hits: true, - query: createCategorizationQuery({ - messageField, - timeField, - startTimestamp, - endTimestamp, - additionalFilters: documentFilters, - }), - }, - }, - { abortSignal: signal } - ) - ); - - const documentCount = - totalHitsResponse.hits.total == null - ? 0 - : typeof totalHitsResponse.hits.total === 'number' - ? totalHitsResponse.hits.total - : totalHitsResponse.hits.total.value; - const samplingProbability = getSampleProbability(documentCount); - - return { - documentCount, - samplingProbability, - }; - } - ); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts deleted file mode 100644 index 149359b7d2015..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './categorize_logs_service'; diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts deleted file mode 100644 index aef12da303bcc..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts +++ /dev/null @@ -1,151 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { calculateAuto } from '@kbn/calculate-auto'; -import { RandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; -import moment from 'moment'; - -const isoTimestampFormat = "YYYY-MM-DD'T'HH:mm:ss.SSS'Z'"; - -export const createCategorizationQuery = ({ - messageField, - timeField, - startTimestamp, - endTimestamp, - additionalFilters = [], - ignoredCategoryTerms = [], -}: { - messageField: string; - timeField: string; - startTimestamp: string; - endTimestamp: string; - additionalFilters?: QueryDslQueryContainer[]; - ignoredCategoryTerms?: string[]; -}): QueryDslQueryContainer => { - return { - bool: { - filter: [ - { - exists: { - field: messageField, - }, - }, - { - range: { - [timeField]: { - gte: startTimestamp, - lte: endTimestamp, - format: 'strict_date_time', - }, - }, - }, - ...additionalFilters, - ], - must_not: ignoredCategoryTerms.map(createCategoryQuery(messageField)), - }, - }; -}; - -export const createCategorizationRequestParams = ({ - index, - timeField, - messageField, - startTimestamp, - endTimestamp, - randomSampler, - minDocsPerCategory = 0, - additionalFilters = [], - ignoredCategoryTerms = [], - maxCategoriesCount = 1000, -}: { - startTimestamp: string; - endTimestamp: string; - index: string; - timeField: string; - messageField: string; - randomSampler: RandomSamplerWrapper; - minDocsPerCategory?: number; - additionalFilters?: QueryDslQueryContainer[]; - ignoredCategoryTerms?: string[]; - maxCategoriesCount?: number; -}) => { - const startMoment = moment(startTimestamp, isoTimestampFormat); - const endMoment = moment(endTimestamp, isoTimestampFormat); - const fixedIntervalDuration = calculateAuto.atLeast( - 24, - moment.duration(endMoment.diff(startMoment)) - ); - const fixedIntervalSize = `${Math.ceil(fixedIntervalDuration?.asMinutes() ?? 1)}m`; - - return { - index, - size: 0, - track_total_hits: false, - query: createCategorizationQuery({ - messageField, - timeField, - startTimestamp, - endTimestamp, - additionalFilters, - ignoredCategoryTerms, - }), - aggs: randomSampler.wrap({ - histogram: { - date_histogram: { - field: timeField, - fixed_interval: fixedIntervalSize, - extended_bounds: { - min: startTimestamp, - max: endTimestamp, - }, - }, - }, - categories: { - categorize_text: { - field: messageField, - size: maxCategoriesCount, - categorization_analyzer: { - tokenizer: 'standard', - }, - ...(minDocsPerCategory > 0 ? { min_doc_count: minDocsPerCategory } : {}), - }, - aggs: { - histogram: { - date_histogram: { - field: timeField, - fixed_interval: fixedIntervalSize, - extended_bounds: { - min: startTimestamp, - max: endTimestamp, - }, - }, - }, - change: { - // @ts-expect-error the official types don't support the change_point aggregation - change_point: { - buckets_path: 'histogram>_count', - }, - }, - }, - }, - }), - }; -}; - -export const createCategoryQuery = - (messageField: string) => - (categoryTerms: string): QueryDslQueryContainer => ({ - match: { - [messageField]: { - query: categoryTerms, - operator: 'AND' as const, - fuzziness: 0, - auto_generate_synonyms_phrase_query: false, - }, - }, - }); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts deleted file mode 100644 index e094317a98d62..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts +++ /dev/null @@ -1,21 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { ISearchGeneric } from '@kbn/search-types'; - -export interface CategorizeLogsServiceDependencies { - search: ISearchGeneric; -} - -export interface LogCategorizationParams { - documentFilters: QueryDslQueryContainer[]; - endTimestamp: string; - index: string; - messageField: string; - startTimestamp: string; - timeField: string; -} diff --git a/x-pack/packages/observability/logs_overview/src/types.ts b/x-pack/packages/observability/logs_overview/src/types.ts deleted file mode 100644 index 4c3d27eca7e7c..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/types.ts +++ /dev/null @@ -1,74 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface LogCategory { - change: LogCategoryChange; - documentCount: number; - histogram: LogCategoryHistogramBucket[]; - terms: string; -} - -export type LogCategoryChange = - | LogCategoryNoChange - | LogCategoryRareChange - | LogCategorySpikeChange - | LogCategoryDipChange - | LogCategoryStepChange - | LogCategoryDistributionChange - | LogCategoryTrendChange - | LogCategoryOtherChange - | LogCategoryUnknownChange; - -export interface LogCategoryNoChange { - type: 'none'; -} - -export interface LogCategoryRareChange { - type: 'rare'; - timestamp: string; -} - -export interface LogCategorySpikeChange { - type: 'spike'; - timestamp: string; -} - -export interface LogCategoryDipChange { - type: 'dip'; - timestamp: string; -} - -export interface LogCategoryStepChange { - type: 'step'; - timestamp: string; -} - -export interface LogCategoryTrendChange { - type: 'trend'; - timestamp: string; - correlationCoefficient: number; -} - -export interface LogCategoryDistributionChange { - type: 'distribution'; - timestamp: string; -} - -export interface LogCategoryOtherChange { - type: 'other'; - timestamp?: string; -} - -export interface LogCategoryUnknownChange { - type: 'unknown'; - rawChange: string; -} - -export interface LogCategoryHistogramBucket { - documentCount: number; - timestamp: string; -} diff --git a/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts b/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts deleted file mode 100644 index 0c8767c8702d4..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts +++ /dev/null @@ -1,60 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { type AbstractDataView } from '@kbn/data-views-plugin/common'; -import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; - -export type LogsSourceConfiguration = - | SharedSettingLogsSourceConfiguration - | IndexNameLogsSourceConfiguration - | DataViewLogsSourceConfiguration; - -export interface SharedSettingLogsSourceConfiguration { - type: 'shared_setting'; - timestampField?: string; - messageField?: string; -} - -export interface IndexNameLogsSourceConfiguration { - type: 'index_name'; - indexName: string; - timestampField: string; - messageField: string; -} - -export interface DataViewLogsSourceConfiguration { - type: 'data_view'; - dataView: AbstractDataView; - messageField?: string; -} - -export const normalizeLogsSource = - ({ logsDataAccess }: { logsDataAccess: LogsDataAccessPluginStart }) => - async (logsSource: LogsSourceConfiguration): Promise => { - switch (logsSource.type) { - case 'index_name': - return logsSource; - case 'shared_setting': - const logSourcesFromSharedSettings = - await logsDataAccess.services.logSourcesService.getLogSources(); - return { - type: 'index_name', - indexName: logSourcesFromSharedSettings - .map((logSource) => logSource.indexPattern) - .join(','), - timestampField: logsSource.timestampField ?? '@timestamp', - messageField: logsSource.messageField ?? 'message', - }; - case 'data_view': - return { - type: 'index_name', - indexName: logsSource.dataView.getIndexPattern(), - timestampField: logsSource.dataView.timeFieldName ?? '@timestamp', - messageField: logsSource.messageField ?? 'message', - }; - } - }; diff --git a/x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts b/x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts deleted file mode 100644 index 3df0bf4ea3988..0000000000000 --- a/x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts +++ /dev/null @@ -1,13 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const getPlaceholderFor = any>( - implementationFactory: ImplementationFactory -): ReturnType => - (() => { - throw new Error('Not implemented'); - }) as ReturnType; diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json deleted file mode 100644 index 886062ae8855f..0000000000000 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "extends": "../../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node", - "react", - "@kbn/ambient-ui-types", - "@kbn/ambient-storybook-types", - "@emotion/react/types/css-prop" - ] - }, - "include": [ - "**/*.ts", - "**/*.tsx", - ], - "exclude": [ - "target/**/*" - ], - "kbn_references": [ - "@kbn/data-views-plugin", - "@kbn/i18n", - "@kbn/search-types", - "@kbn/xstate-utils", - "@kbn/core-ui-settings-browser", - "@kbn/i18n-react", - "@kbn/charts-plugin", - "@kbn/utility-types", - "@kbn/logs-data-access-plugin", - "@kbn/ml-random-sampler-utils", - "@kbn/zod", - "@kbn/calculate-auto", - "@kbn/discover-plugin", - "@kbn/es-query", - "@kbn/router-utils", - "@kbn/share-plugin", - ] -} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index a1dadbf186b91..4df52758ceda3 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -5,36 +5,19 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React from 'react'; import moment from 'moment'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { LogStream } from '@kbn/logs-shared-plugin/public'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; -import { CONTAINER_ID, SERVICE_ENVIRONMENT, SERVICE_NAME } from '../../../../common/es_fields/apm'; +import { useFetcher } from '../../../hooks/use_fetcher'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; -import { useKibana } from '../../../context/kibana_context/use_kibana'; +import { APIReturnType } from '../../../services/rest/create_call_apm_api'; + +import { CONTAINER_ID, SERVICE_ENVIRONMENT, SERVICE_NAME } from '../../../../common/es_fields/apm'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; -import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; -import { APIReturnType } from '../../../services/rest/create_call_apm_api'; export function ServiceLogs() { - const { - services: { - logsShared: { LogsOverview }, - }, - } = useKibana(); - - const isLogsOverviewEnabled = LogsOverview.useIsEnabled(); - - if (isLogsOverviewEnabled) { - return ; - } else { - return ; - } -} - -export function ClassicServiceLogsStream() { const { serviceName } = useApmServiceContext(); const { @@ -75,54 +58,6 @@ export function ClassicServiceLogsStream() { ); } -export function ServiceLogsOverview() { - const { - services: { logsShared }, - } = useKibana(); - const { serviceName } = useApmServiceContext(); - const { - query: { environment, kuery, rangeFrom, rangeTo }, - } = useAnyOfApmParams('/services/{serviceName}/logs'); - const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - const timeRange = useMemo(() => ({ start, end }), [start, end]); - - const { data: logFilters, status } = useFetcher( - async (callApmApi) => { - if (start == null || end == null) { - return; - } - - const { containerIds } = await callApmApi( - 'GET /internal/apm/services/{serviceName}/infrastructure_attributes', - { - params: { - path: { serviceName }, - query: { - environment, - kuery, - start, - end, - }, - }, - } - ); - - return [getInfrastructureFilter({ containerIds, environment, serviceName })]; - }, - [environment, kuery, serviceName, start, end] - ); - - if (status === FETCH_STATUS.SUCCESS) { - return ; - } else if (status === FETCH_STATUS.FAILURE) { - return ( - - ); - } else { - return ; - } -} - export function getInfrastructureKQLFilter({ data, serviceName, @@ -149,99 +84,3 @@ export function getInfrastructureKQLFilter({ return [serviceNameAndEnvironmentCorrelation, ...containerIdCorrelation].join(' or '); } - -export function getInfrastructureFilter({ - containerIds, - environment, - serviceName, -}: { - containerIds: string[]; - environment: string; - serviceName: string; -}): QueryDslQueryContainer { - return { - bool: { - should: [ - ...getServiceShouldClauses({ environment, serviceName }), - ...getContainerShouldClauses({ containerIds }), - ], - minimum_should_match: 1, - }, - }; -} - -export function getServiceShouldClauses({ - environment, - serviceName, -}: { - environment: string; - serviceName: string; -}): QueryDslQueryContainer[] { - const serviceNameFilter: QueryDslQueryContainer = { - term: { - [SERVICE_NAME]: serviceName, - }, - }; - - if (environment === ENVIRONMENT_ALL.value) { - return [serviceNameFilter]; - } else { - return [ - { - bool: { - filter: [ - serviceNameFilter, - { - term: { - [SERVICE_ENVIRONMENT]: environment, - }, - }, - ], - }, - }, - { - bool: { - filter: [serviceNameFilter], - must_not: [ - { - exists: { - field: SERVICE_ENVIRONMENT, - }, - }, - ], - }, - }, - ]; - } -} - -export function getContainerShouldClauses({ - containerIds = [], -}: { - containerIds: string[]; -}): QueryDslQueryContainer[] { - if (containerIds.length === 0) { - return []; - } - - return [ - { - bool: { - filter: [ - { - terms: { - [CONTAINER_ID]: containerIds, - }, - }, - ], - must_not: [ - { - term: { - [SERVICE_NAME]: '*', - }, - }, - ], - }, - }, - ]; -} diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx index 8a4a1c32877c5..d746e0464fd40 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx @@ -330,7 +330,7 @@ export const serviceDetailRoute = { }), element: , searchBarOptions: { - showQueryInput: false, + showUnifiedSearchBar: false, }, }), '/services/{serviceName}/infrastructure': { diff --git a/x-pack/plugins/observability_solution/apm/public/plugin.ts b/x-pack/plugins/observability_solution/apm/public/plugin.ts index b21bdedac9ef8..9a9f45f42a39e 100644 --- a/x-pack/plugins/observability_solution/apm/public/plugin.ts +++ b/x-pack/plugins/observability_solution/apm/public/plugin.ts @@ -69,7 +69,6 @@ import { from } from 'rxjs'; import { map } from 'rxjs'; import type { CloudSetup } from '@kbn/cloud-plugin/public'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; -import { LogsSharedClientStartExports } from '@kbn/logs-shared-plugin/public'; import type { ConfigSchema } from '.'; import { registerApmRuleTypes } from './components/alerting/rule_types/register_apm_rule_types'; import { registerEmbeddables } from './embeddable/register_embeddables'; @@ -143,7 +142,6 @@ export interface ApmPluginStartDeps { dashboard: DashboardStart; metricsDataAccess: MetricsDataPluginStart; uiSettings: IUiSettingsClient; - logsShared: LogsSharedClientStartExports; } const applicationsTitle = i18n.translate('xpack.apm.navigation.rootTitle', { diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx index 78443c9a6ec81..27344ccd1f108 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx @@ -5,37 +5,21 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { LogStream } from '@kbn/logs-shared-plugin/public'; -import React, { useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; import { InfraLoadingPanel } from '../../../../../../components/loading'; -import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana'; -import { useLogViewReference } from '../../../../../../hooks/use_log_view_reference'; -import { buildCombinedAssetFilter } from '../../../../../../utils/filters/build'; import { useHostsViewContext } from '../../../hooks/use_hosts_view'; -import { useLogsSearchUrlState } from '../../../hooks/use_logs_search_url_state'; import { useUnifiedSearchContext } from '../../../hooks/use_unified_search'; +import { useLogsSearchUrlState } from '../../../hooks/use_logs_search_url_state'; import { LogsLinkToStream } from './logs_link_to_stream'; import { LogsSearchBar } from './logs_search_bar'; +import { buildCombinedAssetFilter } from '../../../../../../utils/filters/build'; +import { useLogViewReference } from '../../../../../../hooks/use_log_view_reference'; export const LogsTabContent = () => { - const { - services: { - logsShared: { LogsOverview }, - }, - } = useKibanaContextForPlugin(); - const isLogsOverviewEnabled = LogsOverview.useIsEnabled(); - if (isLogsOverviewEnabled) { - return ; - } else { - return ; - } -}; - -export const LogsTabLogStreamContent = () => { const [filterQuery] = useLogsSearchUrlState(); const { getDateRangeAsTimestamp } = useUnifiedSearchContext(); const { from, to } = useMemo(() => getDateRangeAsTimestamp(), [getDateRangeAsTimestamp]); @@ -69,7 +53,22 @@ export const LogsTabLogStreamContent = () => { }, [filterQuery.query, hostNodes]); if (loading || logViewLoading || !logView) { - return ; + return ( + + + + } + /> + + + ); } return ( @@ -85,7 +84,6 @@ export const LogsTabLogStreamContent = () => { query={logsLinkToStreamQuery} logView={logView} /> - ] @@ -114,53 +112,3 @@ const createHostsFilterQueryParam = (hostNodes: string[]): string => { return hostsQueryParam; }; - -const LogsTabLogsOverviewContent = () => { - const { - services: { - logsShared: { LogsOverview }, - }, - } = useKibanaContextForPlugin(); - - const { parsedDateRange } = useUnifiedSearchContext(); - const timeRange = useMemo( - () => ({ start: parsedDateRange.from, end: parsedDateRange.to }), - [parsedDateRange.from, parsedDateRange.to] - ); - - const { hostNodes, loading, error } = useHostsViewContext(); - const logFilters = useMemo( - () => [ - buildCombinedAssetFilter({ - field: 'host.name', - values: hostNodes.map((p) => p.name), - }).query as QueryDslQueryContainer, - ], - [hostNodes] - ); - - if (loading) { - return ; - } else if (error != null) { - return ; - } else { - return ; - } -}; - -const LogsTabLoadingContent = () => ( - - - - } - /> - - -); diff --git a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc index 10c8fe32cfe9c..ea93fd326dac7 100644 --- a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc @@ -9,14 +9,13 @@ "browser": true, "configPath": ["xpack", "logs_shared"], "requiredPlugins": [ - "charts", "data", "dataViews", "discoverShared", - "logsDataAccess", + "usageCollection", "observabilityShared", "share", - "usageCollection", + "logsDataAccess" ], "optionalPlugins": [ "observabilityAIAssistant", diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx deleted file mode 100644 index 627cdc8447eea..0000000000000 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx +++ /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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './logs_overview'; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx deleted file mode 100644 index 435766bff793d..0000000000000 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx +++ /dev/null @@ -1,32 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import type { - LogsOverviewProps, - SelfContainedLogsOverviewComponent, - SelfContainedLogsOverviewHelpers, -} from './logs_overview'; - -export const createLogsOverviewMock = () => { - const LogsOverviewMock = jest.fn(LogsOverviewMockImpl) as unknown as ILogsOverviewMock; - - LogsOverviewMock.useIsEnabled = jest.fn(() => true); - - LogsOverviewMock.ErrorContent = jest.fn(() =>
    ); - - LogsOverviewMock.LoadingContent = jest.fn(() =>
    ); - - return LogsOverviewMock; -}; - -const LogsOverviewMockImpl = (_props: LogsOverviewProps) => { - return
    ; -}; - -type ILogsOverviewMock = jest.Mocked & - jest.Mocked; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx deleted file mode 100644 index 7b60aee5be57c..0000000000000 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx +++ /dev/null @@ -1,70 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID } from '@kbn/management-settings-ids'; -import type { - LogsOverviewProps as FullLogsOverviewProps, - LogsOverviewDependencies, - LogsOverviewErrorContentProps, -} from '@kbn/observability-logs-overview'; -import { dynamic } from '@kbn/shared-ux-utility'; -import React from 'react'; -import useObservable from 'react-use/lib/useObservable'; - -const LazyLogsOverview = dynamic(() => - import('@kbn/observability-logs-overview').then((mod) => ({ default: mod.LogsOverview })) -); - -const LazyLogsOverviewErrorContent = dynamic(() => - import('@kbn/observability-logs-overview').then((mod) => ({ - default: mod.LogsOverviewErrorContent, - })) -); - -const LazyLogsOverviewLoadingContent = dynamic(() => - import('@kbn/observability-logs-overview').then((mod) => ({ - default: mod.LogsOverviewLoadingContent, - })) -); - -export type LogsOverviewProps = Omit; - -export interface SelfContainedLogsOverviewHelpers { - useIsEnabled: () => boolean; - ErrorContent: React.ComponentType; - LoadingContent: React.ComponentType; -} - -export type SelfContainedLogsOverviewComponent = React.ComponentType; - -export type SelfContainedLogsOverview = SelfContainedLogsOverviewComponent & - SelfContainedLogsOverviewHelpers; - -export const createLogsOverview = ( - dependencies: LogsOverviewDependencies -): SelfContainedLogsOverview => { - const SelfContainedLogsOverview = (props: LogsOverviewProps) => { - return ; - }; - - const isEnabled$ = dependencies.uiSettings.client.get$( - OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID, - defaultIsEnabled - ); - - SelfContainedLogsOverview.useIsEnabled = (): boolean => { - return useObservable(isEnabled$, defaultIsEnabled); - }; - - SelfContainedLogsOverview.ErrorContent = LazyLogsOverviewErrorContent; - - SelfContainedLogsOverview.LoadingContent = LazyLogsOverviewLoadingContent; - - return SelfContainedLogsOverview; -}; - -const defaultIsEnabled = false; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/index.ts b/x-pack/plugins/observability_solution/logs_shared/public/index.ts index 3d601c9936f2d..a602b25786116 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/index.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/index.ts @@ -50,7 +50,6 @@ export type { UpdatedDateRange, VisibleInterval, } from './components/logging/log_text_stream/scrollable_log_text_stream_view'; -export type { LogsOverviewProps } from './components/logs_overview'; export const WithSummary = dynamic(() => import('./containers/logs/log_summary/with_summary')); export const LogEntryFlyout = dynamic( diff --git a/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx b/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx index ffb867abbcc17..a9b0ebd6a6aa3 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx @@ -6,14 +6,12 @@ */ import { createLogAIAssistantMock } from './components/log_ai_assistant/log_ai_assistant.mock'; -import { createLogsOverviewMock } from './components/logs_overview/logs_overview.mock'; import { createLogViewsServiceStartMock } from './services/log_views/log_views_service.mock'; import { LogsSharedClientStartExports } from './types'; export const createLogsSharedPluginStartMock = (): jest.Mocked => ({ logViews: createLogViewsServiceStartMock(), LogAIAssistant: createLogAIAssistantMock(), - LogsOverview: createLogsOverviewMock(), }); export const _ensureTypeCompatibility = (): LogsSharedClientStartExports => diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts index fc17e9b17cc82..d6f4ac81fe266 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts @@ -12,7 +12,6 @@ import { TraceLogsLocatorDefinition, } from '../common/locators'; import { createLogAIAssistant, createLogsAIAssistantRenderer } from './components/log_ai_assistant'; -import { createLogsOverview } from './components/logs_overview'; import { LogViewsService } from './services/log_views'; import { LogsSharedClientCoreSetup, @@ -52,16 +51,8 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { } public start(core: CoreStart, plugins: LogsSharedClientStartDeps) { - const { http, settings } = core; - const { - charts, - data, - dataViews, - discoverShared, - logsDataAccess, - observabilityAIAssistant, - share, - } = plugins; + const { http } = core; + const { data, dataViews, discoverShared, observabilityAIAssistant, logsDataAccess } = plugins; const logViews = this.logViews.start({ http, @@ -70,18 +61,9 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { search: data.search, }); - const LogsOverview = createLogsOverview({ - charts, - logsDataAccess, - search: data.search.search, - uiSettings: settings, - share, - }); - if (!observabilityAIAssistant) { return { logViews, - LogsOverview, }; } @@ -95,7 +77,6 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { return { logViews, LogAIAssistant, - LogsOverview, }; } diff --git a/x-pack/plugins/observability_solution/logs_shared/public/types.ts b/x-pack/plugins/observability_solution/logs_shared/public/types.ts index 4237c28c621b8..58b180ee8b6ef 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/types.ts @@ -5,19 +5,19 @@ * 2.0. */ -import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { CoreSetup, CoreStart, Plugin as PluginClass } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; -import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; +import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import type { LogsSharedLocators } from '../common/locators'; + +import { LogsSharedLocators } from '../common/locators'; import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; -import type { SelfContainedLogsOverview } from './components/logs_overview'; -import type { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views'; +// import type { OsqueryPluginStart } from '../../osquery/public'; +import { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views'; // Our own setup and start contract values export interface LogsSharedClientSetupExports { @@ -28,7 +28,6 @@ export interface LogsSharedClientSetupExports { export interface LogsSharedClientStartExports { logViews: LogViewsServiceStart; LogAIAssistant?: (props: Omit) => JSX.Element; - LogsOverview: SelfContainedLogsOverview; } export interface LogsSharedClientSetupDeps { @@ -36,7 +35,6 @@ export interface LogsSharedClientSetupDeps { } export interface LogsSharedClientStartDeps { - charts: ChartsPluginStart; data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; discoverShared: DiscoverSharedPublicStart; diff --git a/x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts b/x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts deleted file mode 100644 index 0298416bd3f26..0000000000000 --- a/x-pack/plugins/observability_solution/logs_shared/server/feature_flags.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { UiSettingsParams } from '@kbn/core-ui-settings-common'; -import { i18n } from '@kbn/i18n'; -import { OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID } from '@kbn/management-settings-ids'; - -const technicalPreviewLabel = i18n.translate('xpack.logsShared.technicalPreviewSettingLabel', { - defaultMessage: 'Technical Preview', -}); - -export const featureFlagUiSettings: Record = { - [OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID]: { - category: ['observability'], - name: i18n.translate('xpack.logsShared.newLogsOverviewSettingName', { - defaultMessage: 'New logs overview', - }), - value: false, - description: i18n.translate('xpack.logsShared.newLogsOverviewSettingDescription', { - defaultMessage: '{technicalPreviewLabel} Enable the new logs overview experience.', - - values: { technicalPreviewLabel: `[${technicalPreviewLabel}]` }, - }), - type: 'boolean', - schema: schema.boolean(), - requiresPageReload: true, - }, -}; diff --git a/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts index d1f6399104fc2..7c97e175ed64f 100644 --- a/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts @@ -5,19 +5,8 @@ * 2.0. */ -import { CoreStart, Logger, Plugin, PluginInitializerContext } from '@kbn/core/server'; -import { defaultLogViewId } from '../common/log_views'; -import { LogsSharedConfig } from '../common/plugin_config'; -import { registerDeprecations } from './deprecations'; -import { featureFlagUiSettings } from './feature_flags'; -import { KibanaFramework } from './lib/adapters/framework/kibana_framework_adapter'; -import { LogsSharedKibanaLogEntriesAdapter } from './lib/adapters/log_entries/kibana_log_entries_adapter'; -import { LogsSharedLogEntriesDomain } from './lib/domains/log_entries_domain'; -import { LogsSharedBackendLibs, LogsSharedDomainLibs } from './lib/logs_shared_types'; -import { initLogsSharedServer } from './logs_shared_server'; -import { logViewSavedObjectType } from './saved_objects'; -import { LogEntriesService } from './services/log_entries'; -import { LogViewsService } from './services/log_views'; +import { PluginInitializerContext, CoreStart, Plugin, Logger } from '@kbn/core/server'; + import { LogsSharedPluginCoreSetup, LogsSharedPluginSetup, @@ -26,6 +15,17 @@ import { LogsSharedServerPluginStartDeps, UsageCollector, } from './types'; +import { logViewSavedObjectType } from './saved_objects'; +import { initLogsSharedServer } from './logs_shared_server'; +import { LogViewsService } from './services/log_views'; +import { KibanaFramework } from './lib/adapters/framework/kibana_framework_adapter'; +import { LogsSharedBackendLibs, LogsSharedDomainLibs } from './lib/logs_shared_types'; +import { LogsSharedLogEntriesDomain } from './lib/domains/log_entries_domain'; +import { LogsSharedKibanaLogEntriesAdapter } from './lib/adapters/log_entries/kibana_log_entries_adapter'; +import { LogEntriesService } from './services/log_entries'; +import { LogsSharedConfig } from '../common/plugin_config'; +import { registerDeprecations } from './deprecations'; +import { defaultLogViewId } from '../common/log_views'; export class LogsSharedPlugin implements @@ -88,8 +88,6 @@ export class LogsSharedPlugin registerDeprecations({ core }); - core.uiSettings.register(featureFlagUiSettings); - return { ...domainLibs, logViews, diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index 788f55c9b6fc5..38cbba7c252c0 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -44,9 +44,5 @@ "@kbn/logs-data-access-plugin", "@kbn/core-deprecations-common", "@kbn/core-deprecations-server", - "@kbn/management-settings-ids", - "@kbn/observability-logs-overview", - "@kbn/charts-plugin", - "@kbn/core-ui-settings-common", ] } diff --git a/yarn.lock b/yarn.lock index 019de6121540e..54a38b2c0e5d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5879,10 +5879,6 @@ version "0.0.0" uid "" -"@kbn/observability-logs-overview@link:x-pack/packages/observability/logs_overview": - version "0.0.0" - uid "" - "@kbn/observability-onboarding-e2e@link:x-pack/plugins/observability_solution/observability_onboarding/e2e": version "0.0.0" uid "" @@ -12109,14 +12105,6 @@ use-isomorphic-layout-effect "^1.1.2" use-sync-external-store "^1.0.0" -"@xstate5/react@npm:@xstate/react@^4.1.2": - version "4.1.2" - resolved "https://registry.yarnpkg.com/@xstate/react/-/react-4.1.2.tgz#4bfcdf2d9e9ef1eaea7388d1896649345e6679cd" - integrity sha512-orAidFrKCrU0ZwN5l/ABPlBfW2ziRDT2RrYoktRlZ0WRoLvA2E/uAC1JpZt43mCLtc8jrdwYCgJiqx1V8NvGTw== - dependencies: - use-isomorphic-layout-effect "^1.1.2" - use-sync-external-store "^1.2.0" - "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -32812,11 +32800,6 @@ xpath@^0.0.33: resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.33.tgz#5136b6094227c5df92002e7c3a13516a5074eb07" integrity sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA== -"xstate5@npm:xstate@^5.18.1", xstate@^5.18.1: - version "5.18.1" - resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.18.1.tgz#c4d43ceaba6e6c31705d36bd96e285de4be4f7f4" - integrity sha512-m02IqcCQbaE/kBQLunwub/5i8epvkD2mFutnL17Oeg1eXTShe1sRF4D5mhv1dlaFO4vbW5gRGRhraeAD5c938g== - xstate@^4.38.2: version "4.38.2" resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.38.2.tgz#1b74544fc9c8c6c713ba77f81c6017e65aa89804" From bd6533f30b58fc831670d400f25a61321379902c Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Wed, 9 Oct 2024 13:08:18 -0700 Subject: [PATCH 088/110] [UII] Add types to return content packages correctly (#195505) ## Summary Related to #192484. This PR adding [new content package types and schemas](https://github.com/elastic/package-spec/pull/777) so that content packages can be returned correctly from EPR to unblock development of those packages. The only current content package is `kubernetes_otel`. You will need to bump up the max allowed spec version and search with beta (prerelease) packages enabled to find it: ``` xpack.fleet.internal.registry.spec.max: '3.4' ``` Tests will come with the rest of work for #192484 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- oas_docs/bundle.json | 144 +++++++++++++++++- oas_docs/bundle.serverless.json | 144 +++++++++++++++++- .../output/kibana.serverless.staging.yaml | 90 +++++++++++ oas_docs/output/kibana.serverless.yaml | 90 +++++++++++ oas_docs/output/kibana.staging.yaml | 90 +++++++++++ oas_docs/output/kibana.yaml | 90 +++++++++++ .../fleet/common/types/models/package_spec.ts | 9 +- .../fleet/server/types/rest_spec/epm.ts | 13 +- 8 files changed, 655 insertions(+), 15 deletions(-) diff --git a/oas_docs/bundle.json b/oas_docs/bundle.json index 6cc3990de1b51..e52362ff13a6a 100644 --- a/oas_docs/bundle.json +++ b/oas_docs/bundle.json @@ -19328,6 +19328,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -19716,7 +19737,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -19793,6 +19815,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -20181,7 +20224,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -21769,6 +21813,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -22197,7 +22262,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -22329,6 +22395,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -22757,7 +22844,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -23279,6 +23367,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -23707,7 +23816,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -23827,6 +23937,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -24255,7 +24386,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, diff --git a/oas_docs/bundle.serverless.json b/oas_docs/bundle.serverless.json index 6fcc247e1fb22..531ab412ce1bf 100644 --- a/oas_docs/bundle.serverless.json +++ b/oas_docs/bundle.serverless.json @@ -19328,6 +19328,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -19716,7 +19737,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -19793,6 +19815,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -20181,7 +20224,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -21769,6 +21813,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -22197,7 +22262,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -22329,6 +22395,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -22757,7 +22844,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -23279,6 +23367,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -23707,7 +23816,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, @@ -23827,6 +23937,27 @@ "description": { "type": "string" }, + "discovery": { + "additionalProperties": true, + "properties": { + "fields": { + "items": { + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, "download": { "type": "string" }, @@ -24255,7 +24386,8 @@ "type": { "enum": [ "integration", - "input" + "input", + "content" ], "type": "string" }, diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index bd2f5c597ecc4..69b783c6ccc44 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -18990,6 +18990,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string format_version: @@ -19270,6 +19284,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -19322,6 +19337,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string format_version: @@ -19602,6 +19631,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -20574,6 +20604,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -20881,6 +20925,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -20970,6 +21015,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -21277,6 +21336,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -21629,6 +21689,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -21936,6 +22010,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -22017,6 +22092,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -22324,6 +22413,7 @@ paths: enum: - integration - input + - content type: string vars: items: diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index bd2f5c597ecc4..69b783c6ccc44 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -18990,6 +18990,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string format_version: @@ -19270,6 +19284,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -19322,6 +19337,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string format_version: @@ -19602,6 +19631,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -20574,6 +20604,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -20881,6 +20925,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -20970,6 +21015,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -21277,6 +21336,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -21629,6 +21689,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -21936,6 +22010,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -22017,6 +22092,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -22324,6 +22413,7 @@ paths: enum: - integration - input + - content type: string vars: items: diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index 544315cd12646..bc0828a44b619 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -22419,6 +22419,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string format_version: @@ -22699,6 +22713,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -22751,6 +22766,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string format_version: @@ -23031,6 +23060,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -24003,6 +24033,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -24310,6 +24354,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -24399,6 +24444,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -24706,6 +24765,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -25058,6 +25118,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -25365,6 +25439,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -25446,6 +25521,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -25753,6 +25842,7 @@ paths: enum: - integration - input + - content type: string vars: items: diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index 544315cd12646..bc0828a44b619 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -22419,6 +22419,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string format_version: @@ -22699,6 +22713,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -22751,6 +22766,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string format_version: @@ -23031,6 +23060,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -24003,6 +24033,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -24310,6 +24354,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -24399,6 +24444,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -24706,6 +24765,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -25058,6 +25118,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -25365,6 +25439,7 @@ paths: enum: - integration - input + - content type: string vars: items: @@ -25446,6 +25521,20 @@ paths: type: array description: type: string + discovery: + additionalProperties: true + type: object + properties: + fields: + items: + additionalProperties: true + type: object + properties: + name: + type: string + required: + - name + type: array download: type: string elasticsearch: @@ -25753,6 +25842,7 @@ paths: enum: - integration - input + - content type: string vars: items: diff --git a/x-pack/plugins/fleet/common/types/models/package_spec.ts b/x-pack/plugins/fleet/common/types/models/package_spec.ts index 24a592490137c..18c10e4617417 100644 --- a/x-pack/plugins/fleet/common/types/models/package_spec.ts +++ b/x-pack/plugins/fleet/common/types/models/package_spec.ts @@ -18,7 +18,7 @@ export interface PackageSpecManifest { source?: { license: string; }; - type?: 'integration' | 'input'; + type?: PackageSpecPackageType; release?: 'experimental' | 'beta' | 'ga'; categories?: Array; conditions?: PackageSpecConditions; @@ -35,6 +35,11 @@ export interface PackageSpecManifest { privileges?: { root?: boolean }; }; asset_tags?: PackageSpecTags[]; + discovery?: { + fields?: Array<{ + name: string; + }>; + }; } export interface PackageSpecTags { text: string; @@ -42,7 +47,7 @@ export interface PackageSpecTags { asset_ids?: string[]; } -export type PackageSpecPackageType = 'integration' | 'input'; +export type PackageSpecPackageType = 'integration' | 'input' | 'content'; export type PackageSpecCategory = | 'advanced_analytics_ueba' diff --git a/x-pack/plugins/fleet/server/types/rest_spec/epm.ts b/x-pack/plugins/fleet/server/types/rest_spec/epm.ts index 2dc9606a5432d..f08ccd9ff1248 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/epm.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/epm.ts @@ -163,7 +163,13 @@ export const PackageInfoSchema = schema release: schema.maybe( schema.oneOf([schema.literal('ga'), schema.literal('beta'), schema.literal('experimental')]) ), - type: schema.maybe(schema.oneOf([schema.literal('integration'), schema.literal('input')])), + type: schema.maybe( + schema.oneOf([ + schema.literal('integration'), + schema.literal('input'), + schema.literal('content'), + ]) + ), path: schema.maybe(schema.string()), download: schema.maybe(schema.string()), internal: schema.maybe(schema.boolean()), @@ -192,6 +198,11 @@ export const PackageInfoSchema = schema format_version: schema.maybe(schema.string()), vars: schema.maybe(schema.arrayOf(schema.recordOf(schema.string(), schema.any()))), latestVersion: schema.maybe(schema.string()), + discovery: schema.maybe( + schema.object({ + fields: schema.maybe(schema.arrayOf(schema.object({ name: schema.string() }))), + }) + ), }) // sometimes package list response contains extra properties, e.g. installed_kibana .extendsDeep({ From 554ec2e321b6245a56224e0f65ef0fa70bb5425d Mon Sep 17 00:00:00 2001 From: Robert Oskamp Date: Wed, 9 Oct 2024 22:28:19 +0200 Subject: [PATCH 089/110] Tag pipelines related to Kibana serverless release (#195631) ## Summary This PR tags all pipelines that are related to the Kibana serverless release (including requirements like on-merge and artifacts build) with `kibana-serverless-release`. This will allow us to easily find these pipelines in Buildkite. --- .../kibana-artifacts-container-image.yml | 1 + .../kibana-es-serverless-snapshots.yml | 1 + .buildkite/pipeline-resource-definitions/kibana-on-merge.yml | 1 + .../kibana-serverless-emergency-release.yml | 1 + .../kibana-serverless-quality-gates-emergency.yml | 1 + .../kibana-serverless-quality-gates.yml | 1 + .../kibana-serverless-release-testing.yml | 1 + .../pipeline-resource-definitions/kibana-serverless-release.yml | 1 + 8 files changed, 8 insertions(+) diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-container-image.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-container-image.yml index 37bc5ee59ff0b..eb86f8d7aab2a 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-container-image.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-container-image.yml @@ -44,3 +44,4 @@ spec: access_level: MANAGE_BUILD_AND_READ tags: - kibana + - kibana-serverless-release diff --git a/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml b/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml index 684e2e07fb187..6ba182ccd393e 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml @@ -55,3 +55,4 @@ spec: branch: main tags: - kibana + - kibana-serverless-release diff --git a/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml b/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml index 5e6622e6da513..e524adc786c0e 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml @@ -49,3 +49,4 @@ spec: access_level: MANAGE_BUILD_AND_READ tags: - kibana + - kibana-serverless-release diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-emergency-release.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-emergency-release.yml index c51e44432596d..62b05bc49dae6 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-emergency-release.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-emergency-release.yml @@ -30,3 +30,4 @@ spec: access_level: READ_ONLY tags: - kibana + - kibana-serverless-release diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates-emergency.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates-emergency.yml index 267db48ba6d90..ef04fd324b31a 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates-emergency.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates-emergency.yml @@ -33,3 +33,4 @@ spec: access_level: READ_ONLY tags: - kibana + - kibana-serverless-release diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates.yml index 8d4e7f35cd6fe..e9ea3d02b8968 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-quality-gates.yml @@ -33,3 +33,4 @@ spec: access_level: READ_ONLY tags: - kibana + - kibana-serverless-release diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml index 0a033e72d53b8..5276871fa1c9f 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml @@ -46,3 +46,4 @@ spec: access_level: MANAGE_BUILD_AND_READ tags: - kibana + - kibana-serverless-release diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml index 7a35ea3ad1ec8..e1457f10420f7 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml @@ -48,3 +48,4 @@ spec: branch: main tags: - kibana + - kibana-serverless-release From 9221ab19e86ca7d3215205110fc709f7ba4739af Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Wed, 9 Oct 2024 17:01:16 -0400 Subject: [PATCH 090/110] [Response Ops][Alerting] Refactor `ExecutionHandler` stage 2 (#193807) Resolves https://github.com/elastic/kibana/issues/186534 ## Summary This PR splits the for-loop in the `ActionScheduler.run` function into the appropriate scheduler classes. Previously, each scheduler had a `generateExecutables` function that would return an array of executables and the `ActionScheduler` would loop through the array and convert the executable to a scheduleable action depending on whether it was a per-alert action, summary action or system action. This refactor renames `generateExecutables` into `getActionsToSchedule` and moves the logic to convert the executables into a schedulable action into the appropriate scheduler class. ## To Verify Create some rules with per-alert and summary and system actions and verify they are triggered as expected. --------- Co-authored-by: Elastic Machine --- .../server/create_execute_function.test.ts | 90 +++ .../actions/server/create_execute_function.ts | 4 + .../alerting_event_logger.test.ts | 9 + .../alerting_event_logger.ts | 3 + .../action_scheduler/action_scheduler.test.ts | 66 +- .../action_scheduler/action_scheduler.ts | 503 ++------------- .../lib/build_rule_url.test.ts | 141 ++++ .../action_scheduler/lib/build_rule_url.ts | 65 ++ .../lib/format_action_to_enqueue.test.ts | 222 +++++++ .../lib/format_action_to_enqueue.ts | 48 ++ .../{ => lib}/get_summarized_alerts.test.ts | 6 +- .../{ => lib}/get_summarized_alerts.ts | 4 +- .../task_runner/action_scheduler/lib/index.ts | 20 + .../{ => lib}/rule_action_helper.test.ts | 2 +- .../{ => lib}/rule_action_helper.ts | 2 +- .../lib/should_schedule_action.test.ts | 195 ++++++ .../lib/should_schedule_action.ts | 70 ++ .../per_alert_action_scheduler.test.ts | 610 ++++++++++++------ .../schedulers/per_alert_action_scheduler.ts | 136 +++- .../summary_action_scheduler.test.ts | 319 ++++++--- .../schedulers/summary_action_scheduler.ts | 121 +++- .../system_action_scheduler.test.ts | 297 +++++++-- .../schedulers/system_action_scheduler.ts | 118 +++- .../task_runner/action_scheduler/types.ts | 21 +- .../alerting/server/task_runner/fixtures.ts | 10 +- .../server/task_runner/task_runner.test.ts | 34 +- 26 files changed, 2287 insertions(+), 829 deletions(-) create mode 100644 x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/build_rule_url.test.ts create mode 100644 x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/build_rule_url.ts create mode 100644 x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/format_action_to_enqueue.test.ts create mode 100644 x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/format_action_to_enqueue.ts rename x-pack/plugins/alerting/server/task_runner/action_scheduler/{ => lib}/get_summarized_alerts.test.ts (95%) rename x-pack/plugins/alerting/server/task_runner/action_scheduler/{ => lib}/get_summarized_alerts.ts (98%) create mode 100644 x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/index.ts rename x-pack/plugins/alerting/server/task_runner/action_scheduler/{ => lib}/rule_action_helper.test.ts (99%) rename x-pack/plugins/alerting/server/task_runner/action_scheduler/{ => lib}/rule_action_helper.ts (99%) create mode 100644 x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/should_schedule_action.test.ts create mode 100644 x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/should_schedule_action.ts diff --git a/x-pack/plugins/actions/server/create_execute_function.test.ts b/x-pack/plugins/actions/server/create_execute_function.test.ts index a1ab85933d9bc..7be187743e634 100644 --- a/x-pack/plugins/actions/server/create_execute_function.test.ts +++ b/x-pack/plugins/actions/server/create_execute_function.test.ts @@ -1088,6 +1088,7 @@ describe('bulkExecute()', () => { "actionTypeId": "mock-action", "id": "123", "response": "queuedActionsLimitError", + "uuid": undefined, }, ], } @@ -1099,4 +1100,93 @@ describe('bulkExecute()', () => { ] `); }); + + test('passes through action uuid if provided', async () => { + mockTaskManager.aggregate.mockResolvedValue({ + took: 1, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { total: { value: 2, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: {}, + }); + mockActionsConfig.getMaxQueued.mockReturnValueOnce(3); + const executeFn = createBulkExecutionEnqueuerFunction({ + taskManager: mockTaskManager, + actionTypeRegistry: actionTypeRegistryMock.create(), + isESOCanEncrypt: true, + inMemoryConnectors: [], + configurationUtilities: mockActionsConfig, + logger: mockLogger, + }); + savedObjectsClient.bulkGet.mockResolvedValueOnce({ + saved_objects: [ + { id: '123', type: 'action', attributes: { actionTypeId: 'mock-action' }, references: [] }, + ], + }); + savedObjectsClient.bulkCreate.mockResolvedValueOnce({ + saved_objects: [ + { id: '234', type: 'action_task_params', attributes: { actionId: '123' }, references: [] }, + ], + }); + expect( + await executeFn(savedObjectsClient, [ + { + id: '123', + params: { baz: false }, + spaceId: 'default', + executionId: '123abc', + apiKey: null, + source: asHttpRequestExecutionSource(request), + actionTypeId: 'mock-action', + uuid: 'aaa', + }, + { + id: '123', + params: { baz: false }, + spaceId: 'default', + executionId: '456xyz', + apiKey: null, + source: asHttpRequestExecutionSource(request), + actionTypeId: 'mock-action', + uuid: 'bbb', + }, + ]) + ).toMatchInlineSnapshot(` + Object { + "errors": true, + "items": Array [ + Object { + "actionTypeId": "mock-action", + "id": "123", + "response": "success", + "uuid": "aaa", + }, + Object { + "actionTypeId": "mock-action", + "id": "123", + "response": "queuedActionsLimitError", + "uuid": "bbb", + }, + ], + } + `); + expect(mockTaskManager.bulkSchedule).toHaveBeenCalledTimes(1); + expect(mockTaskManager.bulkSchedule.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "params": Object { + "actionTaskParamsId": "234", + "spaceId": "default", + }, + "scope": Array [ + "actions", + ], + "state": Object {}, + "taskType": "actions:mock-action", + }, + ], + ] + `); + }); }); diff --git a/x-pack/plugins/actions/server/create_execute_function.ts b/x-pack/plugins/actions/server/create_execute_function.ts index e8f9c859747ff..a92bff9719559 100644 --- a/x-pack/plugins/actions/server/create_execute_function.ts +++ b/x-pack/plugins/actions/server/create_execute_function.ts @@ -31,6 +31,7 @@ interface CreateExecuteFunctionOptions { export interface ExecuteOptions extends Pick { id: string; + uuid?: string; spaceId: string; apiKey: string | null; executionId: string; @@ -71,6 +72,7 @@ export interface ExecutionResponse { export interface ExecutionResponseItem { id: string; + uuid?: string; actionTypeId: string; response: ExecutionResponseType; } @@ -197,12 +199,14 @@ export function createBulkExecutionEnqueuerFunction({ items: runnableActions .map((a) => ({ id: a.id, + uuid: a.uuid, actionTypeId: a.actionTypeId, response: ExecutionResponseType.SUCCESS, })) .concat( actionsOverLimit.map((a) => ({ id: a.id, + uuid: a.uuid, actionTypeId: a.actionTypeId, response: ExecutionResponseType.QUEUED_ACTIONS_LIMIT_ERROR, })) diff --git a/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.test.ts b/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.test.ts index 82e8663bd6bf8..082d5ea6381df 100644 --- a/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.test.ts +++ b/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.test.ts @@ -807,6 +807,15 @@ describe('AlertingEventLogger', () => { expect(eventLogger.logEvent).toHaveBeenCalledWith(event); }); + + test('should log action event with uuid', () => { + alertingEventLogger.initialize({ context: ruleContext, runDate, ruleData }); + alertingEventLogger.logAction({ ...action, uuid: 'abcdefg' }); + + const event = createActionExecuteRecord(ruleContext, ruleData, [alertSO], action); + + expect(eventLogger.logEvent).toHaveBeenCalledWith(event); + }); }); describe('done()', () => { diff --git a/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.ts b/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.ts index f29e1e00473b2..1607f6090b10c 100644 --- a/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.ts +++ b/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.ts @@ -78,6 +78,9 @@ interface AlertOpts { export interface ActionOpts { id: string; + // uuid is typed as optional but in reality it is always + // populated - https://github.com/elastic/kibana/issues/195255 + uuid?: string; typeId: string; alertId?: string; alertGroup?: string; diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts index 600f6aedbe039..b6f250b47205e 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts @@ -60,7 +60,9 @@ const defaultSchedulerContext = getDefaultSchedulerContext( const defaultExecutionResponse = { errors: false, - items: [{ actionTypeId: 'test', id: '1', response: ExecutionResponseType.SUCCESS }], + items: [ + { actionTypeId: 'test', id: '1', uuid: '111-111', response: ExecutionResponseType.SUCCESS }, + ], }; let ruleRunMetricsStore: RuleRunMetricsStore; @@ -99,7 +101,7 @@ describe('Action Scheduler', () => { }); afterAll(() => clock.restore()); - test('enqueues execution per selected action', async () => { + test('schedules execution per selected action', async () => { const alerts = generateAlert({ id: 1 }); const actionScheduler = new ActionScheduler(getSchedulerContext()); await actionScheduler.run(alerts); @@ -138,6 +140,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "111-111", }, ], ] @@ -146,6 +149,7 @@ describe('Action Scheduler', () => { expect(alertingEventLogger.logAction).toHaveBeenCalledTimes(1); expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, { id: '1', + uuid: '111-111', typeId: 'test', alertId: '1', alertGroup: 'default', @@ -368,6 +372,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "111-111", }, ], ] @@ -409,6 +414,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "111-111", }, ], ] @@ -437,11 +443,13 @@ describe('Action Scheduler', () => { { actionTypeId: 'test2', id: '1', + uuid: '111-111', response: ExecutionResponseType.SUCCESS, }, { actionTypeId: 'test2', id: '2', + uuid: '222-222', response: ExecutionResponseType.SUCCESS, }, ], @@ -508,20 +516,23 @@ describe('Action Scheduler', () => { actionsClient.bulkEnqueueExecution.mockResolvedValueOnce({ errors: false, items: [ - { actionTypeId: 'test', id: '1', response: ExecutionResponseType.SUCCESS }, + { actionTypeId: 'test', id: '1', uuid: '222-222', response: ExecutionResponseType.SUCCESS }, { actionTypeId: 'test-action-type-id', id: '2', + uuid: '222-222', response: ExecutionResponseType.SUCCESS, }, { actionTypeId: 'another-action-type-id', id: '4', + uuid: '444-444', response: ExecutionResponseType.SUCCESS, }, { actionTypeId: 'another-action-type-id', id: '5', + uuid: '555-555', response: ExecutionResponseType.SUCCESS, }, ], @@ -537,6 +548,7 @@ describe('Action Scheduler', () => { contextVal: 'My other {{context.value}} goes here', stateVal: 'My other {{state.value}} goes here', }, + uuid: '222-222', }, { id: '3', @@ -547,6 +559,7 @@ describe('Action Scheduler', () => { contextVal: '{{context.value}} goes here', stateVal: '{{state.value}} goes here', }, + uuid: '333-333', }, { id: '4', @@ -557,6 +570,7 @@ describe('Action Scheduler', () => { contextVal: '{{context.value}} goes here', stateVal: '{{state.value}} goes here', }, + uuid: '444-444', }, { id: '5', @@ -567,6 +581,7 @@ describe('Action Scheduler', () => { contextVal: '{{context.value}} goes here', stateVal: '{{state.value}} goes here', }, + uuid: '555-555', }, ]; const actionScheduler = new ActionScheduler( @@ -612,16 +627,19 @@ describe('Action Scheduler', () => { { actionTypeId: 'test', id: '1', + uuid: '111-111', response: ExecutionResponseType.SUCCESS, }, { actionTypeId: 'test', id: '2', + uuid: '222-222', response: ExecutionResponseType.SUCCESS, }, { actionTypeId: 'test', id: '3', + uuid: '333-333', response: ExecutionResponseType.QUEUED_ACTIONS_LIMIT_ERROR, }, ], @@ -636,6 +654,7 @@ describe('Action Scheduler', () => { contextVal: 'My other {{context.value}} goes here', stateVal: 'My other {{state.value}} goes here', }, + uuid: '111-111', }, { id: '2', @@ -646,6 +665,7 @@ describe('Action Scheduler', () => { contextVal: 'My other {{context.value}} goes here', stateVal: 'My other {{state.value}} goes here', }, + uuid: '222-222', }, { id: '3', @@ -656,6 +676,7 @@ describe('Action Scheduler', () => { contextVal: '{{context.value}} goes here', stateVal: '{{state.value}} goes here', }, + uuid: '333-333', }, ]; const actionScheduler = new ActionScheduler( @@ -679,7 +700,7 @@ describe('Action Scheduler', () => { test('schedules alerts with recovered actions', async () => { const actions = [ { - id: '1', + id: 'action-2', group: 'recovered', actionTypeId: 'test', params: { @@ -689,6 +710,7 @@ describe('Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, + uuid: '222-222', }, ]; const actionScheduler = new ActionScheduler( @@ -711,7 +733,7 @@ describe('Action Scheduler', () => { "apiKey": "MTIzOmFiYw==", "consumer": "rule-consumer", "executionId": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", - "id": "1", + "id": "action-2", "params": Object { "alertVal": "My 1 name-of-alert test1 tag-A,tag-B 1 goes here", "contextVal": "My goes here", @@ -734,6 +756,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "222-222", }, ], ] @@ -883,6 +906,7 @@ describe('Action Scheduler', () => { { actionTypeId: 'testActionTypeId', id: '1', + uuid: '111-111', response: ExecutionResponseType.SUCCESS, }, ], @@ -914,6 +938,7 @@ describe('Action Scheduler', () => { message: 'New: {{alerts.new.count}} Ongoing: {{alerts.ongoing.count}} Recovered: {{alerts.recovered.count}}', }, + uuid: '111-111', }, ], }, @@ -957,6 +982,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "111-111", }, ], ] @@ -964,6 +990,7 @@ describe('Action Scheduler', () => { expect(alertingEventLogger.logAction).toBeCalledWith({ alertSummary: { new: 1, ongoing: 0, recovered: 0 }, id: '1', + uuid: '111-111', typeId: 'testActionTypeId', }); }); @@ -1012,6 +1039,7 @@ describe('Action Scheduler', () => { { actionTypeId: 'testActionTypeId', id: '1', + uuid: '111-111', response: ExecutionResponseType.SUCCESS, }, ], @@ -1095,6 +1123,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "111-111", }, ], ] @@ -1102,6 +1131,7 @@ describe('Action Scheduler', () => { expect(alertingEventLogger.logAction).toBeCalledWith({ alertSummary: { new: 1, ongoing: 0, recovered: 0 }, id: '1', + uuid: '111-111', typeId: 'testActionTypeId', }); }); @@ -1256,10 +1286,11 @@ describe('Action Scheduler', () => { actionsClient.bulkEnqueueExecution.mockResolvedValueOnce({ errors: false, items: [ - { actionTypeId: 'test', id: '1', response: ExecutionResponseType.SUCCESS }, + { actionTypeId: 'test', id: '1', uuid: '111-111', response: ExecutionResponseType.SUCCESS }, { actionTypeId: 'test', id: '2', + uuid: '222-222', response: ExecutionResponseType.SUCCESS, }, ], @@ -1276,6 +1307,7 @@ describe('Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, + uuid: '111-111', }, { id: '2', @@ -1288,6 +1320,7 @@ describe('Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, + uuid: '222-222', }, ]; const actionScheduler = new ActionScheduler( @@ -1333,6 +1366,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "111-111", }, Object { "actionTypeId": "test", @@ -1362,6 +1396,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "222-222", }, ], ] @@ -1448,6 +1483,7 @@ describe('Action Scheduler', () => { { actionTypeId: 'testActionTypeId', id: '1', + uuid: '111-111', response: ExecutionResponseType.SUCCESS, }, ], @@ -1518,6 +1554,7 @@ describe('Action Scheduler', () => { { actionTypeId: 'testActionTypeId', id: '1', + uuid: '111-111', response: ExecutionResponseType.SUCCESS, }, ], @@ -1541,7 +1578,7 @@ describe('Action Scheduler', () => { actions: [ { id: '1', - uuid: '111', + uuid: '111-111', group: 'default', actionTypeId: 'testActionTypeId', frequency: { @@ -1587,17 +1624,19 @@ describe('Action Scheduler', () => { ], source: { source: { id: '1', type: RULE_SAVED_OBJECT_TYPE }, type: 'SAVED_OBJECT' }, spaceId: 'test1', + uuid: '111-111', }, ]); expect(alertingEventLogger.logAction).toHaveBeenCalledWith({ alertGroup: 'default', alertId: '1', id: '1', + uuid: '111-111', typeId: 'testActionTypeId', }); expect(defaultSchedulerContext.logger.debug).toHaveBeenCalledTimes(1); expect(defaultSchedulerContext.logger.debug).toHaveBeenCalledWith( - '(2) alerts have been filtered out for: testActionTypeId:111' + '(2) alerts have been filtered out for: testActionTypeId:111-111' ); }); @@ -1840,6 +1879,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "111-111", }, Object { "actionTypeId": "test", @@ -1869,6 +1909,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "111-111", }, Object { "actionTypeId": "test", @@ -1898,6 +1939,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "111-111", }, ], ] @@ -2261,12 +2303,13 @@ describe('Action Scheduler', () => { const executorParams = getSchedulerContext({ rule: { ...defaultSchedulerContext.rule, + actions: [], systemActions: [ { id: '1', actionTypeId: '.test-system-action', params: actionsParams, - uui: 'test', + uuid: 'test', }, ], }, @@ -2360,6 +2403,7 @@ describe('Action Scheduler', () => { "type": "SAVED_OBJECT", }, "spaceId": "test1", + "uuid": "test", }, ], ] @@ -2368,6 +2412,7 @@ describe('Action Scheduler', () => { expect(alertingEventLogger.logAction).toBeCalledWith({ alertSummary: { new: 1, ongoing: 0, recovered: 0 }, id: '1', + uuid: 'test', typeId: '.test-system-action', }); }); @@ -2387,6 +2432,7 @@ describe('Action Scheduler', () => { const executorParams = getSchedulerContext({ rule: { ...defaultSchedulerContext.rule, + actions: [], systemActions: [ { id: 'action-id', @@ -2443,6 +2489,7 @@ describe('Action Scheduler', () => { }, rule: { ...defaultSchedulerContext.rule, + actions: [], systemActions: [ { id: 'action-id', @@ -2477,6 +2524,7 @@ describe('Action Scheduler', () => { const executorParams = getSchedulerContext({ rule: { ...defaultSchedulerContext.rule, + actions: [], systemActions: [ { id: '1', diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts index 3b804ce3da413..44822657ba86f 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts @@ -5,8 +5,6 @@ * 2.0. */ -import { getRuleDetailsRoute, triggersActionsRoute } from '@kbn/rule-data-utils'; -import { asSavedObjectExecutionSource } from '@kbn/actions-plugin/server'; import { createTaskRunError, isEphemeralTaskRejectedDueToCapacityError, @@ -19,77 +17,21 @@ import { } from '@kbn/actions-plugin/server/create_execute_function'; import { ActionsCompletion } from '@kbn/alerting-state-types'; import { chunk } from 'lodash'; -import { CombinedSummarizedAlerts, ThrottledActions } from '../../types'; -import { injectActionParams } from '../inject_action_params'; -import { ActionSchedulerOptions, IActionScheduler, RuleUrl } from './types'; -import { - transformActionParams, - TransformActionParamsOptions, - transformSummaryActionParams, -} from '../transform_action_params'; +import { ThrottledActions } from '../../types'; +import { ActionSchedulerOptions, ActionsToSchedule, IActionScheduler } from './types'; import { Alert } from '../../alert'; import { AlertInstanceContext, AlertInstanceState, - RuleAction, RuleTypeParams, RuleTypeState, - SanitizedRule, RuleAlertData, - RuleSystemAction, } from '../../../common'; -import { - generateActionHash, - getSummaryActionsFromTaskState, - getSummaryActionTimeBounds, - isActionOnInterval, -} from './rule_action_helper'; -import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; -import { ConnectorAdapter } from '../../connector_adapters/types'; +import { getSummaryActionsFromTaskState } from './lib'; import { withAlertingSpan } from '../lib'; import * as schedulers from './schedulers'; -interface LogAction { - id: string; - typeId: string; - alertId?: string; - alertGroup?: string; - alertSummary?: { - new: number; - ongoing: number; - recovered: number; - }; -} - -interface RunSummarizedActionArgs { - action: RuleAction; - summarizedAlerts: CombinedSummarizedAlerts; - spaceId: string; - bulkActions: EnqueueExecutionOptions[]; -} - -interface RunSystemActionArgs { - action: RuleSystemAction; - connectorAdapter: ConnectorAdapter; - summarizedAlerts: CombinedSummarizedAlerts; - rule: SanitizedRule; - ruleProducer: string; - spaceId: string; - bulkActions: EnqueueExecutionOptions[]; -} - -interface RunActionArgs< - State extends AlertInstanceState, - Context extends AlertInstanceContext, - ActionGroupIds extends string, - RecoveryActionGroupId extends string -> { - action: RuleAction; - alert: Alert; - ruleId: string; - spaceId: string; - bulkActions: EnqueueExecutionOptions[]; -} +const BULK_SCHEDULE_CHUNK_SIZE = 1000; export interface RunResult { throttledSummaryActions: ThrottledActions; @@ -110,9 +52,6 @@ export class ActionScheduler< > = []; private ephemeralActionsToSchedule: number; - private CHUNK_SIZE = 1000; - private ruleTypeActionGroups?: Map; - private previousStartedAt: Date | null; constructor( private readonly context: ActionSchedulerOptions< @@ -127,11 +66,6 @@ export class ActionScheduler< > ) { this.ephemeralActionsToSchedule = context.taskRunnerContext.maxEphemeralActionsPerRule; - this.ruleTypeActionGroups = new Map( - context.ruleType.actionGroups.map((actionGroup) => [actionGroup.id, actionGroup.name]) - ); - this.previousStartedAt = context.previousStartedAt; - for (const [_, scheduler] of Object.entries(schedulers)) { this.schedulers.push(new scheduler(context)); } @@ -148,148 +82,30 @@ export class ActionScheduler< summaryActions: this.context.taskInstance.state?.summaryActions, }); - const executables = []; + const allActionsToScheduleResult: ActionsToSchedule[] = []; for (const scheduler of this.schedulers) { - executables.push( - ...(await scheduler.generateExecutables({ alerts, throttledSummaryActions })) + allActionsToScheduleResult.push( + ...(await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions })) ); } - if (executables.length === 0) { + if (allActionsToScheduleResult.length === 0) { return { throttledSummaryActions }; } - const { - CHUNK_SIZE, - context: { - logger, - alertingEventLogger, - ruleRunMetricsStore, - taskRunnerContext: { actionsConfigMap }, - taskInstance: { - params: { spaceId, alertId: ruleId }, - }, - }, - } = this; - - const logActions: Record = {}; - const bulkActions: EnqueueExecutionOptions[] = []; - let bulkActionsResponse: ExecutionResponseItem[] = []; + const bulkScheduleRequest: EnqueueExecutionOptions[] = []; - this.context.ruleRunMetricsStore.incrementNumberOfGeneratedActions(executables.length); - - for (const { action, alert, summarizedAlerts } of executables) { - const { actionTypeId } = action; - - ruleRunMetricsStore.incrementNumberOfGeneratedActionsByConnectorType(actionTypeId); - if (ruleRunMetricsStore.hasReachedTheExecutableActionsLimit(actionsConfigMap)) { - ruleRunMetricsStore.setTriggeredActionsStatusByConnectorType({ - actionTypeId, - status: ActionsCompletion.PARTIAL, - }); - logger.debug( - `Rule "${this.context.rule.id}" skipped scheduling action "${action.id}" because the maximum number of allowed actions has been reached.` - ); - break; - } - - if ( - ruleRunMetricsStore.hasReachedTheExecutableActionsLimitByConnectorType({ - actionTypeId, - actionsConfigMap, - }) - ) { - if (!ruleRunMetricsStore.hasConnectorTypeReachedTheLimit(actionTypeId)) { - logger.debug( - `Rule "${this.context.rule.id}" skipped scheduling action "${action.id}" because the maximum number of allowed actions for connector type ${actionTypeId} has been reached.` - ); - } - ruleRunMetricsStore.setTriggeredActionsStatusByConnectorType({ - actionTypeId, - status: ActionsCompletion.PARTIAL, - }); - continue; - } - - if (!this.isExecutableAction(action)) { - this.context.logger.warn( - `Rule "${this.context.taskInstance.params.alertId}" skipped scheduling action "${action.id}" because it is disabled` - ); - continue; - } - - ruleRunMetricsStore.incrementNumberOfTriggeredActions(); - ruleRunMetricsStore.incrementNumberOfTriggeredActionsByConnectorType(actionTypeId); - - if (!this.isSystemAction(action) && summarizedAlerts) { - const defaultAction = action as RuleAction; - if (isActionOnInterval(action)) { - throttledSummaryActions[defaultAction.uuid!] = { date: new Date().toISOString() }; - } - - logActions[defaultAction.id] = await this.runSummarizedAction({ - action, - summarizedAlerts, - spaceId, - bulkActions, - }); - } else if (summarizedAlerts && this.isSystemAction(action)) { - const hasConnectorAdapter = this.context.taskRunnerContext.connectorAdapterRegistry.has( - action.actionTypeId - ); - /** - * System actions without an adapter - * cannot be executed - * - */ - if (!hasConnectorAdapter) { - this.context.logger.warn( - `Rule "${this.context.taskInstance.params.alertId}" skipped scheduling system action "${action.id}" because no connector adapter is configured` - ); - - continue; - } - - const connectorAdapter = this.context.taskRunnerContext.connectorAdapterRegistry.get( - action.actionTypeId - ); - logActions[action.id] = await this.runSystemAction({ - action, - connectorAdapter, - summarizedAlerts, - rule: this.context.rule, - ruleProducer: this.context.ruleType.producer, - spaceId, - bulkActions, - }); - } else if (!this.isSystemAction(action) && alert) { - const defaultAction = action as RuleAction; - logActions[defaultAction.id] = await this.runAction({ - action, - spaceId, - alert, - ruleId, - bulkActions, - }); - - const actionGroup = defaultAction.group; - if (!this.isRecoveredAlert(actionGroup)) { - if (isActionOnInterval(action)) { - alert.updateLastScheduledActions( - defaultAction.group as ActionGroupIds, - generateActionHash(action), - defaultAction.uuid - ); - } else { - alert.updateLastScheduledActions(defaultAction.group as ActionGroupIds); - } - alert.unscheduleActions(); - } - } + for (const result of allActionsToScheduleResult) { + await this.runActionAsEphemeralOrAddToBulkScheduleRequest({ + enqueueOptions: result.actionToEnqueue, + bulkScheduleRequest, + }); } - if (!!bulkActions.length) { - for (const c of chunk(bulkActions, CHUNK_SIZE)) { + let bulkScheduleResponse: ExecutionResponseItem[] = []; + + if (!!bulkScheduleRequest.length) { + for (const c of chunk(bulkScheduleRequest, BULK_SCHEDULE_CHUNK_SIZE)) { let enqueueResponse; try { enqueueResponse = await withAlertingSpan('alerting:bulk-enqueue-actions', () => @@ -302,7 +118,7 @@ export class ActionScheduler< throw createTaskRunError(e, TaskErrorSource.FRAMEWORK); } if (enqueueResponse.errors) { - bulkActionsResponse = bulkActionsResponse.concat( + bulkScheduleResponse = bulkScheduleResponse.concat( enqueueResponse.items.filter( (i) => i.response === ExecutionResponseType.QUEUED_ACTIONS_LIMIT_ERROR ) @@ -311,280 +127,53 @@ export class ActionScheduler< } } - if (!!bulkActionsResponse.length) { - for (const r of bulkActionsResponse) { + const actionsToNotLog: string[] = []; + if (!!bulkScheduleResponse.length) { + for (const r of bulkScheduleResponse) { if (r.response === ExecutionResponseType.QUEUED_ACTIONS_LIMIT_ERROR) { - ruleRunMetricsStore.setHasReachedQueuedActionsLimit(true); - ruleRunMetricsStore.decrementNumberOfTriggeredActions(); - ruleRunMetricsStore.decrementNumberOfTriggeredActionsByConnectorType(r.actionTypeId); - ruleRunMetricsStore.setTriggeredActionsStatusByConnectorType({ + this.context.ruleRunMetricsStore.setHasReachedQueuedActionsLimit(true); + this.context.ruleRunMetricsStore.decrementNumberOfTriggeredActions(); + this.context.ruleRunMetricsStore.decrementNumberOfTriggeredActionsByConnectorType( + r.actionTypeId + ); + this.context.ruleRunMetricsStore.setTriggeredActionsStatusByConnectorType({ actionTypeId: r.actionTypeId, status: ActionsCompletion.PARTIAL, }); - logger.debug( + this.context.logger.debug( `Rule "${this.context.rule.id}" skipped scheduling action "${r.id}" because the maximum number of queued actions has been reached.` ); - delete logActions[r.id]; + const uuid = r.uuid; + // uuid is typed as optional but in reality it is always + // populated - https://github.com/elastic/kibana/issues/195255 + if (uuid) { + actionsToNotLog.push(uuid); + } } } } - const logActionsValues = Object.values(logActions); - if (!!logActionsValues.length) { - for (const action of logActionsValues) { - alertingEventLogger.logAction(action); - } - } - - return { throttledSummaryActions }; - } - - private async runSummarizedAction({ - action, - summarizedAlerts, - spaceId, - bulkActions, - }: RunSummarizedActionArgs): Promise { - const { start, end } = getSummaryActionTimeBounds( - action, - this.context.rule.schedule, - this.previousStartedAt + const actionsToLog = allActionsToScheduleResult.filter( + (result) => result.actionToLog.uuid && !actionsToNotLog.includes(result.actionToLog.uuid) ); - const ruleUrl = this.buildRuleUrl(spaceId, start, end); - const actionToRun = { - ...action, - params: injectActionParams({ - actionTypeId: action.actionTypeId, - ruleUrl, - ruleName: this.context.rule.name, - actionParams: transformSummaryActionParams({ - alerts: summarizedAlerts, - rule: this.context.rule, - ruleTypeId: this.context.ruleType.id, - actionId: action.id, - actionParams: action.params, - spaceId, - actionsPlugin: this.context.taskRunnerContext.actionsPlugin, - actionTypeId: action.actionTypeId, - kibanaBaseUrl: this.context.taskRunnerContext.kibanaBaseUrl, - ruleUrl: ruleUrl?.absoluteUrl, - }), - }), - }; - await this.actionRunOrAddToBulk({ - enqueueOptions: this.getEnqueueOptions(actionToRun), - bulkActions, - }); - - return { - id: action.id, - typeId: action.actionTypeId, - alertSummary: { - new: summarizedAlerts.new.count, - ongoing: summarizedAlerts.ongoing.count, - recovered: summarizedAlerts.recovered.count, - }, - }; - } - - private async runSystemAction({ - action, - spaceId, - connectorAdapter, - summarizedAlerts, - rule, - ruleProducer, - bulkActions, - }: RunSystemActionArgs): Promise { - const ruleUrl = this.buildRuleUrl(spaceId); - - const connectorAdapterActionParams = connectorAdapter.buildActionParams({ - alerts: summarizedAlerts, - rule: { - id: rule.id, - tags: rule.tags, - name: rule.name, - consumer: rule.consumer, - producer: ruleProducer, - }, - ruleUrl: ruleUrl?.absoluteUrl, - spaceId, - params: action.params, - }); - - const actionToRun = Object.assign(action, { params: connectorAdapterActionParams }); - - await this.actionRunOrAddToBulk({ - enqueueOptions: this.getEnqueueOptions(actionToRun), - bulkActions, - }); - - return { - id: action.id, - typeId: action.actionTypeId, - alertSummary: { - new: summarizedAlerts.new.count, - ongoing: summarizedAlerts.ongoing.count, - recovered: summarizedAlerts.recovered.count, - }, - }; - } - - private async runAction({ - action, - spaceId, - alert, - ruleId, - bulkActions, - }: RunActionArgs): Promise { - const ruleUrl = this.buildRuleUrl(spaceId); - const executableAlert = alert!; - const actionGroup = action.group as ActionGroupIds; - const transformActionParamsOptions: TransformActionParamsOptions = { - actionsPlugin: this.context.taskRunnerContext.actionsPlugin, - alertId: ruleId, - alertType: this.context.ruleType.id, - actionTypeId: action.actionTypeId, - alertName: this.context.rule.name, - spaceId, - tags: this.context.rule.tags, - alertInstanceId: executableAlert.getId(), - alertUuid: executableAlert.getUuid(), - alertActionGroup: actionGroup, - alertActionGroupName: this.ruleTypeActionGroups!.get(actionGroup)!, - context: executableAlert.getContext(), - actionId: action.id, - state: executableAlert.getState(), - kibanaBaseUrl: this.context.taskRunnerContext.kibanaBaseUrl, - alertParams: this.context.rule.params, - actionParams: action.params, - flapping: executableAlert.getFlapping(), - ruleUrl: ruleUrl?.absoluteUrl, - }; - - if (executableAlert.isAlertAsData()) { - transformActionParamsOptions.aadAlert = executableAlert.getAlertAsData(); - } - const actionToRun = { - ...action, - params: injectActionParams({ - actionTypeId: action.actionTypeId, - ruleUrl, - ruleName: this.context.rule.name, - actionParams: transformActionParams(transformActionParamsOptions), - }), - }; - - await this.actionRunOrAddToBulk({ - enqueueOptions: this.getEnqueueOptions(actionToRun), - bulkActions, - }); - - return { - id: action.id, - typeId: action.actionTypeId, - alertId: alert.getId(), - alertGroup: action.group, - }; - } - - private isExecutableAction(action: RuleAction | RuleSystemAction) { - return this.context.taskRunnerContext.actionsPlugin.isActionExecutable( - action.id, - action.actionTypeId, - { - notifyUsage: true, + if (!!actionsToLog.length) { + for (const action of actionsToLog) { + this.context.alertingEventLogger.logAction(action.actionToLog); } - ); - } - - private isSystemAction(action?: RuleAction | RuleSystemAction): action is RuleSystemAction { - return this.context.taskRunnerContext.actionsPlugin.isSystemActionConnector(action?.id ?? ''); - } - - private isRecoveredAlert(actionGroup: string) { - return actionGroup === this.context.ruleType.recoveryActionGroup.id; - } - - private buildRuleUrl(spaceId: string, start?: number, end?: number): RuleUrl | undefined { - if (!this.context.taskRunnerContext.kibanaBaseUrl) { - return; } - const relativePath = this.context.ruleType.getViewInAppRelativeUrl - ? this.context.ruleType.getViewInAppRelativeUrl({ rule: this.context.rule, start, end }) - : `${triggersActionsRoute}${getRuleDetailsRoute(this.context.rule.id)}`; - - try { - const basePathname = new URL(this.context.taskRunnerContext.kibanaBaseUrl).pathname; - const basePathnamePrefix = basePathname !== '/' ? `${basePathname}` : ''; - const spaceIdSegment = spaceId !== 'default' ? `/s/${spaceId}` : ''; - - const ruleUrl = new URL( - [basePathnamePrefix, spaceIdSegment, relativePath].join(''), - this.context.taskRunnerContext.kibanaBaseUrl - ); - - return { - absoluteUrl: ruleUrl.toString(), - kibanaBaseUrl: this.context.taskRunnerContext.kibanaBaseUrl, - basePathname: basePathnamePrefix, - spaceIdSegment, - relativePath, - }; - } catch (error) { - this.context.logger.debug( - `Rule "${this.context.rule.id}" encountered an error while constructing the rule.url variable: ${error.message}` - ); - return; - } - } - - private getEnqueueOptions(action: RuleAction | RuleSystemAction): EnqueueExecutionOptions { - const { - context: { - apiKey, - ruleConsumer, - executionId, - taskInstance: { - params: { spaceId, alertId: ruleId }, - }, - }, - } = this; - - const namespace = spaceId === 'default' ? {} : { namespace: spaceId }; - return { - id: action.id, - params: action.params, - spaceId, - apiKey: apiKey ?? null, - consumer: ruleConsumer, - source: asSavedObjectExecutionSource({ - id: ruleId, - type: RULE_SAVED_OBJECT_TYPE, - }), - executionId, - relatedSavedObjects: [ - { - id: ruleId, - type: RULE_SAVED_OBJECT_TYPE, - namespace: namespace.namespace, - typeId: this.context.ruleType.id, - }, - ], - actionTypeId: action.actionTypeId, - }; + return { throttledSummaryActions }; } - private async actionRunOrAddToBulk({ + private async runActionAsEphemeralOrAddToBulkScheduleRequest({ enqueueOptions, - bulkActions, + bulkScheduleRequest, }: { enqueueOptions: EnqueueExecutionOptions; - bulkActions: EnqueueExecutionOptions[]; + bulkScheduleRequest: EnqueueExecutionOptions[]; }) { if ( this.context.taskRunnerContext.supportsEphemeralTasks && @@ -595,11 +184,11 @@ export class ActionScheduler< await this.context.actionsClient!.ephemeralEnqueuedExecution(enqueueOptions); } catch (err) { if (isEphemeralTaskRejectedDueToCapacityError(err)) { - bulkActions.push(enqueueOptions); + bulkScheduleRequest.push(enqueueOptions); } } } else { - bulkActions.push(enqueueOptions); + bulkScheduleRequest.push(enqueueOptions); } } } diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/build_rule_url.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/build_rule_url.test.ts new file mode 100644 index 0000000000000..cb1f3c60fd992 --- /dev/null +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/build_rule_url.test.ts @@ -0,0 +1,141 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { buildRuleUrl } from './build_rule_url'; +import { getRule } from '../test_fixtures'; + +const logger = loggingSystemMock.create().get(); +const rule = getRule(); + +describe('buildRuleUrl', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('should return undefined if kibanaBaseUrl is not provided', () => { + expect( + buildRuleUrl({ + kibanaBaseUrl: undefined, + logger, + rule, + spaceId: 'default', + }) + ).toBeUndefined(); + }); + + test('should return the expected URL', () => { + expect( + buildRuleUrl({ + kibanaBaseUrl: 'http://localhost:5601', + logger, + rule, + spaceId: 'default', + }) + ).toEqual({ + absoluteUrl: + 'http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1', + basePathname: '', + kibanaBaseUrl: 'http://localhost:5601', + relativePath: '/app/management/insightsAndAlerting/triggersActions/rule/1', + spaceIdSegment: '', + }); + }); + + test('should return the expected URL for custom space', () => { + expect( + buildRuleUrl({ + kibanaBaseUrl: 'http://localhost:5601', + logger, + rule, + spaceId: 'my-special-space', + }) + ).toEqual({ + absoluteUrl: + 'http://localhost:5601/s/my-special-space/app/management/insightsAndAlerting/triggersActions/rule/1', + basePathname: '', + kibanaBaseUrl: 'http://localhost:5601', + relativePath: '/app/management/insightsAndAlerting/triggersActions/rule/1', + spaceIdSegment: '/s/my-special-space', + }); + }); + + test('should return the expected URL when getViewInAppRelativeUrl is defined', () => { + expect( + buildRuleUrl({ + getViewInAppRelativeUrl: ({ rule: r }) => `/app/test/my-custom-rule-page/${r.id}`, + kibanaBaseUrl: 'http://localhost:5601', + logger, + rule, + spaceId: 'default', + }) + ).toEqual({ + absoluteUrl: 'http://localhost:5601/app/test/my-custom-rule-page/1', + basePathname: '', + kibanaBaseUrl: 'http://localhost:5601', + relativePath: '/app/test/my-custom-rule-page/1', + spaceIdSegment: '', + }); + }); + + test('should return the expected URL when start, end and getViewInAppRelativeUrl is defined', () => { + expect( + buildRuleUrl({ + end: 987654321, + getViewInAppRelativeUrl: ({ rule: r, start: s, end: e }) => + `/app/test/my-custom-rule-page/${r.id}?start=${s}&end=${e}`, + kibanaBaseUrl: 'http://localhost:5601', + logger, + rule, + start: 123456789, + spaceId: 'default', + }) + ).toEqual({ + absoluteUrl: + 'http://localhost:5601/app/test/my-custom-rule-page/1?start=123456789&end=987654321', + basePathname: '', + kibanaBaseUrl: 'http://localhost:5601', + relativePath: '/app/test/my-custom-rule-page/1?start=123456789&end=987654321', + spaceIdSegment: '', + }); + }); + + test('should return the expected URL when start and end are defined but getViewInAppRelativeUrl is undefined', () => { + expect( + buildRuleUrl({ + end: 987654321, + kibanaBaseUrl: 'http://localhost:5601', + logger, + rule, + start: 123456789, + spaceId: 'default', + }) + ).toEqual({ + absoluteUrl: + 'http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1', + basePathname: '', + kibanaBaseUrl: 'http://localhost:5601', + relativePath: '/app/management/insightsAndAlerting/triggersActions/rule/1', + spaceIdSegment: '', + }); + }); + + test('should return undefined if base url is invalid', () => { + expect( + buildRuleUrl({ + kibanaBaseUrl: 'foo-url', + logger, + rule, + spaceId: 'default', + }) + ).toBeUndefined(); + + expect(logger.debug).toHaveBeenCalledWith( + `Rule "1" encountered an error while constructing the rule.url variable: Invalid URL: foo-url` + ); + }); +}); diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/build_rule_url.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/build_rule_url.ts new file mode 100644 index 0000000000000..3df27a512c7f9 --- /dev/null +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/build_rule_url.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Logger } from '@kbn/logging'; +import { RuleTypeParams, SanitizedRule } from '@kbn/alerting-types'; +import { getRuleDetailsRoute, triggersActionsRoute } from '@kbn/rule-data-utils'; +import { GetViewInAppRelativeUrlFn } from '../../../types'; + +interface BuildRuleUrlOpts { + end?: number; + getViewInAppRelativeUrl?: GetViewInAppRelativeUrlFn; + kibanaBaseUrl: string | undefined; + logger: Logger; + rule: SanitizedRule; + spaceId: string; + start?: number; +} + +interface BuildRuleUrlResult { + absoluteUrl: string; + basePathname: string; + kibanaBaseUrl: string; + relativePath: string; + spaceIdSegment: string; +} + +export const buildRuleUrl = ( + opts: BuildRuleUrlOpts +): BuildRuleUrlResult | undefined => { + if (!opts.kibanaBaseUrl) { + return; + } + + const relativePath = opts.getViewInAppRelativeUrl + ? opts.getViewInAppRelativeUrl({ rule: opts.rule, start: opts.start, end: opts.end }) + : `${triggersActionsRoute}${getRuleDetailsRoute(opts.rule.id)}`; + + try { + const basePathname = new URL(opts.kibanaBaseUrl).pathname; + const basePathnamePrefix = basePathname !== '/' ? `${basePathname}` : ''; + const spaceIdSegment = opts.spaceId !== 'default' ? `/s/${opts.spaceId}` : ''; + + const ruleUrl = new URL( + [basePathnamePrefix, spaceIdSegment, relativePath].join(''), + opts.kibanaBaseUrl + ); + + return { + absoluteUrl: ruleUrl.toString(), + kibanaBaseUrl: opts.kibanaBaseUrl, + basePathname: basePathnamePrefix, + spaceIdSegment, + relativePath, + }; + } catch (error) { + opts.logger.debug( + `Rule "${opts.rule.id}" encountered an error while constructing the rule.url variable: ${error.message}` + ); + return; + } +}; diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/format_action_to_enqueue.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/format_action_to_enqueue.test.ts new file mode 100644 index 0000000000000..02ff513c5b639 --- /dev/null +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/format_action_to_enqueue.test.ts @@ -0,0 +1,222 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RULE_SAVED_OBJECT_TYPE } from '../../..'; +import { formatActionToEnqueue } from './format_action_to_enqueue'; + +describe('formatActionToEnqueue', () => { + test('should format a rule action as expected', () => { + expect( + formatActionToEnqueue({ + action: { + id: '1', + group: 'default', + actionTypeId: 'test', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + uuid: '111-111', + }, + apiKey: 'MTIzOmFiYw==', + executionId: '123', + ruleConsumer: 'rule-consumer', + ruleId: 'aaa', + ruleTypeId: 'security-rule', + spaceId: 'default', + }) + ).toEqual({ + id: '1', + uuid: '111-111', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + spaceId: 'default', + apiKey: 'MTIzOmFiYw==', + consumer: 'rule-consumer', + source: { + source: { + id: 'aaa', + type: RULE_SAVED_OBJECT_TYPE, + }, + type: 'SAVED_OBJECT', + }, + executionId: '123', + relatedSavedObjects: [ + { + id: 'aaa', + type: RULE_SAVED_OBJECT_TYPE, + namespace: undefined, + typeId: 'security-rule', + }, + ], + actionTypeId: 'test', + }); + }); + + test('should format a rule action with null apiKey as expected', () => { + expect( + formatActionToEnqueue({ + action: { + id: '1', + group: 'default', + actionTypeId: 'test', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + uuid: '111-111', + }, + apiKey: null, + executionId: '123', + ruleConsumer: 'rule-consumer', + ruleId: 'aaa', + ruleTypeId: 'security-rule', + spaceId: 'default', + }) + ).toEqual({ + id: '1', + uuid: '111-111', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + spaceId: 'default', + apiKey: null, + consumer: 'rule-consumer', + source: { + source: { + id: 'aaa', + type: RULE_SAVED_OBJECT_TYPE, + }, + type: 'SAVED_OBJECT', + }, + executionId: '123', + relatedSavedObjects: [ + { + id: 'aaa', + type: RULE_SAVED_OBJECT_TYPE, + namespace: undefined, + typeId: 'security-rule', + }, + ], + actionTypeId: 'test', + }); + }); + + test('should format a rule action in a custom space as expected', () => { + expect( + formatActionToEnqueue({ + action: { + id: '1', + group: 'default', + actionTypeId: 'test', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + uuid: '111-111', + }, + apiKey: 'MTIzOmFiYw==', + executionId: '123', + ruleConsumer: 'rule-consumer', + ruleId: 'aaa', + ruleTypeId: 'security-rule', + spaceId: 'my-special-space', + }) + ).toEqual({ + id: '1', + uuid: '111-111', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + spaceId: 'my-special-space', + apiKey: 'MTIzOmFiYw==', + consumer: 'rule-consumer', + source: { + source: { + id: 'aaa', + type: RULE_SAVED_OBJECT_TYPE, + }, + type: 'SAVED_OBJECT', + }, + executionId: '123', + relatedSavedObjects: [ + { + id: 'aaa', + type: RULE_SAVED_OBJECT_TYPE, + namespace: 'my-special-space', + typeId: 'security-rule', + }, + ], + actionTypeId: 'test', + }); + }); + + test('should format a system action as expected', () => { + expect( + formatActionToEnqueue({ + action: { + id: '1', + actionTypeId: '.test-system-action', + params: { myParams: 'test' }, + uuid: 'xxxyyyyzzzz', + }, + apiKey: 'MTIzOmFiYw==', + executionId: '123', + ruleConsumer: 'rule-consumer', + ruleId: 'aaa', + ruleTypeId: 'security-rule', + spaceId: 'default', + }) + ).toEqual({ + id: '1', + uuid: 'xxxyyyyzzzz', + params: { myParams: 'test' }, + spaceId: 'default', + apiKey: 'MTIzOmFiYw==', + consumer: 'rule-consumer', + source: { + source: { + id: 'aaa', + type: RULE_SAVED_OBJECT_TYPE, + }, + type: 'SAVED_OBJECT', + }, + executionId: '123', + relatedSavedObjects: [ + { + id: 'aaa', + type: RULE_SAVED_OBJECT_TYPE, + namespace: undefined, + typeId: 'security-rule', + }, + ], + actionTypeId: '.test-system-action', + }); + }); +}); diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/format_action_to_enqueue.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/format_action_to_enqueue.ts new file mode 100644 index 0000000000000..af560a19ab9be --- /dev/null +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/format_action_to_enqueue.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RuleAction, RuleSystemAction } from '@kbn/alerting-types'; +import { asSavedObjectExecutionSource } from '@kbn/actions-plugin/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../..'; + +interface FormatActionToEnqueueOpts { + action: RuleAction | RuleSystemAction; + apiKey: string | null; + executionId: string; + ruleConsumer: string; + ruleId: string; + ruleTypeId: string; + spaceId: string; +} + +export const formatActionToEnqueue = (opts: FormatActionToEnqueueOpts) => { + const { action, apiKey, executionId, ruleConsumer, ruleId, ruleTypeId, spaceId } = opts; + + const namespace = spaceId === 'default' ? {} : { namespace: spaceId }; + return { + id: action.id, + uuid: action.uuid, + params: action.params, + spaceId, + apiKey: apiKey ?? null, + consumer: ruleConsumer, + source: asSavedObjectExecutionSource({ + id: ruleId, + type: RULE_SAVED_OBJECT_TYPE, + }), + executionId, + relatedSavedObjects: [ + { + id: ruleId, + type: RULE_SAVED_OBJECT_TYPE, + namespace: namespace.namespace, + typeId: ruleTypeId, + }, + ], + actionTypeId: action.actionTypeId, + }; +}; diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/get_summarized_alerts.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/get_summarized_alerts.test.ts similarity index 95% rename from x-pack/plugins/alerting/server/task_runner/action_scheduler/get_summarized_alerts.test.ts rename to x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/get_summarized_alerts.test.ts index 9afd0647094eb..036c49c51d1be 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/get_summarized_alerts.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/get_summarized_alerts.test.ts @@ -6,10 +6,10 @@ */ import { getSummarizedAlerts } from './get_summarized_alerts'; -import { alertsClientMock } from '../../alerts_client/alerts_client.mock'; -import { mockAAD } from '../fixtures'; +import { alertsClientMock } from '../../../alerts_client/alerts_client.mock'; +import { mockAAD } from '../../fixtures'; import { ALERT_UUID } from '@kbn/rule-data-utils'; -import { generateAlert } from './test_fixtures'; +import { generateAlert } from '../test_fixtures'; import { getErrorSource } from '@kbn/task-manager-plugin/server/task_running'; const alertsClient = alertsClientMock.create(); diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/get_summarized_alerts.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/get_summarized_alerts.ts similarity index 98% rename from x-pack/plugins/alerting/server/task_runner/action_scheduler/get_summarized_alerts.ts rename to x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/get_summarized_alerts.ts index df667a3e20775..00e155856d946 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/get_summarized_alerts.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/get_summarized_alerts.ts @@ -7,13 +7,13 @@ import { ALERT_UUID } from '@kbn/rule-data-utils'; import { createTaskRunError, TaskErrorSource } from '@kbn/task-manager-plugin/server'; -import { GetSummarizedAlertsParams, IAlertsClient } from '../../alerts_client/types'; +import { GetSummarizedAlertsParams, IAlertsClient } from '../../../alerts_client/types'; import { AlertInstanceContext, AlertInstanceState, CombinedSummarizedAlerts, RuleAlertData, -} from '../../types'; +} from '../../../types'; interface GetSummarizedAlertsOpts< State extends AlertInstanceState, diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/index.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/index.ts new file mode 100644 index 0000000000000..1bd78f302d00c --- /dev/null +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { buildRuleUrl } from './build_rule_url'; +export { formatActionToEnqueue } from './format_action_to_enqueue'; +export { getSummarizedAlerts } from './get_summarized_alerts'; +export { + isSummaryAction, + isActionOnInterval, + isSummaryActionThrottled, + generateActionHash, + getSummaryActionsFromTaskState, + getSummaryActionTimeBounds, + logNumberOfFilteredAlerts, +} from './rule_action_helper'; +export { shouldScheduleAction } from './should_schedule_action'; diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/rule_action_helper.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/rule_action_helper.test.ts similarity index 99% rename from x-pack/plugins/alerting/server/task_runner/action_scheduler/rule_action_helper.test.ts rename to x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/rule_action_helper.test.ts index cc8a0a1b0cde5..1adb68a951351 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/rule_action_helper.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/rule_action_helper.test.ts @@ -7,7 +7,7 @@ import { Logger } from '@kbn/logging'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -import { RuleAction } from '../../types'; +import { RuleAction } from '../../../types'; import { generateActionHash, getSummaryActionsFromTaskState, diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/rule_action_helper.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/rule_action_helper.ts similarity index 99% rename from x-pack/plugins/alerting/server/task_runner/action_scheduler/rule_action_helper.ts rename to x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/rule_action_helper.ts index 67223b0728689..c3ef79b3086d8 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/rule_action_helper.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/rule_action_helper.ts @@ -12,7 +12,7 @@ import { RuleAction, RuleNotifyWhenTypeValues, ThrottledActions, -} from '../../../common'; +} from '../../../../common'; export const isSummaryAction = (action?: RuleAction) => { return action?.frequency?.summary ?? false; diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/should_schedule_action.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/should_schedule_action.test.ts new file mode 100644 index 0000000000000..7ebd65fab005d --- /dev/null +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/should_schedule_action.test.ts @@ -0,0 +1,195 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { shouldScheduleAction } from './should_schedule_action'; +import { ruleRunMetricsStoreMock } from '../../../lib/rule_run_metrics_store.mock'; +import { ActionsCompletion } from '@kbn/alerting-state-types'; + +const logger = loggingSystemMock.create().get(); +const ruleRunMetricsStore = ruleRunMetricsStoreMock.create(); + +describe('shouldScheduleAction', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('should return false if the the limit of executable actions has been reached', () => { + ruleRunMetricsStore.hasReachedTheExecutableActionsLimit.mockReturnValueOnce(true); + expect( + shouldScheduleAction({ + action: { + id: '1', + group: 'default', + actionTypeId: 'test-action-type-id', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + uuid: '111-111', + }, + actionsConfigMap: { + default: { max: 4 }, + 'test-action-type-id': { max: 2 }, + }, + isActionExecutable: () => true, + logger, + ruleId: '1', + ruleRunMetricsStore, + }) + ).toEqual(false); + + expect(ruleRunMetricsStore.setTriggeredActionsStatusByConnectorType).toHaveBeenCalledWith({ + actionTypeId: 'test-action-type-id', + status: ActionsCompletion.PARTIAL, + }); + expect(logger.debug).toHaveBeenCalledWith( + `Rule "1" skipped scheduling action "1" because the maximum number of allowed actions has been reached.` + ); + }); + + test('should return false if the the limit of executable actions for this action type has been reached', () => { + ruleRunMetricsStore.hasReachedTheExecutableActionsLimitByConnectorType.mockReturnValueOnce( + true + ); + ruleRunMetricsStore.hasConnectorTypeReachedTheLimit.mockReturnValueOnce(true); + expect( + shouldScheduleAction({ + action: { + id: '1', + group: 'default', + actionTypeId: 'test-action-type-id', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + uuid: '111-111', + }, + actionsConfigMap: { + default: { max: 4 }, + 'test-action-type-id': { max: 2 }, + }, + isActionExecutable: () => true, + logger, + ruleId: '1', + ruleRunMetricsStore, + }) + ).toEqual(false); + + expect(ruleRunMetricsStore.setTriggeredActionsStatusByConnectorType).toHaveBeenCalledWith({ + actionTypeId: 'test-action-type-id', + status: ActionsCompletion.PARTIAL, + }); + expect(logger.debug).not.toHaveBeenCalled(); + }); + + test('should return false and log if the the limit of executable actions for this action type has been reached', () => { + ruleRunMetricsStore.hasReachedTheExecutableActionsLimitByConnectorType.mockReturnValueOnce( + true + ); + ruleRunMetricsStore.hasConnectorTypeReachedTheLimit.mockReturnValueOnce(false); + expect( + shouldScheduleAction({ + action: { + id: '1', + group: 'default', + actionTypeId: 'test-action-type-id', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + uuid: '111-111', + }, + actionsConfigMap: { + default: { max: 4 }, + 'test-action-type-id': { max: 2 }, + }, + isActionExecutable: () => true, + logger, + ruleId: '1', + ruleRunMetricsStore, + }) + ).toEqual(false); + + expect(ruleRunMetricsStore.setTriggeredActionsStatusByConnectorType).toHaveBeenCalledWith({ + actionTypeId: 'test-action-type-id', + status: ActionsCompletion.PARTIAL, + }); + expect(logger.debug).toHaveBeenCalledWith( + `Rule "1" skipped scheduling action "1" because the maximum number of allowed actions for connector type test-action-type-id has been reached.` + ); + }); + + test('should return false the action is not executable', () => { + expect( + shouldScheduleAction({ + action: { + id: '1', + group: 'default', + actionTypeId: 'test-action-type-id', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + uuid: '111-111', + }, + actionsConfigMap: { + default: { max: 4 }, + 'test-action-type-id': { max: 2 }, + }, + isActionExecutable: () => false, + logger, + ruleId: '1', + ruleRunMetricsStore, + }) + ).toEqual(false); + + expect(logger.warn).toHaveBeenCalledWith( + `Rule "1" skipped scheduling action "1" because it is disabled` + ); + }); + + test('should return true if the action is executable and no limits have been reached', () => { + expect( + shouldScheduleAction({ + action: { + id: '1', + group: 'default', + actionTypeId: 'test-action-type-id', + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + uuid: '111-111', + }, + actionsConfigMap: { + default: { max: 4 }, + 'test-action-type-id': { max: 2 }, + }, + isActionExecutable: () => true, + logger, + ruleId: '1', + ruleRunMetricsStore, + }) + ).toEqual(true); + }); +}); diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/should_schedule_action.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/should_schedule_action.ts new file mode 100644 index 0000000000000..99fa3c42ad3df --- /dev/null +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/lib/should_schedule_action.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Logger } from '@kbn/logging'; +import { ActionsCompletion } from '@kbn/alerting-state-types'; +import { RuleAction, RuleSystemAction } from '@kbn/alerting-types'; +import { RuleRunMetricsStore } from '../../../lib/rule_run_metrics_store'; +import { ActionsConfigMap } from '../../../lib/get_actions_config_map'; + +interface ShouldScheduleActionOpts { + action: RuleAction | RuleSystemAction; + actionsConfigMap: ActionsConfigMap; + isActionExecutable( + actionId: string, + actionTypeId: string, + options?: { notifyUsage: boolean } + ): boolean; + logger: Logger; + ruleId: string; + ruleRunMetricsStore: RuleRunMetricsStore; +} + +export const shouldScheduleAction = (opts: ShouldScheduleActionOpts): boolean => { + const { actionsConfigMap, action, logger, ruleRunMetricsStore } = opts; + + // keep track of how many actions we want to schedule by connector type + ruleRunMetricsStore.incrementNumberOfGeneratedActionsByConnectorType(action.actionTypeId); + + if (ruleRunMetricsStore.hasReachedTheExecutableActionsLimit(actionsConfigMap)) { + ruleRunMetricsStore.setTriggeredActionsStatusByConnectorType({ + actionTypeId: action.actionTypeId, + status: ActionsCompletion.PARTIAL, + }); + logger.debug( + `Rule "${opts.ruleId}" skipped scheduling action "${action.id}" because the maximum number of allowed actions has been reached.` + ); + return false; + } + + if ( + ruleRunMetricsStore.hasReachedTheExecutableActionsLimitByConnectorType({ + actionTypeId: action.actionTypeId, + actionsConfigMap, + }) + ) { + if (!ruleRunMetricsStore.hasConnectorTypeReachedTheLimit(action.actionTypeId)) { + logger.debug( + `Rule "${opts.ruleId}" skipped scheduling action "${action.id}" because the maximum number of allowed actions for connector type ${action.actionTypeId} has been reached.` + ); + } + ruleRunMetricsStore.setTriggeredActionsStatusByConnectorType({ + actionTypeId: action.actionTypeId, + status: ActionsCompletion.PARTIAL, + }); + return false; + } + + if (!opts.isActionExecutable(action.id, action.actionTypeId, { notifyUsage: true })) { + logger.warn( + `Rule "${opts.ruleId}" skipped scheduling action "${action.id}" because it is disabled` + ); + return false; + } + + return true; +}; diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/per_alert_action_scheduler.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/per_alert_action_scheduler.test.ts index 53e75245d94d0..99a693133a2a6 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/per_alert_action_scheduler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/per_alert_action_scheduler.test.ts @@ -16,6 +16,12 @@ import { PerAlertActionScheduler } from './per_alert_action_scheduler'; import { getRule, getRuleType, getDefaultSchedulerContext, generateAlert } from '../test_fixtures'; import { SanitizedRuleAction } from '@kbn/alerting-types'; import { ALERT_UUID } from '@kbn/rule-data-utils'; +import { Alert } from '../../../alert'; +import { + ActionsCompletion, + AlertInstanceContext, + AlertInstanceState, +} from '@kbn/alerting-state-types'; const alertingEventLogger = alertingEventLoggerMock.create(); const actionsClient = actionsClientMock.create(); @@ -25,9 +31,10 @@ const logger = loggingSystemMock.create().get(); let ruleRunMetricsStore: RuleRunMetricsStore; const rule = getRule({ + id: 'rule-id-1', actions: [ { - id: '1', + id: 'action-1', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onActiveAlert', throttle: null }, @@ -41,7 +48,7 @@ const rule = getRule({ uuid: '111-111', }, { - id: '2', + id: 'action-2', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onActiveAlert', throttle: null }, @@ -55,7 +62,7 @@ const rule = getRule({ uuid: '222-222', }, { - id: '3', + id: 'action-3', group: 'default', actionTypeId: 'test', frequency: { summary: true, notifyWhen: 'onActiveAlert' }, @@ -84,6 +91,21 @@ const getSchedulerContext = (params = {}) => { return { ...defaultSchedulerContext, rule, ...params, ruleRunMetricsStore }; }; +const getResult = (actionId: string, alertId: string, actionUuid: string) => ({ + actionToEnqueue: { + actionTypeId: 'test', + apiKey: 'MTIzOmFiYw==', + consumer: 'rule-consumer', + executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + id: actionId, + uuid: actionUuid, + relatedSavedObjects: [{ id: 'rule-id-1', namespace: 'test1', type: 'alert', typeId: 'test' }], + source: { source: { id: 'rule-id-1', type: 'alert' }, type: 'SAVED_OBJECT' }, + spaceId: 'test1', + }, + actionToLog: { alertGroup: 'default', alertId, id: actionId, uuid: actionUuid, typeId: 'test' }, +}); + let clock: sinon.SinonFakeTimers; describe('Per-Alert Action Scheduler', () => { @@ -93,6 +115,7 @@ describe('Per-Alert Action Scheduler', () => { beforeEach(() => { jest.resetAllMocks(); + jest.clearAllMocks(); mockActionsPlugin.isActionTypeEnabled.mockReturnValue(true); mockActionsPlugin.isActionExecutable.mockReturnValue(true); mockActionsPlugin.getActionsClientWithRequest.mockResolvedValue(actionsClient); @@ -163,67 +186,93 @@ describe('Per-Alert Action Scheduler', () => { expect(scheduler.actions).toEqual([actions[0]]); expect(logger.error).toHaveBeenCalledTimes(1); expect(logger.error).toHaveBeenCalledWith( - `Skipping action \"2\" for rule \"1\" because the rule type \"Test\" does not support alert-as-data.` + `Skipping action \"2\" for rule \"rule-id-1\" because the rule type \"Test\" does not support alert-as-data.` ); }); - describe('generateExecutables', () => { - const newAlert1 = generateAlert({ id: 1 }); - const newAlert2 = generateAlert({ id: 2 }); - const alerts = { ...newAlert1, ...newAlert2 }; + describe('getActionsToSchedule', () => { + let newAlert1: Record< + string, + Alert + >; + let newAlert2: Record< + string, + Alert + >; + let alerts: Record< + string, + Alert + >; + + beforeEach(() => { + newAlert1 = generateAlert({ id: 1 }); + newAlert2 = generateAlert({ id: 2 }); + alerts = { ...newAlert1, ...newAlert2 }; + }); - test('should generate executable for each alert and each action', async () => { + test('should create action to schedule for each alert and each action', async () => { + // 2 per-alert actions * 2 alerts = 4 actions to schedule const scheduler = new PerAlertActionScheduler(getSchedulerContext()); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); expect(logger.debug).not.toHaveBeenCalled(); - expect(executables).toHaveLength(4); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(4); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(4); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 4, + numberOfTriggeredActions: 4, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['1'] }, - { action: rule.actions[0], alert: alerts['2'] }, - { action: rule.actions[1], alert: alerts['1'] }, - { action: rule.actions[1], alert: alerts['2'] }, + expect(results).toHaveLength(4); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-2', '1', '222-222'), + getResult('action-2', '2', '222-222'), ]); }); - test('should skip generating executable when alert has maintenance window', async () => { + test('should skip creating actions to schedule when alert has maintenance window', async () => { + // 2 per-alert actions * 2 alerts = 4 actions to schedule + // but alert 1 has maintenance window, so only actions for alert 2 should be scheduled const scheduler = new PerAlertActionScheduler(getSchedulerContext()); const newAlertWithMaintenanceWindow = generateAlert({ id: 1, maintenanceWindowIds: ['mw-1'], }); const alertsWithMaintenanceWindow = { ...newAlertWithMaintenanceWindow, ...newAlert2 }; - const executables = await scheduler.generateExecutables({ - alerts: alertsWithMaintenanceWindow, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts: alertsWithMaintenanceWindow }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); expect(logger.debug).toHaveBeenCalledTimes(2); expect(logger.debug).toHaveBeenNthCalledWith( 1, - `no scheduling of summary actions \"1\" for rule \"1\": has active maintenance windows mw-1.` + `no scheduling of summary actions \"action-1\" for rule \"rule-id-1\": has active maintenance windows mw-1.` ); expect(logger.debug).toHaveBeenNthCalledWith( 2, - `no scheduling of summary actions \"2\" for rule \"1\": has active maintenance windows mw-1.` + `no scheduling of summary actions \"action-2\" for rule \"rule-id-1\": has active maintenance windows mw-1.` ); - expect(executables).toHaveLength(2); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(2); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 2, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['2'] }, - { action: rule.actions[1], alert: alerts['2'] }, + expect(results).toHaveLength(2); + expect(results).toEqual([ + getResult('action-1', '2', '111-111'), + getResult('action-2', '2', '222-222'), ]); }); - test('should skip generating executable when alert has invalid action group', async () => { + test('should skip creating actions to schedule when alert has invalid action group', async () => { + // 2 per-alert actions * 2 alerts = 4 actions to schedule + // but alert 1 has invalid action group, so only actions for alert 2 should be scheduled const scheduler = new PerAlertActionScheduler(getSchedulerContext()); const newAlertInvalidActionGroup = generateAlert({ id: 1, @@ -231,9 +280,8 @@ describe('Per-Alert Action Scheduler', () => { group: 'invalid', }); const alertsWithInvalidActionGroup = { ...newAlertInvalidActionGroup, ...newAlert2 }; - const executables = await scheduler.generateExecutables({ + const results = await scheduler.getActionsToSchedule({ alerts: alertsWithInvalidActionGroup, - throttledSummaryActions: {}, }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); @@ -247,15 +295,23 @@ describe('Per-Alert Action Scheduler', () => { `Invalid action group \"invalid\" for rule \"test\".` ); - expect(executables).toHaveLength(2); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(2); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 2, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['2'] }, - { action: rule.actions[1], alert: alerts['2'] }, + expect(results).toHaveLength(2); + expect(results).toEqual([ + getResult('action-1', '2', '111-111'), + getResult('action-2', '2', '222-222'), ]); }); - test('should skip generating executable when alert has pending recovered count greater than 0 and notifyWhen is onActiveAlert', async () => { + test('should skip creating actions to schedule when alert has pending recovered count greater than 0 and notifyWhen is onActiveAlert', async () => { + // 2 per-alert actions * 2 alerts = 4 actions to schedule + // but alert 1 has a pending recovered count > 0 & notifyWhen is onActiveAlert, so only actions for alert 2 should be scheduled const scheduler = new PerAlertActionScheduler(getSchedulerContext()); const newAlertWithPendingRecoveredCount = generateAlert({ id: 1, @@ -265,23 +321,31 @@ describe('Per-Alert Action Scheduler', () => { ...newAlertWithPendingRecoveredCount, ...newAlert2, }; - const executables = await scheduler.generateExecutables({ + const results = await scheduler.getActionsToSchedule({ alerts: alertsWithPendingRecoveredCount, - throttledSummaryActions: {}, }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); - expect(executables).toHaveLength(2); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['2'] }, - { action: rule.actions[1], alert: alerts['2'] }, + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(2); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 2, + }); + + expect(results).toHaveLength(2); + expect(results).toEqual([ + getResult('action-1', '2', '111-111'), + getResult('action-2', '2', '222-222'), ]); }); - test('should skip generating executable when alert has pending recovered count greater than 0 and notifyWhen is onThrottleInterval', async () => { + test('should skip creating actions to schedule when alert has pending recovered count greater than 0 and notifyWhen is onThrottleInterval', async () => { + // 2 per-alert actions * 2 alerts = 4 actions to schedule + // but alert 1 has a pending recovered count > 0 & notifyWhen is onThrottleInterval, so only actions for alert 2 should be scheduled const onThrottleIntervalAction: SanitizedRuleAction = { - id: '2', + id: 'action-4', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onThrottleInterval', throttle: '1h' }, @@ -292,43 +356,45 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '222-222', + uuid: '444-444', }; const scheduler = new PerAlertActionScheduler({ ...getSchedulerContext(), rule: { ...rule, actions: [rule.actions[0], onThrottleIntervalAction] }, }); - const newAlertWithPendingRecoveredCount = generateAlert({ - id: 1, - pendingRecoveredCount: 3, - }); + const newAlertWithPendingRecoveredCount = generateAlert({ id: 1, pendingRecoveredCount: 3 }); const alertsWithPendingRecoveredCount = { ...newAlertWithPendingRecoveredCount, ...newAlert2, }; - const executables = await scheduler.generateExecutables({ + const results = await scheduler.getActionsToSchedule({ alerts: alertsWithPendingRecoveredCount, - throttledSummaryActions: {}, }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); - expect(executables).toHaveLength(2); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['2'] }, - { action: onThrottleIntervalAction, alert: alerts['2'] }, + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(2); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 2, + }); + + expect(results).toHaveLength(2); + expect(results).toEqual([ + getResult('action-1', '2', '111-111'), + getResult('action-4', '2', '444-444'), ]); }); - test('should skip generating executable when alert is muted', async () => { + test('should skip creating actions to schedule when alert is muted', async () => { + // 2 per-alert actions * 2 alerts = 4 actions to schedule + // but alert 2 is muted, so only actions for alert 1 should be scheduled const scheduler = new PerAlertActionScheduler({ ...getSchedulerContext(), rule: { ...rule, mutedInstanceIds: ['2'] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); expect(logger.debug).toHaveBeenCalledTimes(1); @@ -336,20 +402,27 @@ describe('Per-Alert Action Scheduler', () => { 1, `skipping scheduling of actions for '2' in rule rule-label: rule is muted` ); - expect(executables).toHaveLength(2); - // @ts-expect-error private variable - expect(scheduler.skippedAlerts).toEqual({ '2': { reason: 'muted' } }); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(2); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 2, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['1'] }, - { action: rule.actions[1], alert: alerts['1'] }, + expect(results).toHaveLength(2); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-2', '1', '222-222'), ]); + + // @ts-expect-error private variable + expect(scheduler.skippedAlerts).toEqual({ '2': { reason: 'muted' } }); }); - test('should skip generating executable when alert action group has not changed and notifyWhen is onActionGroupChange', async () => { + test('should skip creating actions to schedule when alert action group has not changed and notifyWhen is onActionGroupChange', async () => { const onActionGroupChangeAction: SanitizedRuleAction = { - id: '2', + id: 'action-4', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onActionGroupChange', throttle: null }, @@ -360,7 +433,7 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '222-222', + uuid: '444-444', }; const activeAlert1 = generateAlert({ @@ -380,10 +453,7 @@ describe('Per-Alert Action Scheduler', () => { rule: { ...rule, actions: [rule.actions[0], onActionGroupChangeAction] }, }); - const executables = await scheduler.generateExecutables({ - alerts: alertsWithOngoingAlert, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts: alertsWithOngoingAlert }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); expect(logger.debug).toHaveBeenCalledTimes(1); @@ -391,21 +461,28 @@ describe('Per-Alert Action Scheduler', () => { 1, `skipping scheduling of actions for '2' in rule rule-label: alert is active but action group has not changed` ); - expect(executables).toHaveLength(3); - // @ts-expect-error private variable - expect(scheduler.skippedAlerts).toEqual({ '2': { reason: 'actionGroupHasNotChanged' } }); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(3); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(3); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 3, + numberOfTriggeredActions: 3, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alertsWithOngoingAlert['1'] }, - { action: rule.actions[0], alert: alertsWithOngoingAlert['2'] }, - { action: onActionGroupChangeAction, alert: alertsWithOngoingAlert['1'] }, + expect(results).toHaveLength(3); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-4', '1', '444-444'), ]); + + // @ts-expect-error private variable + expect(scheduler.skippedAlerts).toEqual({ '2': { reason: 'actionGroupHasNotChanged' } }); }); - test('should skip generating executable when throttle interval has not passed and notifyWhen is onThrottleInterval', async () => { + test('should skip creating actions to schedule when throttle interval has not passed and notifyWhen is onThrottleInterval', async () => { const onThrottleIntervalAction: SanitizedRuleAction = { - id: '2', + id: 'action-5', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onThrottleInterval', throttle: '1h' }, @@ -416,13 +493,13 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '222-222', + uuid: '555-555', }; const activeAlert2 = generateAlert({ id: 2, lastScheduledActionsGroup: 'default', - throttledActions: { '222-222': { date: '1969-12-31T23:10:00.000Z' } }, + throttledActions: { '555-555': { date: '1969-12-31T23:10:00.000Z' } }, }); const alertsWithOngoingAlert = { ...newAlert1, ...activeAlert2 }; @@ -431,10 +508,7 @@ describe('Per-Alert Action Scheduler', () => { rule: { ...rule, actions: [rule.actions[0], onThrottleIntervalAction] }, }); - const executables = await scheduler.generateExecutables({ - alerts: alertsWithOngoingAlert, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts: alertsWithOngoingAlert }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); expect(logger.debug).toHaveBeenCalledTimes(1); @@ -442,21 +516,28 @@ describe('Per-Alert Action Scheduler', () => { 1, `skipping scheduling of actions for '2' in rule rule-label: rule is throttled` ); - expect(executables).toHaveLength(3); - // @ts-expect-error private variable - expect(scheduler.skippedAlerts).toEqual({ '2': { reason: 'throttled' } }); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(3); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(3); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 3, + numberOfTriggeredActions: 3, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alertsWithOngoingAlert['1'] }, - { action: rule.actions[0], alert: alertsWithOngoingAlert['2'] }, - { action: onThrottleIntervalAction, alert: alertsWithOngoingAlert['1'] }, + expect(results).toHaveLength(3); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-5', '1', '555-555'), ]); + + // @ts-expect-error private variable + expect(scheduler.skippedAlerts).toEqual({ '2': { reason: 'throttled' } }); }); - test('should not skip generating executable when throttle interval has passed and notifyWhen is onThrottleInterval', async () => { + test('should not skip creating actions to schedule when throttle interval has passed and notifyWhen is onThrottleInterval', async () => { const onThrottleIntervalAction: SanitizedRuleAction = { - id: '2', + id: 'action-5', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onThrottleInterval', throttle: '1h' }, @@ -467,7 +548,7 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '222-222', + uuid: '555-555', }; const activeAlert2 = generateAlert({ @@ -482,24 +563,28 @@ describe('Per-Alert Action Scheduler', () => { rule: { ...rule, actions: [rule.actions[0], onThrottleIntervalAction] }, }); - const executables = await scheduler.generateExecutables({ - alerts: alertsWithOngoingAlert, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts: alertsWithOngoingAlert }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); expect(logger.debug).not.toHaveBeenCalled(); - expect(executables).toHaveLength(4); - // @ts-expect-error private variable - expect(scheduler.skippedAlerts).toEqual({}); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(4); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(4); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 4, + numberOfTriggeredActions: 4, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alertsWithOngoingAlert['1'] }, - { action: rule.actions[0], alert: alertsWithOngoingAlert['2'] }, - { action: onThrottleIntervalAction, alert: alertsWithOngoingAlert['1'] }, - { action: onThrottleIntervalAction, alert: alertsWithOngoingAlert['2'] }, + expect(results).toHaveLength(4); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-5', '1', '555-555'), + getResult('action-5', '2', '555-555'), ]); + + // @ts-expect-error private variable + expect(scheduler.skippedAlerts).toEqual({}); }); test('should query for summarized alerts if useAlertDataForTemplate is true', async () => { @@ -517,7 +602,7 @@ describe('Per-Alert Action Scheduler', () => { }; alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); const actionWithUseAlertDataForTemplate: SanitizedRuleAction = { - id: '1', + id: 'action-6', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onActiveAlert', throttle: null }, @@ -528,33 +613,36 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '111-111', + uuid: '666-666', useAlertDataForTemplate: true, }; const scheduler = new PerAlertActionScheduler({ ...getSchedulerContext(), rule: { ...rule, actions: [rule.actions[0], actionWithUseAlertDataForTemplate] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', }); - expect(executables).toHaveLength(4); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(4); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(4); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 4, + numberOfTriggeredActions: 4, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['1'] }, - { action: rule.actions[0], alert: alerts['2'] }, - { action: actionWithUseAlertDataForTemplate, alert: alerts['1'] }, - { action: actionWithUseAlertDataForTemplate, alert: alerts['2'] }, + expect(results).toHaveLength(4); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-6', '1', '666-666'), + getResult('action-6', '2', '666-666'), ]); }); @@ -573,7 +661,7 @@ describe('Per-Alert Action Scheduler', () => { }; alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); const actionWithUseAlertDataForTemplate: SanitizedRuleAction = { - id: '1', + id: 'action-6', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onThrottleInterval', throttle: '1h' }, @@ -584,34 +672,37 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '111-111', + uuid: '666-666', useAlertDataForTemplate: true, }; const scheduler = new PerAlertActionScheduler({ ...getSchedulerContext(), rule: { ...rule, actions: [rule.actions[0], actionWithUseAlertDataForTemplate] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', start: new Date('1969-12-31T23:00:00.000Z'), end: new Date('1970-01-01T00:00:00.000Z'), }); - expect(executables).toHaveLength(4); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(4); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(4); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 4, + numberOfTriggeredActions: 4, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['1'] }, - { action: rule.actions[0], alert: alerts['2'] }, - { action: actionWithUseAlertDataForTemplate, alert: alerts['1'] }, - { action: actionWithUseAlertDataForTemplate, alert: alerts['2'] }, + expect(results).toHaveLength(4); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-6', '1', '666-666'), + getResult('action-6', '2', '666-666'), ]); }); @@ -630,7 +721,7 @@ describe('Per-Alert Action Scheduler', () => { }; alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); const actionWithAlertsFilter: SanitizedRuleAction = { - id: '1', + id: 'action-7', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onActiveAlert', throttle: null }, @@ -641,34 +732,37 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '111-111', + uuid: '777-777', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', filters: [] } }, }; const scheduler = new PerAlertActionScheduler({ ...getSchedulerContext(), rule: { ...rule, actions: [rule.actions[0], actionWithAlertsFilter] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', filters: [] } }, }); - expect(executables).toHaveLength(4); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(4); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(4); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 4, + numberOfTriggeredActions: 4, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['1'] }, - { action: rule.actions[0], alert: alerts['2'] }, - { action: actionWithAlertsFilter, alert: alerts['1'] }, - { action: actionWithAlertsFilter, alert: alerts['2'] }, + expect(results).toHaveLength(4); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-7', '1', '777-777'), + getResult('action-7', '2', '777-777'), ]); }); @@ -687,7 +781,7 @@ describe('Per-Alert Action Scheduler', () => { }; alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); const actionWithAlertsFilter: SanitizedRuleAction = { - id: '1', + id: 'action-7', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onThrottleInterval', throttle: '6h' }, @@ -698,39 +792,42 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '111-111', + uuid: '777-777', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', filters: [] } }, }; const scheduler = new PerAlertActionScheduler({ ...getSchedulerContext(), rule: { ...rule, actions: [rule.actions[0], actionWithAlertsFilter] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', filters: [] } }, start: new Date('1969-12-31T18:00:00.000Z'), end: new Date('1970-01-01T00:00:00.000Z'), }); - expect(executables).toHaveLength(4); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(4); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(4); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 4, + numberOfTriggeredActions: 4, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['1'] }, - { action: rule.actions[0], alert: alerts['2'] }, - { action: actionWithAlertsFilter, alert: alerts['1'] }, - { action: actionWithAlertsFilter, alert: alerts['2'] }, + expect(results).toHaveLength(4); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-7', '1', '777-777'), + getResult('action-7', '2', '777-777'), ]); }); - test('should skip generating executable if alert does not match any alerts in summarized alerts', async () => { + test('should skip creating actions to schedule if alert does not match any alerts in summarized alerts', async () => { alertsClient.getProcessedAlerts.mockReturnValue(alerts); const summarizedAlerts = { new: { @@ -745,7 +842,7 @@ describe('Per-Alert Action Scheduler', () => { }; alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); const actionWithAlertsFilter: SanitizedRuleAction = { - id: '1', + id: 'action-8', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onActiveAlert', throttle: null }, @@ -756,33 +853,36 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '111-111', + uuid: '888-888', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', filters: [] } }, }; const scheduler = new PerAlertActionScheduler({ ...getSchedulerContext(), rule: { ...rule, actions: [rule.actions[0], actionWithAlertsFilter] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', filters: [] } }, }); - expect(executables).toHaveLength(3); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(3); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(3); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 3, + numberOfTriggeredActions: 3, + }); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['1'] }, - { action: rule.actions[0], alert: alerts['2'] }, - { action: actionWithAlertsFilter, alert: alerts['1'] }, + expect(results).toHaveLength(3); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-8', '1', '888-888'), ]); }); @@ -801,7 +901,7 @@ describe('Per-Alert Action Scheduler', () => { }; alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); const actionWithAlertsFilter: SanitizedRuleAction = { - id: '1', + id: 'action-9', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onActiveAlert', throttle: null }, @@ -812,38 +912,168 @@ describe('Per-Alert Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '111-111', + uuid: '999-999', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', filters: [] } }, }; const scheduler = new PerAlertActionScheduler({ ...getSchedulerContext(), rule: { ...rule, actions: [rule.actions[0], actionWithAlertsFilter] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', filters: [] } }, }); - expect(executables).toHaveLength(4); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(4); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(4); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 4, + numberOfTriggeredActions: 4, + }); + + expect(results).toHaveLength(4); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-9', '1', '999-999'), + getResult('action-9', '2', '999-999'), + ]); expect(alerts['1'].getAlertAsData()).not.toBeUndefined(); expect(alerts['2'].getAlertAsData()).not.toBeUndefined(); + }); + + test('should skip creating actions to schedule if overall max actions limit exceeded', async () => { + const defaultContext = getSchedulerContext(); + const scheduler = new PerAlertActionScheduler({ + ...defaultContext, + taskRunnerContext: { + ...defaultContext.taskRunnerContext, + actionsConfigMap: { + default: { max: 3 }, + }, + }, + }); + const results = await scheduler.getActionsToSchedule({ alerts }); + + expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); - expect(executables).toEqual([ - { action: rule.actions[0], alert: alerts['1'] }, - { action: rule.actions[0], alert: alerts['2'] }, - { action: actionWithAlertsFilter, alert: alerts['1'] }, - { action: actionWithAlertsFilter, alert: alerts['2'] }, + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(4); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(3); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 4, + numberOfTriggeredActions: 3, + triggeredActionsStatus: ActionsCompletion.PARTIAL, + }); + + expect(logger.debug).toHaveBeenCalledWith( + `Rule "rule-id-1" skipped scheduling action "action-2" because the maximum number of allowed actions has been reached.` + ); + + expect(results).toHaveLength(3); + expect(results).toEqual([ + getResult('action-1', '1', '111-111'), + getResult('action-1', '2', '111-111'), + getResult('action-2', '1', '222-222'), ]); }); + + test('should skip creating actions to schedule if connector type max actions limit exceeded', async () => { + const defaultContext = getSchedulerContext(); + const scheduler = new PerAlertActionScheduler({ + ...defaultContext, + taskRunnerContext: { + ...defaultContext.taskRunnerContext, + actionsConfigMap: { + default: { max: 1000 }, + test: { max: 1 }, + }, + }, + }); + const results = await scheduler.getActionsToSchedule({ alerts }); + + expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); + + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(4); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 4, + numberOfTriggeredActions: 1, + triggeredActionsStatus: ActionsCompletion.PARTIAL, + }); + + expect(logger.debug).toHaveBeenCalledWith( + `Rule "rule-id-1" skipped scheduling action "action-1" because the maximum number of allowed actions for connector type test has been reached.` + ); + + expect(results).toHaveLength(1); + expect(results).toEqual([getResult('action-1', '1', '111-111')]); + }); + + test('should correctly update last scheduled actions for alert when action is "onActiveAlert"', async () => { + const alert = new Alert('1', { + state: { test: true }, + meta: {}, + }); + alert.scheduleActions('default'); + const scheduler = new PerAlertActionScheduler({ + ...getSchedulerContext(), + rule: { ...rule, actions: [rule.actions[0]] }, + }); + + expect(alert.getLastScheduledActions()).toBeUndefined(); + expect(alert.hasScheduledActions()).toBe(true); + await scheduler.getActionsToSchedule({ alerts: { '1': alert } }); + + expect(alert.getLastScheduledActions()).toEqual({ + date: '1970-01-01T00:00:00.000Z', + group: 'default', + }); + expect(alert.hasScheduledActions()).toBe(false); + }); + + test('should correctly update last scheduled actions for alert', async () => { + const alert = new Alert('1', { + state: { test: true }, + meta: {}, + }); + alert.scheduleActions('default'); + const onThrottleIntervalAction: SanitizedRuleAction = { + id: 'action-4', + group: 'default', + actionTypeId: 'test', + frequency: { summary: false, notifyWhen: 'onThrottleInterval', throttle: '1h' }, + params: { + foo: true, + contextVal: 'My {{context.value}} goes here', + stateVal: 'My {{state.value}} goes here', + alertVal: + 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', + }, + uuid: '222-222', + }; + + expect(alert.getLastScheduledActions()).toBeUndefined(); + expect(alert.hasScheduledActions()).toBe(true); + const scheduler = new PerAlertActionScheduler({ + ...getSchedulerContext(), + rule: { ...rule, actions: [onThrottleIntervalAction] }, + }); + + await scheduler.getActionsToSchedule({ alerts: { '1': alert } }); + + expect(alert.getLastScheduledActions()).toEqual({ + date: '1970-01-01T00:00:00.000Z', + group: 'default', + actions: { '222-222': { date: '1970-01-01T00:00:00.000Z' } }, + }); + expect(alert.hasScheduledActions()).toBe(false); + }); }); }); diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/per_alert_action_scheduler.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/per_alert_action_scheduler.ts index 602d3c31688c1..b35d86dff0105 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/per_alert_action_scheduler.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/per_alert_action_scheduler.ts @@ -12,19 +12,24 @@ import { RuleTypeState, RuleAlertData, parseDuration } from '../../../../common' import { GetSummarizedAlertsParams } from '../../../alerts_client/types'; import { AlertHit } from '../../../types'; import { Alert } from '../../../alert'; -import { getSummarizedAlerts } from '../get_summarized_alerts'; import { + buildRuleUrl, + formatActionToEnqueue, generateActionHash, + getSummarizedAlerts, isActionOnInterval, isSummaryAction, logNumberOfFilteredAlerts, -} from '../rule_action_helper'; + shouldScheduleAction, +} from '../lib'; import { ActionSchedulerOptions, - Executable, - GenerateExecutablesOpts, + ActionsToSchedule, + GetActionsToScheduleOpts, IActionScheduler, } from '../types'; +import { TransformActionParamsOptions, transformActionParams } from '../../transform_action_params'; +import { injectActionParams } from '../../inject_action_params'; enum Reasons { MUTED = 'muted', @@ -90,12 +95,16 @@ export class PerAlertActionScheduler< return 2; } - public async generateExecutables({ + public async getActionsToSchedule({ alerts, - }: GenerateExecutablesOpts): Promise< - Array> + }: GetActionsToScheduleOpts): Promise< + ActionsToSchedule[] > { - const executables = []; + const executables: Array<{ + action: RuleAction; + alert: Alert; + }> = []; + const results: ActionsToSchedule[] = []; const alertsArray = Object.entries(alerts); for (const action of this.actions) { @@ -104,7 +113,7 @@ export class PerAlertActionScheduler< if (action.useAlertDataForTemplate || action.alertsFilter) { const optionsBase = { spaceId: this.context.taskInstance.params.spaceId, - ruleId: this.context.taskInstance.params.alertId, + ruleId: this.context.rule.id, excludedAlertInstanceIds: this.context.rule.mutedInstanceIds, alertsFilter: action.alertsFilter, }; @@ -135,7 +144,7 @@ export class PerAlertActionScheduler< if (alertMaintenanceWindowIds.length !== 0) { this.context.logger.debug( `no scheduling of summary actions "${action.id}" for rule "${ - this.context.taskInstance.params.alertId + this.context.rule.id }": has active maintenance windows ${alertMaintenanceWindowIds.join(', ')}.` ); continue; @@ -185,7 +194,112 @@ export class PerAlertActionScheduler< } } - return executables; + if (executables.length === 0) return []; + + this.context.ruleRunMetricsStore.incrementNumberOfGeneratedActions(executables.length); + + const ruleUrl = buildRuleUrl({ + getViewInAppRelativeUrl: this.context.ruleType.getViewInAppRelativeUrl, + kibanaBaseUrl: this.context.taskRunnerContext.kibanaBaseUrl, + logger: this.context.logger, + rule: this.context.rule, + spaceId: this.context.taskInstance.params.spaceId, + }); + + for (const { action, alert } of executables) { + const { actionTypeId } = action; + + if ( + !shouldScheduleAction({ + action, + actionsConfigMap: this.context.taskRunnerContext.actionsConfigMap, + isActionExecutable: this.context.taskRunnerContext.actionsPlugin.isActionExecutable, + logger: this.context.logger, + ruleId: this.context.rule.id, + ruleRunMetricsStore: this.context.ruleRunMetricsStore, + }) + ) { + continue; + } + + this.context.ruleRunMetricsStore.incrementNumberOfTriggeredActions(); + this.context.ruleRunMetricsStore.incrementNumberOfTriggeredActionsByConnectorType( + actionTypeId + ); + + const actionGroup = action.group as ActionGroupIds; + const transformActionParamsOptions: TransformActionParamsOptions = { + actionsPlugin: this.context.taskRunnerContext.actionsPlugin, + alertId: this.context.rule.id, + alertType: this.context.ruleType.id, + actionTypeId: action.actionTypeId, + alertName: this.context.rule.name, + spaceId: this.context.taskInstance.params.spaceId, + tags: this.context.rule.tags, + alertInstanceId: alert.getId(), + alertUuid: alert.getUuid(), + alertActionGroup: actionGroup, + alertActionGroupName: this.ruleTypeActionGroups!.get(actionGroup)!, + context: alert.getContext(), + actionId: action.id, + state: alert.getState(), + kibanaBaseUrl: this.context.taskRunnerContext.kibanaBaseUrl, + alertParams: this.context.rule.params, + actionParams: action.params, + flapping: alert.getFlapping(), + ruleUrl: ruleUrl?.absoluteUrl, + }; + + if (alert.isAlertAsData()) { + transformActionParamsOptions.aadAlert = alert.getAlertAsData(); + } + + const actionToRun = { + ...action, + params: injectActionParams({ + actionTypeId: action.actionTypeId, + ruleUrl, + ruleName: this.context.rule.name, + actionParams: transformActionParams(transformActionParamsOptions), + }), + }; + + results.push({ + actionToEnqueue: formatActionToEnqueue({ + action: actionToRun, + apiKey: this.context.apiKey, + executionId: this.context.executionId, + ruleConsumer: this.context.ruleConsumer, + ruleId: this.context.rule.id, + ruleTypeId: this.context.ruleType.id, + spaceId: this.context.taskInstance.params.spaceId, + }), + actionToLog: { + id: action.id, + // uuid is typed as optional but in reality it is always + // populated - https://github.com/elastic/kibana/issues/195255 + uuid: action.uuid, + typeId: action.actionTypeId, + alertId: alert.getId(), + alertGroup: action.group, + }, + }); + + if (!this.isRecoveredAlert(actionGroup)) { + if (isActionOnInterval(action)) { + alert.updateLastScheduledActions( + action.group as ActionGroupIds, + generateActionHash(action), + action.uuid + ); + } else { + alert.updateLastScheduledActions(action.group as ActionGroupIds); + } + alert.unscheduleActions(); + } + } + + return results; } private isAlertMuted(alertId: string) { diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/summary_action_scheduler.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/summary_action_scheduler.test.ts index 600dd0e1951d5..fc810fc4ef34c 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/summary_action_scheduler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/summary_action_scheduler.test.ts @@ -20,6 +20,8 @@ import { getErrorSource, TaskErrorSource, } from '@kbn/task-manager-plugin/server/task_running/errors'; +import { CombinedSummarizedAlerts } from '../../../types'; +import { ActionsCompletion } from '@kbn/alerting-state-types'; const alertingEventLogger = alertingEventLoggerMock.create(); const actionsClient = actionsClientMock.create(); @@ -29,9 +31,10 @@ const logger = loggingSystemMock.create().get(); let ruleRunMetricsStore: RuleRunMetricsStore; const rule = getRule({ + id: 'rule-id-1', actions: [ { - id: '1', + id: 'action-1', group: 'default', actionTypeId: 'test', frequency: { summary: false, notifyWhen: 'onActiveAlert', throttle: null }, @@ -45,7 +48,7 @@ const rule = getRule({ uuid: '111-111', }, { - id: '2', + id: 'action-2', group: 'default', actionTypeId: 'test', frequency: { summary: true, notifyWhen: 'onActiveAlert', throttle: null }, @@ -59,7 +62,7 @@ const rule = getRule({ uuid: '222-222', }, { - id: '3', + id: 'action-3', group: 'default', actionTypeId: 'test', frequency: { summary: true, notifyWhen: 'onActiveAlert', throttle: null }, @@ -88,6 +91,30 @@ const getSchedulerContext = (params = {}) => { return { ...defaultSchedulerContext, rule, ...params, ruleRunMetricsStore }; }; +const getResult = (actionId: string, actionUuid: string, summary: CombinedSummarizedAlerts) => ({ + actionToEnqueue: { + actionTypeId: 'test', + apiKey: 'MTIzOmFiYw==', + consumer: 'rule-consumer', + executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + id: actionId, + uuid: actionUuid, + relatedSavedObjects: [{ id: 'rule-id-1', namespace: 'test1', type: 'alert', typeId: 'test' }], + source: { source: { id: 'rule-id-1', type: 'alert' }, type: 'SAVED_OBJECT' }, + spaceId: 'test1', + }, + actionToLog: { + alertSummary: { + new: summary.new.count, + ongoing: summary.ongoing.count, + recovered: summary.recovered.count, + }, + id: actionId, + uuid: actionUuid, + typeId: 'test', + }, +}); + let clock: sinon.SinonFakeTimers; describe('Summary Action Scheduler', () => { @@ -127,21 +154,21 @@ describe('Summary Action Scheduler', () => { expect(logger.error).toHaveBeenCalledTimes(2); expect(logger.error).toHaveBeenNthCalledWith( 1, - `Skipping action \"2\" for rule \"1\" because the rule type \"Test\" does not support alert-as-data.` + `Skipping action \"action-2\" for rule \"rule-id-1\" because the rule type \"Test\" does not support alert-as-data.` ); expect(logger.error).toHaveBeenNthCalledWith( 2, - `Skipping action \"3\" for rule \"1\" because the rule type \"Test\" does not support alert-as-data.` + `Skipping action \"action-3\" for rule \"rule-id-1\" because the rule type \"Test\" does not support alert-as-data.` ); }); - describe('generateExecutables', () => { + describe('getActionsToSchedule', () => { const newAlert1 = generateAlert({ id: 1 }); const newAlert2 = generateAlert({ id: 2 }); const alerts = { ...newAlert1, ...newAlert2 }; const summaryActionWithAlertFilter: RuleAction = { - id: '2', + id: 'action-3', group: 'default', actionTypeId: 'test', frequency: { @@ -157,11 +184,11 @@ describe('Summary Action Scheduler', () => { 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', dsl: '{}', filters: [] } }, - uuid: '222-222', + uuid: '333-333', }; const summaryActionWithThrottle: RuleAction = { - id: '2', + id: 'action-4', group: 'default', actionTypeId: 'test', frequency: { @@ -176,10 +203,10 @@ describe('Summary Action Scheduler', () => { alertVal: 'My {{rule.id}} {{rule.name}} {{rule.spaceId}} {{rule.tags}} {{alert.id}} goes here', }, - uuid: '222-222', + uuid: '444-444', }; - test('should generate executable for summary action when summary action is per rule run', async () => { + test('should create action to schedule for summary action when summary action is per rule run', async () => { alertsClient.getProcessedAlerts.mockReturnValue(alerts); const summarizedAlerts = { new: { count: 2, data: [mockAAD, mockAAD] }, @@ -188,37 +215,43 @@ describe('Summary Action Scheduler', () => { }; alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); + const throttledSummaryActions = {}; const scheduler = new SummaryActionScheduler(getSchedulerContext()); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions }); + expect(throttledSummaryActions).toEqual({}); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(2); expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(1, { excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', }); expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(2, { excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', }); expect(logger.debug).not.toHaveBeenCalled(); - expect(executables).toHaveLength(2); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(2); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 2, + }); + + expect(results).toHaveLength(2); const finalSummary = { ...summarizedAlerts, all: { count: 2, data: [mockAAD, mockAAD] } }; - expect(executables).toEqual([ - { action: rule.actions[1], summarizedAlerts: finalSummary }, - { action: rule.actions[2], summarizedAlerts: finalSummary }, + expect(results).toEqual([ + getResult('action-2', '222-222', finalSummary), + getResult('action-3', '333-333', finalSummary), ]); }); - test('should generate executable for summary action when summary action has alertsFilter', async () => { + test('should create actions to schedule for summary action when summary action has alertsFilter', async () => { alertsClient.getProcessedAlerts.mockReturnValue(alerts); const summarizedAlerts = { new: { count: 2, data: [mockAAD, mockAAD] }, @@ -232,30 +265,34 @@ describe('Summary Action Scheduler', () => { rule: { ...rule, actions: [summaryActionWithAlertFilter] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const throttledSummaryActions = {}; + const results = await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions }); + expect(throttledSummaryActions).toEqual({}); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', dsl: '{}', filters: [] } }, }); expect(logger.debug).not.toHaveBeenCalled(); - expect(executables).toHaveLength(1); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(1); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 1, + numberOfTriggeredActions: 1, + }); + + expect(results).toHaveLength(1); const finalSummary = { ...summarizedAlerts, all: { count: 2, data: [mockAAD, mockAAD] } }; - expect(executables).toEqual([ - { action: summaryActionWithAlertFilter, summarizedAlerts: finalSummary }, - ]); + expect(results).toEqual([getResult('action-3', '333-333', finalSummary)]); }); - test('should generate executable for summary action when summary action is throttled with no throttle history', async () => { + test('should create actions to schedule for summary action when summary action is throttled with no throttle history', async () => { alertsClient.getProcessedAlerts.mockReturnValue(alerts); const summarizedAlerts = { new: { count: 2, data: [mockAAD, mockAAD] }, @@ -269,48 +306,52 @@ describe('Summary Action Scheduler', () => { rule: { ...rule, actions: [summaryActionWithThrottle] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const throttledSummaryActions = {}; + const results = await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions }); + expect(throttledSummaryActions).toEqual({ '444-444': { date: '1970-01-01T00:00:00.000Z' } }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', start: new Date('1969-12-31T00:00:00.000Z'), end: new Date(), }); expect(logger.debug).not.toHaveBeenCalled(); - expect(executables).toHaveLength(1); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(1); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 1, + numberOfTriggeredActions: 1, + }); + + expect(results).toHaveLength(1); const finalSummary = { ...summarizedAlerts, all: { count: 2, data: [mockAAD, mockAAD] } }; - expect(executables).toEqual([ - { action: summaryActionWithThrottle, summarizedAlerts: finalSummary }, - ]); + expect(results).toEqual([getResult('action-4', '444-444', finalSummary)]); }); - test('should skip generating executable for summary action when summary action is throttled', async () => { + test('should skip creating actions to schedule for summary action when summary action is throttled', async () => { const scheduler = new SummaryActionScheduler({ ...getSchedulerContext(), rule: { ...rule, actions: [summaryActionWithThrottle] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: { - '222-222': { date: '1969-12-31T13:00:00.000Z' }, - }, - }); + const throttledSummaryActions = { '444-444': { date: '1969-12-31T13:00:00.000Z' } }; + const results = await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions }); + expect(throttledSummaryActions).toEqual({ '444-444': { date: '1969-12-31T13:00:00.000Z' } }); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); expect(logger.debug).toHaveBeenCalledWith( - `skipping scheduling the action 'test:2', summary action is still being throttled` + `skipping scheduling the action 'test:action-4', summary action is still being throttled` ); - expect(executables).toHaveLength(0); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(0); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(0); + + expect(results).toHaveLength(0); }); test('should remove new alerts from summary if suppressed by maintenance window', async () => { @@ -332,22 +373,21 @@ describe('Summary Action Scheduler', () => { alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); const scheduler = new SummaryActionScheduler(getSchedulerContext()); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const throttledSummaryActions = {}; + const results = await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions }); + expect(throttledSummaryActions).toEqual({}); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(2); expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(1, { excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', }); expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(2, { excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', }); expect(logger.debug).toHaveBeenCalledTimes(2); @@ -360,7 +400,14 @@ describe('Summary Action Scheduler', () => { `(1) alert has been filtered out for: test:333-333` ); - expect(executables).toHaveLength(2); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(2); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 2, + }); + + expect(results).toHaveLength(2); const finalSummary = { all: { count: 1, data: [newAADAlerts[1]] }, @@ -368,13 +415,13 @@ describe('Summary Action Scheduler', () => { ongoing: { count: 0, data: [] }, recovered: { count: 0, data: [] }, }; - expect(executables).toEqual([ - { action: rule.actions[1], summarizedAlerts: finalSummary }, - { action: rule.actions[2], summarizedAlerts: finalSummary }, + expect(results).toEqual([ + getResult('action-2', '222-222', finalSummary), + getResult('action-3', '333-333', finalSummary), ]); }); - test('should generate executable for summary action and log when alerts have been filtered out by action condition', async () => { + test('should create alerts to schedule for summary action and log when alerts have been filtered out by action condition', async () => { alertsClient.getProcessedAlerts.mockReturnValue(alerts); const summarizedAlerts = { new: { count: 1, data: [mockAAD] }, @@ -388,33 +435,37 @@ describe('Summary Action Scheduler', () => { rule: { ...rule, actions: [summaryActionWithAlertFilter] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const throttledSummaryActions = {}; + const results = await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions }); + expect(throttledSummaryActions).toEqual({}); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', alertsFilter: { query: { kql: 'kibana.alert.rule.name:foo', dsl: '{}', filters: [] } }, }); expect(logger.debug).toHaveBeenCalledTimes(1); expect(logger.debug).toHaveBeenCalledWith( - `(1) alert has been filtered out for: test:222-222` + `(1) alert has been filtered out for: test:333-333` ); - expect(executables).toHaveLength(1); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(1); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 1, + numberOfTriggeredActions: 1, + }); + + expect(results).toHaveLength(1); const finalSummary = { ...summarizedAlerts, all: { count: 1, data: [mockAAD] } }; - expect(executables).toEqual([ - { action: summaryActionWithAlertFilter, summarizedAlerts: finalSummary }, - ]); + expect(results).toEqual([getResult('action-3', '333-333', finalSummary)]); }); - test('should skip generating executable for summary action when no alerts found', async () => { + test('should skip creating actions to schedule for summary action when no alerts found', async () => { alertsClient.getProcessedAlerts.mockReturnValue(alerts); const summarizedAlerts = { new: { count: 0, data: [] }, @@ -428,22 +479,23 @@ describe('Summary Action Scheduler', () => { rule: { ...rule, actions: [summaryActionWithThrottle] }, }); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const throttledSummaryActions = {}; + const results = await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions }); + expect(throttledSummaryActions).toEqual({}); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', start: new Date('1969-12-31T00:00:00.000Z'), end: new Date(), }); expect(logger.debug).not.toHaveBeenCalled(); - expect(executables).toHaveLength(0); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(0); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(0); + expect(results).toHaveLength(0); }); test('should throw framework error if getSummarizedAlerts throws error', async () => { @@ -455,14 +507,117 @@ describe('Summary Action Scheduler', () => { const scheduler = new SummaryActionScheduler(getSchedulerContext()); try { - await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions: {} }); } catch (err) { expect(err.message).toEqual(`no alerts for you`); expect(getErrorSource(err)).toBe(TaskErrorSource.FRAMEWORK); } }); + + test('should skip creating actions to schedule if overall max actions limit exceeded', async () => { + alertsClient.getProcessedAlerts.mockReturnValue(alerts); + const summarizedAlerts = { + new: { count: 2, data: [mockAAD, mockAAD] }, + ongoing: { count: 0, data: [] }, + recovered: { count: 0, data: [] }, + }; + alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); + + const defaultContext = getSchedulerContext(); + const scheduler = new SummaryActionScheduler({ + ...defaultContext, + taskRunnerContext: { + ...defaultContext.taskRunnerContext, + actionsConfigMap: { + default: { max: 1 }, + }, + }, + }); + const results = await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions: {} }); + + expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(2); + expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(1, { + excludedAlertInstanceIds: [], + executionUuid: defaultSchedulerContext.executionId, + ruleId: 'rule-id-1', + spaceId: 'test1', + }); + expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(2, { + excludedAlertInstanceIds: [], + executionUuid: defaultSchedulerContext.executionId, + ruleId: 'rule-id-1', + spaceId: 'test1', + }); + + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 1, + triggeredActionsStatus: ActionsCompletion.PARTIAL, + }); + + expect(logger.debug).toHaveBeenCalledWith( + `Rule "rule-id-1" skipped scheduling action "action-3" because the maximum number of allowed actions has been reached.` + ); + + expect(results).toHaveLength(1); + + const finalSummary = { ...summarizedAlerts, all: { count: 2, data: [mockAAD, mockAAD] } }; + expect(results).toEqual([getResult('action-2', '222-222', finalSummary)]); + }); + + test('should skip creating actions to schedule if connector type max actions limit exceeded', async () => { + alertsClient.getProcessedAlerts.mockReturnValue(alerts); + const summarizedAlerts = { + new: { count: 2, data: [mockAAD, mockAAD] }, + ongoing: { count: 0, data: [] }, + recovered: { count: 0, data: [] }, + }; + alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); + + const defaultContext = getSchedulerContext(); + const scheduler = new SummaryActionScheduler({ + ...defaultContext, + taskRunnerContext: { + ...defaultContext.taskRunnerContext, + actionsConfigMap: { + default: { max: 1000 }, + test: { max: 1 }, + }, + }, + }); + const results = await scheduler.getActionsToSchedule({ alerts, throttledSummaryActions: {} }); + + expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(2); + expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(1, { + excludedAlertInstanceIds: [], + executionUuid: defaultSchedulerContext.executionId, + ruleId: 'rule-id-1', + spaceId: 'test1', + }); + expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(2, { + excludedAlertInstanceIds: [], + executionUuid: defaultSchedulerContext.executionId, + ruleId: 'rule-id-1', + spaceId: 'test1', + }); + + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('test')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 1, + triggeredActionsStatus: ActionsCompletion.PARTIAL, + }); + + expect(logger.debug).toHaveBeenCalledWith( + `Rule "rule-id-1" skipped scheduling action "action-3" because the maximum number of allowed actions for connector type test has been reached.` + ); + + expect(results).toHaveLength(1); + const finalSummary = { ...summarizedAlerts, all: { count: 2, data: [mockAAD, mockAAD] } }; + expect(results).toEqual([getResult('action-2', '222-222', finalSummary)]); + }); }); }); diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/summary_action_scheduler.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/summary_action_scheduler.ts index 9b67c37e6216e..050eea352f0d5 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/summary_action_scheduler.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/summary_action_scheduler.ts @@ -8,21 +8,28 @@ import { AlertInstanceState, AlertInstanceContext } from '@kbn/alerting-state-types'; import { RuleAction, RuleTypeParams } from '@kbn/alerting-types'; import { compact } from 'lodash'; +import { CombinedSummarizedAlerts } from '../../../types'; import { RuleTypeState, RuleAlertData, parseDuration } from '../../../../common'; import { GetSummarizedAlertsParams } from '../../../alerts_client/types'; -import { getSummarizedAlerts } from '../get_summarized_alerts'; import { + buildRuleUrl, + formatActionToEnqueue, + getSummarizedAlerts, + getSummaryActionTimeBounds, isActionOnInterval, isSummaryAction, isSummaryActionThrottled, logNumberOfFilteredAlerts, -} from '../rule_action_helper'; + shouldScheduleAction, +} from '../lib'; import { ActionSchedulerOptions, - Executable, - GenerateExecutablesOpts, + ActionsToSchedule, + GetActionsToScheduleOpts, IActionScheduler, } from '../types'; +import { injectActionParams } from '../../inject_action_params'; +import { transformSummaryActionParams } from '../../transform_action_params'; export class SummaryActionScheduler< Params extends RuleTypeParams, @@ -73,13 +80,18 @@ export class SummaryActionScheduler< return 0; } - public async generateExecutables({ + public async getActionsToSchedule({ alerts, throttledSummaryActions, - }: GenerateExecutablesOpts): Promise< - Array> + }: GetActionsToScheduleOpts): Promise< + ActionsToSchedule[] > { - const executables = []; + const executables: Array<{ + action: RuleAction; + summarizedAlerts: CombinedSummarizedAlerts; + }> = []; + const results: ActionsToSchedule[] = []; + for (const action of this.actions) { if ( // if summary action is throttled, we won't send any notifications @@ -88,7 +100,7 @@ export class SummaryActionScheduler< const actionHasThrottleInterval = isActionOnInterval(action); const optionsBase = { spaceId: this.context.taskInstance.params.spaceId, - ruleId: this.context.taskInstance.params.alertId, + ruleId: this.context.rule.id, excludedAlertInstanceIds: this.context.rule.mutedInstanceIds, alertsFilter: action.alertsFilter, }; @@ -122,6 +134,95 @@ export class SummaryActionScheduler< } } - return executables; + if (executables.length === 0) return []; + + this.context.ruleRunMetricsStore.incrementNumberOfGeneratedActions(executables.length); + + for (const { action, summarizedAlerts } of executables) { + const { actionTypeId } = action; + + if ( + !shouldScheduleAction({ + action, + actionsConfigMap: this.context.taskRunnerContext.actionsConfigMap, + isActionExecutable: this.context.taskRunnerContext.actionsPlugin.isActionExecutable, + logger: this.context.logger, + ruleId: this.context.rule.id, + ruleRunMetricsStore: this.context.ruleRunMetricsStore, + }) + ) { + continue; + } + + this.context.ruleRunMetricsStore.incrementNumberOfTriggeredActions(); + this.context.ruleRunMetricsStore.incrementNumberOfTriggeredActionsByConnectorType( + actionTypeId + ); + + if (isActionOnInterval(action) && throttledSummaryActions) { + throttledSummaryActions[action.uuid!] = { date: new Date().toISOString() }; + } + + const { start, end } = getSummaryActionTimeBounds( + action, + this.context.rule.schedule, + this.context.previousStartedAt + ); + + const ruleUrl = buildRuleUrl({ + end, + getViewInAppRelativeUrl: this.context.ruleType.getViewInAppRelativeUrl, + kibanaBaseUrl: this.context.taskRunnerContext.kibanaBaseUrl, + logger: this.context.logger, + rule: this.context.rule, + spaceId: this.context.taskInstance.params.spaceId, + start, + }); + + const actionToRun = { + ...action, + params: injectActionParams({ + actionTypeId: action.actionTypeId, + ruleUrl, + ruleName: this.context.rule.name, + actionParams: transformSummaryActionParams({ + alerts: summarizedAlerts, + rule: this.context.rule, + ruleTypeId: this.context.ruleType.id, + actionId: action.id, + actionParams: action.params, + spaceId: this.context.taskInstance.params.spaceId, + actionsPlugin: this.context.taskRunnerContext.actionsPlugin, + actionTypeId: action.actionTypeId, + kibanaBaseUrl: this.context.taskRunnerContext.kibanaBaseUrl, + ruleUrl: ruleUrl?.absoluteUrl, + }), + }), + }; + + results.push({ + actionToEnqueue: formatActionToEnqueue({ + action: actionToRun, + apiKey: this.context.apiKey, + executionId: this.context.executionId, + ruleConsumer: this.context.ruleConsumer, + ruleId: this.context.rule.id, + ruleTypeId: this.context.ruleType.id, + spaceId: this.context.taskInstance.params.spaceId, + }), + actionToLog: { + id: action.id, + uuid: action.uuid, + typeId: action.actionTypeId, + alertSummary: { + new: summarizedAlerts.new.count, + ongoing: summarizedAlerts.ongoing.count, + recovered: summarizedAlerts.recovered.count, + }, + }, + }); + } + + return results; } } diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/system_action_scheduler.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/system_action_scheduler.test.ts index fd4db6ce34678..28bf58a30c689 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/system_action_scheduler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/system_action_scheduler.test.ts @@ -12,6 +12,12 @@ import { alertsClientMock } from '../../../alerts_client/alerts_client.mock'; import { alertingEventLoggerMock } from '../../../lib/alerting_event_logger/alerting_event_logger.mock'; import { RuleRunMetricsStore } from '../../../lib/rule_run_metrics_store'; import { mockAAD } from '../../fixtures'; +import { Alert } from '../../../alert'; +import { + ActionsCompletion, + AlertInstanceContext, + AlertInstanceState, +} from '@kbn/alerting-state-types'; import { getRule, getRuleType, getDefaultSchedulerContext, generateAlert } from '../test_fixtures'; import { SystemActionScheduler } from './system_action_scheduler'; import { ALERT_UUID } from '@kbn/rule-data-utils'; @@ -19,6 +25,8 @@ import { getErrorSource, TaskErrorSource, } from '@kbn/task-manager-plugin/server/task_running/errors'; +import { CombinedSummarizedAlerts } from '../../../types'; +import { schema } from '@kbn/config-schema'; const alertingEventLogger = alertingEventLoggerMock.create(); const actionsClient = actionsClientMock.create(); @@ -28,12 +36,13 @@ const logger = loggingSystemMock.create().get(); let ruleRunMetricsStore: RuleRunMetricsStore; const rule = getRule({ + id: 'rule-id-1', systemActions: [ { - id: '1', + id: 'system-action-1', actionTypeId: '.test-system-action', params: { myParams: 'test' }, - uui: 'test', + uuid: 'xxx-xxx', }, ], }); @@ -46,11 +55,43 @@ const defaultSchedulerContext = getDefaultSchedulerContext( alertsClient ); +const actionsParams = { myParams: 'test' }; +const buildActionParams = jest.fn().mockReturnValue({ ...actionsParams, foo: 'bar' }); +defaultSchedulerContext.taskRunnerContext.connectorAdapterRegistry.register({ + connectorTypeId: '.test-system-action', + ruleActionParamsSchema: schema.object({}), + buildActionParams, +}); + // @ts-ignore const getSchedulerContext = (params = {}) => { return { ...defaultSchedulerContext, rule, ...params, ruleRunMetricsStore }; }; +const getResult = (actionId: string, actionUuid: string, summary: CombinedSummarizedAlerts) => ({ + actionToEnqueue: { + actionTypeId: '.test-system-action', + apiKey: 'MTIzOmFiYw==', + consumer: 'rule-consumer', + executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + id: actionId, + uuid: actionUuid, + relatedSavedObjects: [{ id: 'rule-id-1', namespace: 'test1', type: 'alert', typeId: 'test' }], + source: { source: { id: 'rule-id-1', type: 'alert' }, type: 'SAVED_OBJECT' }, + spaceId: 'test1', + }, + actionToLog: { + alertSummary: { + new: summary.new.count, + ongoing: summary.ongoing.count, + recovered: summary.recovered.count, + }, + id: actionId, + uuid: actionUuid, + typeId: '.test-system-action', + }, +}); + let clock: sinon.SinonFakeTimers; describe('System Action Scheduler', () => { @@ -88,13 +129,29 @@ describe('System Action Scheduler', () => { expect(scheduler.actions).toHaveLength(0); }); - describe('generateExecutables', () => { - const newAlert1 = generateAlert({ id: 1 }); - const newAlert2 = generateAlert({ id: 2 }); - const alerts = { ...newAlert1, ...newAlert2 }; + describe('getActionsToSchedule', () => { + let newAlert1: Record< + string, + Alert + >; + let newAlert2: Record< + string, + Alert + >; + let alerts: Record< + string, + Alert + >; - test('should generate executable for each system action', async () => { + beforeEach(() => { + newAlert1 = generateAlert({ id: 1 }); + newAlert2 = generateAlert({ id: 2 }); + alerts = { ...newAlert1, ...newAlert2 }; + }); + + test('should create actions to schedule for each system action', async () => { alertsClient.getProcessedAlerts.mockReturnValue(alerts); + const summarizedAlerts = { new: { count: 2, data: [mockAAD, mockAAD] }, ongoing: { count: 0, data: [] }, @@ -103,25 +160,27 @@ describe('System Action Scheduler', () => { alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); const scheduler = new SystemActionScheduler(getSchedulerContext()); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', }); - expect(executables).toHaveLength(1); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(1); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('.test-system-action')).toEqual({ + numberOfGeneratedActions: 1, + numberOfTriggeredActions: 1, + }); + + expect(results).toHaveLength(1); const finalSummary = { ...summarizedAlerts, all: { count: 2, data: [mockAAD, mockAAD] } }; - expect(executables).toEqual([ - { action: rule.systemActions?.[0], summarizedAlerts: finalSummary }, - ]); + expect(results).toEqual([getResult('system-action-1', 'xxx-xxx', finalSummary)]); }); test('should remove new alerts from summary if suppressed by maintenance window', async () => { @@ -141,22 +200,26 @@ describe('System Action Scheduler', () => { recovered: { count: 0, data: [] }, }; alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); - const scheduler = new SystemActionScheduler(getSchedulerContext()); - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const scheduler = new SystemActionScheduler(getSchedulerContext()); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', }); - expect(executables).toHaveLength(1); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(1); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('.test-system-action')).toEqual({ + numberOfGeneratedActions: 1, + numberOfTriggeredActions: 1, + }); + + expect(results).toHaveLength(1); const finalSummary = { all: { count: 1, data: [newAADAlerts[1]] }, @@ -164,12 +227,10 @@ describe('System Action Scheduler', () => { ongoing: { count: 0, data: [] }, recovered: { count: 0, data: [] }, }; - expect(executables).toEqual([ - { action: rule.systemActions?.[0], summarizedAlerts: finalSummary }, - ]); + expect(results).toEqual([getResult('system-action-1', 'xxx-xxx', finalSummary)]); }); - test('should skip generating executable for summary action when no alerts found', async () => { + test('should skip creating actions to schedule for summary action when no alerts found', async () => { alertsClient.getProcessedAlerts.mockReturnValue(alerts); const summarizedAlerts = { new: { count: 0, data: [] }, @@ -179,21 +240,20 @@ describe('System Action Scheduler', () => { alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); const scheduler = new SystemActionScheduler(getSchedulerContext()); - - const executables = await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + const results = await scheduler.getActionsToSchedule({ alerts }); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ excludedAlertInstanceIds: [], executionUuid: defaultSchedulerContext.executionId, - ruleId: '1', + ruleId: 'rule-id-1', spaceId: 'test1', }); - expect(executables).toHaveLength(0); + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(0); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(0); + + expect(results).toHaveLength(0); }); test('should throw framework error if getSummarizedAlerts throws error', async () => { @@ -205,14 +265,175 @@ describe('System Action Scheduler', () => { const scheduler = new SystemActionScheduler(getSchedulerContext()); try { - await scheduler.generateExecutables({ - alerts, - throttledSummaryActions: {}, - }); + await scheduler.getActionsToSchedule({ alerts }); } catch (err) { expect(err.message).toEqual(`no alerts for you`); expect(getErrorSource(err)).toBe(TaskErrorSource.FRAMEWORK); } }); + + test('should skip creating actions to schedule if overall max actions limit exceeded', async () => { + const anotherSystemAction = { + id: 'system-action-1', + actionTypeId: '.test-system-action', + params: { myParams: 'foo' }, + uuid: 'yyy-yyy', + }; + + alertsClient.getProcessedAlerts.mockReturnValue(alerts); + const summarizedAlerts = { + new: { count: 2, data: [mockAAD, mockAAD] }, + ongoing: { count: 0, data: [] }, + recovered: { count: 0, data: [] }, + }; + alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); + + const defaultContext = getSchedulerContext(); + const scheduler = new SystemActionScheduler({ + ...defaultContext, + rule: { ...rule, systemActions: [rule.systemActions?.[0]!, anotherSystemAction] }, + taskRunnerContext: { + ...defaultContext.taskRunnerContext, + actionsConfigMap: { + default: { max: 1 }, + }, + }, + }); + const results = await scheduler.getActionsToSchedule({ alerts }); + + expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(2); + expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(1, { + excludedAlertInstanceIds: [], + executionUuid: defaultSchedulerContext.executionId, + ruleId: 'rule-id-1', + spaceId: 'test1', + }); + expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(2, { + excludedAlertInstanceIds: [], + executionUuid: defaultSchedulerContext.executionId, + ruleId: 'rule-id-1', + spaceId: 'test1', + }); + + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('.test-system-action')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 1, + triggeredActionsStatus: ActionsCompletion.PARTIAL, + }); + + expect(logger.debug).toHaveBeenCalledWith( + `Rule "rule-id-1" skipped scheduling action "system-action-1" because the maximum number of allowed actions has been reached.` + ); + + expect(results).toHaveLength(1); + + const finalSummary = { ...summarizedAlerts, all: { count: 2, data: [mockAAD, mockAAD] } }; + expect(results).toEqual([getResult('system-action-1', 'xxx-xxx', finalSummary)]); + }); + + test('should skip creating actions to schedule if connector type max actions limit exceeded', async () => { + const anotherSystemAction = { + id: 'system-action-1', + actionTypeId: '.test-system-action', + params: { myParams: 'foo' }, + uuid: 'yyy-yyy', + }; + + alertsClient.getProcessedAlerts.mockReturnValue(alerts); + const summarizedAlerts = { + new: { count: 2, data: [mockAAD, mockAAD] }, + ongoing: { count: 0, data: [] }, + recovered: { count: 0, data: [] }, + }; + alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); + + const defaultContext = getSchedulerContext(); + const scheduler = new SystemActionScheduler({ + ...defaultContext, + rule: { ...rule, systemActions: [rule.systemActions?.[0]!, anotherSystemAction] }, + taskRunnerContext: { + ...defaultContext.taskRunnerContext, + actionsConfigMap: { + default: { max: 1000 }, + '.test-system-action': { max: 1 }, + }, + }, + }); + const results = await scheduler.getActionsToSchedule({ alerts }); + + expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(2); + expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(1, { + excludedAlertInstanceIds: [], + executionUuid: defaultSchedulerContext.executionId, + ruleId: 'rule-id-1', + spaceId: 'test1', + }); + expect(alertsClient.getSummarizedAlerts).toHaveBeenNthCalledWith(2, { + excludedAlertInstanceIds: [], + executionUuid: defaultSchedulerContext.executionId, + ruleId: 'rule-id-1', + spaceId: 'test1', + }); + + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(2); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(1); + expect(ruleRunMetricsStore.getStatusByConnectorType('.test-system-action')).toEqual({ + numberOfGeneratedActions: 2, + numberOfTriggeredActions: 1, + triggeredActionsStatus: ActionsCompletion.PARTIAL, + }); + + expect(logger.debug).toHaveBeenCalledWith( + `Rule "rule-id-1" skipped scheduling action "system-action-1" because the maximum number of allowed actions for connector type .test-system-action has been reached.` + ); + + expect(results).toHaveLength(1); + + const finalSummary = { ...summarizedAlerts, all: { count: 2, data: [mockAAD, mockAAD] } }; + expect(results).toEqual([getResult('system-action-1', 'xxx-xxx', finalSummary)]); + }); + + test('should skip creating actions to schedule if no connector adapter exists for connector type', async () => { + const differentSystemAction = { + id: 'different-action-1', + actionTypeId: '.test-bad-system-action', + params: { myParams: 'foo' }, + uuid: 'zzz-zzz', + }; + + alertsClient.getProcessedAlerts.mockReturnValue(alerts); + const summarizedAlerts = { + new: { count: 2, data: [mockAAD, mockAAD] }, + ongoing: { count: 0, data: [] }, + recovered: { count: 0, data: [] }, + }; + alertsClient.getSummarizedAlerts.mockResolvedValue(summarizedAlerts); + + const defaultContext = getSchedulerContext(); + const scheduler = new SystemActionScheduler({ + ...defaultContext, + rule: { ...rule, systemActions: [differentSystemAction] }, + }); + const results = await scheduler.getActionsToSchedule({ alerts }); + + expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledTimes(1); + expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ + excludedAlertInstanceIds: [], + executionUuid: defaultSchedulerContext.executionId, + ruleId: 'rule-id-1', + spaceId: 'test1', + }); + + expect(ruleRunMetricsStore.getNumberOfGeneratedActions()).toEqual(1); + expect(ruleRunMetricsStore.getNumberOfTriggeredActions()).toEqual(0); + + expect(logger.warn).toHaveBeenCalledWith( + `Rule "rule-id-1" skipped scheduling system action "different-action-1" because no connector adapter is configured` + ); + + expect(results).toHaveLength(0); + }); }); }); diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/system_action_scheduler.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/system_action_scheduler.ts index b923baf8fbf38..0c5cceb0f0a52 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/system_action_scheduler.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/schedulers/system_action_scheduler.ts @@ -7,13 +7,19 @@ import { AlertInstanceState, AlertInstanceContext } from '@kbn/alerting-state-types'; import { RuleSystemAction, RuleTypeParams } from '@kbn/alerting-types'; +import { CombinedSummarizedAlerts } from '../../../types'; import { RuleTypeState, RuleAlertData } from '../../../../common'; import { GetSummarizedAlertsParams } from '../../../alerts_client/types'; -import { getSummarizedAlerts } from '../get_summarized_alerts'; +import { + buildRuleUrl, + formatActionToEnqueue, + getSummarizedAlerts, + shouldScheduleAction, +} from '../lib'; import { ActionSchedulerOptions, - Executable, - GenerateExecutablesOpts, + ActionsToSchedule, + GetActionsToScheduleOpts, IActionScheduler, } from '../types'; @@ -53,14 +59,19 @@ export class SystemActionScheduler< return 1; } - public async generateExecutables( - _: GenerateExecutablesOpts - ): Promise>> { - const executables = []; + public async getActionsToSchedule( + _: GetActionsToScheduleOpts + ): Promise { + const executables: Array<{ + action: RuleSystemAction; + summarizedAlerts: CombinedSummarizedAlerts; + }> = []; + const results: ActionsToSchedule[] = []; + for (const action of this.actions) { const options: GetSummarizedAlertsParams = { spaceId: this.context.taskInstance.params.spaceId, - ruleId: this.context.taskInstance.params.alertId, + ruleId: this.context.rule.id, excludedAlertInstanceIds: this.context.rule.mutedInstanceIds, executionUuid: this.context.executionId, }; @@ -75,6 +86,95 @@ export class SystemActionScheduler< } } - return executables; + if (executables.length === 0) return []; + + this.context.ruleRunMetricsStore.incrementNumberOfGeneratedActions(executables.length); + + const ruleUrl = buildRuleUrl({ + getViewInAppRelativeUrl: this.context.ruleType.getViewInAppRelativeUrl, + kibanaBaseUrl: this.context.taskRunnerContext.kibanaBaseUrl, + logger: this.context.logger, + rule: this.context.rule, + spaceId: this.context.taskInstance.params.spaceId, + }); + + for (const { action, summarizedAlerts } of executables) { + const { actionTypeId } = action; + + if ( + !shouldScheduleAction({ + action, + actionsConfigMap: this.context.taskRunnerContext.actionsConfigMap, + isActionExecutable: this.context.taskRunnerContext.actionsPlugin.isActionExecutable, + logger: this.context.logger, + ruleId: this.context.rule.id, + ruleRunMetricsStore: this.context.ruleRunMetricsStore, + }) + ) { + continue; + } + + const hasConnectorAdapter = this.context.taskRunnerContext.connectorAdapterRegistry.has( + action.actionTypeId + ); + + // System actions without an adapter cannot be executed + if (!hasConnectorAdapter) { + this.context.logger.warn( + `Rule "${this.context.rule.id}" skipped scheduling system action "${action.id}" because no connector adapter is configured` + ); + + continue; + } + + this.context.ruleRunMetricsStore.incrementNumberOfTriggeredActions(); + this.context.ruleRunMetricsStore.incrementNumberOfTriggeredActionsByConnectorType( + actionTypeId + ); + + const connectorAdapter = this.context.taskRunnerContext.connectorAdapterRegistry.get( + action.actionTypeId + ); + + const connectorAdapterActionParams = connectorAdapter.buildActionParams({ + alerts: summarizedAlerts, + rule: { + id: this.context.rule.id, + tags: this.context.rule.tags, + name: this.context.rule.name, + consumer: this.context.rule.consumer, + producer: this.context.ruleType.producer, + }, + ruleUrl: ruleUrl?.absoluteUrl, + spaceId: this.context.taskInstance.params.spaceId, + params: action.params, + }); + + const actionToRun = Object.assign(action, { params: connectorAdapterActionParams }); + + results.push({ + actionToEnqueue: formatActionToEnqueue({ + action: actionToRun, + apiKey: this.context.apiKey, + executionId: this.context.executionId, + ruleConsumer: this.context.ruleConsumer, + ruleId: this.context.rule.id, + ruleTypeId: this.context.ruleType.id, + spaceId: this.context.taskInstance.params.spaceId, + }), + actionToLog: { + id: action.id, + uuid: action.uuid, + typeId: action.actionTypeId, + alertSummary: { + new: summarizedAlerts.new.count, + ongoing: summarizedAlerts.ongoing.count, + recovered: summarizedAlerts.recovered.count, + }, + }, + }); + } + + return results; } } diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/types.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/types.ts index efcb51fcb2698..b90ffb88d541b 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/types.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/types.ts @@ -8,6 +8,7 @@ import type { Logger } from '@kbn/core/server'; import { PublicMethodsOf } from '@kbn/utility-types'; import { ActionsClient } from '@kbn/actions-plugin/server/actions_client'; +import { ExecuteOptions as EnqueueExecutionOptions } from '@kbn/actions-plugin/server/create_execute_function'; import { IAlertsClient } from '../../alerts_client/types'; import { Alert } from '../../alert'; import { @@ -24,7 +25,10 @@ import { import { NormalizedRuleType } from '../../rule_type_registry'; import { CombinedSummarizedAlerts, RawRule } from '../../types'; import { RuleRunMetricsStore } from '../../lib/rule_run_metrics_store'; -import { AlertingEventLogger } from '../../lib/alerting_event_logger/alerting_event_logger'; +import { + ActionOpts, + AlertingEventLogger, +} from '../../lib/alerting_event_logger/alerting_event_logger'; import { RuleTaskInstance, TaskRunnerContext } from '../types'; export interface ActionSchedulerOptions< @@ -80,14 +84,19 @@ export type Executable< } ); -export interface GenerateExecutablesOpts< +export interface GetActionsToScheduleOpts< State extends AlertInstanceState, Context extends AlertInstanceContext, ActionGroupIds extends string, RecoveryActionGroupId extends string > { alerts: Record>; - throttledSummaryActions: ThrottledActions; + throttledSummaryActions?: ThrottledActions; +} + +export interface ActionsToSchedule { + actionToEnqueue: EnqueueExecutionOptions; + actionToLog: ActionOpts; } export interface IActionScheduler< @@ -97,9 +106,9 @@ export interface IActionScheduler< RecoveryActionGroupId extends string > { get priority(): number; - generateExecutables( - opts: GenerateExecutablesOpts - ): Promise>>; + getActionsToSchedule( + opts: GetActionsToScheduleOpts + ): Promise; } export interface RuleUrl { diff --git a/x-pack/plugins/alerting/server/task_runner/fixtures.ts b/x-pack/plugins/alerting/server/task_runner/fixtures.ts index 5174aa9b965ec..d820f2690caeb 100644 --- a/x-pack/plugins/alerting/server/task_runner/fixtures.ts +++ b/x-pack/plugins/alerting/server/task_runner/fixtures.ts @@ -21,7 +21,7 @@ import { import { getDefaultMonitoring } from '../lib/monitoring'; import { UntypedNormalizedRuleType } from '../rule_type_registry'; import { EVENT_LOG_ACTIONS } from '../plugin'; -import { RawRule } from '../types'; +import { AlertHit, RawRule } from '../types'; import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; interface GeneratorParams { @@ -349,9 +349,10 @@ export const generateAlertOpts = ({ }; }; -export const generateActionOpts = ({ id, alertGroup, alertId }: GeneratorParams = {}) => ({ +export const generateActionOpts = ({ id, alertGroup, alertId, uuid }: GeneratorParams = {}) => ({ id: id ?? '1', typeId: 'action', + uuid: uuid ?? '111-111', alertId: alertId ?? '1', alertGroup: alertGroup ?? 'default', }); @@ -403,11 +404,13 @@ export const generateRunnerResult = ({ export const generateEnqueueFunctionInput = ({ id = '1', + uuid = '111-111', isBulk = false, isResolved, foo, actionTypeId, }: { + uuid?: string; id: string; isBulk?: boolean; isResolved?: boolean; @@ -419,6 +422,7 @@ export const generateEnqueueFunctionInput = ({ apiKey: 'MTIzOmFiYw==', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', id, + uuid, params: { ...(isResolved !== undefined ? { isResolved } : {}), ...(foo !== undefined ? { foo } : {}), @@ -504,4 +508,4 @@ export const mockAAD = { }, }, }, -}; +} as unknown as AlertHit; diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index eb531f0e00b88..b6e59402ba4c6 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -1420,7 +1420,7 @@ describe('Task Runner', () => { expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith( 2, - generateActionOpts({ id: '2', alertId: '2', alertGroup: 'recovered' }) + generateActionOpts({ id: '2', alertId: '2', alertGroup: 'recovered', uuid: '222-222' }) ); expect(enqueueFunction).toHaveBeenCalledTimes(isBulk ? 1 : 2); @@ -1428,7 +1428,12 @@ describe('Task Runner', () => { isBulk ? [ generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), - generateEnqueueFunctionInput({ isBulk: false, id: '2', isResolved: true }), + generateEnqueueFunctionInput({ + isBulk: false, + id: '2', + isResolved: true, + uuid: '222-222', + }), ] : generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }) ); @@ -1645,7 +1650,12 @@ describe('Task Runner', () => { isBulk ? [ generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), - generateEnqueueFunctionInput({ isBulk: false, id: '2', isResolved: true }), + generateEnqueueFunctionInput({ + isBulk: false, + id: '2', + isResolved: true, + uuid: '222-222', + }), ] : generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }) ); @@ -2891,26 +2901,31 @@ describe('Task Runner', () => { { group: 'default', id: '1', + uuid: '111-111', actionTypeId: 'action', }, { group: 'default', id: '2', + uuid: '222-222', actionTypeId: 'action', }, { group: 'default', id: '3', + uuid: '333-333', actionTypeId: 'action', }, { group: 'default', id: '4', + uuid: '444-444', actionTypeId: 'action', }, { group: 'default', id: '5', + uuid: '555-555', actionTypeId: 'action', }, ]; @@ -2975,7 +2990,7 @@ describe('Task Runner', () => { }) ); - expect(logger.debug).toHaveBeenCalledTimes(7); + expect(logger.debug).toHaveBeenCalledTimes(8); expect(logger.debug).nthCalledWith( 3, @@ -3012,11 +3027,11 @@ describe('Task Runner', () => { expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith( 2, - generateActionOpts({ id: '2' }) + generateActionOpts({ id: '2', uuid: '222-222' }) ); expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith( 3, - generateActionOpts({ id: '3' }) + generateActionOpts({ id: '3', uuid: '333-333' }) ); }); @@ -3061,26 +3076,31 @@ describe('Task Runner', () => { { group: 'default', id: '1', + uuid: '111-111', actionTypeId: '.server-log', }, { group: 'default', id: '2', + uuid: '222-222', actionTypeId: '.server-log', }, { group: 'default', id: '3', + uuid: '333-333', actionTypeId: '.server-log', }, { group: 'default', id: '4', + uuid: '444-444', actionTypeId: 'any-action', }, { group: 'default', id: '5', + uuid: '555-555', actionTypeId: 'any-action', }, ] as RuleAction[], @@ -3176,7 +3196,7 @@ describe('Task Runner', () => { status: 'warning', errorReason: `maxExecutableActions`, logAlert: 4, - logAction: 3, + logAction: 5, }); }); From 742cd1336e71d2236608450e2a6a77b3ce9b3c4c Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Wed, 9 Oct 2024 17:01:49 -0400 Subject: [PATCH 091/110] Fixes Failing test: Jest Integration Tests.x-pack/plugins/task_manager/server/integration_tests - unrecognized task types should be no workload aggregator errors when there are removed task types (#195496) Resolves https://github.com/elastic/kibana/issues/194208 ## Summary The original integration test was checking for the (non) existence of any error logs on startup when there are removed task types, which was not specific enough because there were occasionally error logs like ``` "Task SLO:ORPHAN_SUMMARIES-CLEANUP-TASK \"SLO:ORPHAN_SUMMARIES-CLEANUP-TASK:1.0.0\" failed: ResponseError: search_phase_execution_exception ``` so this PR updates the integration test to check specifically for workload aggregator error logs Co-authored-by: Elastic Machine --- .../server/integration_tests/removed_types.test.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/task_manager/server/integration_tests/removed_types.test.ts b/x-pack/plugins/task_manager/server/integration_tests/removed_types.test.ts index 69bf717b95fc6..aeb182c4794e6 100644 --- a/x-pack/plugins/task_manager/server/integration_tests/removed_types.test.ts +++ b/x-pack/plugins/task_manager/server/integration_tests/removed_types.test.ts @@ -121,7 +121,15 @@ describe('unrecognized task types', () => { // so we want to wait that long to let it refresh await new Promise((r) => setTimeout(r, 5100)); - expect(errorLogSpy).not.toHaveBeenCalled(); + const errorLogCalls = errorLogSpy.mock.calls[0]; + + // if there are any error logs, none of them should be workload aggregator errors + if (errorLogCalls) { + // should be no workload aggregator errors + for (const elog of errorLogCalls) { + expect(elog).not.toMatch(/^\[WorkloadAggregator\]: Error: Unsupported task type/i); + } + } }); }); From 8f8e9883e0a8e78a632418a0677980f758450351 Mon Sep 17 00:00:00 2001 From: Kevin Lacabane Date: Wed, 9 Oct 2024 23:15:33 +0200 Subject: [PATCH 092/110] [eem] remove history transforms (#193999) ### Summary Remove history and backfill transforms, leaving latest transform in place. Notable changes to latest transform: - it does not read from history output anymore but source indices defined on the definition - it defines a `latest.lookbackPeriod` to limit the amount of data ingested, which defaults to 24h - each metadata aggregation now accepts a `metadata.aggregation.lookbackPeriod` which defaults to the `latest.lookbackPeriod` - `entity.firstSeenTimestamp` is removed. this should be temporary until we have a solution for https://github.com/elastic/elastic-entity-model/issues/174 - latest metrics used to get the latest pre-computed value from history data, but is it now aggregating over the `lookbackPeriod` in the source indices (which can be filtered down with `metrics.filter`) - `latest` block on the entity definition is now mandatory --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Mark Hopkin --- .../check_registered_types.test.ts | 2 +- .../schema/__snapshots__/common.test.ts.snap | 12 +- .../src/schema/common.test.ts | 30 +- .../kbn-entities-schema/src/schema/common.ts | 10 +- .../kbn-entities-schema/src/schema/entity.ts | 1 - .../src/schema/entity_definition.ts | 39 ++- .../common/constants_entities.ts | 8 +- .../built_in/containers_from_ecs_data.ts | 4 +- .../entities/built_in/hosts_from_ecs_data.ts | 4 +- .../built_in/services_from_ecs_data.ts | 5 +- .../create_and_install_ingest_pipeline.ts | 40 +-- .../entities/create_and_install_transform.ts | 45 +-- .../lib/entities/delete_ingest_pipeline.ts | 24 +- .../server/lib/entities/delete_transforms.ts | 57 ++- .../lib/entities/find_entity_definition.ts | 33 +- .../lib/entities/helpers/calculate_offset.ts | 34 -- .../fixtures/builtin_entity_definition.ts | 3 +- .../helpers/fixtures/entity_definition.ts | 9 +- .../entity_definition_with_backfill.ts | 51 --- .../lib/entities/helpers/fixtures/index.ts | 1 - .../entities/helpers/is_backfill_enabled.ts | 12 - .../generate_history_processors.test.ts.snap | 327 ------------------ .../generate_latest_processors.test.ts.snap | 140 ++++++-- .../generate_history_processors.test.ts | 21 -- .../generate_history_processors.ts | 222 ------------ .../generate_latest_processors.ts | 90 +++-- .../install_entity_definition.test.ts | 133 ++++--- .../lib/entities/install_entity_definition.ts | 114 ++---- .../lib/entities/save_entity_definition.ts | 2 +- .../server/lib/entities/start_transforms.ts | 37 +- .../server/lib/entities/stop_transforms.ts | 65 ++-- .../entities_history_template.test.ts.snap | 152 -------- .../entities_history_template.test.ts | 21 -- .../templates/entities_history_template.ts | 96 ----- .../templates/entities_latest_template.ts | 15 +- .../generate_history_transform.test.ts.snap | 305 ---------------- .../generate_latest_transform.test.ts.snap | 150 ++++---- .../generate_history_transform.test.ts | 24 -- .../transform/generate_history_transform.ts | 178 ---------- .../transform/generate_latest_transform.ts | 97 ++++-- .../generate_metadata_aggregations.test.ts | 144 +------- .../generate_metadata_aggregations.ts | 54 +-- .../transform/generate_metric_aggregations.ts | 30 +- .../transform/validate_transform_ids.ts | 16 +- .../entities/uninstall_entity_definition.ts | 18 +- .../server/lib/entity_client.ts | 2 +- .../server/lib/manage_index_templates.ts | 39 ++- .../server/routes/enablement/disable.ts | 5 +- .../server/routes/enablement/enable.ts | 9 +- .../server/routes/entities/reset.ts | 30 +- .../server/saved_objects/entity_definition.ts | 33 ++ .../templates/components/helpers.test.ts | 31 -- .../server/templates/components/helpers.ts | 35 -- x-pack/plugins/entity_manager/tsconfig.json | 1 + .../server/services/get_entities.ts | 1 - .../entity_store/definition.ts | 6 +- .../apis/entity_manager/definitions.ts | 18 +- .../trial_license_complete_tier/engine.ts | 12 +- .../engine_nondefault_spaces.ts | 10 +- 59 files changed, 712 insertions(+), 2395 deletions(-) delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/helpers/calculate_offset.ts delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/entity_definition_with_backfill.ts delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/helpers/is_backfill_enabled.ts delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/__snapshots__/generate_history_processors.test.ts.snap delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_history_processors.test.ts delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_history_processors.ts delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/templates/__snapshots__/entities_history_template.test.ts.snap delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/templates/entities_history_template.test.ts delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/templates/entities_history_template.ts delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/transform/__snapshots__/generate_history_transform.test.ts.snap delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/transform/generate_history_transform.test.ts delete mode 100644 x-pack/plugins/entity_manager/server/lib/entities/transform/generate_history_transform.ts delete mode 100644 x-pack/plugins/entity_manager/server/templates/components/helpers.test.ts delete mode 100644 x-pack/plugins/entity_manager/server/templates/components/helpers.ts diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index c8803a1fbd071..7736e1ad7e90b 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -91,7 +91,7 @@ describe('checking migration metadata changes on all registered SO types', () => "endpoint:unified-user-artifact-manifest": "71c7fcb52c658b21ea2800a6b6a76972ae1c776e", "endpoint:user-artifact-manifest": "1c3533161811a58772e30cdc77bac4631da3ef2b", "enterprise_search_telemetry": "9ac912e1417fc8681e0cd383775382117c9e3d3d", - "entity-definition": "61be3e95966045122b55e181bb39658b1dc9bbe9", + "entity-definition": "e3811fd5fbb878d170067c0d6897a2e63010af36", "entity-discovery-api-key": "c267a65c69171d1804362155c1378365f5acef88", "entity-engine-status": "0738aa1a06d3361911740f8f166071ea43a00927", "epm-packages": "8042d4a1522f6c4e6f5486e791b3ffe3a22f88fd", diff --git a/x-pack/packages/kbn-entities-schema/src/schema/__snapshots__/common.test.ts.snap b/x-pack/packages/kbn-entities-schema/src/schema/__snapshots__/common.test.ts.snap index 9210d3b9991cf..766ce1c70ac3a 100644 --- a/x-pack/packages/kbn-entities-schema/src/schema/__snapshots__/common.test.ts.snap +++ b/x-pack/packages/kbn-entities-schema/src/schema/__snapshots__/common.test.ts.snap @@ -78,7 +78,8 @@ exports[`schemas metadataSchema should parse successfully with a source and desi Object { "data": Object { "aggregation": Object { - "limit": 1000, + "limit": 10, + "lookbackPeriod": undefined, "type": "terms", }, "destination": "hostName", @@ -92,7 +93,8 @@ exports[`schemas metadataSchema should parse successfully with an valid string 1 Object { "data": Object { "aggregation": Object { - "limit": 1000, + "limit": 10, + "lookbackPeriod": undefined, "type": "terms", }, "destination": "host.name", @@ -106,7 +108,8 @@ exports[`schemas metadataSchema should parse successfully with just a source 1`] Object { "data": Object { "aggregation": Object { - "limit": 1000, + "limit": 10, + "lookbackPeriod": undefined, "type": "terms", }, "destination": "host.name", @@ -120,7 +123,8 @@ exports[`schemas metadataSchema should parse successfully with valid object 1`] Object { "data": Object { "aggregation": Object { - "limit": 1000, + "limit": 10, + "lookbackPeriod": undefined, "type": "terms", }, "destination": "hostName", diff --git a/x-pack/packages/kbn-entities-schema/src/schema/common.test.ts b/x-pack/packages/kbn-entities-schema/src/schema/common.test.ts index 1a737ac3f4d9b..210e34943bd40 100644 --- a/x-pack/packages/kbn-entities-schema/src/schema/common.test.ts +++ b/x-pack/packages/kbn-entities-schema/src/schema/common.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { durationSchema, metadataSchema, semVerSchema, historySettingsSchema } from './common'; +import { durationSchema, metadataSchema, semVerSchema } from './common'; describe('schemas', () => { describe('metadataSchema', () => { @@ -66,7 +66,7 @@ describe('schemas', () => { expect(result.data).toEqual({ source: 'host.name', destination: 'hostName', - aggregation: { type: 'terms', limit: 1000 }, + aggregation: { type: 'terms', limit: 10, lookbackPeriod: undefined }, }); }); @@ -139,30 +139,4 @@ describe('schemas', () => { expect(result).toMatchSnapshot(); }); }); - - describe('historySettingsSchema', () => { - it('should return default values when not defined', () => { - let result = historySettingsSchema.safeParse(undefined); - expect(result.success).toBeTruthy(); - expect(result.data).toEqual({ lookbackPeriod: '1h' }); - - result = historySettingsSchema.safeParse({ syncDelay: '1m' }); - expect(result.success).toBeTruthy(); - expect(result.data).toEqual({ syncDelay: '1m', lookbackPeriod: '1h' }); - }); - - it('should return user defined values when defined', () => { - const result = historySettingsSchema.safeParse({ - lookbackPeriod: '30m', - syncField: 'event.ingested', - syncDelay: '5m', - }); - expect(result.success).toBeTruthy(); - expect(result.data).toEqual({ - lookbackPeriod: '30m', - syncField: 'event.ingested', - syncDelay: '5m', - }); - }); - }); }); diff --git a/x-pack/packages/kbn-entities-schema/src/schema/common.ts b/x-pack/packages/kbn-entities-schema/src/schema/common.ts index aa54dbd16c9aa..caecf48d88aac 100644 --- a/x-pack/packages/kbn-entities-schema/src/schema/common.ts +++ b/x-pack/packages/kbn-entities-schema/src/schema/common.ts @@ -85,7 +85,11 @@ export const keyMetricSchema = z.object({ export type KeyMetric = z.infer; export const metadataAggregation = z.union([ - z.object({ type: z.literal('terms'), limit: z.number().default(1000) }), + z.object({ + type: z.literal('terms'), + limit: z.number().default(10), + lookbackPeriod: z.optional(durationSchema), + }), z.object({ type: z.literal('top_value'), sort: z.record(z.string(), z.union([z.literal('asc'), z.literal('desc')])), @@ -99,13 +103,13 @@ export const metadataSchema = z destination: z.optional(z.string()), aggregation: z .optional(metadataAggregation) - .default({ type: z.literal('terms').value, limit: 1000 }), + .default({ type: z.literal('terms').value, limit: 10, lookbackPeriod: undefined }), }) .or( z.string().transform((value) => ({ source: value, destination: value, - aggregation: { type: z.literal('terms').value, limit: 1000 }, + aggregation: { type: z.literal('terms').value, limit: 10, lookbackPeriod: undefined }, })) ) .transform((metadata) => ({ diff --git a/x-pack/packages/kbn-entities-schema/src/schema/entity.ts b/x-pack/packages/kbn-entities-schema/src/schema/entity.ts index eae6873356c14..3eb87a797ef21 100644 --- a/x-pack/packages/kbn-entities-schema/src/schema/entity.ts +++ b/x-pack/packages/kbn-entities-schema/src/schema/entity.ts @@ -35,7 +35,6 @@ export const entityLatestSchema = z entity: entityBaseSchema.merge( z.object({ lastSeenTimestamp: z.string(), - firstSeenTimestamp: z.string(), }) ), }) diff --git a/x-pack/packages/kbn-entities-schema/src/schema/entity_definition.ts b/x-pack/packages/kbn-entities-schema/src/schema/entity_definition.ts index 74be36cc5d802..d9d8e6b610013 100644 --- a/x-pack/packages/kbn-entities-schema/src/schema/entity_definition.ts +++ b/x-pack/packages/kbn-entities-schema/src/schema/entity_definition.ts @@ -14,8 +14,6 @@ import { durationSchema, identityFieldsSchema, semVerSchema, - historySettingsSchema, - durationSchemaWithMinimum, } from './common'; export const entityDefinitionSchema = z.object({ @@ -32,22 +30,17 @@ export const entityDefinitionSchema = z.object({ metrics: z.optional(z.array(keyMetricSchema)), staticFields: z.optional(z.record(z.string(), z.string())), managed: z.optional(z.boolean()).default(false), - history: z.object({ + latest: z.object({ timestampField: z.string(), - interval: durationSchemaWithMinimum(1), - settings: historySettingsSchema, + lookbackPeriod: z.optional(durationSchema).default('24h'), + settings: z.optional( + z.object({ + syncField: z.optional(z.string()), + syncDelay: z.optional(durationSchema), + frequency: z.optional(durationSchema), + }) + ), }), - latest: z.optional( - z.object({ - settings: z.optional( - z.object({ - syncField: z.optional(z.string()), - syncDelay: z.optional(durationSchema), - frequency: z.optional(durationSchema), - }) - ), - }) - ), installStatus: z.optional( z.union([ z.literal('installing'), @@ -57,6 +50,18 @@ export const entityDefinitionSchema = z.object({ ]) ), installStartedAt: z.optional(z.string()), + installedComponents: z.optional( + z.array( + z.object({ + type: z.union([ + z.literal('transform'), + z.literal('ingest_pipeline'), + z.literal('template'), + ]), + id: z.string(), + }) + ) + ), }); export const entityDefinitionUpdateSchema = entityDefinitionSchema @@ -69,7 +74,7 @@ export const entityDefinitionUpdateSchema = entityDefinitionSchema .partial() .merge( z.object({ - history: z.optional(entityDefinitionSchema.shape.history.partial()), + latest: z.optional(entityDefinitionSchema.shape.latest.partial()), version: semVerSchema, }) ); diff --git a/x-pack/plugins/entity_manager/common/constants_entities.ts b/x-pack/plugins/entity_manager/common/constants_entities.ts index c53847afbb548..c17e6f33918c6 100644 --- a/x-pack/plugins/entity_manager/common/constants_entities.ts +++ b/x-pack/plugins/entity_manager/common/constants_entities.ts @@ -33,8 +33,6 @@ export const ENTITY_LATEST_PREFIX_V1 = `${ENTITY_BASE_PREFIX}-${ENTITY_SCHEMA_VERSION_V1}-${ENTITY_LATEST}` as const; // Transform constants -export const ENTITY_DEFAULT_HISTORY_FREQUENCY = '1m'; -export const ENTITY_DEFAULT_HISTORY_SYNC_DELAY = '60s'; -export const ENTITY_DEFAULT_LATEST_FREQUENCY = '30s'; -export const ENTITY_DEFAULT_LATEST_SYNC_DELAY = '1s'; -export const ENTITY_DEFAULT_METADATA_LIMIT = 1000; +export const ENTITY_DEFAULT_LATEST_FREQUENCY = '1m'; +export const ENTITY_DEFAULT_LATEST_SYNC_DELAY = '60s'; +export const ENTITY_DEFAULT_METADATA_LIMIT = 10; diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/containers_from_ecs_data.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/containers_from_ecs_data.ts index 6ce76e127c8e8..e3356c4826ae8 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/containers_from_ecs_data.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/containers_from_ecs_data.ts @@ -20,9 +20,9 @@ export const builtInContainersFromEcsEntityDefinition: EntityDefinition = indexPatterns: ['filebeat-*', 'logs-*', 'metrics-*', 'metricbeat-*'], identityFields: ['container.id'], displayNameTemplate: '{{container.id}}', - history: { + latest: { timestampField: '@timestamp', - interval: '5m', + lookbackPeriod: '10m', settings: { frequency: '5m', }, diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/hosts_from_ecs_data.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/hosts_from_ecs_data.ts index 56f83d5fbaed6..5d7a30093419e 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/hosts_from_ecs_data.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/hosts_from_ecs_data.ts @@ -19,9 +19,9 @@ export const builtInHostsFromEcsEntityDefinition: EntityDefinition = entityDefin indexPatterns: ['filebeat-*', 'logs-*', 'metrics-*', 'metricbeat-*'], identityFields: ['host.name'], displayNameTemplate: '{{host.name}}', - history: { + latest: { timestampField: '@timestamp', - interval: '5m', + lookbackPeriod: '10m', settings: { frequency: '5m', }, diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/services_from_ecs_data.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/services_from_ecs_data.ts index 6caa209da02ca..d6aa4d08ad221 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/services_from_ecs_data.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/services_from_ecs_data.ts @@ -18,11 +18,10 @@ export const builtInServicesFromEcsEntityDefinition: EntityDefinition = type: 'service', managed: true, indexPatterns: ['logs-*', 'filebeat*', 'traces-apm*'], - history: { + latest: { timestampField: '@timestamp', - interval: '1m', + lookbackPeriod: '10m', settings: { - lookbackPeriod: '10m', frequency: '2m', syncDelay: '2m', }, diff --git a/x-pack/plugins/entity_manager/server/lib/entities/create_and_install_ingest_pipeline.ts b/x-pack/plugins/entity_manager/server/lib/entities/create_and_install_ingest_pipeline.ts index 360f416cd5a00..0b3900363c0c8 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/create_and_install_ingest_pipeline.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/create_and_install_ingest_pipeline.ts @@ -7,46 +7,15 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { EntityDefinition } from '@kbn/entities-schema'; -import { - generateHistoryIngestPipelineId, - generateLatestIngestPipelineId, -} from './helpers/generate_component_id'; +import { generateLatestIngestPipelineId } from './helpers/generate_component_id'; import { retryTransientEsErrors } from './helpers/retry'; -import { generateHistoryProcessors } from './ingest_pipeline/generate_history_processors'; import { generateLatestProcessors } from './ingest_pipeline/generate_latest_processors'; -export async function createAndInstallHistoryIngestPipeline( +export async function createAndInstallIngestPipelines( esClient: ElasticsearchClient, definition: EntityDefinition, logger: Logger -) { - try { - const historyProcessors = generateHistoryProcessors(definition); - const historyId = generateHistoryIngestPipelineId(definition); - await retryTransientEsErrors( - () => - esClient.ingest.putPipeline({ - id: historyId, - processors: historyProcessors, - _meta: { - definitionVersion: definition.version, - managed: definition.managed, - }, - }), - { logger } - ); - } catch (e) { - logger.error( - `Cannot create entity history ingest pipelines for [${definition.id}] entity defintion` - ); - throw e; - } -} -export async function createAndInstallLatestIngestPipeline( - esClient: ElasticsearchClient, - definition: EntityDefinition, - logger: Logger -) { +): Promise> { try { const latestProcessors = generateLatestProcessors(definition); const latestId = generateLatestIngestPipelineId(definition); @@ -62,9 +31,10 @@ export async function createAndInstallLatestIngestPipeline( }), { logger } ); + return [{ type: 'ingest_pipeline', id: latestId }]; } catch (e) { logger.error( - `Cannot create entity latest ingest pipelines for [${definition.id}] entity defintion` + `Cannot create entity latest ingest pipelines for [${definition.id}] entity definition` ); throw e; } diff --git a/x-pack/plugins/entity_manager/server/lib/entities/create_and_install_transform.ts b/x-pack/plugins/entity_manager/server/lib/entities/create_and_install_transform.ts index d6379773479fc..779e0994a33b8 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/create_and_install_transform.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/create_and_install_transform.ts @@ -9,57 +9,20 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { EntityDefinition } from '@kbn/entities-schema'; import { retryTransientEsErrors } from './helpers/retry'; import { generateLatestTransform } from './transform/generate_latest_transform'; -import { - generateBackfillHistoryTransform, - generateHistoryTransform, -} from './transform/generate_history_transform'; -export async function createAndInstallHistoryTransform( +export async function createAndInstallTransforms( esClient: ElasticsearchClient, definition: EntityDefinition, logger: Logger -) { - try { - const historyTransform = generateHistoryTransform(definition); - await retryTransientEsErrors(() => esClient.transform.putTransform(historyTransform), { - logger, - }); - } catch (e) { - logger.error(`Cannot create entity history transform for [${definition.id}] entity definition`); - throw e; - } -} - -export async function createAndInstallHistoryBackfillTransform( - esClient: ElasticsearchClient, - definition: EntityDefinition, - logger: Logger -) { - try { - const historyTransform = generateBackfillHistoryTransform(definition); - await retryTransientEsErrors(() => esClient.transform.putTransform(historyTransform), { - logger, - }); - } catch (e) { - logger.error( - `Cannot create entity history backfill transform for [${definition.id}] entity definition` - ); - throw e; - } -} - -export async function createAndInstallLatestTransform( - esClient: ElasticsearchClient, - definition: EntityDefinition, - logger: Logger -) { +): Promise> { try { const latestTransform = generateLatestTransform(definition); await retryTransientEsErrors(() => esClient.transform.putTransform(latestTransform), { logger, }); + return [{ type: 'transform', id: latestTransform.transform_id }]; } catch (e) { - logger.error(`Cannot create entity latest transform for [${definition.id}] entity definition`); + logger.error(`Cannot create entity history transform for [${definition.id}] entity definition`); throw e; } } diff --git a/x-pack/plugins/entity_manager/server/lib/entities/delete_ingest_pipeline.ts b/x-pack/plugins/entity_manager/server/lib/entities/delete_ingest_pipeline.ts index f4c46d8447d8f..a3b910dd4cb5e 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/delete_ingest_pipeline.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/delete_ingest_pipeline.ts @@ -7,24 +7,24 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { EntityDefinition } from '@kbn/entities-schema'; -import { - generateHistoryIngestPipelineId, - generateLatestIngestPipelineId, -} from './helpers/generate_component_id'; import { retryTransientEsErrors } from './helpers/retry'; +import { generateLatestIngestPipelineId } from './helpers/generate_component_id'; -export async function deleteHistoryIngestPipeline( +export async function deleteIngestPipelines( esClient: ElasticsearchClient, definition: EntityDefinition, logger: Logger ) { try { - const historyPipelineId = generateHistoryIngestPipelineId(definition); - await retryTransientEsErrors(() => - esClient.ingest.deletePipeline({ id: historyPipelineId }, { ignore: [404] }) + await Promise.all( + (definition.installedComponents ?? []) + .filter(({ type }) => type === 'ingest_pipeline') + .map(({ id }) => + retryTransientEsErrors(() => esClient.ingest.deletePipeline({ id }, { ignore: [404] })) + ) ); } catch (e) { - logger.error(`Unable to delete history ingest pipeline [${definition.id}]: ${e}`); + logger.error(`Unable to delete ingest pipelines for definition [${definition.id}]: ${e}`); throw e; } } @@ -35,9 +35,11 @@ export async function deleteLatestIngestPipeline( logger: Logger ) { try { - const latestPipelineId = generateLatestIngestPipelineId(definition); await retryTransientEsErrors(() => - esClient.ingest.deletePipeline({ id: latestPipelineId }, { ignore: [404] }) + esClient.ingest.deletePipeline( + { id: generateLatestIngestPipelineId(definition) }, + { ignore: [404] } + ) ); } catch (e) { logger.error(`Unable to delete latest ingest pipeline [${definition.id}]: ${e}`); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/delete_transforms.ts b/x-pack/plugins/entity_manager/server/lib/entities/delete_transforms.ts index a66c0998c014d..79b83998d38db 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/delete_transforms.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/delete_transforms.ts @@ -7,14 +7,8 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { EntityDefinition } from '@kbn/entities-schema'; - -import { - generateHistoryTransformId, - generateHistoryBackfillTransformId, - generateLatestTransformId, -} from './helpers/generate_component_id'; import { retryTransientEsErrors } from './helpers/retry'; -import { isBackfillEnabled } from './helpers/is_backfill_enabled'; +import { generateLatestTransformId } from './helpers/generate_component_id'; export async function deleteTransforms( esClient: ElasticsearchClient, @@ -22,37 +16,42 @@ export async function deleteTransforms( logger: Logger ) { try { - const historyTransformId = generateHistoryTransformId(definition); - const latestTransformId = generateLatestTransformId(definition); - await retryTransientEsErrors( - () => - esClient.transform.deleteTransform( - { transform_id: historyTransformId, force: true }, - { ignore: [404] } - ), - { logger } + await Promise.all( + (definition.installedComponents ?? []) + .filter(({ type }) => type === 'transform') + .map(({ id }) => + retryTransientEsErrors( + () => + esClient.transform.deleteTransform( + { transform_id: id, force: true }, + { ignore: [404] } + ), + { logger } + ) + ) ); - if (isBackfillEnabled(definition)) { - const historyBackfillTransformId = generateHistoryBackfillTransformId(definition); - await retryTransientEsErrors( - () => - esClient.transform.deleteTransform( - { transform_id: historyBackfillTransformId, force: true }, - { ignore: [404] } - ), - { logger } - ); - } + } catch (e) { + logger.error(`Cannot delete transforms for definition [${definition.id}]: ${e}`); + throw e; + } +} + +export async function deleteLatestTransform( + esClient: ElasticsearchClient, + definition: EntityDefinition, + logger: Logger +) { + try { await retryTransientEsErrors( () => esClient.transform.deleteTransform( - { transform_id: latestTransformId, force: true }, + { transform_id: generateLatestTransformId(definition), force: true }, { ignore: [404] } ), { logger } ); } catch (e) { - logger.error(`Cannot delete history transform [${definition.id}]: ${e}`); + logger.error(`Cannot delete latest transform for definition [${definition.id}]: ${e}`); throw e; } } diff --git a/x-pack/plugins/entity_manager/server/lib/entities/find_entity_definition.ts b/x-pack/plugins/entity_manager/server/lib/entities/find_entity_definition.ts index d1d84f27414af..cfbb5a5ef5556 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/find_entity_definition.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/find_entity_definition.ts @@ -10,18 +10,8 @@ import { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/serve import { EntityDefinition } from '@kbn/entities-schema'; import { NodesIngestTotal } from '@elastic/elasticsearch/lib/api/types'; import { SO_ENTITY_DEFINITION_TYPE } from '../../saved_objects'; -import { - generateHistoryTransformId, - generateHistoryBackfillTransformId, - generateHistoryIngestPipelineId, - generateHistoryIndexTemplateId, - generateLatestTransformId, - generateLatestIngestPipelineId, - generateLatestIndexTemplateId, -} from './helpers/generate_component_id'; import { BUILT_IN_ID_PREFIX } from './built_in'; import { EntityDefinitionState, EntityDefinitionWithState } from './types'; -import { isBackfillEnabled } from './helpers/is_backfill_enabled'; export async function findEntityDefinitions({ soClient, @@ -120,11 +110,9 @@ async function getTransformState({ definition: EntityDefinition; esClient: ElasticsearchClient; }) { - const transformIds = [ - generateHistoryTransformId(definition), - generateLatestTransformId(definition), - ...(isBackfillEnabled(definition) ? [generateHistoryBackfillTransformId(definition)] : []), - ]; + const transformIds = (definition.installedComponents ?? []) + .filter(({ type }) => type === 'transform') + .map(({ id }) => id); const transformStats = await Promise.all( transformIds.map((id) => esClient.transform.getTransformStats({ transform_id: id })) @@ -152,10 +140,10 @@ async function getIngestPipelineState({ definition: EntityDefinition; esClient: ElasticsearchClient; }) { - const ingestPipelineIds = [ - generateHistoryIngestPipelineId(definition), - generateLatestIngestPipelineId(definition), - ]; + const ingestPipelineIds = (definition.installedComponents ?? []) + .filter(({ type }) => type === 'ingest_pipeline') + .map(({ id }) => id); + const [ingestPipelines, ingestPipelinesStats] = await Promise.all([ esClient.ingest.getPipeline({ id: ingestPipelineIds.join(',') }, { ignore: [404] }), esClient.nodes.stats({ @@ -193,10 +181,9 @@ async function getIndexTemplatesState({ definition: EntityDefinition; esClient: ElasticsearchClient; }) { - const indexTemplatesIds = [ - generateLatestIndexTemplateId(definition), - generateHistoryIndexTemplateId(definition), - ]; + const indexTemplatesIds = (definition.installedComponents ?? []) + .filter(({ type }) => type === 'template') + .map(({ id }) => id); const templates = await Promise.all( indexTemplatesIds.map((id) => esClient.indices diff --git a/x-pack/plugins/entity_manager/server/lib/entities/helpers/calculate_offset.ts b/x-pack/plugins/entity_manager/server/lib/entities/helpers/calculate_offset.ts deleted file mode 100644 index 3eba710561abf..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/helpers/calculate_offset.ts +++ /dev/null @@ -1,34 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EntityDefinition } from '@kbn/entities-schema'; -import moment from 'moment'; -import { - ENTITY_DEFAULT_HISTORY_FREQUENCY, - ENTITY_DEFAULT_HISTORY_SYNC_DELAY, -} from '../../../../common/constants_entities'; - -const durationToSeconds = (dateMath: string) => { - const parts = dateMath.match(/(\d+)([m|s|h|d])/); - if (!parts) { - throw new Error(`Invalid date math supplied: ${dateMath}`); - } - const value = parseInt(parts[1], 10); - const unit = parts[2] as 'm' | 's' | 'h' | 'd'; - return moment.duration(value, unit).asSeconds(); -}; - -export function calculateOffset(definition: EntityDefinition) { - const syncDelay = durationToSeconds( - definition.history.settings.syncDelay || ENTITY_DEFAULT_HISTORY_SYNC_DELAY - ); - const frequency = - durationToSeconds(definition.history.settings.frequency || ENTITY_DEFAULT_HISTORY_FREQUENCY) * - 2; - - return syncDelay + frequency; -} diff --git a/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/builtin_entity_definition.ts b/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/builtin_entity_definition.ts index 5092e2caa5d78..b1e506150fb60 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/builtin_entity_definition.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/builtin_entity_definition.ts @@ -13,9 +13,8 @@ export const builtInEntityDefinition = entityDefinitionSchema.parse({ type: 'service', indexPatterns: ['kbn-data-forge-fake_stack.*'], managed: true, - history: { + latest: { timestampField: '@timestamp', - interval: '1m', }, identityFields: ['log.logger', { field: 'event.category', optional: true }], displayNameTemplate: '{{log.logger}}{{#event.category}}:{{.}}{{/event.category}}', diff --git a/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/entity_definition.ts b/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/entity_definition.ts index 940e209260c54..00ab9ac7759af 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/entity_definition.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/entity_definition.ts @@ -12,13 +12,12 @@ export const rawEntityDefinition = { name: 'Services for Admin Console', type: 'service', indexPatterns: ['kbn-data-forge-fake_stack.*'], - history: { + latest: { timestampField: '@timestamp', - interval: '1m', + lookbackPeriod: '10m', settings: { - lookbackPeriod: '10m', - frequency: '2m', - syncDelay: '2m', + frequency: '30s', + syncDelay: '10s', }, }, identityFields: ['log.logger', { field: 'event.category', optional: true }], diff --git a/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/entity_definition_with_backfill.ts b/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/entity_definition_with_backfill.ts deleted file mode 100644 index 66a79825fbfb0..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/entity_definition_with_backfill.ts +++ /dev/null @@ -1,51 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { entityDefinitionSchema } from '@kbn/entities-schema'; -export const entityDefinitionWithBackfill = entityDefinitionSchema.parse({ - id: 'admin-console-services-backfill', - version: '999.999.999', - name: 'Services for Admin Console', - type: 'service', - indexPatterns: ['kbn-data-forge-fake_stack.*'], - history: { - timestampField: '@timestamp', - interval: '1m', - settings: { - backfillSyncDelay: '15m', - backfillLookbackPeriod: '72h', - backfillFrequency: '5m', - }, - }, - identityFields: ['log.logger', { field: 'event.category', optional: true }], - displayNameTemplate: '{{log.logger}}{{#event.category}}:{{.}}{{/event.category}}', - metadata: ['tags', 'host.name', 'host.os.name', { source: '_index', destination: 'sourceIndex' }], - metrics: [ - { - name: 'logRate', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'doc_count', - filter: 'log.level: *', - }, - ], - }, - { - name: 'errorRate', - equation: 'A', - metrics: [ - { - name: 'A', - aggregation: 'doc_count', - filter: 'log.level: "ERROR"', - }, - ], - }, - ], -}); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/index.ts b/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/index.ts index c24dcee1f8cf7..e841b1c8e23dd 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/index.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/helpers/fixtures/index.ts @@ -6,5 +6,4 @@ */ export { entityDefinition } from './entity_definition'; -export { entityDefinitionWithBackfill } from './entity_definition_with_backfill'; export { builtInEntityDefinition } from './builtin_entity_definition'; diff --git a/x-pack/plugins/entity_manager/server/lib/entities/helpers/is_backfill_enabled.ts b/x-pack/plugins/entity_manager/server/lib/entities/helpers/is_backfill_enabled.ts deleted file mode 100644 index 4c34f5d3c0256..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/helpers/is_backfill_enabled.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EntityDefinition } from '@kbn/entities-schema'; - -export function isBackfillEnabled(definition: EntityDefinition) { - return definition.history.settings.backfillSyncDelay != null; -} diff --git a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/__snapshots__/generate_history_processors.test.ts.snap b/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/__snapshots__/generate_history_processors.test.ts.snap deleted file mode 100644 index c2e4605e5f909..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/__snapshots__/generate_history_processors.test.ts.snap +++ /dev/null @@ -1,327 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`generateHistoryProcessors(definition) should generate a valid pipeline for builtin definition 1`] = ` -Array [ - Object { - "set": Object { - "field": "event.ingested", - "value": "{{{_ingest.timestamp}}}", - }, - }, - Object { - "set": Object { - "field": "entity.type", - "value": "service", - }, - }, - Object { - "set": Object { - "field": "entity.definitionId", - "value": "builtin_mock_entity_definition", - }, - }, - Object { - "set": Object { - "field": "entity.definitionVersion", - "value": "1.0.0", - }, - }, - Object { - "set": Object { - "field": "entity.schemaVersion", - "value": "v1", - }, - }, - Object { - "set": Object { - "field": "entity.identityFields", - "value": Array [ - "log.logger", - "event.category", - ], - }, - }, - Object { - "script": Object { - "description": "Generated the entity.id field", - "source": "// This function will recursively collect all the values of a HashMap of HashMaps -Collection collectValues(HashMap subject) { - Collection values = new ArrayList(); - // Iterate through the values - for(Object value: subject.values()) { - // If the value is a HashMap, recurse - if (value instanceof HashMap) { - values.addAll(collectValues((HashMap) value)); - } else { - values.add(String.valueOf(value)); - } - } - return values; -} -// Create the string builder -StringBuilder entityId = new StringBuilder(); -if (ctx[\\"entity\\"][\\"identity\\"] != null) { - // Get the values as a collection - Collection values = collectValues(ctx[\\"entity\\"][\\"identity\\"]); - // Convert to a list and sort - List sortedValues = new ArrayList(values); - Collections.sort(sortedValues); - // Create comma delimited string - for(String instanceValue: sortedValues) { - entityId.append(instanceValue); - entityId.append(\\":\\"); - } - // Assign the entity.id - ctx[\\"entity\\"][\\"id\\"] = entityId.length() > 0 ? entityId.substring(0, entityId.length() - 1) : \\"unknown\\"; -}", - }, - }, - Object { - "fingerprint": Object { - "fields": Array [ - "entity.id", - ], - "method": "MurmurHash3", - "target_field": "entity.id", - }, - }, - Object { - "script": Object { - "source": "if (ctx.entity?.metadata?.tags != null) { - ctx.tags = ctx.entity.metadata.tags.keySet(); -} -if (ctx.entity?.metadata?.host?.name != null) { - if (ctx.host == null) { - ctx.host = new HashMap(); - } - ctx.host.name = ctx.entity.metadata.host.name.keySet(); -} -if (ctx.entity?.metadata?.host?.os?.name != null) { - if (ctx.host == null) { - ctx.host = new HashMap(); - } - if (ctx.host.os == null) { - ctx.host.os = new HashMap(); - } - ctx.host.os.name = ctx.entity.metadata.host.os.name.keySet(); -} -if (ctx.entity?.metadata?.sourceIndex != null) { - ctx.sourceIndex = ctx.entity.metadata.sourceIndex.keySet(); -}", - }, - }, - Object { - "remove": Object { - "field": "entity.metadata", - "ignore_missing": true, - }, - }, - Object { - "set": Object { - "field": "log.logger", - "if": "ctx.entity?.identity?.log?.logger != null", - "value": "{{entity.identity.log.logger}}", - }, - }, - Object { - "set": Object { - "field": "event.category", - "if": "ctx.entity?.identity?.event?.category != null", - "value": "{{entity.identity.event.category}}", - }, - }, - Object { - "remove": Object { - "field": "entity.identity", - "ignore_missing": true, - }, - }, - Object { - "date_index_name": Object { - "date_formats": Array [ - "UNIX_MS", - "ISO8601", - "yyyy-MM-dd'T'HH:mm:ss.SSSXX", - ], - "date_rounding": "M", - "field": "@timestamp", - "index_name_prefix": ".entities.v1.history.builtin_mock_entity_definition.", - }, - }, -] -`; - -exports[`generateHistoryProcessors(definition) should generate a valid pipeline for custom definition 1`] = ` -Array [ - Object { - "set": Object { - "field": "event.ingested", - "value": "{{{_ingest.timestamp}}}", - }, - }, - Object { - "set": Object { - "field": "entity.type", - "value": "service", - }, - }, - Object { - "set": Object { - "field": "entity.definitionId", - "value": "admin-console-services", - }, - }, - Object { - "set": Object { - "field": "entity.definitionVersion", - "value": "1.0.0", - }, - }, - Object { - "set": Object { - "field": "entity.schemaVersion", - "value": "v1", - }, - }, - Object { - "set": Object { - "field": "entity.identityFields", - "value": Array [ - "log.logger", - "event.category", - ], - }, - }, - Object { - "script": Object { - "description": "Generated the entity.id field", - "source": "// This function will recursively collect all the values of a HashMap of HashMaps -Collection collectValues(HashMap subject) { - Collection values = new ArrayList(); - // Iterate through the values - for(Object value: subject.values()) { - // If the value is a HashMap, recurse - if (value instanceof HashMap) { - values.addAll(collectValues((HashMap) value)); - } else { - values.add(String.valueOf(value)); - } - } - return values; -} -// Create the string builder -StringBuilder entityId = new StringBuilder(); -if (ctx[\\"entity\\"][\\"identity\\"] != null) { - // Get the values as a collection - Collection values = collectValues(ctx[\\"entity\\"][\\"identity\\"]); - // Convert to a list and sort - List sortedValues = new ArrayList(values); - Collections.sort(sortedValues); - // Create comma delimited string - for(String instanceValue: sortedValues) { - entityId.append(instanceValue); - entityId.append(\\":\\"); - } - // Assign the entity.id - ctx[\\"entity\\"][\\"id\\"] = entityId.length() > 0 ? entityId.substring(0, entityId.length() - 1) : \\"unknown\\"; -}", - }, - }, - Object { - "fingerprint": Object { - "fields": Array [ - "entity.id", - ], - "method": "MurmurHash3", - "target_field": "entity.id", - }, - }, - Object { - "script": Object { - "source": "if (ctx.entity?.metadata?.tags != null) { - ctx.tags = ctx.entity.metadata.tags.keySet(); -} -if (ctx.entity?.metadata?.host?.name != null) { - if (ctx.host == null) { - ctx.host = new HashMap(); - } - ctx.host.name = ctx.entity.metadata.host.name.keySet(); -} -if (ctx.entity?.metadata?.host?.os?.name != null) { - if (ctx.host == null) { - ctx.host = new HashMap(); - } - if (ctx.host.os == null) { - ctx.host.os = new HashMap(); - } - ctx.host.os.name = ctx.entity.metadata.host.os.name.keySet(); -} -if (ctx.entity?.metadata?.sourceIndex != null) { - ctx.sourceIndex = ctx.entity.metadata.sourceIndex.keySet(); -}", - }, - }, - Object { - "remove": Object { - "field": "entity.metadata", - "ignore_missing": true, - }, - }, - Object { - "set": Object { - "field": "log.logger", - "if": "ctx.entity?.identity?.log?.logger != null", - "value": "{{entity.identity.log.logger}}", - }, - }, - Object { - "set": Object { - "field": "event.category", - "if": "ctx.entity?.identity?.event?.category != null", - "value": "{{entity.identity.event.category}}", - }, - }, - Object { - "remove": Object { - "field": "entity.identity", - "ignore_missing": true, - }, - }, - Object { - "date_index_name": Object { - "date_formats": Array [ - "UNIX_MS", - "ISO8601", - "yyyy-MM-dd'T'HH:mm:ss.SSSXX", - ], - "date_rounding": "M", - "field": "@timestamp", - "index_name_prefix": ".entities.v1.history.admin-console-services.", - }, - }, - Object { - "pipeline": Object { - "ignore_missing_pipeline": true, - "name": "admin-console-services@platform", - }, - }, - Object { - "pipeline": Object { - "ignore_missing_pipeline": true, - "name": "admin-console-services-history@platform", - }, - }, - Object { - "pipeline": Object { - "ignore_missing_pipeline": true, - "name": "admin-console-services@custom", - }, - }, - Object { - "pipeline": Object { - "ignore_missing_pipeline": true, - "name": "admin-console-services-history@custom", - }, - }, -] -`; diff --git a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/__snapshots__/generate_latest_processors.test.ts.snap b/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/__snapshots__/generate_latest_processors.test.ts.snap index f277b3ac84ab8..218deda422fe2 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/__snapshots__/generate_latest_processors.test.ts.snap +++ b/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/__snapshots__/generate_latest_processors.test.ts.snap @@ -43,16 +43,60 @@ Array [ }, Object { "script": Object { - "source": "if (ctx.entity?.metadata?.tags.data != null) { + "description": "Generated the entity.id field", + "source": "// This function will recursively collect all the values of a HashMap of HashMaps +Collection collectValues(HashMap subject) { + Collection values = new ArrayList(); + // Iterate through the values + for(Object value: subject.values()) { + // If the value is a HashMap, recurse + if (value instanceof HashMap) { + values.addAll(collectValues((HashMap) value)); + } else { + values.add(String.valueOf(value)); + } + } + return values; +} +// Create the string builder +StringBuilder entityId = new StringBuilder(); +if (ctx[\\"entity\\"][\\"identity\\"] != null) { + // Get the values as a collection + Collection values = collectValues(ctx[\\"entity\\"][\\"identity\\"]); + // Convert to a list and sort + List sortedValues = new ArrayList(values); + Collections.sort(sortedValues); + // Create comma delimited string + for(String instanceValue: sortedValues) { + entityId.append(instanceValue); + entityId.append(\\":\\"); + } + // Assign the entity.id + ctx[\\"entity\\"][\\"id\\"] = entityId.length() > 0 ? entityId.substring(0, entityId.length() - 1) : \\"unknown\\"; +}", + }, + }, + Object { + "fingerprint": Object { + "fields": Array [ + "entity.id", + ], + "method": "MurmurHash3", + "target_field": "entity.id", + }, + }, + Object { + "script": Object { + "source": "if (ctx.entity?.metadata?.tags?.data != null) { ctx.tags = ctx.entity.metadata.tags.data.keySet(); } -if (ctx.entity?.metadata?.host?.name.data != null) { +if (ctx.entity?.metadata?.host?.name?.data != null) { if (ctx.host == null) { ctx.host = new HashMap(); } ctx.host.name = ctx.entity.metadata.host.name.data.keySet(); } -if (ctx.entity?.metadata?.host?.os?.name.data != null) { +if (ctx.entity?.metadata?.host?.os?.name?.data != null) { if (ctx.host == null) { ctx.host = new HashMap(); } @@ -61,7 +105,7 @@ if (ctx.entity?.metadata?.host?.os?.name.data != null) { } ctx.host.os.name = ctx.entity.metadata.host.os.name.data.keySet(); } -if (ctx.entity?.metadata?.sourceIndex.data != null) { +if (ctx.entity?.metadata?.sourceIndex?.data != null) { ctx.sourceIndex = ctx.entity.metadata.sourceIndex.data.keySet(); }", }, @@ -72,28 +116,18 @@ if (ctx.entity?.metadata?.sourceIndex.data != null) { "ignore_missing": true, }, }, - Object { - "dot_expander": Object { - "field": "log.logger", - "path": "entity.identity.log.logger.top_metric", - }, - }, Object { "set": Object { "field": "log.logger", - "value": "{{entity.identity.log.logger.top_metric.log.logger}}", - }, - }, - Object { - "dot_expander": Object { - "field": "event.category", - "path": "entity.identity.event.category.top_metric", + "if": "ctx.entity?.identity?.log?.logger != null", + "value": "{{entity.identity.log.logger}}", }, }, Object { "set": Object { "field": "event.category", - "value": "{{entity.identity.event.category.top_metric.event.category}}", + "if": "ctx.entity?.identity?.event?.category != null", + "value": "{{entity.identity.event.category}}", }, }, Object { @@ -160,16 +194,60 @@ Array [ }, Object { "script": Object { - "source": "if (ctx.entity?.metadata?.tags.data != null) { + "description": "Generated the entity.id field", + "source": "// This function will recursively collect all the values of a HashMap of HashMaps +Collection collectValues(HashMap subject) { + Collection values = new ArrayList(); + // Iterate through the values + for(Object value: subject.values()) { + // If the value is a HashMap, recurse + if (value instanceof HashMap) { + values.addAll(collectValues((HashMap) value)); + } else { + values.add(String.valueOf(value)); + } + } + return values; +} +// Create the string builder +StringBuilder entityId = new StringBuilder(); +if (ctx[\\"entity\\"][\\"identity\\"] != null) { + // Get the values as a collection + Collection values = collectValues(ctx[\\"entity\\"][\\"identity\\"]); + // Convert to a list and sort + List sortedValues = new ArrayList(values); + Collections.sort(sortedValues); + // Create comma delimited string + for(String instanceValue: sortedValues) { + entityId.append(instanceValue); + entityId.append(\\":\\"); + } + // Assign the entity.id + ctx[\\"entity\\"][\\"id\\"] = entityId.length() > 0 ? entityId.substring(0, entityId.length() - 1) : \\"unknown\\"; +}", + }, + }, + Object { + "fingerprint": Object { + "fields": Array [ + "entity.id", + ], + "method": "MurmurHash3", + "target_field": "entity.id", + }, + }, + Object { + "script": Object { + "source": "if (ctx.entity?.metadata?.tags?.data != null) { ctx.tags = ctx.entity.metadata.tags.data.keySet(); } -if (ctx.entity?.metadata?.host?.name.data != null) { +if (ctx.entity?.metadata?.host?.name?.data != null) { if (ctx.host == null) { ctx.host = new HashMap(); } ctx.host.name = ctx.entity.metadata.host.name.data.keySet(); } -if (ctx.entity?.metadata?.host?.os?.name.data != null) { +if (ctx.entity?.metadata?.host?.os?.name?.data != null) { if (ctx.host == null) { ctx.host = new HashMap(); } @@ -178,7 +256,7 @@ if (ctx.entity?.metadata?.host?.os?.name.data != null) { } ctx.host.os.name = ctx.entity.metadata.host.os.name.data.keySet(); } -if (ctx.entity?.metadata?.sourceIndex.data != null) { +if (ctx.entity?.metadata?.sourceIndex?.data != null) { ctx.sourceIndex = ctx.entity.metadata.sourceIndex.data.keySet(); }", }, @@ -189,28 +267,18 @@ if (ctx.entity?.metadata?.sourceIndex.data != null) { "ignore_missing": true, }, }, - Object { - "dot_expander": Object { - "field": "log.logger", - "path": "entity.identity.log.logger.top_metric", - }, - }, Object { "set": Object { "field": "log.logger", - "value": "{{entity.identity.log.logger.top_metric.log.logger}}", - }, - }, - Object { - "dot_expander": Object { - "field": "event.category", - "path": "entity.identity.event.category.top_metric", + "if": "ctx.entity?.identity?.log?.logger != null", + "value": "{{entity.identity.log.logger}}", }, }, Object { "set": Object { "field": "event.category", - "value": "{{entity.identity.event.category.top_metric.event.category}}", + "if": "ctx.entity?.identity?.event?.category != null", + "value": "{{entity.identity.event.category}}", }, }, Object { diff --git a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_history_processors.test.ts b/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_history_processors.test.ts deleted file mode 100644 index 717241b89143d..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_history_processors.test.ts +++ /dev/null @@ -1,21 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { entityDefinition, builtInEntityDefinition } from '../helpers/fixtures'; -import { generateHistoryProcessors } from './generate_history_processors'; - -describe('generateHistoryProcessors(definition)', () => { - it('should generate a valid pipeline for custom definition', () => { - const processors = generateHistoryProcessors(entityDefinition); - expect(processors).toMatchSnapshot(); - }); - - it('should generate a valid pipeline for builtin definition', () => { - const processors = generateHistoryProcessors(builtInEntityDefinition); - expect(processors).toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_history_processors.ts b/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_history_processors.ts deleted file mode 100644 index d51ab0be75db1..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_history_processors.ts +++ /dev/null @@ -1,222 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EntityDefinition, ENTITY_SCHEMA_VERSION_V1, MetadataField } from '@kbn/entities-schema'; -import { - initializePathScript, - cleanScript, -} from '../helpers/ingest_pipeline_script_processor_helpers'; -import { generateHistoryIndexName } from '../helpers/generate_component_id'; -import { isBuiltinDefinition } from '../helpers/is_builtin_definition'; - -function getMetadataSourceField({ aggregation, destination, source }: MetadataField) { - if (aggregation.type === 'terms') { - return `ctx.entity.metadata.${destination}.keySet()`; - } else if (aggregation.type === 'top_value') { - return `ctx.entity.metadata.${destination}.top_value["${source}"]`; - } -} - -function mapDestinationToPainless(metadata: MetadataField) { - const field = metadata.destination; - return ` - ${initializePathScript(field)} - ctx.${field} = ${getMetadataSourceField(metadata)}; - `; -} - -function createMetadataPainlessScript(definition: EntityDefinition) { - if (!definition.metadata) { - return ''; - } - - return definition.metadata.reduce((acc, metadata) => { - const { destination, source } = metadata; - const optionalFieldPath = destination.replaceAll('.', '?.'); - - if (metadata.aggregation.type === 'terms') { - const next = ` - if (ctx.entity?.metadata?.${optionalFieldPath} != null) { - ${mapDestinationToPainless(metadata)} - } - `; - return `${acc}\n${next}`; - } else if (metadata.aggregation.type === 'top_value') { - const next = ` - if (ctx.entity?.metadata?.${optionalFieldPath}?.top_value["${source}"] != null) { - ${mapDestinationToPainless(metadata)} - } - `; - return `${acc}\n${next}`; - } - - return acc; - }, ''); -} - -function liftIdentityFieldsToDocumentRoot(definition: EntityDefinition) { - return definition.identityFields.map((key) => ({ - set: { - if: `ctx.entity?.identity?.${key.field.replaceAll('.', '?.')} != null`, - field: key.field, - value: `{{entity.identity.${key.field}}}`, - }, - })); -} - -function getCustomIngestPipelines(definition: EntityDefinition) { - if (isBuiltinDefinition(definition)) { - return []; - } - - return [ - { - pipeline: { - ignore_missing_pipeline: true, - name: `${definition.id}@platform`, - }, - }, - { - pipeline: { - ignore_missing_pipeline: true, - name: `${definition.id}-history@platform`, - }, - }, - { - pipeline: { - ignore_missing_pipeline: true, - name: `${definition.id}@custom`, - }, - }, - { - pipeline: { - ignore_missing_pipeline: true, - name: `${definition.id}-history@custom`, - }, - }, - ]; -} - -export function generateHistoryProcessors(definition: EntityDefinition) { - return [ - { - set: { - field: 'event.ingested', - value: '{{{_ingest.timestamp}}}', - }, - }, - { - set: { - field: 'entity.type', - value: definition.type, - }, - }, - { - set: { - field: 'entity.definitionId', - value: definition.id, - }, - }, - { - set: { - field: 'entity.definitionVersion', - value: definition.version, - }, - }, - { - set: { - field: 'entity.schemaVersion', - value: ENTITY_SCHEMA_VERSION_V1, - }, - }, - { - set: { - field: 'entity.identityFields', - value: definition.identityFields.map((identityField) => identityField.field), - }, - }, - { - script: { - description: 'Generated the entity.id field', - source: cleanScript(` - // This function will recursively collect all the values of a HashMap of HashMaps - Collection collectValues(HashMap subject) { - Collection values = new ArrayList(); - // Iterate through the values - for(Object value: subject.values()) { - // If the value is a HashMap, recurse - if (value instanceof HashMap) { - values.addAll(collectValues((HashMap) value)); - } else { - values.add(String.valueOf(value)); - } - } - return values; - } - - // Create the string builder - StringBuilder entityId = new StringBuilder(); - - if (ctx["entity"]["identity"] != null) { - // Get the values as a collection - Collection values = collectValues(ctx["entity"]["identity"]); - - // Convert to a list and sort - List sortedValues = new ArrayList(values); - Collections.sort(sortedValues); - - // Create comma delimited string - for(String instanceValue: sortedValues) { - entityId.append(instanceValue); - entityId.append(":"); - } - - // Assign the entity.id - ctx["entity"]["id"] = entityId.length() > 0 ? entityId.substring(0, entityId.length() - 1) : "unknown"; - } - `), - }, - }, - { - fingerprint: { - fields: ['entity.id'], - target_field: 'entity.id', - method: 'MurmurHash3', - }, - }, - ...(definition.staticFields != null - ? Object.keys(definition.staticFields).map((field) => ({ - set: { field, value: definition.staticFields![field] }, - })) - : []), - ...(definition.metadata != null - ? [{ script: { source: cleanScript(createMetadataPainlessScript(definition)) } }] - : []), - { - remove: { - field: 'entity.metadata', - ignore_missing: true, - }, - }, - ...liftIdentityFieldsToDocumentRoot(definition), - { - remove: { - field: 'entity.identity', - ignore_missing: true, - }, - }, - { - date_index_name: { - field: '@timestamp', - index_name_prefix: `${generateHistoryIndexName(definition)}.`, - date_rounding: 'M', - date_formats: ['UNIX_MS', 'ISO8601', "yyyy-MM-dd'T'HH:mm:ss.SSSXX"], - }, - }, - ...getCustomIngestPipelines(definition), - ]; -} diff --git a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_latest_processors.ts b/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_latest_processors.ts index 16823221fffb3..0e3812de2e320 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_latest_processors.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/ingest_pipeline/generate_latest_processors.ts @@ -17,7 +17,7 @@ function getMetadataSourceField({ aggregation, destination, source }: MetadataFi if (aggregation.type === 'terms') { return `ctx.entity.metadata.${destination}.data.keySet()`; } else if (aggregation.type === 'top_value') { - return `ctx.entity.metadata.${destination}.top_value["${destination}"]`; + return `ctx.entity.metadata.${destination}.top_value["${source}"]`; } } @@ -35,19 +35,19 @@ function createMetadataPainlessScript(definition: EntityDefinition) { } return definition.metadata.reduce((acc, metadata) => { - const destination = metadata.destination; + const { destination, source } = metadata; const optionalFieldPath = destination.replaceAll('.', '?.'); if (metadata.aggregation.type === 'terms') { const next = ` - if (ctx.entity?.metadata?.${optionalFieldPath}.data != null) { + if (ctx.entity?.metadata?.${optionalFieldPath}?.data != null) { ${mapDestinationToPainless(metadata)} } `; return `${acc}\n${next}`; } else if (metadata.aggregation.type === 'top_value') { const next = ` - if (ctx.entity?.metadata?.${optionalFieldPath}?.top_value["${destination}"] != null) { + if (ctx.entity?.metadata?.${optionalFieldPath}?.top_value["${source}"] != null) { ${mapDestinationToPainless(metadata)} } `; @@ -59,30 +59,13 @@ function createMetadataPainlessScript(definition: EntityDefinition) { } function liftIdentityFieldsToDocumentRoot(definition: EntityDefinition) { - return definition.identityFields - .map((identityField) => { - const setProcessor = { - set: { - field: identityField.field, - value: `{{entity.identity.${identityField.field}.top_metric.${identityField.field}}}`, - }, - }; - - if (!identityField.field.includes('.')) { - return [setProcessor]; - } - - return [ - { - dot_expander: { - field: identityField.field, - path: `entity.identity.${identityField.field}.top_metric`, - }, - }, - setProcessor, - ]; - }) - .flat(); + return definition.identityFields.map((key) => ({ + set: { + if: `ctx.entity?.identity?.${key.field.replaceAll('.', '?.')} != null`, + field: key.field, + value: `{{entity.identity.${key.field}}}`, + }, + })); } function getCustomIngestPipelines(definition: EntityDefinition) { @@ -156,6 +139,55 @@ export function generateLatestProcessors(definition: EntityDefinition) { value: definition.identityFields.map((identityField) => identityField.field), }, }, + { + script: { + description: 'Generated the entity.id field', + source: cleanScript(` + // This function will recursively collect all the values of a HashMap of HashMaps + Collection collectValues(HashMap subject) { + Collection values = new ArrayList(); + // Iterate through the values + for(Object value: subject.values()) { + // If the value is a HashMap, recurse + if (value instanceof HashMap) { + values.addAll(collectValues((HashMap) value)); + } else { + values.add(String.valueOf(value)); + } + } + return values; + } + + // Create the string builder + StringBuilder entityId = new StringBuilder(); + + if (ctx["entity"]["identity"] != null) { + // Get the values as a collection + Collection values = collectValues(ctx["entity"]["identity"]); + + // Convert to a list and sort + List sortedValues = new ArrayList(values); + Collections.sort(sortedValues); + + // Create comma delimited string + for(String instanceValue: sortedValues) { + entityId.append(instanceValue); + entityId.append(":"); + } + + // Assign the entity.id + ctx["entity"]["id"] = entityId.length() > 0 ? entityId.substring(0, entityId.length() - 1) : "unknown"; + } + `), + }, + }, + { + fingerprint: { + fields: ['entity.id'], + target_field: 'entity.id', + method: 'MurmurHash3', + }, + }, ...(definition.staticFields != null ? Object.keys(definition.staticFields).map((field) => ({ set: { field, value: definition.staticFields![field] }, @@ -177,8 +209,8 @@ export function generateLatestProcessors(definition: EntityDefinition) { ignore_missing: true, }, }, + // This must happen AFTER we lift the identity fields into the root of the document { - // This must happen AFTER we lift the identity fields into the root of the document set: { field: 'entity.displayName', value: definition.displayNameTemplate, diff --git a/x-pack/plugins/entity_manager/server/lib/entities/install_entity_definition.test.ts b/x-pack/plugins/entity_manager/server/lib/entities/install_entity_definition.test.ts index 5cee21dc43a07..e07670c58fd9b 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/install_entity_definition.test.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/install_entity_definition.test.ts @@ -19,19 +19,23 @@ import { } from './install_entity_definition'; import { SO_ENTITY_DEFINITION_TYPE } from '../../saved_objects'; import { - generateHistoryIndexTemplateId, - generateHistoryIngestPipelineId, - generateHistoryTransformId, generateLatestIndexTemplateId, generateLatestIngestPipelineId, generateLatestTransformId, } from './helpers/generate_component_id'; -import { generateHistoryTransform } from './transform/generate_history_transform'; import { generateLatestTransform } from './transform/generate_latest_transform'; import { entityDefinition as mockEntityDefinition } from './helpers/fixtures/entity_definition'; import { EntityDefinitionIdInvalid } from './errors/entity_definition_id_invalid'; import { EntityIdConflict } from './errors/entity_id_conflict_error'; +const getExpectedInstalledComponents = (definition: EntityDefinition) => { + return [ + { type: 'template', id: generateLatestIndexTemplateId(definition) }, + { type: 'ingest_pipeline', id: generateLatestIngestPipelineId(definition) }, + { type: 'transform', id: generateLatestTransformId(definition) }, + ]; +}; + const assertHasCreatedDefinition = ( definition: EntityDefinition, soClient: SavedObjectsClientContract, @@ -44,6 +48,7 @@ const assertHasCreatedDefinition = ( ...definition, installStatus: 'installing', installStartedAt: expect.any(String), + installedComponents: [], }, { id: definition.id, @@ -54,29 +59,17 @@ const assertHasCreatedDefinition = ( expect(soClient.update).toBeCalledTimes(1); expect(soClient.update).toBeCalledWith(SO_ENTITY_DEFINITION_TYPE, definition.id, { installStatus: 'installed', + installedComponents: getExpectedInstalledComponents(definition), }); - expect(esClient.indices.putIndexTemplate).toBeCalledTimes(2); - expect(esClient.indices.putIndexTemplate).toBeCalledWith( - expect.objectContaining({ - name: `entities_v1_history_${definition.id}_index_template`, - }) - ); + expect(esClient.indices.putIndexTemplate).toBeCalledTimes(1); expect(esClient.indices.putIndexTemplate).toBeCalledWith( expect.objectContaining({ name: `entities_v1_latest_${definition.id}_index_template`, }) ); - expect(esClient.ingest.putPipeline).toBeCalledTimes(2); - expect(esClient.ingest.putPipeline).toBeCalledWith({ - id: generateHistoryIngestPipelineId(definition), - processors: expect.anything(), - _meta: { - definitionVersion: definition.version, - managed: definition.managed, - }, - }); + expect(esClient.ingest.putPipeline).toBeCalledTimes(1); expect(esClient.ingest.putPipeline).toBeCalledWith({ id: generateLatestIngestPipelineId(definition), processors: expect.anything(), @@ -86,8 +79,7 @@ const assertHasCreatedDefinition = ( }, }); - expect(esClient.transform.putTransform).toBeCalledTimes(2); - expect(esClient.transform.putTransform).toBeCalledWith(generateHistoryTransform(definition)); + expect(esClient.transform.putTransform).toBeCalledTimes(1); expect(esClient.transform.putTransform).toBeCalledWith(generateLatestTransform(definition)); }; @@ -101,32 +93,21 @@ const assertHasUpgradedDefinition = ( ...definition, installStatus: 'upgrading', installStartedAt: expect.any(String), + installedComponents: getExpectedInstalledComponents(definition), }); expect(soClient.update).toBeCalledWith(SO_ENTITY_DEFINITION_TYPE, definition.id, { installStatus: 'installed', + installedComponents: getExpectedInstalledComponents(definition), }); - expect(esClient.indices.putIndexTemplate).toBeCalledTimes(2); - expect(esClient.indices.putIndexTemplate).toBeCalledWith( - expect.objectContaining({ - name: `entities_v1_history_${definition.id}_index_template`, - }) - ); + expect(esClient.indices.putIndexTemplate).toBeCalledTimes(1); expect(esClient.indices.putIndexTemplate).toBeCalledWith( expect.objectContaining({ name: `entities_v1_latest_${definition.id}_index_template`, }) ); - expect(esClient.ingest.putPipeline).toBeCalledTimes(2); - expect(esClient.ingest.putPipeline).toBeCalledWith({ - id: generateHistoryIngestPipelineId(definition), - processors: expect.anything(), - _meta: { - definitionVersion: definition.version, - managed: definition.managed, - }, - }); + expect(esClient.ingest.putPipeline).toBeCalledTimes(1); expect(esClient.ingest.putPipeline).toBeCalledWith({ id: generateLatestIngestPipelineId(definition), processors: expect.anything(), @@ -136,8 +117,7 @@ const assertHasUpgradedDefinition = ( }, }); - expect(esClient.transform.putTransform).toBeCalledTimes(2); - expect(esClient.transform.putTransform).toBeCalledWith(generateHistoryTransform(definition)); + expect(esClient.transform.putTransform).toBeCalledTimes(1); expect(esClient.transform.putTransform).toBeCalledWith(generateLatestTransform(definition)); }; @@ -148,13 +128,7 @@ const assertHasDeletedDefinition = ( ) => { assertHasDeletedTransforms(definition, esClient); - expect(esClient.ingest.deletePipeline).toBeCalledTimes(2); - expect(esClient.ingest.deletePipeline).toBeCalledWith( - { - id: generateHistoryIngestPipelineId(definition), - }, - { ignore: [404] } - ); + expect(esClient.ingest.deletePipeline).toBeCalledTimes(1); expect(esClient.ingest.deletePipeline).toBeCalledWith( { id: generateLatestIngestPipelineId(definition), @@ -162,13 +136,7 @@ const assertHasDeletedDefinition = ( { ignore: [404] } ); - expect(esClient.indices.deleteIndexTemplate).toBeCalledTimes(2); - expect(esClient.indices.deleteIndexTemplate).toBeCalledWith( - { - name: generateHistoryIndexTemplateId(definition), - }, - { ignore: [404] } - ); + expect(esClient.indices.deleteIndexTemplate).toBeCalledTimes(1); expect(esClient.indices.deleteIndexTemplate).toBeCalledWith( { name: generateLatestIndexTemplateId(definition), @@ -184,33 +152,21 @@ const assertHasDeletedTransforms = ( definition: EntityDefinition, esClient: ElasticsearchClient ) => { - expect(esClient.transform.stopTransform).toBeCalledTimes(2); - expect(esClient.transform.stopTransform).toBeCalledWith( - expect.objectContaining({ - transform_id: generateHistoryTransformId(definition), - }), - expect.anything() - ); - expect(esClient.transform.deleteTransform).toBeCalledWith( - expect.objectContaining({ - transform_id: generateHistoryTransformId(definition), - }), - expect.anything() - ); + expect(esClient.transform.stopTransform).toBeCalledTimes(1); expect(esClient.transform.stopTransform).toBeCalledWith( expect.objectContaining({ transform_id: generateLatestTransformId(definition), }), expect.anything() ); + + expect(esClient.transform.deleteTransform).toBeCalledTimes(1); expect(esClient.transform.deleteTransform).toBeCalledWith( expect.objectContaining({ transform_id: generateLatestTransformId(definition), }), expect.anything() ); - - expect(esClient.transform.deleteTransform).toBeCalledTimes(2); }; describe('install_entity_definition', () => { @@ -223,7 +179,7 @@ describe('install_entity_definition', () => { installEntityDefinition({ esClient, soClient, - definition: { id: 'a'.repeat(40) } as EntityDefinition, + definition: { id: 'a'.repeat(50) } as EntityDefinition, logger: loggerMock.create(), }) ).rejects.toThrow(EntityDefinitionIdInvalid); @@ -242,6 +198,7 @@ describe('install_entity_definition', () => { attributes: { ...mockEntityDefinition, installStatus: 'installed', + installedComponents: [], }, }, ], @@ -264,6 +221,12 @@ describe('install_entity_definition', () => { const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; const soClient = savedObjectsClientMock.create(); soClient.find.mockResolvedValue({ saved_objects: [], total: 0, page: 1, per_page: 10 }); + soClient.update.mockResolvedValue({ + id: mockEntityDefinition.id, + type: 'entity-definition', + references: [], + attributes: {}, + }); await installEntityDefinition({ esClient, @@ -300,6 +263,12 @@ describe('install_entity_definition', () => { const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; const soClient = savedObjectsClientMock.create(); soClient.find.mockResolvedValue({ saved_objects: [], total: 0, page: 1, per_page: 10 }); + soClient.update.mockResolvedValue({ + id: mockEntityDefinition.id, + type: 'entity-definition', + references: [], + attributes: {}, + }); await installBuiltInEntityDefinitions({ esClient, @@ -329,6 +298,7 @@ describe('install_entity_definition', () => { attributes: { ...mockEntityDefinition, installStatus: 'installed', + installedComponents: getExpectedInstalledComponents(mockEntityDefinition), }, }, ], @@ -336,6 +306,12 @@ describe('install_entity_definition', () => { page: 1, per_page: 10, }); + soClient.update.mockResolvedValue({ + id: mockEntityDefinition.id, + type: 'entity-definition', + references: [], + attributes: {}, + }); await installBuiltInEntityDefinitions({ esClient, @@ -367,6 +343,7 @@ describe('install_entity_definition', () => { attributes: { ...mockEntityDefinition, installStatus: 'installed', + installedComponents: getExpectedInstalledComponents(mockEntityDefinition), }, }, ], @@ -374,6 +351,12 @@ describe('install_entity_definition', () => { page: 1, per_page: 10, }); + soClient.update.mockResolvedValue({ + id: mockEntityDefinition.id, + type: 'entity-definition', + references: [], + attributes: {}, + }); await installBuiltInEntityDefinitions({ esClient, @@ -407,6 +390,7 @@ describe('install_entity_definition', () => { // upgrading for 1h installStatus: 'upgrading', installStartedAt: moment().subtract(1, 'hour').toISOString(), + installedComponents: getExpectedInstalledComponents(mockEntityDefinition), }, }, ], @@ -414,6 +398,12 @@ describe('install_entity_definition', () => { page: 1, per_page: 10, }); + soClient.update.mockResolvedValue({ + id: mockEntityDefinition.id, + type: 'entity-definition', + references: [], + attributes: {}, + }); await installBuiltInEntityDefinitions({ esClient, @@ -442,6 +432,7 @@ describe('install_entity_definition', () => { ...mockEntityDefinition, installStatus: 'failed', installStartedAt: new Date().toISOString(), + installedComponents: getExpectedInstalledComponents(mockEntityDefinition), }, }, ], @@ -449,6 +440,12 @@ describe('install_entity_definition', () => { page: 1, per_page: 10, }); + soClient.update.mockResolvedValue({ + id: mockEntityDefinition.id, + type: 'entity-definition', + references: [], + attributes: {}, + }); await installBuiltInEntityDefinitions({ esClient, diff --git a/x-pack/plugins/entity_manager/server/lib/entities/install_entity_definition.ts b/x-pack/plugins/entity_manager/server/lib/entities/install_entity_definition.ts index 7d6dee4fb2ced..b4adedaf10374 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/install_entity_definition.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/install_entity_definition.ts @@ -10,39 +10,25 @@ import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { EntityDefinition, EntityDefinitionUpdate } from '@kbn/entities-schema'; import { Logger } from '@kbn/logging'; -import { - generateHistoryIndexTemplateId, - generateLatestIndexTemplateId, -} from './helpers/generate_component_id'; -import { - createAndInstallHistoryIngestPipeline, - createAndInstallLatestIngestPipeline, -} from './create_and_install_ingest_pipeline'; -import { - createAndInstallHistoryBackfillTransform, - createAndInstallHistoryTransform, - createAndInstallLatestTransform, -} from './create_and_install_transform'; +import { generateLatestIndexTemplateId } from './helpers/generate_component_id'; +import { createAndInstallIngestPipelines } from './create_and_install_ingest_pipeline'; +import { createAndInstallTransforms } from './create_and_install_transform'; import { validateDefinitionCanCreateValidTransformIds } from './transform/validate_transform_ids'; import { deleteEntityDefinition } from './delete_entity_definition'; -import { deleteHistoryIngestPipeline, deleteLatestIngestPipeline } from './delete_ingest_pipeline'; +import { deleteLatestIngestPipeline } from './delete_ingest_pipeline'; import { findEntityDefinitionById } from './find_entity_definition'; import { entityDefinitionExists, saveEntityDefinition, updateEntityDefinition, } from './save_entity_definition'; - -import { isBackfillEnabled } from './helpers/is_backfill_enabled'; -import { deleteTemplate, upsertTemplate } from '../manage_index_templates'; -import { generateEntitiesLatestIndexTemplateConfig } from './templates/entities_latest_template'; -import { generateEntitiesHistoryIndexTemplateConfig } from './templates/entities_history_template'; +import { createAndInstallTemplates, deleteTemplate } from '../manage_index_templates'; import { EntityIdConflict } from './errors/entity_id_conflict_error'; import { EntityDefinitionNotFound } from './errors/entity_not_found'; import { mergeEntityDefinitionUpdate } from './helpers/merge_definition_update'; import { EntityDefinitionWithState } from './types'; -import { stopTransforms } from './stop_transforms'; -import { deleteTransforms } from './delete_transforms'; +import { stopLatestTransform, stopTransforms } from './stop_transforms'; +import { deleteLatestTransform, deleteTransforms } from './delete_transforms'; export interface InstallDefinitionParams { esClient: ElasticsearchClient; @@ -51,16 +37,6 @@ export interface InstallDefinitionParams { logger: Logger; } -const throwIfRejected = (values: Array | PromiseRejectedResult>) => { - const rejectedPromise = values.find( - (value) => value.status === 'rejected' - ) as PromiseRejectedResult; - if (rejectedPromise) { - throw new Error(rejectedPromise.reason); - } - return values; -}; - // install an entity definition from scratch with all its required components // after verifying that the definition id is valid and available. // attempt to remove all installed components if the installation fails. @@ -72,42 +48,35 @@ export async function installEntityDefinition({ }: InstallDefinitionParams): Promise { validateDefinitionCanCreateValidTransformIds(definition); - try { - if (await entityDefinitionExists(soClient, definition.id)) { - throw new EntityIdConflict( - `Entity definition with [${definition.id}] already exists.`, - definition - ); - } + if (await entityDefinitionExists(soClient, definition.id)) { + throw new EntityIdConflict( + `Entity definition with [${definition.id}] already exists.`, + definition + ); + } + try { const entityDefinition = await saveEntityDefinition(soClient, { ...definition, installStatus: 'installing', installStartedAt: new Date().toISOString(), + installedComponents: [], }); return await install({ esClient, soClient, logger, definition: entityDefinition }); } catch (e) { logger.error(`Failed to install entity definition ${definition.id}: ${e}`); - await stopAndDeleteTransforms(esClient, definition, logger); - await Promise.all([ - deleteHistoryIngestPipeline(esClient, definition, logger), - deleteLatestIngestPipeline(esClient, definition, logger), - ]); + await stopLatestTransform(esClient, definition, logger); + await deleteLatestTransform(esClient, definition, logger); - await Promise.all([ - deleteTemplate({ - esClient, - logger, - name: generateHistoryIndexTemplateId(definition), - }), - deleteTemplate({ - esClient, - logger, - name: generateLatestIndexTemplateId(definition), - }), - ]); + await deleteLatestIngestPipeline(esClient, definition, logger); + + await deleteTemplate({ + esClient, + logger, + name: generateLatestIndexTemplateId(definition), + }); await deleteEntityDefinition(soClient, definition).catch((err) => { if (err instanceof EntityDefinitionNotFound) { @@ -191,36 +160,19 @@ async function install({ ); logger.debug(`Installing index templates for definition ${definition.id}`); - await Promise.allSettled([ - upsertTemplate({ - esClient, - logger, - template: generateEntitiesHistoryIndexTemplateConfig(definition), - }), - upsertTemplate({ - esClient, - logger, - template: generateEntitiesLatestIndexTemplateConfig(definition), - }), - ]).then(throwIfRejected); + const templates = await createAndInstallTemplates(esClient, definition, logger); logger.debug(`Installing ingest pipelines for definition ${definition.id}`); - await Promise.allSettled([ - createAndInstallHistoryIngestPipeline(esClient, definition, logger), - createAndInstallLatestIngestPipeline(esClient, definition, logger), - ]).then(throwIfRejected); + const pipelines = await createAndInstallIngestPipelines(esClient, definition, logger); logger.debug(`Installing transforms for definition ${definition.id}`); - await Promise.allSettled([ - createAndInstallHistoryTransform(esClient, definition, logger), - isBackfillEnabled(definition) - ? createAndInstallHistoryBackfillTransform(esClient, definition, logger) - : Promise.resolve(), - createAndInstallLatestTransform(esClient, definition, logger), - ]).then(throwIfRejected); - - await updateEntityDefinition(soClient, definition.id, { installStatus: 'installed' }); - return { ...definition, installStatus: 'installed' }; + const transforms = await createAndInstallTransforms(esClient, definition, logger); + + const updatedProps = await updateEntityDefinition(soClient, definition.id, { + installStatus: 'installed', + installedComponents: [...templates, ...pipelines, ...transforms], + }); + return { ...definition, ...updatedProps.attributes }; } // stop and delete the current transforms and reinstall all the components diff --git a/x-pack/plugins/entity_manager/server/lib/entities/save_entity_definition.ts b/x-pack/plugins/entity_manager/server/lib/entities/save_entity_definition.ts index 2dff5178aeeaf..d32edfa146917 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/save_entity_definition.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/save_entity_definition.ts @@ -41,5 +41,5 @@ export async function updateEntityDefinition( id: string, definition: Partial ) { - await soClient.update(SO_ENTITY_DEFINITION_TYPE, id, definition); + return await soClient.update(SO_ENTITY_DEFINITION_TYPE, id, definition); } diff --git a/x-pack/plugins/entity_manager/server/lib/entities/start_transforms.ts b/x-pack/plugins/entity_manager/server/lib/entities/start_transforms.ts index ea2ec7adb5ddc..f4cd8fc89dd11 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/start_transforms.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/start_transforms.ts @@ -7,13 +7,7 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { EntityDefinition } from '@kbn/entities-schema'; -import { - generateHistoryBackfillTransformId, - generateHistoryTransformId, - generateLatestTransformId, -} from './helpers/generate_component_id'; import { retryTransientEsErrors } from './helpers/retry'; -import { isBackfillEnabled } from './helpers/is_backfill_enabled'; export async function startTransforms( esClient: ElasticsearchClient, @@ -21,28 +15,15 @@ export async function startTransforms( logger: Logger ) { try { - const historyTransformId = generateHistoryTransformId(definition); - const latestTransformId = generateLatestTransformId(definition); - await retryTransientEsErrors( - () => - esClient.transform.startTransform({ transform_id: historyTransformId }, { ignore: [409] }), - { logger } - ); - if (isBackfillEnabled(definition)) { - const historyBackfillTransformId = generateHistoryBackfillTransformId(definition); - await retryTransientEsErrors( - () => - esClient.transform.startTransform( - { transform_id: historyBackfillTransformId }, - { ignore: [409] } - ), - { logger } - ); - } - await retryTransientEsErrors( - () => - esClient.transform.startTransform({ transform_id: latestTransformId }, { ignore: [409] }), - { logger } + await Promise.all( + (definition.installedComponents ?? []) + .filter(({ type }) => type === 'transform') + .map(({ id }) => + retryTransientEsErrors( + () => esClient.transform.startTransform({ transform_id: id }, { ignore: [409] }), + { logger } + ) + ) ); } catch (err) { logger.error(`Cannot start entity transforms [${definition.id}]: ${err}`); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/stop_transforms.ts b/x-pack/plugins/entity_manager/server/lib/entities/stop_transforms.ts index 98f9ad351e377..9aabad926b239 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/stop_transforms.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/stop_transforms.ts @@ -8,14 +8,8 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { EntityDefinition } from '@kbn/entities-schema'; -import { - generateHistoryTransformId, - generateHistoryBackfillTransformId, - generateLatestTransformId, -} from './helpers/generate_component_id'; import { retryTransientEsErrors } from './helpers/retry'; - -import { isBackfillEnabled } from './helpers/is_backfill_enabled'; +import { generateLatestTransformId } from './helpers/generate_component_id'; export async function stopTransforms( esClient: ElasticsearchClient, @@ -23,43 +17,46 @@ export async function stopTransforms( logger: Logger ) { try { - const historyTransformId = generateHistoryTransformId(definition); - const latestTransformId = generateLatestTransformId(definition); - - await retryTransientEsErrors( - () => - esClient.transform.stopTransform( - { transform_id: historyTransformId, wait_for_completion: true, force: true }, - { ignore: [409, 404] } - ), - { logger } + await Promise.all( + (definition.installedComponents ?? []) + .filter(({ type }) => type === 'transform') + .map(({ id }) => + retryTransientEsErrors( + () => + esClient.transform.stopTransform( + { transform_id: id, wait_for_completion: true, force: true }, + { ignore: [409, 404] } + ), + { logger } + ) + ) ); + } catch (e) { + logger.error(`Cannot stop transforms for definition [${definition.id}]: ${e}`); + throw e; + } +} - if (isBackfillEnabled(definition)) { - const historyBackfillTransformId = generateHistoryBackfillTransformId(definition); - await retryTransientEsErrors( - () => - esClient.transform.stopTransform( - { - transform_id: historyBackfillTransformId, - wait_for_completion: true, - force: true, - }, - { ignore: [409, 404] } - ), - { logger } - ); - } +export async function stopLatestTransform( + esClient: ElasticsearchClient, + definition: EntityDefinition, + logger: Logger +) { + try { await retryTransientEsErrors( () => esClient.transform.stopTransform( - { transform_id: latestTransformId, wait_for_completion: true, force: true }, + { + transform_id: generateLatestTransformId(definition), + wait_for_completion: true, + force: true, + }, { ignore: [409, 404] } ), { logger } ); } catch (e) { - logger.error(`Cannot stop entity transforms [${definition.id}]: ${e}`); + logger.error(`Cannot stop latest transform for definition [${definition.id}]: ${e}`); throw e; } } diff --git a/x-pack/plugins/entity_manager/server/lib/entities/templates/__snapshots__/entities_history_template.test.ts.snap b/x-pack/plugins/entity_manager/server/lib/entities/templates/__snapshots__/entities_history_template.test.ts.snap deleted file mode 100644 index fd4ed11f8cb94..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/templates/__snapshots__/entities_history_template.test.ts.snap +++ /dev/null @@ -1,152 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`generateEntitiesHistoryIndexTemplateConfig(definition) should generate a valid index template for builtin definition 1`] = ` -Object { - "_meta": Object { - "description": "Index template for indices managed by the Elastic Entity Model's entity discovery framework for the history dataset", - "ecs_version": "8.0.0", - "managed": true, - "managed_by": "elastic_entity_model", - }, - "composed_of": Array [ - "entities_v1_history_base", - "entities_v1_entity", - "entities_v1_event", - ], - "ignore_missing_component_templates": Array [], - "index_patterns": Array [ - ".entities.v1.history.builtin_mock_entity_definition.*", - ], - "name": "entities_v1_history_builtin_mock_entity_definition_index_template", - "priority": 200, - "template": Object { - "aliases": Object { - "entities-service-history": Object {}, - }, - "mappings": Object { - "_meta": Object { - "version": "1.6.0", - }, - "date_detection": false, - "dynamic_templates": Array [ - Object { - "strings_as_keyword": Object { - "mapping": Object { - "fields": Object { - "text": Object { - "type": "text", - }, - }, - "ignore_above": 1024, - "type": "keyword", - }, - "match_mapping_type": "string", - }, - }, - Object { - "entity_metrics": Object { - "mapping": Object { - "type": "{dynamic_type}", - }, - "match_mapping_type": Array [ - "long", - "double", - ], - "path_match": "entity.metrics.*", - }, - }, - ], - }, - "settings": Object { - "index": Object { - "codec": "best_compression", - "mapping": Object { - "total_fields": Object { - "limit": 2000, - }, - }, - }, - }, - }, -} -`; - -exports[`generateEntitiesHistoryIndexTemplateConfig(definition) should generate a valid index template for custom definition 1`] = ` -Object { - "_meta": Object { - "description": "Index template for indices managed by the Elastic Entity Model's entity discovery framework for the history dataset", - "ecs_version": "8.0.0", - "managed": true, - "managed_by": "elastic_entity_model", - }, - "composed_of": Array [ - "entities_v1_history_base", - "entities_v1_entity", - "entities_v1_event", - "admin-console-services@platform", - "admin-console-services-history@platform", - "admin-console-services@custom", - "admin-console-services-history@custom", - ], - "ignore_missing_component_templates": Array [ - "admin-console-services@platform", - "admin-console-services-history@platform", - "admin-console-services@custom", - "admin-console-services-history@custom", - ], - "index_patterns": Array [ - ".entities.v1.history.admin-console-services.*", - ], - "name": "entities_v1_history_admin-console-services_index_template", - "priority": 200, - "template": Object { - "aliases": Object { - "entities-service-history": Object {}, - }, - "mappings": Object { - "_meta": Object { - "version": "1.6.0", - }, - "date_detection": false, - "dynamic_templates": Array [ - Object { - "strings_as_keyword": Object { - "mapping": Object { - "fields": Object { - "text": Object { - "type": "text", - }, - }, - "ignore_above": 1024, - "type": "keyword", - }, - "match_mapping_type": "string", - }, - }, - Object { - "entity_metrics": Object { - "mapping": Object { - "type": "{dynamic_type}", - }, - "match_mapping_type": Array [ - "long", - "double", - ], - "path_match": "entity.metrics.*", - }, - }, - ], - }, - "settings": Object { - "index": Object { - "codec": "best_compression", - "mapping": Object { - "total_fields": Object { - "limit": 2000, - }, - }, - }, - }, - }, -} -`; diff --git a/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_history_template.test.ts b/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_history_template.test.ts deleted file mode 100644 index 72e8d8591ab2d..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_history_template.test.ts +++ /dev/null @@ -1,21 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { entityDefinition, builtInEntityDefinition } from '../helpers/fixtures'; -import { generateEntitiesHistoryIndexTemplateConfig } from './entities_history_template'; - -describe('generateEntitiesHistoryIndexTemplateConfig(definition)', () => { - it('should generate a valid index template for custom definition', () => { - const template = generateEntitiesHistoryIndexTemplateConfig(entityDefinition); - expect(template).toMatchSnapshot(); - }); - - it('should generate a valid index template for builtin definition', () => { - const template = generateEntitiesHistoryIndexTemplateConfig(builtInEntityDefinition); - expect(template).toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_history_template.ts b/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_history_template.ts deleted file mode 100644 index b1539d8108a6d..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_history_template.ts +++ /dev/null @@ -1,96 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IndicesPutIndexTemplateRequest } from '@elastic/elasticsearch/lib/api/types'; -import { - ENTITY_HISTORY, - EntityDefinition, - entitiesIndexPattern, - entitiesAliasPattern, - ENTITY_SCHEMA_VERSION_V1, -} from '@kbn/entities-schema'; -import { generateHistoryIndexTemplateId } from '../helpers/generate_component_id'; -import { - ENTITY_ENTITY_COMPONENT_TEMPLATE_V1, - ENTITY_EVENT_COMPONENT_TEMPLATE_V1, - ENTITY_HISTORY_BASE_COMPONENT_TEMPLATE_V1, -} from '../../../../common/constants_entities'; -import { getCustomHistoryTemplateComponents } from '../../../templates/components/helpers'; - -export const generateEntitiesHistoryIndexTemplateConfig = ( - definition: EntityDefinition -): IndicesPutIndexTemplateRequest => ({ - name: generateHistoryIndexTemplateId(definition), - _meta: { - description: - "Index template for indices managed by the Elastic Entity Model's entity discovery framework for the history dataset", - ecs_version: '8.0.0', - managed: true, - managed_by: 'elastic_entity_model', - }, - ignore_missing_component_templates: getCustomHistoryTemplateComponents(definition), - composed_of: [ - ENTITY_HISTORY_BASE_COMPONENT_TEMPLATE_V1, - ENTITY_ENTITY_COMPONENT_TEMPLATE_V1, - ENTITY_EVENT_COMPONENT_TEMPLATE_V1, - ...getCustomHistoryTemplateComponents(definition), - ], - index_patterns: [ - `${entitiesIndexPattern({ - schemaVersion: ENTITY_SCHEMA_VERSION_V1, - dataset: ENTITY_HISTORY, - definitionId: definition.id, - })}.*`, - ], - priority: 200, - template: { - aliases: { - [entitiesAliasPattern({ type: definition.type, dataset: ENTITY_HISTORY })]: {}, - }, - mappings: { - _meta: { - version: '1.6.0', - }, - date_detection: false, - dynamic_templates: [ - { - strings_as_keyword: { - mapping: { - ignore_above: 1024, - type: 'keyword', - fields: { - text: { - type: 'text', - }, - }, - }, - match_mapping_type: 'string', - }, - }, - { - entity_metrics: { - mapping: { - type: '{dynamic_type}', - }, - match_mapping_type: ['long', 'double'], - path_match: 'entity.metrics.*', - }, - }, - ], - }, - settings: { - index: { - codec: 'best_compression', - mapping: { - total_fields: { - limit: 2000, - }, - }, - }, - }, - }, -}); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_latest_template.ts b/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_latest_template.ts index ea476cf769644..e0c02c7471217 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_latest_template.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/templates/entities_latest_template.ts @@ -19,7 +19,7 @@ import { ENTITY_EVENT_COMPONENT_TEMPLATE_V1, ENTITY_LATEST_BASE_COMPONENT_TEMPLATE_V1, } from '../../../../common/constants_entities'; -import { getCustomLatestTemplateComponents } from '../../../templates/components/helpers'; +import { isBuiltinDefinition } from '../helpers/is_builtin_definition'; export const generateEntitiesLatestIndexTemplateConfig = ( definition: EntityDefinition @@ -94,3 +94,16 @@ export const generateEntitiesLatestIndexTemplateConfig = ( }, }, }); + +function getCustomLatestTemplateComponents(definition: EntityDefinition) { + if (isBuiltinDefinition(definition)) { + return []; + } + + return [ + `${definition.id}@platform`, // @platform goes before so it can be overwritten by custom + `${definition.id}-latest@platform`, + `${definition.id}@custom`, + `${definition.id}-latest@custom`, + ]; +} diff --git a/x-pack/plugins/entity_manager/server/lib/entities/transform/__snapshots__/generate_history_transform.test.ts.snap b/x-pack/plugins/entity_manager/server/lib/entities/transform/__snapshots__/generate_history_transform.test.ts.snap deleted file mode 100644 index b19a805b24b12..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/transform/__snapshots__/generate_history_transform.test.ts.snap +++ /dev/null @@ -1,305 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`generateHistoryTransform(definition) should generate a valid history backfill transform 1`] = ` -Object { - "_meta": Object { - "definitionVersion": "999.999.999", - "managed": false, - }, - "defer_validation": true, - "dest": Object { - "index": ".entities.v1.history.noop", - "pipeline": "entities-v1-history-admin-console-services-backfill", - }, - "frequency": "5m", - "pivot": Object { - "aggs": Object { - "_errorRate_A": Object { - "filter": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match_phrase": Object { - "log.level": "ERROR", - }, - }, - ], - }, - }, - }, - "_logRate_A": Object { - "filter": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "log.level", - }, - }, - ], - }, - }, - }, - "entity.lastSeenTimestamp": Object { - "max": Object { - "field": "@timestamp", - }, - }, - "entity.metadata.host.name": Object { - "terms": Object { - "field": "host.name", - "size": 1000, - }, - }, - "entity.metadata.host.os.name": Object { - "terms": Object { - "field": "host.os.name", - "size": 1000, - }, - }, - "entity.metadata.sourceIndex": Object { - "terms": Object { - "field": "_index", - "size": 1000, - }, - }, - "entity.metadata.tags": Object { - "terms": Object { - "field": "tags", - "size": 1000, - }, - }, - "entity.metrics.errorRate": Object { - "bucket_script": Object { - "buckets_path": Object { - "A": "_errorRate_A>_count", - }, - "script": Object { - "lang": "painless", - "source": "params.A", - }, - }, - }, - "entity.metrics.logRate": Object { - "bucket_script": Object { - "buckets_path": Object { - "A": "_logRate_A>_count", - }, - "script": Object { - "lang": "painless", - "source": "params.A", - }, - }, - }, - }, - "group_by": Object { - "@timestamp": Object { - "date_histogram": Object { - "field": "@timestamp", - "fixed_interval": "1m", - }, - }, - "entity.identity.event.category": Object { - "terms": Object { - "field": "event.category", - "missing_bucket": true, - }, - }, - "entity.identity.log.logger": Object { - "terms": Object { - "field": "log.logger", - "missing_bucket": false, - }, - }, - }, - }, - "settings": Object { - "deduce_mappings": false, - "unattended": true, - }, - "source": Object { - "index": Array [ - "kbn-data-forge-fake_stack.*", - ], - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "range": Object { - "@timestamp": Object { - "gte": "now-72h", - }, - }, - }, - Object { - "exists": Object { - "field": "log.logger", - }, - }, - ], - }, - }, - }, - "sync": Object { - "time": Object { - "delay": "15m", - "field": "@timestamp", - }, - }, - "transform_id": "entities-v1-history-backfill-admin-console-services-backfill", -} -`; - -exports[`generateHistoryTransform(definition) should generate a valid history transform 1`] = ` -Object { - "_meta": Object { - "definitionVersion": "1.0.0", - "managed": false, - }, - "defer_validation": true, - "dest": Object { - "index": ".entities.v1.history.noop", - "pipeline": "entities-v1-history-admin-console-services", - }, - "frequency": "2m", - "pivot": Object { - "aggs": Object { - "_errorRate_A": Object { - "filter": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match_phrase": Object { - "log.level": "ERROR", - }, - }, - ], - }, - }, - }, - "_logRate_A": Object { - "filter": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "log.level", - }, - }, - ], - }, - }, - }, - "entity.lastSeenTimestamp": Object { - "max": Object { - "field": "@timestamp", - }, - }, - "entity.metadata.host.name": Object { - "terms": Object { - "field": "host.name", - "size": 1000, - }, - }, - "entity.metadata.host.os.name": Object { - "terms": Object { - "field": "host.os.name", - "size": 1000, - }, - }, - "entity.metadata.sourceIndex": Object { - "terms": Object { - "field": "_index", - "size": 1000, - }, - }, - "entity.metadata.tags": Object { - "terms": Object { - "field": "tags", - "size": 1000, - }, - }, - "entity.metrics.errorRate": Object { - "bucket_script": Object { - "buckets_path": Object { - "A": "_errorRate_A>_count", - }, - "script": Object { - "lang": "painless", - "source": "params.A", - }, - }, - }, - "entity.metrics.logRate": Object { - "bucket_script": Object { - "buckets_path": Object { - "A": "_logRate_A>_count", - }, - "script": Object { - "lang": "painless", - "source": "params.A", - }, - }, - }, - }, - "group_by": Object { - "@timestamp": Object { - "date_histogram": Object { - "field": "@timestamp", - "fixed_interval": "1m", - }, - }, - "entity.identity.event.category": Object { - "terms": Object { - "field": "event.category", - "missing_bucket": true, - }, - }, - "entity.identity.log.logger": Object { - "terms": Object { - "field": "log.logger", - "missing_bucket": false, - }, - }, - }, - }, - "settings": Object { - "deduce_mappings": false, - "unattended": true, - }, - "source": Object { - "index": Array [ - "kbn-data-forge-fake_stack.*", - ], - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "exists": Object { - "field": "log.logger", - }, - }, - Object { - "range": Object { - "@timestamp": Object { - "gte": "now-10m", - }, - }, - }, - ], - }, - }, - }, - "sync": Object { - "time": Object { - "delay": "2m", - "field": "@timestamp", - }, - }, - "transform_id": "entities-v1-history-admin-console-services", -} -`; diff --git a/x-pack/plugins/entity_manager/server/lib/entities/transform/__snapshots__/generate_latest_transform.test.ts.snap b/x-pack/plugins/entity_manager/server/lib/entities/transform/__snapshots__/generate_latest_transform.test.ts.snap index ab1224525f4d7..49f8ff4536120 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/transform/__snapshots__/generate_latest_transform.test.ts.snap +++ b/x-pack/plugins/entity_manager/server/lib/entities/transform/__snapshots__/generate_latest_transform.test.ts.snap @@ -14,76 +14,37 @@ Object { "frequency": "30s", "pivot": Object { "aggs": Object { - "_errorRate": Object { - "top_metrics": Object { - "metrics": Array [ - Object { - "field": "entity.metrics.errorRate", - }, - ], - "sort": Array [ - Object { - "@timestamp": "desc", - }, - ], - }, - }, - "_logRate": Object { - "top_metrics": Object { - "metrics": Array [ - Object { - "field": "entity.metrics.logRate", - }, - ], - "sort": Array [ - Object { - "@timestamp": "desc", - }, - ], - }, - }, - "entity.firstSeenTimestamp": Object { - "min": Object { - "field": "@timestamp", - }, - }, - "entity.identity.event.category": Object { - "aggs": Object { - "top_metric": Object { - "top_metrics": Object { - "metrics": Object { - "field": "event.category", - }, - "sort": "_score", - }, - }, - }, + "_errorRate_A": Object { "filter": Object { - "exists": Object { - "field": "event.category", - }, - }, - }, - "entity.identity.log.logger": Object { - "aggs": Object { - "top_metric": Object { - "top_metrics": Object { - "metrics": Object { - "field": "log.logger", + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match_phrase": Object { + "log.level": "ERROR", + }, }, - "sort": "_score", - }, + ], }, }, + }, + "_logRate_A": Object { "filter": Object { - "exists": Object { - "field": "log.logger", + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "exists": Object { + "field": "log.level", + }, + }, + ], }, }, }, "entity.lastSeenTimestamp": Object { "max": Object { - "field": "entity.lastSeenTimestamp", + "field": "@timestamp", }, }, "entity.metadata.host.name": Object { @@ -91,14 +52,14 @@ Object { "data": Object { "terms": Object { "field": "host.name", - "size": 1000, + "size": 10, }, }, }, "filter": Object { "range": Object { "@timestamp": Object { - "gte": "now-360s", + "gte": "now-10m", }, }, }, @@ -108,14 +69,14 @@ Object { "data": Object { "terms": Object { "field": "host.os.name", - "size": 1000, + "size": 10, }, }, }, "filter": Object { "range": Object { "@timestamp": Object { - "gte": "now-360s", + "gte": "now-10m", }, }, }, @@ -124,15 +85,15 @@ Object { "aggs": Object { "data": Object { "terms": Object { - "field": "sourceIndex", - "size": 1000, + "field": "_index", + "size": 10, }, }, }, "filter": Object { "range": Object { "@timestamp": Object { - "gte": "now-360s", + "gte": "now-10m", }, }, }, @@ -142,14 +103,14 @@ Object { "data": Object { "terms": Object { "field": "tags", - "size": 1000, + "size": 10, }, }, }, "filter": Object { "range": Object { "@timestamp": Object { - "gte": "now-360s", + "gte": "now-10m", }, }, }, @@ -157,24 +118,37 @@ Object { "entity.metrics.errorRate": Object { "bucket_script": Object { "buckets_path": Object { - "value": "_errorRate[entity.metrics.errorRate]", + "A": "_errorRate_A>_count", + }, + "script": Object { + "lang": "painless", + "source": "params.A", }, - "script": "params.value", }, }, "entity.metrics.logRate": Object { "bucket_script": Object { "buckets_path": Object { - "value": "_logRate[entity.metrics.logRate]", + "A": "_logRate_A>_count", + }, + "script": Object { + "lang": "painless", + "source": "params.A", }, - "script": "params.value", }, }, }, "group_by": Object { - "entity.id": Object { + "entity.identity.event.category": Object { + "terms": Object { + "field": "event.category", + "missing_bucket": true, + }, + }, + "entity.identity.log.logger": Object { "terms": Object { - "field": "entity.id", + "field": "log.logger", + "missing_bucket": false, }, }, }, @@ -184,12 +158,32 @@ Object { "unattended": true, }, "source": Object { - "index": ".entities.v1.history.admin-console-services.*", + "index": Array [ + "kbn-data-forge-fake_stack.*", + ], + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "exists": Object { + "field": "log.logger", + }, + }, + Object { + "range": Object { + "@timestamp": Object { + "gte": "now-10m", + }, + }, + }, + ], + }, + }, }, "sync": Object { "time": Object { - "delay": "1s", - "field": "event.ingested", + "delay": "10s", + "field": "@timestamp", }, }, "transform_id": "entities-v1-latest-admin-console-services", diff --git a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_history_transform.test.ts b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_history_transform.test.ts deleted file mode 100644 index f49ec0cd88a37..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_history_transform.test.ts +++ /dev/null @@ -1,24 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { entityDefinition } from '../helpers/fixtures/entity_definition'; -import { entityDefinitionWithBackfill } from '../helpers/fixtures/entity_definition_with_backfill'; -import { - generateBackfillHistoryTransform, - generateHistoryTransform, -} from './generate_history_transform'; - -describe('generateHistoryTransform(definition)', () => { - it('should generate a valid history transform', () => { - const transform = generateHistoryTransform(entityDefinition); - expect(transform).toMatchSnapshot(); - }); - it('should generate a valid history backfill transform', () => { - const transform = generateBackfillHistoryTransform(entityDefinitionWithBackfill); - expect(transform).toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_history_transform.ts b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_history_transform.ts deleted file mode 100644 index 239359738624c..0000000000000 --- a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_history_transform.ts +++ /dev/null @@ -1,178 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EntityDefinition } from '@kbn/entities-schema'; -import { - QueryDslQueryContainer, - TransformPutTransformRequest, -} from '@elastic/elasticsearch/lib/api/types'; -import { getElasticsearchQueryOrThrow } from '../helpers/get_elasticsearch_query_or_throw'; -import { generateHistoryMetricAggregations } from './generate_metric_aggregations'; -import { - ENTITY_DEFAULT_HISTORY_FREQUENCY, - ENTITY_DEFAULT_HISTORY_SYNC_DELAY, -} from '../../../../common/constants_entities'; -import { generateHistoryMetadataAggregations } from './generate_metadata_aggregations'; -import { - generateHistoryTransformId, - generateHistoryIngestPipelineId, - generateHistoryIndexName, - generateHistoryBackfillTransformId, -} from '../helpers/generate_component_id'; -import { isBackfillEnabled } from '../helpers/is_backfill_enabled'; - -export function generateHistoryTransform( - definition: EntityDefinition -): TransformPutTransformRequest { - const filter: QueryDslQueryContainer[] = []; - - if (definition.filter) { - filter.push(getElasticsearchQueryOrThrow(definition.filter)); - } - - if (definition.identityFields.some(({ optional }) => !optional)) { - definition.identityFields - .filter(({ optional }) => !optional) - .forEach(({ field }) => { - filter.push({ exists: { field } }); - }); - } - - filter.push({ - range: { - [definition.history.timestampField]: { - gte: `now-${definition.history.settings.lookbackPeriod}`, - }, - }, - }); - - return generateTransformPutRequest({ - definition, - filter, - transformId: generateHistoryTransformId(definition), - frequency: definition.history.settings.frequency, - syncDelay: definition.history.settings.syncDelay, - }); -} - -export function generateBackfillHistoryTransform( - definition: EntityDefinition -): TransformPutTransformRequest { - if (!isBackfillEnabled(definition)) { - throw new Error( - 'generateBackfillHistoryTransform called without history.settings.backfillSyncDelay set' - ); - } - - const filter: QueryDslQueryContainer[] = []; - - if (definition.filter) { - filter.push(getElasticsearchQueryOrThrow(definition.filter)); - } - - if (definition.history.settings.backfillLookbackPeriod) { - filter.push({ - range: { - [definition.history.timestampField]: { - gte: `now-${definition.history.settings.backfillLookbackPeriod}`, - }, - }, - }); - } - - if (definition.identityFields.some(({ optional }) => !optional)) { - definition.identityFields - .filter(({ optional }) => !optional) - .forEach(({ field }) => { - filter.push({ exists: { field } }); - }); - } - - return generateTransformPutRequest({ - definition, - filter, - transformId: generateHistoryBackfillTransformId(definition), - frequency: definition.history.settings.backfillFrequency, - syncDelay: definition.history.settings.backfillSyncDelay, - }); -} - -const generateTransformPutRequest = ({ - definition, - filter, - transformId, - frequency, - syncDelay, -}: { - definition: EntityDefinition; - transformId: string; - filter: QueryDslQueryContainer[]; - frequency?: string; - syncDelay?: string; -}) => { - return { - transform_id: transformId, - _meta: { - definitionVersion: definition.version, - managed: definition.managed, - }, - defer_validation: true, - source: { - index: definition.indexPatterns, - ...(filter.length > 0 && { - query: { - bool: { - filter, - }, - }, - }), - }, - dest: { - index: `${generateHistoryIndexName({ id: 'noop' } as EntityDefinition)}`, - pipeline: generateHistoryIngestPipelineId(definition), - }, - frequency: frequency || ENTITY_DEFAULT_HISTORY_FREQUENCY, - sync: { - time: { - field: definition.history.settings.syncField || definition.history.timestampField, - delay: syncDelay || ENTITY_DEFAULT_HISTORY_SYNC_DELAY, - }, - }, - settings: { - deduce_mappings: false, - unattended: true, - }, - pivot: { - group_by: { - ...definition.identityFields.reduce( - (acc, id) => ({ - ...acc, - [`entity.identity.${id.field}`]: { - terms: { field: id.field, missing_bucket: id.optional }, - }, - }), - {} - ), - ['@timestamp']: { - date_histogram: { - field: definition.history.timestampField, - fixed_interval: definition.history.interval, - }, - }, - }, - aggs: { - ...generateHistoryMetricAggregations(definition), - ...generateHistoryMetadataAggregations(definition), - 'entity.lastSeenTimestamp': { - max: { - field: definition.history.timestampField, - }, - }, - }, - }, - }; -}; diff --git a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_latest_transform.ts b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_latest_transform.ts index 85ee57fefea2c..573bb2225f183 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_latest_transform.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_latest_transform.ts @@ -5,44 +5,97 @@ * 2.0. */ -import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; import { EntityDefinition } from '@kbn/entities-schema'; +import { + QueryDslQueryContainer, + TransformPutTransformRequest, +} from '@elastic/elasticsearch/lib/api/types'; +import { getElasticsearchQueryOrThrow } from '../helpers/get_elasticsearch_query_or_throw'; +import { generateLatestMetricAggregations } from './generate_metric_aggregations'; import { ENTITY_DEFAULT_LATEST_FREQUENCY, ENTITY_DEFAULT_LATEST_SYNC_DELAY, } from '../../../../common/constants_entities'; import { - generateHistoryIndexName, - generateLatestIndexName, - generateLatestIngestPipelineId, generateLatestTransformId, + generateLatestIngestPipelineId, + generateLatestIndexName, } from '../helpers/generate_component_id'; -import { generateIdentityAggregations } from './generate_identity_aggregations'; import { generateLatestMetadataAggregations } from './generate_metadata_aggregations'; -import { generateLatestMetricAggregations } from './generate_metric_aggregations'; export function generateLatestTransform( definition: EntityDefinition ): TransformPutTransformRequest { + const filter: QueryDslQueryContainer[] = []; + + if (definition.filter) { + filter.push(getElasticsearchQueryOrThrow(definition.filter)); + } + + if (definition.identityFields.some(({ optional }) => !optional)) { + definition.identityFields + .filter(({ optional }) => !optional) + .forEach(({ field }) => { + filter.push({ exists: { field } }); + }); + } + + filter.push({ + range: { + [definition.latest.timestampField]: { + gte: `now-${definition.latest.lookbackPeriod}`, + }, + }, + }); + + return generateTransformPutRequest({ + definition, + filter, + transformId: generateLatestTransformId(definition), + frequency: definition.latest.settings?.frequency ?? ENTITY_DEFAULT_LATEST_FREQUENCY, + syncDelay: definition.latest.settings?.syncDelay ?? ENTITY_DEFAULT_LATEST_SYNC_DELAY, + }); +} + +const generateTransformPutRequest = ({ + definition, + filter, + transformId, + frequency, + syncDelay, +}: { + definition: EntityDefinition; + transformId: string; + filter: QueryDslQueryContainer[]; + frequency: string; + syncDelay: string; +}) => { return { - transform_id: generateLatestTransformId(definition), + transform_id: transformId, _meta: { definitionVersion: definition.version, managed: definition.managed, }, defer_validation: true, source: { - index: `${generateHistoryIndexName(definition)}.*`, + index: definition.indexPatterns, + ...(filter.length > 0 && { + query: { + bool: { + filter, + }, + }, + }), }, dest: { index: `${generateLatestIndexName({ id: 'noop' } as EntityDefinition)}`, pipeline: generateLatestIngestPipelineId(definition), }, - frequency: definition.latest?.settings?.frequency ?? ENTITY_DEFAULT_LATEST_FREQUENCY, + frequency, sync: { time: { - field: definition.latest?.settings?.syncField ?? 'event.ingested', - delay: definition.latest?.settings?.syncDelay ?? ENTITY_DEFAULT_LATEST_SYNC_DELAY, + field: definition.latest.settings?.syncField || definition.latest.timestampField, + delay: syncDelay, }, }, settings: { @@ -51,25 +104,25 @@ export function generateLatestTransform( }, pivot: { group_by: { - ['entity.id']: { - terms: { field: 'entity.id' }, - }, + ...definition.identityFields.reduce( + (acc, id) => ({ + ...acc, + [`entity.identity.${id.field}`]: { + terms: { field: id.field, missing_bucket: id.optional }, + }, + }), + {} + ), }, aggs: { ...generateLatestMetricAggregations(definition), ...generateLatestMetadataAggregations(definition), - ...generateIdentityAggregations(definition), 'entity.lastSeenTimestamp': { max: { - field: 'entity.lastSeenTimestamp', - }, - }, - 'entity.firstSeenTimestamp': { - min: { - field: '@timestamp', + field: definition.latest.timestampField, }, }, }, }, }; -} +}; diff --git a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.test.ts b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.test.ts index 7746be66f5033..12535d313143b 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.test.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.test.ts @@ -7,134 +7,22 @@ import { entityDefinitionSchema } from '@kbn/entities-schema'; import { rawEntityDefinition } from '../helpers/fixtures/entity_definition'; -import { - generateHistoryMetadataAggregations, - generateLatestMetadataAggregations, -} from './generate_metadata_aggregations'; +import { generateLatestMetadataAggregations } from './generate_metadata_aggregations'; describe('Generate Metadata Aggregations for history and latest', () => { - describe('generateHistoryMetadataAggregations()', () => { - it('should generate metadata aggregations for string format', () => { - const definition = entityDefinitionSchema.parse({ - ...rawEntityDefinition, - metadata: ['host.name'], - }); - expect(generateHistoryMetadataAggregations(definition)).toEqual({ - 'entity.metadata.host.name': { - terms: { - field: 'host.name', - size: 1000, - }, - }, - }); - }); - - it('should generate metadata aggregations for object format with only source', () => { - const definition = entityDefinitionSchema.parse({ - ...rawEntityDefinition, - metadata: [{ source: 'host.name' }], - }); - expect(generateHistoryMetadataAggregations(definition)).toEqual({ - 'entity.metadata.host.name': { - terms: { - field: 'host.name', - size: 1000, - }, - }, - }); - }); - - it('should generate metadata aggregations for object format with source and aggregation', () => { - const definition = entityDefinitionSchema.parse({ - ...rawEntityDefinition, - metadata: [{ source: 'host.name', aggregation: { type: 'terms', limit: 10 } }], - }); - expect(generateHistoryMetadataAggregations(definition)).toEqual({ - 'entity.metadata.host.name': { - terms: { - field: 'host.name', - size: 10, - }, - }, - }); - }); - - it('should generate metadata aggregations for object format with source, aggregation, and destination', () => { - const definition = entityDefinitionSchema.parse({ - ...rawEntityDefinition, - metadata: [ - { - source: 'host.name', - aggregation: { type: 'terms', limit: 20 }, - destination: 'hostName', - }, - ], - }); - expect(generateHistoryMetadataAggregations(definition)).toEqual({ - 'entity.metadata.hostName': { - terms: { - field: 'host.name', - size: 20, - }, - }, - }); - }); - - it('should generate metadata aggregations for terms and top_value', () => { - const definition = entityDefinitionSchema.parse({ - ...rawEntityDefinition, - metadata: [ - { - source: 'host.name', - aggregation: { type: 'terms', limit: 10 }, - destination: 'hostName', - }, - { - source: 'agent.name', - aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, - destination: 'agentName', - }, - ], - }); - - expect(generateHistoryMetadataAggregations(definition)).toEqual({ - 'entity.metadata.hostName': { - terms: { - field: 'host.name', - size: 10, - }, - }, - 'entity.metadata.agentName': { - filter: { - exists: { - field: 'agent.name', - }, - }, - aggs: { - top_value: { - top_metrics: { - metrics: { field: 'agent.name' }, - sort: { '@timestamp': 'desc' }, - }, - }, - }, - }, - }); - }); - }); - describe('generateLatestMetadataAggregations()', () => { it('should generate metadata aggregations for string format', () => { const definition = entityDefinitionSchema.parse({ ...rawEntityDefinition, metadata: ['host.name'], }); + expect(generateLatestMetadataAggregations(definition)).toEqual({ 'entity.metadata.host.name': { filter: { range: { '@timestamp': { - gte: 'now-360s', + gte: 'now-10m', }, }, }, @@ -142,7 +30,7 @@ describe('Generate Metadata Aggregations for history and latest', () => { data: { terms: { field: 'host.name', - size: 1000, + size: 10, }, }, }, @@ -160,7 +48,7 @@ describe('Generate Metadata Aggregations for history and latest', () => { filter: { range: { '@timestamp': { - gte: 'now-360s', + gte: 'now-10m', }, }, }, @@ -168,7 +56,7 @@ describe('Generate Metadata Aggregations for history and latest', () => { data: { terms: { field: 'host.name', - size: 1000, + size: 10, }, }, }, @@ -179,14 +67,16 @@ describe('Generate Metadata Aggregations for history and latest', () => { it('should generate metadata aggregations for object format with source and aggregation', () => { const definition = entityDefinitionSchema.parse({ ...rawEntityDefinition, - metadata: [{ source: 'host.name', aggregation: { type: 'terms', limit: 10 } }], + metadata: [ + { source: 'host.name', aggregation: { type: 'terms', limit: 10, lookbackPeriod: '1h' } }, + ], }); expect(generateLatestMetadataAggregations(definition)).toEqual({ 'entity.metadata.host.name': { filter: { range: { '@timestamp': { - gte: 'now-360s', + gte: 'now-1h', }, }, }, @@ -218,14 +108,14 @@ describe('Generate Metadata Aggregations for history and latest', () => { filter: { range: { '@timestamp': { - gte: 'now-360s', + gte: 'now-10m', }, }, }, aggs: { data: { terms: { - field: 'hostName', + field: 'host.name', size: 10, }, }, @@ -255,14 +145,14 @@ describe('Generate Metadata Aggregations for history and latest', () => { filter: { range: { '@timestamp': { - gte: 'now-360s', + gte: 'now-10m', }, }, }, aggs: { data: { terms: { - field: 'hostName', + field: 'host.name', size: 10, }, }, @@ -275,13 +165,13 @@ describe('Generate Metadata Aggregations for history and latest', () => { { range: { '@timestamp': { - gte: 'now-360s', + gte: 'now-10m', }, }, }, { exists: { - field: 'agentName', + field: 'agent.name', }, }, ], @@ -291,7 +181,7 @@ describe('Generate Metadata Aggregations for history and latest', () => { top_value: { top_metrics: { metrics: { - field: 'agentName', + field: 'agent.name', }, sort: { '@timestamp': 'desc', diff --git a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.ts b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.ts index 0fc4464672219..796d1e25b55ec 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.ts @@ -6,70 +6,28 @@ */ import { EntityDefinition } from '@kbn/entities-schema'; -import { calculateOffset } from '../helpers/calculate_offset'; - -export function generateHistoryMetadataAggregations(definition: EntityDefinition) { - if (!definition.metadata) { - return {}; - } - return definition.metadata.reduce((aggs, metadata) => { - let agg; - if (metadata.aggregation.type === 'terms') { - agg = { - terms: { - field: metadata.source, - size: metadata.aggregation.limit, - }, - }; - } else if (metadata.aggregation.type === 'top_value') { - agg = { - filter: { - exists: { - field: metadata.source, - }, - }, - aggs: { - top_value: { - top_metrics: { - metrics: { - field: metadata.source, - }, - sort: metadata.aggregation.sort, - }, - }, - }, - }; - } - - return { - ...aggs, - [`entity.metadata.${metadata.destination}`]: agg, - }; - }, {}); -} export function generateLatestMetadataAggregations(definition: EntityDefinition) { if (!definition.metadata) { return {}; } - const offsetInSeconds = `${calculateOffset(definition)}s`; - return definition.metadata.reduce((aggs, metadata) => { + const lookbackPeriod = metadata.aggregation.lookbackPeriod || definition.latest.lookbackPeriod; let agg; if (metadata.aggregation.type === 'terms') { agg = { filter: { range: { '@timestamp': { - gte: `now-${offsetInSeconds}`, + gte: `now-${lookbackPeriod}`, }, }, }, aggs: { data: { terms: { - field: metadata.destination, + field: metadata.source, size: metadata.aggregation.limit, }, }, @@ -83,13 +41,13 @@ export function generateLatestMetadataAggregations(definition: EntityDefinition) { range: { '@timestamp': { - gte: `now-${metadata.aggregation.lookbackPeriod ?? offsetInSeconds}`, + gte: `now-${lookbackPeriod}`, }, }, }, { exists: { - field: metadata.destination, + field: metadata.source, }, }, ], @@ -99,7 +57,7 @@ export function generateLatestMetadataAggregations(definition: EntityDefinition) top_value: { top_metrics: { metrics: { - field: metadata.destination, + field: metadata.source, }, sort: metadata.aggregation.sort, }, diff --git a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metric_aggregations.ts b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metric_aggregations.ts index bd1af365116cb..d42dd69b37eff 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metric_aggregations.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/transform/generate_metric_aggregations.ts @@ -104,41 +104,15 @@ function buildMetricEquation(keyMetric: KeyMetric) { }; } -export function generateHistoryMetricAggregations(definition: EntityDefinition) { - if (!definition.metrics) { - return {}; - } - return definition.metrics.reduce((aggs, keyMetric) => { - return { - ...aggs, - ...buildMetricAggregations(keyMetric, definition.history.timestampField), - [`entity.metrics.${keyMetric.name}`]: buildMetricEquation(keyMetric), - }; - }, {}); -} - export function generateLatestMetricAggregations(definition: EntityDefinition) { if (!definition.metrics) { return {}; } - return definition.metrics.reduce((aggs, keyMetric) => { return { ...aggs, - [`_${keyMetric.name}`]: { - top_metrics: { - metrics: [{ field: `entity.metrics.${keyMetric.name}` }], - sort: [{ '@timestamp': 'desc' }], - }, - }, - [`entity.metrics.${keyMetric.name}`]: { - bucket_script: { - buckets_path: { - value: `_${keyMetric.name}[entity.metrics.${keyMetric.name}]`, - }, - script: 'params.value', - }, - }, + ...buildMetricAggregations(keyMetric, definition.latest.timestampField), + [`entity.metrics.${keyMetric.name}`]: buildMetricEquation(keyMetric), }; }, {}); } diff --git a/x-pack/plugins/entity_manager/server/lib/entities/transform/validate_transform_ids.ts b/x-pack/plugins/entity_manager/server/lib/entities/transform/validate_transform_ids.ts index c16b7f126dded..c703124bdf082 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/transform/validate_transform_ids.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/transform/validate_transform_ids.ts @@ -7,26 +7,14 @@ import { EntityDefinition } from '@kbn/entities-schema'; import { EntityDefinitionIdInvalid } from '../errors/entity_definition_id_invalid'; -import { - generateHistoryBackfillTransformId, - generateHistoryTransformId, - generateLatestTransformId, -} from '../helpers/generate_component_id'; +import { generateLatestTransformId } from '../helpers/generate_component_id'; const TRANSFORM_ID_MAX_LENGTH = 64; export function validateDefinitionCanCreateValidTransformIds(definition: EntityDefinition) { - const historyTransformId = generateHistoryTransformId(definition); const latestTransformId = generateLatestTransformId(definition); - const historyBackfillTransformId = generateHistoryBackfillTransformId(definition); - const spareChars = - TRANSFORM_ID_MAX_LENGTH - - Math.max( - historyTransformId.length, - latestTransformId.length, - historyBackfillTransformId.length - ); + const spareChars = TRANSFORM_ID_MAX_LENGTH - latestTransformId.length; if (spareChars < 0) { throw new EntityDefinitionIdInvalid( diff --git a/x-pack/plugins/entity_manager/server/lib/entities/uninstall_entity_definition.ts b/x-pack/plugins/entity_manager/server/lib/entities/uninstall_entity_definition.ts index 8bc8efa3870aa..d0e0410b6e422 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/uninstall_entity_definition.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/uninstall_entity_definition.ts @@ -11,14 +11,10 @@ import { EntityDefinition } from '@kbn/entities-schema'; import { Logger } from '@kbn/logging'; import { deleteEntityDefinition } from './delete_entity_definition'; import { deleteIndices } from './delete_index'; -import { deleteHistoryIngestPipeline, deleteLatestIngestPipeline } from './delete_ingest_pipeline'; +import { deleteIngestPipelines } from './delete_ingest_pipeline'; import { findEntityDefinitions } from './find_entity_definition'; -import { - generateHistoryIndexTemplateId, - generateLatestIndexTemplateId, -} from './helpers/generate_component_id'; -import { deleteTemplate } from '../manage_index_templates'; +import { deleteTemplates } from '../manage_index_templates'; import { stopTransforms } from './stop_transforms'; @@ -40,19 +36,13 @@ export async function uninstallEntityDefinition({ await stopTransforms(esClient, definition, logger); await deleteTransforms(esClient, definition, logger); - await Promise.all([ - deleteHistoryIngestPipeline(esClient, definition, logger), - deleteLatestIngestPipeline(esClient, definition, logger), - ]); + await deleteIngestPipelines(esClient, definition, logger); if (deleteData) { await deleteIndices(esClient, definition, logger); } - await Promise.all([ - deleteTemplate({ esClient, logger, name: generateHistoryIndexTemplateId(definition) }), - deleteTemplate({ esClient, logger, name: generateLatestIndexTemplateId(definition) }), - ]); + await deleteTemplates(esClient, definition, logger); await deleteEntityDefinition(soClient, definition); } diff --git a/x-pack/plugins/entity_manager/server/lib/entity_client.ts b/x-pack/plugins/entity_manager/server/lib/entity_client.ts index ee6b59b0ae0ea..710872c04eda0 100644 --- a/x-pack/plugins/entity_manager/server/lib/entity_client.ts +++ b/x-pack/plugins/entity_manager/server/lib/entity_client.ts @@ -41,7 +41,7 @@ export class EntityClient { }); if (!installOnly) { - await startTransforms(this.options.esClient, definition, this.options.logger); + await startTransforms(this.options.esClient, installedDefinition, this.options.logger); } return installedDefinition; diff --git a/x-pack/plugins/entity_manager/server/lib/manage_index_templates.ts b/x-pack/plugins/entity_manager/server/lib/manage_index_templates.ts index b0789b6cf2769..ffa58cd9c0145 100644 --- a/x-pack/plugins/entity_manager/server/lib/manage_index_templates.ts +++ b/x-pack/plugins/entity_manager/server/lib/manage_index_templates.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { EntityDefinition } from '@kbn/entities-schema'; import { ClusterPutComponentTemplateRequest, IndicesPutIndexTemplateRequest, @@ -15,6 +16,7 @@ import { entitiesLatestBaseComponentTemplateConfig } from '../templates/componen import { entitiesEntityComponentTemplateConfig } from '../templates/components/entity'; import { entitiesEventComponentTemplateConfig } from '../templates/components/event'; import { retryTransientEsErrors } from './entities/helpers/retry'; +import { generateEntitiesLatestIndexTemplateConfig } from './entities/templates/entities_latest_template'; interface TemplateManagementOptions { esClient: ElasticsearchClient; @@ -67,14 +69,27 @@ interface DeleteTemplateOptions { export async function upsertTemplate({ esClient, template, logger }: TemplateManagementOptions) { try { - await retryTransientEsErrors(() => esClient.indices.putIndexTemplate(template), { logger }); + const result = await retryTransientEsErrors(() => esClient.indices.putIndexTemplate(template), { + logger, + }); logger.debug(() => `Installed entity manager index template: ${JSON.stringify(template)}`); + return result; } catch (error: any) { logger.error(`Error updating entity manager index template: ${error.message}`); throw error; } } +export async function createAndInstallTemplates( + esClient: ElasticsearchClient, + definition: EntityDefinition, + logger: Logger +): Promise> { + const template = generateEntitiesLatestIndexTemplateConfig(definition); + await upsertTemplate({ esClient, template, logger }); + return [{ type: 'template', id: template.name }]; +} + export async function deleteTemplate({ esClient, name, logger }: DeleteTemplateOptions) { try { await retryTransientEsErrors( @@ -87,6 +102,28 @@ export async function deleteTemplate({ esClient, name, logger }: DeleteTemplateO } } +export async function deleteTemplates( + esClient: ElasticsearchClient, + definition: EntityDefinition, + logger: Logger +) { + try { + await Promise.all( + (definition.installedComponents ?? []) + .filter(({ type }) => type === 'template') + .map(({ id }) => + retryTransientEsErrors( + () => esClient.indices.deleteIndexTemplate({ name: id }, { ignore: [404] }), + { logger } + ) + ) + ); + } catch (error: any) { + logger.error(`Error deleting entity manager index template: ${error.message}`); + throw error; + } +} + export async function upsertComponent({ esClient, component, logger }: ComponentManagementOptions) { try { await retryTransientEsErrors(() => esClient.cluster.putComponentTemplate(component), { diff --git a/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts b/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts index bde68eb85ba9f..9c1c4f403636b 100644 --- a/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts +++ b/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts @@ -51,8 +51,8 @@ export const disableEntityDiscoveryRoute = createEntityManagerServerRoute({ }), handler: async ({ context, response, params, logger, server }) => { try { - const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const canDisable = await canDisableEntityDiscovery(esClient); + const esClientAsCurrentUser = (await context.core).elasticsearch.client.asCurrentUser; + const canDisable = await canDisableEntityDiscovery(esClientAsCurrentUser); if (!canDisable) { return response.forbidden({ body: { @@ -62,6 +62,7 @@ export const disableEntityDiscoveryRoute = createEntityManagerServerRoute({ }); } + const esClient = (await context.core).elasticsearch.client.asSecondaryAuthUser; const soClient = (await context.core).savedObjects.getClient({ includedHiddenTypes: [EntityDiscoveryApiKeyType.name], }); diff --git a/x-pack/plugins/entity_manager/server/routes/enablement/enable.ts b/x-pack/plugins/entity_manager/server/routes/enablement/enable.ts index 9814840d20a0b..1002c1e716df2 100644 --- a/x-pack/plugins/entity_manager/server/routes/enablement/enable.ts +++ b/x-pack/plugins/entity_manager/server/routes/enablement/enable.ts @@ -80,8 +80,10 @@ export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({ }); } - const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const canEnable = await canEnableEntityDiscovery(esClient); + const core = await context.core; + + const esClientAsCurrentUser = core.elasticsearch.client.asCurrentUser; + const canEnable = await canEnableEntityDiscovery(esClientAsCurrentUser); if (!canEnable) { return response.forbidden({ body: { @@ -91,7 +93,7 @@ export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({ }); } - const soClient = (await context.core).savedObjects.getClient({ + const soClient = core.savedObjects.getClient({ includedHiddenTypes: [EntityDiscoveryApiKeyType.name], }); const existingApiKey = await readEntityDiscoveryAPIKey(server); @@ -117,6 +119,7 @@ export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({ await saveEntityDiscoveryAPIKey(soClient, apiKey); + const esClient = core.elasticsearch.client.asSecondaryAuthUser; const installedDefinitions = await installBuiltInEntityDefinitions({ esClient, soClient, diff --git a/x-pack/plugins/entity_manager/server/routes/entities/reset.ts b/x-pack/plugins/entity_manager/server/routes/entities/reset.ts index a59c38b3acf7c..0b6942e335e51 100644 --- a/x-pack/plugins/entity_manager/server/routes/entities/reset.ts +++ b/x-pack/plugins/entity_manager/server/routes/entities/reset.ts @@ -12,25 +12,13 @@ import { EntitySecurityException } from '../../lib/entities/errors/entity_securi import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; import { readEntityDefinition } from '../../lib/entities/read_entity_definition'; -import { - deleteHistoryIngestPipeline, - deleteLatestIngestPipeline, -} from '../../lib/entities/delete_ingest_pipeline'; +import { deleteIngestPipelines } from '../../lib/entities/delete_ingest_pipeline'; import { deleteIndices } from '../../lib/entities/delete_index'; -import { - createAndInstallHistoryIngestPipeline, - createAndInstallLatestIngestPipeline, -} from '../../lib/entities/create_and_install_ingest_pipeline'; -import { - createAndInstallHistoryBackfillTransform, - createAndInstallHistoryTransform, - createAndInstallLatestTransform, -} from '../../lib/entities/create_and_install_transform'; +import { createAndInstallIngestPipelines } from '../../lib/entities/create_and_install_ingest_pipeline'; +import { createAndInstallTransforms } from '../../lib/entities/create_and_install_transform'; import { startTransforms } from '../../lib/entities/start_transforms'; import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found'; -import { isBackfillEnabled } from '../../lib/entities/helpers/is_backfill_enabled'; - import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; import { deleteTransforms } from '../../lib/entities/delete_transforms'; import { stopTransforms } from '../../lib/entities/stop_transforms'; @@ -51,18 +39,12 @@ export const resetEntityDefinitionRoute = createEntityManagerServerRoute({ await stopTransforms(esClient, definition, logger); await deleteTransforms(esClient, definition, logger); - await deleteHistoryIngestPipeline(esClient, definition, logger); - await deleteLatestIngestPipeline(esClient, definition, logger); + await deleteIngestPipelines(esClient, definition, logger); await deleteIndices(esClient, definition, logger); // Recreate everything - await createAndInstallHistoryIngestPipeline(esClient, definition, logger); - await createAndInstallLatestIngestPipeline(esClient, definition, logger); - await createAndInstallHistoryTransform(esClient, definition, logger); - if (isBackfillEnabled(definition)) { - await createAndInstallHistoryBackfillTransform(esClient, definition, logger); - } - await createAndInstallLatestTransform(esClient, definition, logger); + await createAndInstallIngestPipelines(esClient, definition, logger); + await createAndInstallTransforms(esClient, definition, logger); await startTransforms(esClient, definition, logger); return response.ok({ body: { acknowledged: true } }); diff --git a/x-pack/plugins/entity_manager/server/saved_objects/entity_definition.ts b/x-pack/plugins/entity_manager/server/saved_objects/entity_definition.ts index fdf2510e8627e..bdea2b71e4141 100644 --- a/x-pack/plugins/entity_manager/server/saved_objects/entity_definition.ts +++ b/x-pack/plugins/entity_manager/server/saved_objects/entity_definition.ts @@ -5,11 +5,36 @@ * 2.0. */ +import { SavedObjectModelDataBackfillFn } from '@kbn/core-saved-objects-server'; import { SavedObject, SavedObjectsType } from '@kbn/core/server'; import { EntityDefinition } from '@kbn/entities-schema'; +import { + generateHistoryIndexTemplateId, + generateHistoryIngestPipelineId, + generateHistoryTransformId, + generateLatestIndexTemplateId, + generateLatestIngestPipelineId, + generateLatestTransformId, +} from '../lib/entities/helpers/generate_component_id'; export const SO_ENTITY_DEFINITION_TYPE = 'entity-definition'; +export const backfillInstalledComponents: SavedObjectModelDataBackfillFn< + EntityDefinition, + EntityDefinition +> = (savedObject) => { + const definition = savedObject.attributes; + definition.installedComponents = [ + { type: 'transform', id: generateHistoryTransformId(definition) }, + { type: 'transform', id: generateLatestTransformId(definition) }, + { type: 'ingest_pipeline', id: generateHistoryIngestPipelineId(definition) }, + { type: 'ingest_pipeline', id: generateLatestIngestPipelineId(definition) }, + { type: 'template', id: generateHistoryIndexTemplateId(definition) }, + { type: 'template', id: generateLatestIndexTemplateId(definition) }, + ]; + return savedObject; +}; + export const entityDefinition: SavedObjectsType = { name: SO_ENTITY_DEFINITION_TYPE, hidden: false, @@ -64,5 +89,13 @@ export const entityDefinition: SavedObjectsType = { }, ], }, + '3': { + changes: [ + { + type: 'data_backfill', + backfillFn: backfillInstalledComponents, + }, + ], + }, }, }; diff --git a/x-pack/plugins/entity_manager/server/templates/components/helpers.test.ts b/x-pack/plugins/entity_manager/server/templates/components/helpers.test.ts deleted file mode 100644 index 90c5e90d43f3a..0000000000000 --- a/x-pack/plugins/entity_manager/server/templates/components/helpers.test.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EntityDefinition } from '@kbn/entities-schema'; -import { getCustomHistoryTemplateComponents, getCustomLatestTemplateComponents } from './helpers'; - -describe('helpers', () => { - it('getCustomLatestTemplateComponents should return template component in the right sort order', () => { - const result = getCustomLatestTemplateComponents({ id: 'test' } as EntityDefinition); - expect(result).toEqual([ - 'test@platform', - 'test-latest@platform', - 'test@custom', - 'test-latest@custom', - ]); - }); - - it('getCustomHistoryTemplateComponents should return template component in the right sort order', () => { - const result = getCustomHistoryTemplateComponents({ id: 'test' } as EntityDefinition); - expect(result).toEqual([ - 'test@platform', - 'test-history@platform', - 'test@custom', - 'test-history@custom', - ]); - }); -}); diff --git a/x-pack/plugins/entity_manager/server/templates/components/helpers.ts b/x-pack/plugins/entity_manager/server/templates/components/helpers.ts deleted file mode 100644 index 23cc7cccb6a13..0000000000000 --- a/x-pack/plugins/entity_manager/server/templates/components/helpers.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EntityDefinition } from '@kbn/entities-schema'; -import { isBuiltinDefinition } from '../../lib/entities/helpers/is_builtin_definition'; - -export const getCustomLatestTemplateComponents = (definition: EntityDefinition) => { - if (isBuiltinDefinition(definition)) { - return []; - } - - return [ - `${definition.id}@platform`, // @platform goes before so it can be overwritten by custom - `${definition.id}-latest@platform`, - `${definition.id}@custom`, - `${definition.id}-latest@custom`, - ]; -}; - -export const getCustomHistoryTemplateComponents = (definition: EntityDefinition) => { - if (isBuiltinDefinition(definition)) { - return []; - } - - return [ - `${definition.id}@platform`, // @platform goes before so it can be overwritten by custom - `${definition.id}-history@platform`, - `${definition.id}@custom`, - `${definition.id}-history@custom`, - ]; -}; diff --git a/x-pack/plugins/entity_manager/tsconfig.json b/x-pack/plugins/entity_manager/tsconfig.json index 29c100ee4c9d2..34c57a27dd829 100644 --- a/x-pack/plugins/entity_manager/tsconfig.json +++ b/x-pack/plugins/entity_manager/tsconfig.json @@ -34,5 +34,6 @@ "@kbn/zod-helpers", "@kbn/encrypted-saved-objects-plugin", "@kbn/licensing-plugin", + "@kbn/core-saved-objects-server", ] } diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/get_entities.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/get_entities.ts index 8f3a0abb62b67..00151f2029d21 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/get_entities.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/get_entities.ts @@ -61,7 +61,6 @@ export async function getEntitiesWithSource({ identityFields: entity?.entity.identityFields, id: entity?.entity.id, definitionId: entity?.entity.definitionId, - firstSeenTimestamp: entity?.entity.firstSeenTimestamp, lastSeenTimestamp: entity?.entity.lastSeenTimestamp, displayName: entity?.entity.displayName, metrics: entity?.entity.metrics, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/definition.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/definition.ts index a72e00bf7aceb..09dea151a050a 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/definition.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/definition.ts @@ -27,9 +27,8 @@ export const buildHostEntityDefinition = (space: string): EntityDefinition => 'host.type', 'host.architecture', ], - history: { + latest: { timestampField: '@timestamp', - interval: '1m', }, version: '1.0.0', managed: true, @@ -44,9 +43,8 @@ export const buildUserEntityDefinition = (space: string): EntityDefinition => identityFields: ['user.name'], displayNameTemplate: '{{user.name}}', metadata: ['user.email', 'user.full_name', 'user.hash', 'user.id', 'user.name', 'user.roles'], - history: { + latest: { timestampField: '@timestamp', - interval: '1m', }, version: '1.0.0', managed: true, diff --git a/x-pack/test/api_integration/apis/entity_manager/definitions.ts b/x-pack/test/api_integration/apis/entity_manager/definitions.ts index 466b5e0232bf0..b51a26ad7b5ad 100644 --- a/x-pack/test/api_integration/apis/entity_manager/definitions.ts +++ b/x-pack/test/api_integration/apis/entity_manager/definitions.ts @@ -8,10 +8,7 @@ import semver from 'semver'; import expect from '@kbn/expect'; import { entityLatestSchema } from '@kbn/entities-schema'; -import { - entityDefinition as mockDefinition, - entityDefinitionWithBackfill as mockBackfillDefinition, -} from '@kbn/entityManager-plugin/server/lib/entities/helpers/fixtures'; +import { entityDefinition as mockDefinition } from '@kbn/entityManager-plugin/server/lib/entities/helpers/fixtures'; import { PartialConfig, cleanup, generate } from '@kbn/data-forge'; import { generateLatestIndexName } from '@kbn/entityManager-plugin/server/lib/entities/helpers/generate_component_id'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -33,8 +30,9 @@ export default function ({ getService }: FtrProviderContext) { describe('Entity definitions', () => { describe('definitions installations', () => { it('can install multiple definitions', async () => { + const mockDefinitionDup = { ...mockDefinition, id: 'mock_definition_dup' }; await installDefinition(supertest, { definition: mockDefinition }); - await installDefinition(supertest, { definition: mockBackfillDefinition }); + await installDefinition(supertest, { definition: mockDefinitionDup }); const { definitions } = await getInstalledDefinitions(supertest); expect(definitions.length).to.eql(2); @@ -49,7 +47,7 @@ export default function ({ getService }: FtrProviderContext) { expect( definitions.some( (definition) => - definition.id === mockBackfillDefinition.id && + definition.id === mockDefinitionDup.id && definition.state.installed === true && definition.state.running === true ) @@ -57,7 +55,7 @@ export default function ({ getService }: FtrProviderContext) { await Promise.all([ uninstallDefinition(supertest, { id: mockDefinition.id, deleteData: true }), - uninstallDefinition(supertest, { id: mockBackfillDefinition.id, deleteData: true }), + uninstallDefinition(supertest, { id: mockDefinitionDup.id, deleteData: true }), ]); }); @@ -89,7 +87,7 @@ export default function ({ getService }: FtrProviderContext) { id: mockDefinition.id, update: { version: incVersion!, - history: { + latest: { timestampField: '@updatedTimestampField', }, }, @@ -99,7 +97,7 @@ export default function ({ getService }: FtrProviderContext) { definitions: [updatedDefinition], } = await getInstalledDefinitions(supertest); expect(updatedDefinition.version).to.eql(incVersion); - expect(updatedDefinition.history.timestampField).to.eql('@updatedTimestampField'); + expect(updatedDefinition.latest.timestampField).to.eql('@updatedTimestampField'); await uninstallDefinition(supertest, { id: mockDefinition.id }); }); @@ -114,7 +112,7 @@ export default function ({ getService }: FtrProviderContext) { id: mockDefinition.id, update: { version: '1.0.0', - history: { + latest: { timestampField: '@updatedTimestampField', }, }, diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine.ts index 99d84fbc5427b..4fb2360a049cf 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine.ts @@ -27,10 +27,7 @@ export default ({ getService }: FtrProviderContext) => { it('should have installed the expected user resources', async () => { await utils.initEntityEngineForEntityType('user'); - const expectedTransforms = [ - 'entities-v1-history-ea_default_user_entity_store', - 'entities-v1-latest-ea_default_user_entity_store', - ]; + const expectedTransforms = ['entities-v1-latest-ea_default_user_entity_store']; await utils.expectTransformsExist(expectedTransforms); }); @@ -38,10 +35,7 @@ export default ({ getService }: FtrProviderContext) => { it('should have installed the expected host resources', async () => { await utils.initEntityEngineForEntityType('host'); - const expectedTransforms = [ - 'entities-v1-history-ea_default_host_entity_store', - 'entities-v1-latest-ea_default_host_entity_store', - ]; + const expectedTransforms = ['entities-v1-latest-ea_default_host_entity_store']; await utils.expectTransformsExist(expectedTransforms); }); @@ -173,7 +167,6 @@ export default ({ getService }: FtrProviderContext) => { }) .expect(200); - await utils.expectTransformNotFound('entities-v1-history-ea_host_entity_store'); await utils.expectTransformNotFound('entities-v1-latest-ea_host_entity_store'); }); @@ -187,7 +180,6 @@ export default ({ getService }: FtrProviderContext) => { }) .expect(200); - await utils.expectTransformNotFound('entities-v1-history-ea_user_entity_store'); await utils.expectTransformNotFound('entities-v1-latest-ea_user_entity_store'); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine_nondefault_spaces.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine_nondefault_spaces.ts index 112c8b8b21511..e3ef29d937183 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine_nondefault_spaces.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine_nondefault_spaces.ts @@ -38,10 +38,7 @@ export default ({ getService }: FtrProviderContextWithSpaces) => { it('should have installed the expected user resources', async () => { await utils.initEntityEngineForEntityType('user'); - const expectedTransforms = [ - `entities-v1-history-ea_${namespace}_user_entity_store`, - `entities-v1-latest-ea_${namespace}_user_entity_store`, - ]; + const expectedTransforms = [`entities-v1-latest-ea_${namespace}_user_entity_store`]; await utils.expectTransformsExist(expectedTransforms); }); @@ -49,10 +46,7 @@ export default ({ getService }: FtrProviderContextWithSpaces) => { it('should have installed the expected host resources', async () => { await utils.initEntityEngineForEntityType('host'); - const expectedTransforms = [ - `entities-v1-history-ea_${namespace}_host_entity_store`, - `entities-v1-latest-ea_${namespace}_host_entity_store`, - ]; + const expectedTransforms = [`entities-v1-latest-ea_${namespace}_host_entity_store`]; await utils.expectTransformsExist(expectedTransforms); }); From 3fa70e122c6a3c77edea3f2c47980403c1835256 Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Wed, 9 Oct 2024 23:41:02 +0200 Subject: [PATCH 093/110] [Security Solution][Notes] - update notes management page columns (#194860) --- .../notes/components/delete_confirm_modal.tsx | 29 +++- .../notes/components/delete_note_button.tsx | 7 +- .../public/notes/components/notes_list.tsx | 85 ++++++---- .../components/open_event_in_timeline.tsx | 24 --- .../components/open_flyout_button.test.tsx | 15 +- .../notes/components/open_flyout_button.tsx | 71 ++++---- .../notes/components/open_timeline_button.tsx | 13 +- .../public/notes/components/translations.ts | 58 ------- .../public/notes/components/utility_bar.tsx | 32 +++- .../public/notes/hooks/use_fetch_notes.ts | 15 +- .../notes/pages/note_management_page.tsx | 155 +++++++++--------- .../public/notes/pages/translations.ts | 27 +-- .../public/notes/store/notes.slice.test.ts | 8 +- .../public/notes/store/notes.slice.ts | 4 +- .../translations/translations/fr-FR.json | 5 - .../translations/translations/ja-JP.json | 5 - .../translations/translations/zh-CN.json | 5 - 17 files changed, 263 insertions(+), 295 deletions(-) delete mode 100644 x-pack/plugins/security_solution/public/notes/components/open_event_in_timeline.tsx delete mode 100644 x-pack/plugins/security_solution/public/notes/components/translations.ts diff --git a/x-pack/plugins/security_solution/public/notes/components/delete_confirm_modal.tsx b/x-pack/plugins/security_solution/public/notes/components/delete_confirm_modal.tsx index cba7e81b0fb2b..3c6d6da08e190 100644 --- a/x-pack/plugins/security_solution/public/notes/components/delete_confirm_modal.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/delete_confirm_modal.tsx @@ -7,7 +7,7 @@ import React, { useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { EuiConfirmModal } from '@elastic/eui'; -import * as i18n from './translations'; +import { i18n } from '@kbn/i18n'; import { deleteNotes, userClosedDeleteModal, @@ -16,6 +16,25 @@ import { ReqStatus, } from '..'; +export const DELETE = i18n.translate('xpack.securitySolution.notes.management.deleteAction', { + defaultMessage: 'Delete', +}); +export const DELETE_NOTES_CONFIRM = (selectedNotes: number) => + i18n.translate('xpack.securitySolution.notes.management.deleteNotesConfirm', { + values: { selectedNotes }, + defaultMessage: + 'Are you sure you want to delete {selectedNotes} {selectedNotes, plural, one {note} other {notes}}?', + }); +export const DELETE_NOTES_CANCEL = i18n.translate( + 'xpack.securitySolution.notes.management.deleteNotesCancel', + { + defaultMessage: 'Cancel', + } +); + +/** + * Renders a confirmation modal to delete notes in the notes management page + */ export const DeleteConfirmModal = React.memo(() => { const dispatch = useDispatch(); const pendingDeleteIds = useSelector(selectNotesTablePendingDeleteIds); @@ -33,16 +52,16 @@ export const DeleteConfirmModal = React.memo(() => { return ( - {i18n.DELETE_NOTES_CONFIRM(pendingDeleteIds.length)} + {DELETE_NOTES_CONFIRM(pendingDeleteIds.length)} ); }); diff --git a/x-pack/plugins/security_solution/public/notes/components/delete_note_button.tsx b/x-pack/plugins/security_solution/public/notes/components/delete_note_button.tsx index 3f9e757d3f5a5..4744c362e469c 100644 --- a/x-pack/plugins/security_solution/public/notes/components/delete_note_button.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/delete_note_button.tsx @@ -13,10 +13,10 @@ import { DELETE_NOTE_BUTTON_TEST_ID } from './test_ids'; import type { State } from '../../common/store'; import type { Note } from '../../../common/api/timeline'; import { - deleteNotes, ReqStatus, selectDeleteNotesError, selectDeleteNotesStatus, + userSelectedNotesForDeletion, } from '../store/notes.slice'; import { useAppToasts } from '../../common/hooks/use_app_toasts'; @@ -42,7 +42,8 @@ export interface DeleteNoteButtonIconProps { } /** - * Renders a button to delete a note + * Renders a button to delete a note. + * This button works in combination with the DeleteConfirmModal. */ export const DeleteNoteButtonIcon = memo(({ note, index }: DeleteNoteButtonIconProps) => { const dispatch = useDispatch(); @@ -54,8 +55,8 @@ export const DeleteNoteButtonIcon = memo(({ note, index }: DeleteNoteButtonIconP const deleteNoteFc = useCallback( (noteId: string) => { + dispatch(userSelectedNotesForDeletion(noteId)); setDeletingNoteId(noteId); - dispatch(deleteNotes({ ids: [noteId] })); }, [dispatch] ); diff --git a/x-pack/plugins/security_solution/public/notes/components/notes_list.tsx b/x-pack/plugins/security_solution/public/notes/components/notes_list.tsx index 47dcf89b06452..344935413731e 100644 --- a/x-pack/plugins/security_solution/public/notes/components/notes_list.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/notes_list.tsx @@ -10,6 +10,7 @@ import { EuiAvatar, EuiComment, EuiCommentList, EuiLoadingElastic } from '@elast import { useSelector } from 'react-redux'; import { FormattedRelative } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import { DeleteConfirmModal } from './delete_confirm_modal'; import { OpenFlyoutButtonIcon } from './open_flyout_button'; import { OpenTimelineButtonIcon } from './open_timeline_button'; import { DeleteNoteButtonIcon } from './delete_note_button'; @@ -17,7 +18,11 @@ import { MarkdownRenderer } from '../../common/components/markdown_editor'; import { ADD_NOTE_LOADING_TEST_ID, NOTE_AVATAR_TEST_ID, NOTES_COMMENT_TEST_ID } from './test_ids'; import type { State } from '../../common/store'; import type { Note } from '../../../common/api/timeline'; -import { ReqStatus, selectCreateNoteStatus } from '../store/notes.slice'; +import { + ReqStatus, + selectCreateNoteStatus, + selectNotesTablePendingDeleteIds, +} from '../store/notes.slice'; import { useUserPrivileges } from '../../common/components/user_privileges'; export const ADDED_A_NOTE = i18n.translate('xpack.securitySolution.notes.addedANoteLabel', { @@ -59,41 +64,51 @@ export const NotesList = memo(({ notes, options }: NotesListProps) => { const createStatus = useSelector((state: State) => selectCreateNoteStatus(state)); + const pendingDeleteIds = useSelector(selectNotesTablePendingDeleteIds); + const isDeleteModalVisible = pendingDeleteIds.length > 0; + return ( - - {notes.map((note, index) => ( - {note.created && }} - event={ADDED_A_NOTE} - actions={ - <> - {note.eventId && !options?.hideFlyoutIcon && ( - - )} - {note.timelineId && note.timelineId.length > 0 && !options?.hideTimelineIcon && ( - - )} - {canDeleteNotes && } - - } - timelineAvatar={ - - } - > - {note.note || ''} - - ))} - {createStatus === ReqStatus.Loading && ( - - )} - + <> + + {notes.map((note, index) => ( + {note.created && }} + event={ADDED_A_NOTE} + actions={ + <> + {note.eventId && !options?.hideFlyoutIcon && ( + + )} + {note.timelineId && note.timelineId.length > 0 && !options?.hideTimelineIcon && ( + + )} + {canDeleteNotes && } + + } + timelineAvatar={ + + } + > + {note.note || ''} + + ))} + {createStatus === ReqStatus.Loading && ( + + )} + + {isDeleteModalVisible && } + ); }); diff --git a/x-pack/plugins/security_solution/public/notes/components/open_event_in_timeline.tsx b/x-pack/plugins/security_solution/public/notes/components/open_event_in_timeline.tsx deleted file mode 100644 index 43f039836ccad..0000000000000 --- a/x-pack/plugins/security_solution/public/notes/components/open_event_in_timeline.tsx +++ /dev/null @@ -1,24 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React, { memo } from 'react'; -import { EuiLink } from '@elastic/eui'; -import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; -import { useInvestigateInTimeline } from '../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline'; -import * as i18n from './translations'; - -export const OpenEventInTimeline: React.FC<{ eventId?: string | null }> = memo(({ eventId }) => { - const ecsRowData = { event: { id: [eventId] }, _id: eventId } as Ecs; - const { investigateInTimelineAlertClick } = useInvestigateInTimeline({ ecsRowData }); - - return ( - - {i18n.VIEW_EVENT_IN_TIMELINE} - - ); -}); - -OpenEventInTimeline.displayName = 'OpenEventInTimeline'; diff --git a/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.test.tsx b/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.test.tsx index eed5e5bcbd5da..c22a0ebff3fce 100644 --- a/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.test.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.test.tsx @@ -13,6 +13,7 @@ import { OpenFlyoutButtonIcon } from './open_flyout_button'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { DocumentDetailsRightPanelKey } from '../../flyout/document_details/shared/constants/panel_keys'; import { useSourcererDataView } from '../../sourcerer/containers'; +import { TableId } from '@kbn/securitysolution-data-table'; jest.mock('@kbn/expandable-flyout'); jest.mock('../../sourcerer/containers'); @@ -27,7 +28,11 @@ describe('OpenFlyoutButtonIcon', () => { const { getByTestId } = render( - + ); @@ -41,7 +46,11 @@ describe('OpenFlyoutButtonIcon', () => { const { getByTestId } = render( - + ); @@ -54,7 +63,7 @@ describe('OpenFlyoutButtonIcon', () => { params: { id: mockEventId, indexName: 'test1,test2', - scopeId: mockTimelineId, + scopeId: TableId.alertsOnAlertsPage, }, }, }); diff --git a/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.tsx b/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.tsx index 0c541cc95740c..34ae9405fdf86 100644 --- a/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.tsx @@ -6,9 +6,11 @@ */ import React, { memo, useCallback } from 'react'; +import type { IconType } from '@elastic/eui'; import { EuiButtonIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { TableId } from '@kbn/securitysolution-data-table'; import { OPEN_FLYOUT_BUTTON_TEST_ID } from './test_ids'; import { useSourcererDataView } from '../../sourcerer/containers'; import { SourcererScopeName } from '../../sourcerer/store/model'; @@ -31,44 +33,51 @@ export interface OpenFlyoutButtonIconProps { * Id of the timeline to pass to the flyout for scope */ timelineId: string; + /** + * Icon type to render in the button + */ + iconType: IconType; } /** - * Renders a button to open the alert and event details flyout + * Renders a button to open the alert and event details flyout. + * This component is meant to be used in timeline and the notes management page, where the cell actions are more basic (no filter in/out). */ -export const OpenFlyoutButtonIcon = memo(({ eventId, timelineId }: OpenFlyoutButtonIconProps) => { - const { selectedPatterns } = useSourcererDataView(SourcererScopeName.timeline); +export const OpenFlyoutButtonIcon = memo( + ({ eventId, timelineId, iconType }: OpenFlyoutButtonIconProps) => { + const { selectedPatterns } = useSourcererDataView(SourcererScopeName.timeline); - const { telemetry } = useKibana().services; - const { openFlyout } = useExpandableFlyoutApi(); + const { telemetry } = useKibana().services; + const { openFlyout } = useExpandableFlyoutApi(); - const handleClick = useCallback(() => { - openFlyout({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: eventId, - indexName: selectedPatterns.join(','), - scopeId: timelineId, + const handleClick = useCallback(() => { + openFlyout({ + right: { + id: DocumentDetailsRightPanelKey, + params: { + id: eventId, + indexName: selectedPatterns.join(','), + scopeId: TableId.alertsOnAlertsPage, // TODO we should update the flyout's code to separate scopeId and preview + }, }, - }, - }); - telemetry.reportDetailsFlyoutOpened({ - location: timelineId, - panel: 'right', - }); - }, [eventId, openFlyout, selectedPatterns, telemetry, timelineId]); + }); + telemetry.reportDetailsFlyoutOpened({ + location: timelineId, + panel: 'right', + }); + }, [eventId, openFlyout, selectedPatterns, telemetry, timelineId]); - return ( - - ); -}); + return ( + + ); + } +); OpenFlyoutButtonIcon.displayName = 'OpenFlyoutButtonIcon'; diff --git a/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.tsx b/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.tsx index 531983429acd1..b44ffd55a767a 100644 --- a/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.tsx @@ -7,11 +7,16 @@ import React, { memo, useCallback } from 'react'; import { EuiButtonIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { useQueryTimelineById } from '../../timelines/components/open_timeline/helpers'; import { OPEN_TIMELINE_BUTTON_TEST_ID } from './test_ids'; import type { Note } from '../../../common/api/timeline'; +const OPEN_TIMELINE = i18n.translate('xpack.securitySolution.notes.management.openTimelineButton', { + defaultMessage: 'Open saved timeline', +}); + export interface OpenTimelineButtonIconProps { /** * The note that contains the id of the timeline to open @@ -20,7 +25,7 @@ export interface OpenTimelineButtonIconProps { /** * The index of the note in the list of notes (used to have unique data-test-subj) */ - index: number; + index?: number; } /** @@ -47,10 +52,10 @@ export const OpenTimelineButtonIcon = memo(({ note, index }: OpenTimelineButtonI return ( openTimeline(note)} /> ); diff --git a/x-pack/plugins/security_solution/public/notes/components/translations.ts b/x-pack/plugins/security_solution/public/notes/components/translations.ts deleted file mode 100644 index 8d7a5b4262815..0000000000000 --- a/x-pack/plugins/security_solution/public/notes/components/translations.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const BATCH_ACTIONS = i18n.translate( - 'xpack.securitySolution.notes.management.batchActionsTitle', - { - defaultMessage: 'Bulk actions', - } -); - -export const DELETE = i18n.translate('xpack.securitySolution.notes.management.deleteAction', { - defaultMessage: 'Delete', -}); - -export const DELETE_NOTES_MODAL_TITLE = i18n.translate( - 'xpack.securitySolution.notes.management.deleteNotesModalTitle', - { - defaultMessage: 'Delete notes?', - } -); - -export const DELETE_NOTES_CONFIRM = (selectedNotes: number) => - i18n.translate('xpack.securitySolution.notes.management.deleteNotesConfirm', { - values: { selectedNotes }, - defaultMessage: - 'Are you sure you want to delete {selectedNotes} {selectedNotes, plural, one {note} other {notes}}?', - }); - -export const DELETE_NOTES_CANCEL = i18n.translate( - 'xpack.securitySolution.notes.management.deleteNotesCancel', - { - defaultMessage: 'Cancel', - } -); - -export const DELETE_SELECTED = i18n.translate( - 'xpack.securitySolution.notes.management.deleteSelected', - { - defaultMessage: 'Delete selected notes', - } -); - -export const REFRESH = i18n.translate('xpack.securitySolution.notes.management.refresh', { - defaultMessage: 'Refresh', -}); - -export const VIEW_EVENT_IN_TIMELINE = i18n.translate( - 'xpack.securitySolution.notes.management.viewEventInTimeline', - { - defaultMessage: 'View event in timeline', - } -); diff --git a/x-pack/plugins/security_solution/public/notes/components/utility_bar.tsx b/x-pack/plugins/security_solution/public/notes/components/utility_bar.tsx index 0c09f6393f668..f0a337cb6c217 100644 --- a/x-pack/plugins/security_solution/public/notes/components/utility_bar.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/utility_bar.tsx @@ -4,9 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import React, { useMemo, useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { EuiContextMenuItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { UtilityBarGroup, UtilityBarText, @@ -22,8 +24,28 @@ import { selectNotesTableSearch, userSelectedBulkDelete, } from '..'; -import * as i18n from './translations'; +export const BATCH_ACTIONS = i18n.translate( + 'xpack.securitySolution.notes.management.batchActionsTitle', + { + defaultMessage: 'Bulk actions', + } +); + +export const DELETE_SELECTED = i18n.translate( + 'xpack.securitySolution.notes.management.deleteSelected', + { + defaultMessage: 'Delete selected notes', + } +); + +export const REFRESH = i18n.translate('xpack.securitySolution.notes.management.refresh', { + defaultMessage: 'Refresh', +}); + +/** + * Renders the utility bar for the notes management page + */ export const NotesUtilityBar = React.memo(() => { const dispatch = useDispatch(); const pagination = useSelector(selectNotesPagination); @@ -49,7 +71,7 @@ export const NotesUtilityBar = React.memo(() => { icon="trash" key="DeleteItemKey" > - {i18n.DELETE_SELECTED} + {DELETE_SELECTED} ); }, [deleteSelectedNotes, selectedItems.length]); @@ -83,9 +105,7 @@ export const NotesUtilityBar = React.memo(() => { iconType="arrowDown" popoverContent={BulkActionPopoverContent} > - - {i18n.BATCH_ACTIONS} - + {BATCH_ACTIONS} { iconType="refresh" onClick={refresh} > - {i18n.REFRESH} + {REFRESH} diff --git a/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.ts b/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.ts index c9f64bc382454..2cf599e76bcc9 100644 --- a/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.ts +++ b/x-pack/plugins/security_solution/public/notes/hooks/use_fetch_notes.ts @@ -4,12 +4,23 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { useCallback } from 'react'; import { useDispatch } from 'react-redux'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; -import { fetchNotesByDocumentIds } from '..'; +import { fetchNotesByDocumentIds } from '../store/notes.slice'; + +export interface UseFetchNotesResult { + /** + * Function to fetch the notes for an array of documents + */ + onLoad: (events: Array>) => void; +} -export const useFetchNotes = () => { +/** + * Hook that returns a function to fetch the notes for an array of documents + */ +export const useFetchNotes = (): UseFetchNotesResult => { const dispatch = useDispatch(); const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( 'securitySolutionNotesEnabled' diff --git a/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx b/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx index ddfed3fbb6287..9c2900ca4d599 100644 --- a/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx +++ b/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx @@ -6,11 +6,18 @@ */ import React, { useCallback, useMemo, useEffect } from 'react'; -import type { DefaultItemAction, EuiBasicTableColumn } from '@elastic/eui'; -import { EuiBasicTable, EuiEmptyPrompt, EuiLink, EuiSpacer } from '@elastic/eui'; +import type { EuiBasicTableColumn } from '@elastic/eui'; +import { + EuiAvatar, + EuiBasicTable, + EuiEmptyPrompt, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, +} from '@elastic/eui'; import { useDispatch, useSelector } from 'react-redux'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; -import { useQueryTimelineById } from '../../timelines/components/open_timeline/helpers'; +import { css } from '@emotion/react'; +import { DeleteNoteButtonIcon } from '../components/delete_note_button'; import { Title } from '../../common/components/header_page/title'; // TODO unify this type from the api with the one in public/common/lib/note import type { Note } from '../../../common/api/timeline'; @@ -27,7 +34,6 @@ import { selectNotesTableSearch, selectFetchNotesStatus, selectNotesTablePendingDeleteIds, - userSelectedRowForDeletion, selectFetchNotesError, ReqStatus, } from '..'; @@ -36,42 +42,67 @@ import { SearchRow } from '../components/search_row'; import { NotesUtilityBar } from '../components/utility_bar'; import { DeleteConfirmModal } from '../components/delete_confirm_modal'; import * as i18n from './translations'; -import { OpenEventInTimeline } from '../components/open_event_in_timeline'; - -const columns: ( - onOpenTimeline: (timelineId: string) => void -) => Array> = (onOpenTimeline) => { - return [ - { - field: 'created', - name: i18n.CREATED_COLUMN, - sortable: true, - render: (created: Note['created']) => , - }, - { - field: 'createdBy', - name: i18n.CREATED_BY_COLUMN, - }, - { - field: 'eventId', - name: i18n.EVENT_ID_COLUMN, - sortable: true, - render: (eventId: Note['eventId']) => , - }, - { - field: 'timelineId', - name: i18n.TIMELINE_ID_COLUMN, - render: (timelineId: Note['timelineId']) => - timelineId ? ( - onOpenTimeline(timelineId)}>{i18n.OPEN_TIMELINE} - ) : null, - }, - { - field: 'note', - name: i18n.NOTE_CONTENT_COLUMN, - }, - ]; -}; +import { OpenFlyoutButtonIcon } from '../components/open_flyout_button'; +import { OpenTimelineButtonIcon } from '../components/open_timeline_button'; + +const columns: Array> = [ + { + name: i18n.ACTIONS_COLUMN, + render: (note: Note) => ( + + + {note.eventId ? ( + + ) : null} + + + <>{note.timelineId ? : null} + + + + + + ), + width: '72px', + }, + { + field: 'createdBy', + name: i18n.CREATED_BY_COLUMN, + render: (createdBy: Note['createdBy']) => , + width: '100px', + align: 'center', + }, + { + field: 'note', + name: i18n.NOTE_CONTENT_COLUMN, + }, + { + field: 'created', + name: i18n.CREATED_COLUMN, + sortable: true, + render: (created: Note['created']) => , + width: '225px', + }, +]; const pageSizeOptions = [10, 25, 50, 100]; @@ -129,13 +160,6 @@ export const NoteManagementPage = () => { [dispatch] ); - const selectRowForDeletion = useCallback( - (id: string) => { - dispatch(userSelectedRowForDeletion(id)); - }, - [dispatch] - ); - const onSelectionChange = useCallback( (selection: Note[]) => { const rowIds = selection.map((item) => item.noteId); @@ -148,39 +172,6 @@ export const NoteManagementPage = () => { return item.noteId; }, []); - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const queryTimelineById = useQueryTimelineById(); - const openTimeline = useCallback( - (timelineId: string) => - queryTimelineById({ - timelineId, - unifiedComponentsInTimelineDisabled, - }), - [queryTimelineById, unifiedComponentsInTimelineDisabled] - ); - - const columnWithActions = useMemo(() => { - const actions: Array> = [ - { - name: i18n.DELETE, - description: i18n.DELETE_SINGLE_NOTE_DESCRIPTION, - color: 'primary', - icon: 'trash', - type: 'icon', - onClick: (note: Note) => selectRowForDeletion(note.noteId), - }, - ]; - return [ - ...columns(openTimeline), - { - name: 'actions', - actions, - }, - ]; - }, [selectRowForDeletion, openTimeline]); - const currentPagination = useMemo(() => { return { pageIndex: pagination.page - 1, @@ -223,7 +214,7 @@ export const NoteManagementPage = () => { { }); }); - describe('userSelectedRowForDeletion', () => { - it('should set correct id when user selects a row', () => { - const action = { type: userSelectedRowForDeletion.type, payload: '1' }; + describe('userSelectedNotesForDeletion', () => { + it('should set correct id when user selects a note to delete', () => { + const action = { type: userSelectedNotesForDeletion.type, payload: '1' }; expect(notesReducer(initalEmptyState, action)).toEqual({ ...initalEmptyState, diff --git a/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts b/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts index 6732f9491676e..2d24ab838ee06 100644 --- a/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts +++ b/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts @@ -193,7 +193,7 @@ const notesSlice = createSlice({ userClosedDeleteModal: (state) => { state.pendingDeleteIds = []; }, - userSelectedRowForDeletion: (state, action: { payload: string }) => { + userSelectedNotesForDeletion: (state, action: { payload: string }) => { state.pendingDeleteIds = [action.payload]; }, userSelectedBulkDelete: (state) => { @@ -391,6 +391,6 @@ export const { userSearchedNotes, userSelectedRow, userClosedDeleteModal, - userSelectedRowForDeletion, + userSelectedNotesForDeletion, userSelectedBulkDelete, } = notesSlice.actions; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 3b078d6bb8a90..c441b91d23e31 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -39618,18 +39618,13 @@ "xpack.securitySolution.notes.management.createdByColumnTitle": "Créé par", "xpack.securitySolution.notes.management.createdColumnTitle": "Créé", "xpack.securitySolution.notes.management.deleteAction": "Supprimer", - "xpack.securitySolution.notes.management.deleteDescription": "Supprimer cette note", "xpack.securitySolution.notes.management.deleteNotesCancel": "Annuler", "xpack.securitySolution.notes.management.deleteNotesConfirm": "Voulez-vous vraiment supprimer {selectedNotes} {selectedNotes, plural, one {note} other {notes}} ?", - "xpack.securitySolution.notes.management.deleteNotesModalTitle": "Supprimer les notes ?", "xpack.securitySolution.notes.management.deleteSelected": "Supprimer les notes sélectionnées", - "xpack.securitySolution.notes.management.eventIdColumnTitle": "Afficher le document", "xpack.securitySolution.notes.management.noteContentColumnTitle": "Contenu de la note", "xpack.securitySolution.notes.management.openTimeline": "Ouvrir la chronologie", "xpack.securitySolution.notes.management.refresh": "Actualiser", "xpack.securitySolution.notes.management.tableError": "Impossible de charger les notes", - "xpack.securitySolution.notes.management.timelineColumnTitle": "Chronologie", - "xpack.securitySolution.notes.management.viewEventInTimeline": "Afficher l'événement dans la chronologie", "xpack.securitySolution.notes.noteLabel": "Note", "xpack.securitySolution.notes.notesTitle": "Notes", "xpack.securitySolution.notes.search.FilterByUserOrNotePlaceholder": "Filtre par utilisateur ou note", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e579f87771b20..93e7ab2270f4c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -39362,18 +39362,13 @@ "xpack.securitySolution.notes.management.createdByColumnTitle": "作成者", "xpack.securitySolution.notes.management.createdColumnTitle": "作成済み", "xpack.securitySolution.notes.management.deleteAction": "削除", - "xpack.securitySolution.notes.management.deleteDescription": "このメモを削除", "xpack.securitySolution.notes.management.deleteNotesCancel": "キャンセル", "xpack.securitySolution.notes.management.deleteNotesConfirm": "{selectedNotes} {selectedNotes, plural, other {件のメモ}}を削除しますか?", - "xpack.securitySolution.notes.management.deleteNotesModalTitle": "メモを削除しますか?", "xpack.securitySolution.notes.management.deleteSelected": "選択したメモを削除", - "xpack.securitySolution.notes.management.eventIdColumnTitle": "ドキュメンテーションを表示", "xpack.securitySolution.notes.management.noteContentColumnTitle": "メモコンテンツ", "xpack.securitySolution.notes.management.openTimeline": "タイムラインを開く", "xpack.securitySolution.notes.management.refresh": "更新", "xpack.securitySolution.notes.management.tableError": "メモを読み込めません", - "xpack.securitySolution.notes.management.timelineColumnTitle": "Timeline", - "xpack.securitySolution.notes.management.viewEventInTimeline": "タイムラインでイベントを表示", "xpack.securitySolution.notes.noteLabel": "注", "xpack.securitySolution.notes.notesTitle": "メモ", "xpack.securitySolution.notes.search.FilterByUserOrNotePlaceholder": "ユーザーまたはメモでフィルター", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 09662465c4833..6f81b20c89d2b 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -39407,18 +39407,13 @@ "xpack.securitySolution.notes.management.createdByColumnTitle": "创建者", "xpack.securitySolution.notes.management.createdColumnTitle": "创建时间", "xpack.securitySolution.notes.management.deleteAction": "删除", - "xpack.securitySolution.notes.management.deleteDescription": "删除此备注", "xpack.securitySolution.notes.management.deleteNotesCancel": "取消", "xpack.securitySolution.notes.management.deleteNotesConfirm": "是否确定要删除 {selectedNotes} 个{selectedNotes, plural, other {备注}}?", - "xpack.securitySolution.notes.management.deleteNotesModalTitle": "删除备注?", "xpack.securitySolution.notes.management.deleteSelected": "删除所选备注", - "xpack.securitySolution.notes.management.eventIdColumnTitle": "查看文档", "xpack.securitySolution.notes.management.noteContentColumnTitle": "备注内容", "xpack.securitySolution.notes.management.openTimeline": "打开时间线", "xpack.securitySolution.notes.management.refresh": "刷新", "xpack.securitySolution.notes.management.tableError": "无法加载备注", - "xpack.securitySolution.notes.management.timelineColumnTitle": "时间线", - "xpack.securitySolution.notes.management.viewEventInTimeline": "在时间线中查看事件", "xpack.securitySolution.notes.noteLabel": "备注", "xpack.securitySolution.notes.notesTitle": "备注", "xpack.securitySolution.notes.search.FilterByUserOrNotePlaceholder": "按用户或备注筛选", From 56e1e68b307bc62445f04ae6f443f4854a308547 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Wed, 9 Oct 2024 14:44:30 -0700 Subject: [PATCH 094/110] [ES|QL] Present ES|QL as an equal to data views on the "no data views" screen (#194077) ## Summary Resolves https://github.com/elastic/kibana/issues/176291 ### Screenshots #### Discover/Dashboard/Visualize image #### Stack Management > Data view image #### If User does not have privilege to create a Data View image ### Checklist Delete any items that are not applicable to this PR. - [x] Use a new SVG resource for the ES|QL illustration - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com> Co-authored-by: Andrea Del Rio --- .../src/analytics_no_data_page.component.tsx | 12 +- .../src/analytics_no_data_page.stories.tsx | 4 +- .../impl/src/analytics_no_data_page.test.tsx | 95 +- .../impl/src/analytics_no_data_page.tsx | 4 +- .../page/analytics_no_data/impl/tsconfig.json | 1 + .../analytics_no_data/mocks/src/storybook.ts | 18 +- .../page/analytics_no_data/types/index.d.ts | 2 + .../impl/src/kibana_no_data_page.tsx | 6 +- .../page/kibana_no_data/types/index.d.ts | 2 + .../prompt/no_data_views/impl/src/actions.tsx | 76 - .../impl/src/data_view_illustration.tsx | 11 +- .../impl/src/documentation_link.tsx | 5 +- .../impl/src/esql_illustration.svg | 1600 +++++++++++++++++ .../impl/src/esql_illustration.tsx | 24 + .../impl/src/no_data_views.component.test.tsx | 50 +- .../impl/src/no_data_views.component.tsx | 261 ++- .../no_data_views/impl/src/no_data_views.tsx | 7 +- .../prompt/no_data_views/impl/tsconfig.json | 2 - .../no_data_views/mocks/src/storybook.ts | 14 +- .../prompt/no_data_views/types/index.d.ts | 8 +- src/plugins/data_view_management/kibana.jsonc | 1 + .../index_pattern_table.tsx | 11 +- .../mount_management_section.tsx | 44 +- .../data_view_management/public/plugin.ts | 2 + .../data_view_management/public/types.ts | 2 + .../data_view_management/tsconfig.json | 1 + .../group6/dashboard_esql_no_data.ts | 33 + .../functional/apps/dashboard/group6/index.ts | 1 + .../apps/management/data_views/_try_esql.ts | 34 + test/functional/apps/management/index.ts | 1 + test/functional/page_objects/discover_page.ts | 6 + test/functional/services/esql.ts | 7 + .../translations/translations/fr-FR.json | 5 - .../translations/translations/ja-JP.json | 5 - .../translations/translations/zh-CN.json | 5 - .../data_views/feature_controls/security.ts | 6 +- 36 files changed, 2132 insertions(+), 234 deletions(-) delete mode 100644 packages/shared-ux/prompt/no_data_views/impl/src/actions.tsx create mode 100644 packages/shared-ux/prompt/no_data_views/impl/src/esql_illustration.svg create mode 100644 packages/shared-ux/prompt/no_data_views/impl/src/esql_illustration.tsx create mode 100644 test/functional/apps/dashboard/group6/dashboard_esql_no_data.ts create mode 100644 test/functional/apps/management/data_views/_try_esql.ts diff --git a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.tsx b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.tsx index 41c525c5ca0b0..16d1bebd46548 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.tsx +++ b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.tsx @@ -22,12 +22,14 @@ import { getHasApiKeys$ } from '../lib/get_has_api_keys'; export interface Props { /** Handler for successfully creating a new data view. */ onDataViewCreated: (dataView: unknown) => void; - /** Handler for when try ES|QL is clicked and user has been navigated to try ES|QL in discover. */ - onESQLNavigationComplete?: () => void; /** if set to true allows creation of an ad-hoc dataview from data view editor */ allowAdHocDataView?: boolean; /** if the kibana instance is customly branded */ showPlainSpinner: boolean; + /** If the cluster has data, this handler allows the user to try ES|QL */ + onTryESQL?: () => void; + /** Handler for when try ES|QL is clicked and user has been navigated to try ES|QL in discover. */ + onESQLNavigationComplete?: () => void; } type AnalyticsNoDataPageProps = Props & @@ -119,9 +121,10 @@ const flavors: { */ export const AnalyticsNoDataPage: React.FC = ({ onDataViewCreated, - onESQLNavigationComplete, allowAdHocDataView, showPlainSpinner, + onTryESQL, + onESQLNavigationComplete, ...services }) => { const { prependBasePath, kibanaGuideDocLink, getHttp: get, pageFlavor } = services; @@ -138,8 +141,9 @@ export const AnalyticsNoDataPage: React.FC = ({ {...{ noDataConfig, onDataViewCreated, - onESQLNavigationComplete, allowAdHocDataView, + onTryESQL, + onESQLNavigationComplete, showPlainSpinner, }} /> diff --git a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.stories.tsx b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.stories.tsx index 3c75cefb38cb2..fa251cb03bdbe 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.stories.tsx +++ b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.stories.tsx @@ -29,8 +29,8 @@ export default { export const Analytics = (params: AnalyticsNoDataPageStorybookParams) => { return ( - - + + ); }; diff --git a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.test.tsx b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.test.tsx index 543c1c4817c5b..6b2d3441ed0d1 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.test.tsx +++ b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.test.tsx @@ -14,6 +14,7 @@ import { getAnalyticsNoDataPageServicesMock, getAnalyticsNoDataPageServicesMockWithCustomBranding, } from '@kbn/shared-ux-page-analytics-no-data-mocks'; +import { NoDataViewsPrompt } from '@kbn/shared-ux-prompt-no-data-views'; import { AnalyticsNoDataPageProvider } from './services'; import { AnalyticsNoDataPage as Component } from './analytics_no_data_page.component'; @@ -29,28 +30,86 @@ describe('AnalyticsNoDataPage', () => { jest.resetAllMocks(); }); - it('renders correctly', async () => { - const component = mountWithIntl( - - - - ); + describe('loading state', () => { + it('renders correctly', async () => { + const component = mountWithIntl( + + + + ); - await act(() => new Promise(setImmediate)); + await act(() => new Promise(setImmediate)); - expect(component.find(Component).length).toBe(1); - expect(component.find(Component).props().onDataViewCreated).toBe(onDataViewCreated); - expect(component.find(Component).props().allowAdHocDataView).toBe(true); + expect(component.find(Component).length).toBe(1); + expect(component.find(Component).props().onDataViewCreated).toBe(onDataViewCreated); + expect(component.find(Component).props().allowAdHocDataView).toBe(true); + }); + + it('passes correct boolean value to showPlainSpinner', async () => { + const component = mountWithIntl( + + + + ); + + await act(async () => { + component.update(); + }); + + expect(component.find(Component).length).toBe(1); + expect(component.find(Component).props().showPlainSpinner).toBe(true); + }); }); - it('passes correct boolean value to showPlainSpinner', () => { - const component = mountWithIntl( - - - - ); + describe('with ES data', () => { + jest.spyOn(services, 'hasESData').mockResolvedValue(true); + jest.spyOn(services, 'hasUserDataView').mockResolvedValue(false); + + it('renders the prompt to create a data view', async () => { + const onTryESQL = jest.fn(); + + await act(async () => { + const component = mountWithIntl( + + + + ); + + await new Promise(setImmediate); + component.update(); + + expect(component.find(Component).length).toBe(1); + expect(component.find(NoDataViewsPrompt).length).toBe(1); + }); + }); + + it('renders the prompt to create a data view with a custom onTryESQL action', async () => { + const onTryESQL = jest.fn(); + + await act(async () => { + const component = mountWithIntl( + + + + ); + + await new Promise(setImmediate); + component.update(); + + const tryESQLLink = component.find('button[data-test-subj="tryESQLLink"]'); + expect(tryESQLLink.length).toBe(1); + tryESQLLink.simulate('click'); - expect(component.find(Component).length).toBe(1); - expect(component.find(Component).props().showPlainSpinner).toBe(true); + expect(onTryESQL).toHaveBeenCalled(); + }); + }); }); }); diff --git a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.tsx b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.tsx index b64a296bbf74a..f7c80705daa58 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.tsx +++ b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.tsx @@ -20,8 +20,9 @@ import { AnalyticsNoDataPage as Component } from './analytics_no_data_page.compo */ export const AnalyticsNoDataPage = ({ onDataViewCreated, - onESQLNavigationComplete, allowAdHocDataView, + onTryESQL, + onESQLNavigationComplete, }: AnalyticsNoDataPageProps) => { const { customBranding, ...services } = useServices(); const showPlainSpinner = useObservable(customBranding.hasCustomBranding$) ?? false; @@ -33,6 +34,7 @@ export const AnalyticsNoDataPage = ({ allowAdHocDataView={allowAdHocDataView} onDataViewCreated={onDataViewCreated} onESQLNavigationComplete={onESQLNavigationComplete} + onTryESQL={onTryESQL} /> ); }; diff --git a/packages/shared-ux/page/analytics_no_data/impl/tsconfig.json b/packages/shared-ux/page/analytics_no_data/impl/tsconfig.json index 659aacfd3874d..ba872e1ecd761 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/tsconfig.json +++ b/packages/shared-ux/page/analytics_no_data/impl/tsconfig.json @@ -23,6 +23,7 @@ "@kbn/i18n-react", "@kbn/core-http-browser", "@kbn/core-http-browser-mocks", + "@kbn/shared-ux-prompt-no-data-views", ], "exclude": [ "target/**/*", diff --git a/packages/shared-ux/page/analytics_no_data/mocks/src/storybook.ts b/packages/shared-ux/page/analytics_no_data/mocks/src/storybook.ts index c664bb192518c..f8cca693a072c 100644 --- a/packages/shared-ux/page/analytics_no_data/mocks/src/storybook.ts +++ b/packages/shared-ux/page/analytics_no_data/mocks/src/storybook.ts @@ -18,9 +18,14 @@ import type { } from '@kbn/shared-ux-page-analytics-no-data-types'; import { of } from 'rxjs'; +interface PropArguments { + useCustomOnTryESQL: boolean; +} + type ServiceArguments = Pick; -export type Params = ArgumentParams<{}, ServiceArguments> & KibanaNoDataPageStorybookParams; +export type Params = ArgumentParams & + KibanaNoDataPageStorybookParams; const kibanaNoDataMock = new KibanaNoDataPageStorybookMock(); @@ -30,7 +35,13 @@ export class StorybookMock extends AbstractStorybookMock< {}, ServiceArguments > { - propArguments = {}; + propArguments = { + // requires hasESData to be toggled to true + useCustomOnTryESQL: { + control: 'boolean', + defaultValue: false, + }, + }; serviceArguments = { kibanaGuideDocLink: { control: 'text', @@ -59,9 +70,10 @@ export class StorybookMock extends AbstractStorybookMock< }; } - getProps() { + getProps(params: Params) { return { onDataViewCreated: action('onDataViewCreated'), + onTryESQL: params.useCustomOnTryESQL ? action('onTryESQL-from-props') : undefined, }; } } diff --git a/packages/shared-ux/page/analytics_no_data/types/index.d.ts b/packages/shared-ux/page/analytics_no_data/types/index.d.ts index 9fd6653a48b6a..94bf85500da6b 100644 --- a/packages/shared-ux/page/analytics_no_data/types/index.d.ts +++ b/packages/shared-ux/page/analytics_no_data/types/index.d.ts @@ -70,6 +70,8 @@ export interface AnalyticsNoDataPageProps { onDataViewCreated: (dataView: unknown) => void; /** if set to true allows creation of an ad-hoc data view from data view editor */ allowAdHocDataView?: boolean; + /** If the cluster has data, this handler allows the user to try ES|QL */ + onTryESQL?: () => void; /** Handler for when try ES|QL is clicked and user has been navigated to try ES|QL in discover. */ onESQLNavigationComplete?: () => void; } diff --git a/packages/shared-ux/page/kibana_no_data/impl/src/kibana_no_data_page.tsx b/packages/shared-ux/page/kibana_no_data/impl/src/kibana_no_data_page.tsx index 2042d7fa1420d..d74c3aabd5662 100644 --- a/packages/shared-ux/page/kibana_no_data/impl/src/kibana_no_data_page.tsx +++ b/packages/shared-ux/page/kibana_no_data/impl/src/kibana_no_data_page.tsx @@ -20,9 +20,10 @@ import { useServices } from './services'; */ export const KibanaNoDataPage = ({ onDataViewCreated, - onESQLNavigationComplete, noDataConfig, allowAdHocDataView, + onTryESQL, + onESQLNavigationComplete, showPlainSpinner, }: KibanaNoDataPageProps) => { // These hooks are temporary, until this component is moved to a package. @@ -58,8 +59,9 @@ export const KibanaNoDataPage = ({ return ( ); } diff --git a/packages/shared-ux/page/kibana_no_data/types/index.d.ts b/packages/shared-ux/page/kibana_no_data/types/index.d.ts index 56067e9d555f9..c391149f7efaa 100644 --- a/packages/shared-ux/page/kibana_no_data/types/index.d.ts +++ b/packages/shared-ux/page/kibana_no_data/types/index.d.ts @@ -60,6 +60,8 @@ export interface KibanaNoDataPageProps { allowAdHocDataView?: boolean; /** Set to true if the kibana is customly branded */ showPlainSpinner: boolean; + /** If the cluster has data, this handler allows the user to try ES|QL */ + onTryESQL?: () => void; /** Handler for when try ES|QL is clicked and user has been navigated to try ES|QL in discover. */ onESQLNavigationComplete?: () => void; } diff --git a/packages/shared-ux/prompt/no_data_views/impl/src/actions.tsx b/packages/shared-ux/prompt/no_data_views/impl/src/actions.tsx deleted file mode 100644 index 6f2af97df6e04..0000000000000 --- a/packages/shared-ux/prompt/no_data_views/impl/src/actions.tsx +++ /dev/null @@ -1,76 +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 - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EuiButton, EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React from 'react'; - -interface NoDataButtonProps { - onClickCreate: (() => void) | undefined; - canCreateNewDataView: boolean; - onTryESQL?: () => void; - esqlDocLink?: string; -} - -const createDataViewText = i18n.translate('sharedUXPackages.noDataViewsPrompt.addDataViewText', { - defaultMessage: 'Create data view', -}); - -export const NoDataButtonLink = ({ - onClickCreate, - canCreateNewDataView, - onTryESQL, - esqlDocLink, -}: NoDataButtonProps) => { - if (!onTryESQL && !canCreateNewDataView) { - return null; - } - - return ( - <> - {canCreateNewDataView && ( - - {createDataViewText} - - )} - {canCreateNewDataView && onTryESQL && } - {onTryESQL && ( - - - - - ), - }} - /> - - - - - - )} - - ); -}; diff --git a/packages/shared-ux/prompt/no_data_views/impl/src/data_view_illustration.tsx b/packages/shared-ux/prompt/no_data_views/impl/src/data_view_illustration.tsx index cb817225254a9..099cdc87a21eb 100644 --- a/packages/shared-ux/prompt/no_data_views/impl/src/data_view_illustration.tsx +++ b/packages/shared-ux/prompt/no_data_views/impl/src/data_view_illustration.tsx @@ -26,5 +26,14 @@ export const DataViewIllustration = () => { } `; - return Data view illustration; + return ( + Data view illustration + ); }; diff --git a/packages/shared-ux/prompt/no_data_views/impl/src/documentation_link.tsx b/packages/shared-ux/prompt/no_data_views/impl/src/documentation_link.tsx index 8e74bead6922e..d190764af947d 100644 --- a/packages/shared-ux/prompt/no_data_views/impl/src/documentation_link.tsx +++ b/packages/shared-ux/prompt/no_data_views/impl/src/documentation_link.tsx @@ -13,9 +13,10 @@ import { FormattedMessage } from '@kbn/i18n-react'; interface Props { href: string; + ['data-test-subj']?: string; } -export function DocumentationLink({ href }: Props) { +export function DocumentationLink({ href, ['data-test-subj']: dataTestSubj }: Props) { return (
    @@ -28,7 +29,7 @@ export function DocumentationLink({ href }: Props) {
    - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/shared-ux/prompt/no_data_views/impl/src/esql_illustration.tsx b/packages/shared-ux/prompt/no_data_views/impl/src/esql_illustration.tsx new file mode 100644 index 0000000000000..a2da4c416ed55 --- /dev/null +++ b/packages/shared-ux/prompt/no_data_views/impl/src/esql_illustration.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React from 'react'; + +import png from './esql_illustration.svg'; + +export const EsqlIllustration = () => { + return ( + ES|QL illustration + ); +}; diff --git a/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.component.test.tsx b/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.component.test.tsx index ad2e176a511f0..75363c80b67b5 100644 --- a/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.component.test.tsx +++ b/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.component.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; +import { EuiButton, EuiCard } from '@elastic/eui'; import { NoDataViewsPrompt } from './no_data_views.component'; import { DocumentationLink } from './documentation_link'; @@ -19,36 +19,64 @@ describe('', () => { ); - expect(component.find(EuiEmptyPrompt).length).toBe(1); - expect(component.find(EuiButton).length).toBe(1); - expect(component.find(DocumentationLink).length).toBe(1); + expect(component.find(EuiCard).length).toBe(2); + expect(component.find(EuiButton).length).toBe(2); + expect(component.find(DocumentationLink).length).toBe(2); + + expect(component.find('EuiButton[data-test-subj="createDataViewButton"]').length).toBe(1); + expect(component.find('DocumentationLink[data-test-subj="docLinkDataViews"]').length).toBe(1); + + expect(component.find('EuiButton[data-test-subj="tryESQLLink"]').length).toBe(1); + expect(component.find('DocumentationLink[data-test-subj="docLinkEsql"]').length).toBe(1); }); - test('does not render button if canCreateNewDataViews is false', () => { + test('does not render "Create data view" button if canCreateNewDataViews is false', () => { const component = mountWithIntl(); - expect(component.find(EuiButton).length).toBe(0); + expect(component.find('EuiButton[data-test-subj="createDataViewButton"]').length).toBe(0); }); - test('does not documentation link if linkToDocumentation is not provided', () => { + test('does not render documentation links if links to documentation are not provided', () => { const component = mountWithIntl( ); - expect(component.find(DocumentationLink).length).toBe(0); + expect(component.find('DocumentationLink[data-test-subj="docLinkDataViews"]').length).toBe(0); + expect(component.find('DocumentationLink[data-test-subj="docLinkEsql"]').length).toBe(0); }); test('onClickCreate', () => { const onClickCreate = jest.fn(); const component = mountWithIntl( - + ); - component.find('button').simulate('click'); + component.find('button[data-test-subj="createDataViewButton"]').simulate('click'); expect(onClickCreate).toHaveBeenCalledTimes(1); }); + + test('onClickTryEsql', () => { + const onClickTryEsql = jest.fn(); + const component = mountWithIntl( + + ); + + component.find('button[data-test-subj="tryESQLLink"]').simulate('click'); + + expect(onClickTryEsql).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.component.tsx b/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.component.tsx index d5807891e734d..3bfed37aa0b1a 100644 --- a/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.component.tsx +++ b/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.component.tsx @@ -7,95 +7,222 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React from 'react'; import { css } from '@emotion/react'; +import React from 'react'; -import { EuiEmptyPrompt, EuiPanel } from '@elastic/eui'; +import { + EuiButton, + EuiCard, + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiSpacer, + EuiText, + EuiTextAlign, + EuiToolTip, + useEuiPaddingCSS, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { withSuspense } from '@kbn/shared-ux-utility'; import { NoDataViewsPromptComponentProps } from '@kbn/shared-ux-prompt-no-data-views-types'; import { DocumentationLink } from './documentation_link'; -import { NoDataButtonLink } from './actions'; +import { DataViewIllustration } from './data_view_illustration'; +import { EsqlIllustration } from './esql_illustration'; -// Using raw value because it is content dependent -const MAX_WIDTH = 830; +// max width value to use in pixels +const MAX_WIDTH = 770; -/** - * A presentational component that is shown in cases when there are no data views created yet. - */ -export const NoDataViewsPrompt = ({ +const PromptAddDataViews = ({ onClickCreate, canCreateNewDataView, dataViewsDocLink, + emptyPromptColor, +}: Pick< + NoDataViewsPromptComponentProps, + 'onClickCreate' | 'canCreateNewDataView' | 'dataViewsDocLink' | 'emptyPromptColor' +>) => { + const icon = ; + + const title = ( + + ); + + const description = ( + <> + {canCreateNewDataView ? ( + + ) : ( + + )} + + ); + + const footer = dataViewsDocLink ? ( + <> + {canCreateNewDataView ? ( + + + + ) : ( + + } + > + + + + + )} + + + + ) : undefined; + + return ( + + ); +}; + +const PromptTryEsql = ({ onTryESQL, esqlDocLink, - emptyPromptColor = 'plain', -}: NoDataViewsPromptComponentProps) => { - const title = canCreateNewDataView ? ( -

    - -
    - -

    - ) : ( -

    - -

    - ); + emptyPromptColor, +}: Pick< + NoDataViewsPromptComponentProps, + 'onClickCreate' | 'onTryESQL' | 'esqlDocLink' | 'emptyPromptColor' +>) => { + if (!onTryESQL) { + // we need to handle the case where the Try ES|QL click handler is not set because + // onTryESQL is set via a useEffect that has asynchronous dependencies + return null; + } + + const icon = ; - const body = canCreateNewDataView ? ( -

    - -

    - ) : ( -

    - -

    + const title = ( + ); - const footer = dataViewsDocLink ? : undefined; + const description = ( + + ); - // Load this illustration lazily - const Illustration = withSuspense( - React.lazy(() => - import('./data_view_illustration').then(({ DataViewIllustration }) => { - return { default: DataViewIllustration }; - }) - ), - + const footer = ( + <> + + + + + {esqlDocLink && } + ); - const icon = ; - const actions = ( - + return ( + ); +}; + +/** + * A presentational component that is shown in cases when there are no data views created yet. + */ +export const NoDataViewsPrompt = ({ + onClickCreate, + canCreateNewDataView, + dataViewsDocLink, + onTryESQL, + esqlDocLink, + emptyPromptColor = 'plain', +}: NoDataViewsPromptComponentProps) => { + const cssStyles = [ + css` + max-width: ${MAX_WIDTH}px; + `, + useEuiPaddingCSS('top').m, + useEuiPaddingCSS('right').m, + useEuiPaddingCSS('left').m, + ]; return ( - + > + + + +

    + +

    +
    +
    + + + + + + + + + + + +
    + ); }; diff --git a/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.tsx b/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.tsx index 43ae5f267ea90..340147505cb25 100644 --- a/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.tsx +++ b/packages/shared-ux/prompt/no_data_views/impl/src/no_data_views.tsx @@ -27,12 +27,15 @@ type CloseDataViewEditorFn = ReturnType { - const { canCreateNewDataView, openDataViewEditor, dataViewsDocLink, onTryESQL, esqlDocLink } = + const { canCreateNewDataView, openDataViewEditor, dataViewsDocLink, esqlDocLink, ...services } = useServices(); + const onTryESQL = onTryESQLProp ?? services.onTryESQL; + const closeDataViewEditor = useRef(); useEffect(() => { diff --git a/packages/shared-ux/prompt/no_data_views/impl/tsconfig.json b/packages/shared-ux/prompt/no_data_views/impl/tsconfig.json index 673823e620474..2af357080c07c 100644 --- a/packages/shared-ux/prompt/no_data_views/impl/tsconfig.json +++ b/packages/shared-ux/prompt/no_data_views/impl/tsconfig.json @@ -16,8 +16,6 @@ ], "kbn_references": [ "@kbn/i18n-react", - "@kbn/i18n", - "@kbn/shared-ux-utility", "@kbn/test-jest-helpers", "@kbn/shared-ux-prompt-no-data-views-types", "@kbn/shared-ux-prompt-no-data-views-mocks", diff --git a/packages/shared-ux/prompt/no_data_views/mocks/src/storybook.ts b/packages/shared-ux/prompt/no_data_views/mocks/src/storybook.ts index 63f46d2008077..973152201587d 100644 --- a/packages/shared-ux/prompt/no_data_views/mocks/src/storybook.ts +++ b/packages/shared-ux/prompt/no_data_views/mocks/src/storybook.ts @@ -34,17 +34,19 @@ export class StorybookMock extends AbstractStorybookMock< defaultValue: true, }, dataViewsDocLink: { - options: ['some/link', undefined], - control: { type: 'radio' }, - }, - esqlDocLink: { - options: ['some/link', undefined], + options: ['dataviews/link', undefined], control: { type: 'radio' }, + defaultValue: 'dataviews/link', }, canTryEsql: { control: 'boolean', defaultValue: true, }, + esqlDocLink: { + options: ['esql/link', undefined], + control: { type: 'radio' }, + defaultValue: 'esql/link', + }, }; dependencies = []; @@ -59,7 +61,7 @@ export class StorybookMock extends AbstractStorybookMock< let onTryESQL; if (canTryEsql !== false) { - onTryESQL = action('onTryESQL'); + onTryESQL = action('onTryESQL-from-services'); } return { diff --git a/packages/shared-ux/prompt/no_data_views/types/index.d.ts b/packages/shared-ux/prompt/no_data_views/types/index.d.ts index 15f9f53c59fe6..7bca285bee717 100644 --- a/packages/shared-ux/prompt/no_data_views/types/index.d.ts +++ b/packages/shared-ux/prompt/no_data_views/types/index.d.ts @@ -42,7 +42,7 @@ export interface NoDataViewsPromptServices { openDataViewEditor: (options: DataViewEditorOptions) => () => void; /** A link to information about Data Views in Kibana */ dataViewsDocLink: string; - /** Get a handler for trying ES|QL */ + /** If the cluster has data, this handler allows the user to try ES|QL */ onTryESQL: (() => void) | undefined; /** A link to the documentation for ES|QL */ esqlDocLink: string; @@ -92,7 +92,7 @@ export interface NoDataViewsPromptComponentProps { emptyPromptColor?: EuiEmptyPromptProps['color']; /** Click handler for create button. **/ onClickCreate?: () => void; - /** Handler for someone wanting to try ES|QL. */ + /** If the cluster has data, this handler allows the user to try ES|QL */ onTryESQL?: () => void; /** Link to documentation on ES|QL. */ esqlDocLink?: string; @@ -104,6 +104,10 @@ export interface NoDataViewsPromptProps { allowAdHocDataView?: boolean; /** Handler for successfully creating a new data view. */ onDataViewCreated: (dataView: unknown) => void; + /** If the cluster has data, this handler allows the user to try ES|QL */ + onTryESQL?: () => void; /** Handler for when try ES|QL is clicked and user has been navigated to try ES|QL in discover. */ onESQLNavigationComplete?: () => void; + /** Empty prompt color **/ + emptyPromptColor?: PanelColor; } diff --git a/src/plugins/data_view_management/kibana.jsonc b/src/plugins/data_view_management/kibana.jsonc index 479e357804140..5b827868ee1e8 100644 --- a/src/plugins/data_view_management/kibana.jsonc +++ b/src/plugins/data_view_management/kibana.jsonc @@ -20,6 +20,7 @@ ], "optionalPlugins": [ "noDataPage", + "share", "spaces" ], "requiredBundles": [ diff --git a/src/plugins/data_view_management/public/components/index_pattern_table/index_pattern_table.tsx b/src/plugins/data_view_management/public/components/index_pattern_table/index_pattern_table.tsx index cb93e01d1cc15..4512cb520c574 100644 --- a/src/plugins/data_view_management/public/components/index_pattern_table/index_pattern_table.tsx +++ b/src/plugins/data_view_management/public/components/index_pattern_table/index_pattern_table.tsx @@ -26,7 +26,7 @@ import { RouteComponentProps, useLocation, withRouter } from 'react-router-dom'; import useObservable from 'react-use/lib/useObservable'; import { reactRouterNavigate, useKibana } from '@kbn/kibana-react-plugin/public'; -import { NoDataViewsPromptComponent } from '@kbn/shared-ux-prompt-no-data-views'; +import { NoDataViewsPromptComponent, useOnTryESQL } from '@kbn/shared-ux-prompt-no-data-views'; import type { SpacesContextProps } from '@kbn/spaces-plugin/public'; import { DataViewType } from '@kbn/data-views-plugin/public'; import { RollupDeprecationTooltip } from '@kbn/rollup'; @@ -86,6 +86,7 @@ export const IndexPatternTable = ({ application, chrome, dataViews, + share, IndexPatternEditor, spaces, overlays, @@ -116,6 +117,12 @@ export const IndexPatternTable = ({ const hasDataView = useObservable(dataViewController.hasDataView$, defaults.hasDataView); const hasESData = useObservable(dataViewController.hasESData$, defaults.hasEsData); + const useOnTryESQLParams = { + locatorClient: share?.url.locators, + navigateToApp: application.navigateToApp, + }; + const onTryESQL = useOnTryESQL(useOnTryESQLParams); + const handleOnChange = ({ queryText, error }: { queryText: string; error: unknown }) => { if (!error) { setQuery(queryText); @@ -370,6 +377,8 @@ export const IndexPatternTable = ({ onClickCreate={() => setShowCreateDialog(true)} canCreateNewDataView={application.capabilities.indexPatterns.save as boolean} dataViewsDocLink={docLinks.links.indexPatterns.introduction} + onTryESQL={onTryESQL} + esqlDocLink={docLinks.links.query.queryESQL} emptyPromptColor={'subdued'} /> diff --git a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx index 995d5ed977ed3..96e5ae6c96b0c 100644 --- a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx @@ -17,6 +17,7 @@ import { StartServicesAccessor } from '@kbn/core/public'; import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { ManagementAppMountParams } from '@kbn/management-plugin/public'; +import { NoDataViewsPromptKibanaProvider } from '@kbn/shared-ux-prompt-no-data-views'; import { IndexPatternTableWithRouter, EditIndexPatternContainer, @@ -64,11 +65,13 @@ export async function mountManagementSection( dataViews, fieldFormats, unifiedSearch, + share, spaces, savedObjectsManagement, }, indexPatternManagementStart, ] = await getStartServices(); + const canSave = dataViews.getCanSaveSync(); if (!canSave) { @@ -89,6 +92,7 @@ export async function mountManagementSection( chrome, uiSettings, settings, + share, notifications, overlays, unifiedSearch, @@ -115,23 +119,29 @@ export async function mountManagementSection( ReactDOM.render( - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + , params.element diff --git a/src/plugins/data_view_management/public/plugin.ts b/src/plugins/data_view_management/public/plugin.ts index 77e8c12a13ad0..0d03dc8896fd1 100644 --- a/src/plugins/data_view_management/public/plugin.ts +++ b/src/plugins/data_view_management/public/plugin.ts @@ -21,6 +21,7 @@ import { ManagementSetup } from '@kbn/management-plugin/public'; import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; +import { SharePluginStart } from '@kbn/share-plugin/public'; export interface IndexPatternManagementSetupDependencies { management: ManagementSetup; @@ -34,6 +35,7 @@ export interface IndexPatternManagementStartDependencies { dataViewEditor: DataViewEditorStart; dataViews: DataViewsPublicPluginStart; fieldFormats: FieldFormatsStart; + share?: SharePluginStart; spaces?: SpacesPluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; savedObjectsManagement: SavedObjectsManagementPluginStart; diff --git a/src/plugins/data_view_management/public/types.ts b/src/plugins/data_view_management/public/types.ts index b7a9279de8001..161ee3b1e21de 100644 --- a/src/plugins/data_view_management/public/types.ts +++ b/src/plugins/data_view_management/public/types.ts @@ -29,6 +29,7 @@ import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import type { NoDataPagePluginSetup } from '@kbn/no-data-page-plugin/public'; +import { SharePluginStart } from '@kbn/share-plugin/public'; import type { IndexPatternManagementStart } from '.'; import type { DataViewMgmtService } from './management_app/data_view_management_service'; @@ -53,6 +54,7 @@ export interface IndexPatternManagmentContext extends StartServices { fieldFormatEditors: IndexPatternFieldEditorStart['fieldFormatEditors']; IndexPatternEditor: DataViewEditorStart['IndexPatternEditorComponent']; fieldFormats: FieldFormatsStart; + share?: SharePluginStart; spaces?: SpacesPluginStart; savedObjectsManagement: SavedObjectsManagementPluginStart; noDataPage?: NoDataPagePluginSetup; diff --git a/src/plugins/data_view_management/tsconfig.json b/src/plugins/data_view_management/tsconfig.json index ea0c96cc66b74..9857dd44829fa 100644 --- a/src/plugins/data_view_management/tsconfig.json +++ b/src/plugins/data_view_management/tsconfig.json @@ -45,6 +45,7 @@ "@kbn/code-editor", "@kbn/react-kibana-mount", "@kbn/rollup", + "@kbn/share-plugin", ], "exclude": [ "target/**/*", diff --git a/test/functional/apps/dashboard/group6/dashboard_esql_no_data.ts b/test/functional/apps/dashboard/group6/dashboard_esql_no_data.ts new file mode 100644 index 0000000000000..148cb95a82b11 --- /dev/null +++ b/test/functional/apps/dashboard/group6/dashboard_esql_no_data.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const testSubjects = getService('testSubjects'); + const esql = getService('esql'); + const PageObjects = getPageObjects(['discover', 'dashboard']); + + describe('No Data Views: Try ES|QL', () => { + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); + + it('enables user to create a dashboard with ES|QL from no-data-prompt', async () => { + await PageObjects.dashboard.navigateToApp(); + + await testSubjects.existOrFail('noDataViewsPrompt'); + await testSubjects.click('tryESQLLink'); + + await PageObjects.discover.expectOnDiscover(); + await esql.expectEsqlStatement('FROM logs* | LIMIT 10'); + }); + }); +} diff --git a/test/functional/apps/dashboard/group6/index.ts b/test/functional/apps/dashboard/group6/index.ts index 302ca2e0480a0..340c9b425571b 100644 --- a/test/functional/apps/dashboard/group6/index.ts +++ b/test/functional/apps/dashboard/group6/index.ts @@ -37,5 +37,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./dashboard_snapshots')); loadTestFile(require.resolve('./embeddable_library')); loadTestFile(require.resolve('./dashboard_esql_chart')); + loadTestFile(require.resolve('./dashboard_esql_no_data')); }); } diff --git a/test/functional/apps/management/data_views/_try_esql.ts b/test/functional/apps/management/data_views/_try_esql.ts new file mode 100644 index 0000000000000..276e61c4a721f --- /dev/null +++ b/test/functional/apps/management/data_views/_try_esql.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const testSubjects = getService('testSubjects'); + const esql = getService('esql'); + const PageObjects = getPageObjects(['settings', 'common', 'discover']); + + describe('No Data Views: Try ES|QL', () => { + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); + + it('navigates to Discover and presents an ES|QL query', async () => { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaIndexPatterns(); + + await testSubjects.existOrFail('noDataViewsPrompt'); + await testSubjects.click('tryESQLLink'); + + await PageObjects.discover.expectOnDiscover(); + await esql.expectEsqlStatement('FROM logs* | LIMIT 10'); + }); + }); +} diff --git a/test/functional/apps/management/index.ts b/test/functional/apps/management/index.ts index f3d26f2e1c6d7..2300543f06d51 100644 --- a/test/functional/apps/management/index.ts +++ b/test/functional/apps/management/index.ts @@ -38,6 +38,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./data_views/_legacy_url_redirect')); loadTestFile(require.resolve('./data_views/_exclude_index_pattern')); loadTestFile(require.resolve('./data_views/_index_pattern_filter')); + loadTestFile(require.resolve('./data_views/_try_esql')); loadTestFile(require.resolve('./data_views/_scripted_fields_filter')); loadTestFile(require.resolve('./_import_objects')); loadTestFile(require.resolve('./data_views/_test_huge_fields')); diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 1474e9d315538..ab6356075fd81 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -32,6 +32,12 @@ export class DiscoverPageObject extends FtrService { private readonly defaultFindTimeout = this.config.get('timeouts.find'); + /** Ensures that navigation to discover has completed */ + public async expectOnDiscover() { + await this.testSubjects.existOrFail('discoverNewButton'); + await this.testSubjects.existOrFail('discoverOpenButton'); + } + public async getChartTimespan() { return await this.testSubjects.getAttribute('unifiedHistogramChart', 'data-time-range'); } diff --git a/test/functional/services/esql.ts b/test/functional/services/esql.ts index 63836d2c5d2f5..c144c6e8993be 100644 --- a/test/functional/services/esql.ts +++ b/test/functional/services/esql.ts @@ -7,12 +7,19 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import expect from '@kbn/expect'; import { FtrService } from '../ftr_provider_context'; export class ESQLService extends FtrService { private readonly retry = this.ctx.getService('retry'); private readonly testSubjects = this.ctx.getService('testSubjects'); + /** Ensures that the ES|QL code editor is loaded with a given statement */ + public async expectEsqlStatement(statement: string) { + const codeEditor = await this.testSubjects.find('ESQLEditor'); + expect(await codeEditor.getAttribute('innerText')).to.contain(statement); + } + public async getHistoryItems(): Promise { const queryHistory = await this.testSubjects.find('ESQLEditor-queryHistory'); const tableBody = await this.retry.try(async () => queryHistory.findByTagName('tbody')); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index c441b91d23e31..9aa58bd4f5286 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -7268,9 +7268,6 @@ "sharedUXPackages.fileUpload.uploadCompleteButtonLabel": "Chargement terminé", "sharedUXPackages.fileUpload.uploadDoneToolTipContent": "Votre fichier a bien été chargé !", "sharedUXPackages.fileUpload.uploadingButtonLabel": "Chargement", - "sharedUXPackages.no_data_views.esqlButtonLabel": "Langue : ES|QL", - "sharedUXPackages.no_data_views.esqlDocsLink": "En savoir plus.", - "sharedUXPackages.no_data_views.esqlMessage": "Vous pouvez aussi rechercher vos données en utilisant directement ES|QL. {docsLink}", "sharedUXPackages.noDataConfig.addIntegrationsDescription": "Utilisez Elastic Agent pour collecter des données et créer des solutions Analytics.", "sharedUXPackages.noDataConfig.addIntegrationsTitle": "Ajouter des intégrations", "sharedUXPackages.noDataConfig.analytics": "Analyse", @@ -7292,8 +7289,6 @@ "sharedUXPackages.noDataViewsPrompt.dataViewExplanation": "Les vues de données identifient les données Elasticsearch que vous souhaitez explorer. Vous pouvez faire pointer des vues de données vers un ou plusieurs flux de données, index et alias d'index, tels que vos données de log d'hier, ou vers tous les index contenant vos données de log.", "sharedUXPackages.noDataViewsPrompt.learnMore": "Envie d'en savoir plus ?", "sharedUXPackages.noDataViewsPrompt.noPermission.dataViewExplanation": "Les vues de données identifient les données Elasticsearch que vous souhaitez explorer. Pour créer des vues de données, demandez les autorisations requises à votre administrateur.", - "sharedUXPackages.noDataViewsPrompt.noPermission.title": "Vous devez disposer d'une autorisation pour pouvoir créer des vues de données", - "sharedUXPackages.noDataViewsPrompt.nowCreate": "Créez à présent une vue de données.", "sharedUXPackages.noDataViewsPrompt.readDocumentation": "Lisez les documents", "sharedUXPackages.noDataViewsPrompt.youHaveData": "Vous avez des données dans Elasticsearch.", "sharedUXPackages.prompt.errors.notFound.body": "Désolé, la page que vous recherchez est introuvable. Elle a peut-être été retirée ou renommée, ou peut-être qu'elle n'a jamais existé.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 93e7ab2270f4c..72afb1947e928 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7022,9 +7022,6 @@ "sharedUXPackages.fileUpload.uploadCompleteButtonLabel": "アップロード完了", "sharedUXPackages.fileUpload.uploadDoneToolTipContent": "ファイルは正常にアップロードされました。", "sharedUXPackages.fileUpload.uploadingButtonLabel": "アップロード中", - "sharedUXPackages.no_data_views.esqlButtonLabel": "言語:ES|QL", - "sharedUXPackages.no_data_views.esqlDocsLink": "詳細情報", - "sharedUXPackages.no_data_views.esqlMessage": "あるいは、直接ES|QLを使用してデータをクエリできます。{docsLink}", "sharedUXPackages.noDataConfig.addIntegrationsDescription": "Elasticエージェントを使用して、データを収集し、分析ソリューションを構築します。", "sharedUXPackages.noDataConfig.addIntegrationsTitle": "統合の追加", "sharedUXPackages.noDataConfig.analytics": "分析", @@ -7046,8 +7043,6 @@ "sharedUXPackages.noDataViewsPrompt.dataViewExplanation": "データビューは、探索するElasticsearchデータを特定します。昨日からのログデータ、ログデータを含むすべてのインデックスなど、1つ以上のデータストリーム、インデックス、インデックスエイリアスをデータビューで参照できます。", "sharedUXPackages.noDataViewsPrompt.learnMore": "詳細について", "sharedUXPackages.noDataViewsPrompt.noPermission.dataViewExplanation": "データビューは、探索するElasticsearchデータを特定します。データビューを作成するには、必要な権限を管理者に依頼してください。", - "sharedUXPackages.noDataViewsPrompt.noPermission.title": "データビューを作成するための権限が必要です。", - "sharedUXPackages.noDataViewsPrompt.nowCreate": "ここでデータビューを作成します。", "sharedUXPackages.noDataViewsPrompt.readDocumentation": "ドキュメントを読む", "sharedUXPackages.noDataViewsPrompt.youHaveData": "Elasticsearchにデータがあります。", "sharedUXPackages.prompt.errors.notFound.body": "申し訳ございません。お探しのページは見つかりませんでした。削除または名前変更されたか、そもそも存在していなかった可能性があります。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 6f81b20c89d2b..c27a5241e5a33 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7037,9 +7037,6 @@ "sharedUXPackages.fileUpload.uploadCompleteButtonLabel": "上传完成", "sharedUXPackages.fileUpload.uploadDoneToolTipContent": "您的文件已成功上传!", "sharedUXPackages.fileUpload.uploadingButtonLabel": "正在上传", - "sharedUXPackages.no_data_views.esqlButtonLabel": "语言:ES|QL", - "sharedUXPackages.no_data_views.esqlDocsLink": "了解详情。", - "sharedUXPackages.no_data_views.esqlMessage": "或者,您可以直接使用 ES|QL 查询数据。{docsLink}", "sharedUXPackages.noDataConfig.addIntegrationsDescription": "使用 Elastic 代理收集数据并增建分析解决方案。", "sharedUXPackages.noDataConfig.addIntegrationsTitle": "添加集成", "sharedUXPackages.noDataConfig.analytics": "分析", @@ -7061,8 +7058,6 @@ "sharedUXPackages.noDataViewsPrompt.dataViewExplanation": "数据视图标识您要浏览的 Elasticsearch 数据。您可以将数据视图指向一个或多个数据流、索引和索引别名(例如昨天的日志数据),或包含日志数据的所有索引。", "sharedUXPackages.noDataViewsPrompt.learnMore": "希望了解详情?", "sharedUXPackages.noDataViewsPrompt.noPermission.dataViewExplanation": "数据视图标识您要浏览的 Elasticsearch 数据。要创建数据视图,请联系管理员获得所需权限。", - "sharedUXPackages.noDataViewsPrompt.noPermission.title": "您需要权限以创建数据视图", - "sharedUXPackages.noDataViewsPrompt.nowCreate": "现在,创建数据视图。", "sharedUXPackages.noDataViewsPrompt.readDocumentation": "阅读文档", "sharedUXPackages.noDataViewsPrompt.youHaveData": "您在 Elasticsearch 中有数据。", "sharedUXPackages.prompt.errors.notFound.body": "抱歉,找不到您要查找的页面。该页面可能已移除、重命名,或可能根本不存在。", diff --git a/x-pack/test/functional/apps/data_views/feature_controls/security.ts b/x-pack/test/functional/apps/data_views/feature_controls/security.ts index 1cc62baf0abba..34317932a6b21 100644 --- a/x-pack/test/functional/apps/data_views/feature_controls/security.ts +++ b/x-pack/test/functional/apps/data_views/feature_controls/security.ts @@ -131,10 +131,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(navLinks).to.eql(['Stack Management']); }); - it(`index pattern listing doesn't show create button`, async () => { + it(`index pattern listing shows disabled create button`, async () => { await settings.clickKibanaIndexPatterns(); await testSubjects.existOrFail('noDataViewsPrompt'); - await testSubjects.missingOrFail('createDataViewButton'); + const createDataViewButton = await testSubjects.find('createDataViewButton'); + const isDisabled = await createDataViewButton.getAttribute('disabled'); + expect(isDisabled).to.be('true'); }); it(`shows read-only badge`, async () => { From 57096d1f4fbcb4fc0135505b6c6100566ff08cc9 Mon Sep 17 00:00:00 2001 From: Patrick Mueller Date: Wed, 9 Oct 2024 17:52:09 -0400 Subject: [PATCH 095/110] [ResponseOps] add pre-create, pre-update, and post-delete hooks for connectors (#194081) Allows connector types to add functions to be called when connectors are created, updated, and deleted. Extracted from https://github.com/elastic/kibana/pull/189027, commit c97afebbe1462eb3eb2b0fb89d0ce9126ff118db Co-authored-by: Yuliia Naumenko --- x-pack/plugins/actions/README.md | 72 +++- .../actions_client/actions_client.test.ts | 49 +++ .../server/actions_client/actions_client.ts | 110 ++++- .../actions_client_hooks.test.ts | 385 ++++++++++++++++++ .../connector/methods/update/update.ts | 98 ++++- x-pack/plugins/actions/server/lib/index.ts | 1 + .../plugins/actions/server/lib/try_catch.ts | 17 + .../sub_action_framework/register.test.ts | 13 +- .../server/sub_action_framework/register.ts | 3 + .../server/sub_action_framework/types.ts | 33 ++ x-pack/plugins/actions/server/types.ts | 46 +++ .../alerting_api_integration/common/config.ts | 1 + .../plugins/alerts/server/action_types.ts | 91 +++++ .../group2/tests/actions/create.ts | 81 +++- .../group2/tests/actions/delete.ts | 85 +++- .../group2/tests/actions/update.ts | 103 ++++- 16 files changed, 1151 insertions(+), 37 deletions(-) create mode 100644 x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts create mode 100644 x-pack/plugins/actions/server/lib/try_catch.ts diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index 7cab1ffe0c0b3..4e7f20e47cb7d 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -89,13 +89,16 @@ The following table describes the properties of the `options` object. | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | | id | Unique identifier for the action type. For convention, ids starting with `.` are reserved for built in action types. We recommend using a convention like `.mySpecialAction` for your action types. | string | | name | A user-friendly name for the action type. These will be displayed in dropdowns when chosing action types. | string | -| maxAttempts | The maximum number of times this action will attempt to run when scheduled. | number | +| maxAttempts | The maximum number of times this action will attempt to run when scheduled. | number | | minimumLicenseRequired | The license required to use the action type. | string | | supportedFeatureIds | List of IDs of the features that this action type is available in. Allowed values are `alerting`, `siem`, `uptime`, `cases`. See `x-pack/plugins/actions/common/connector_feature_config.ts` for the most up to date list. | string[] | | validate.params | When developing an action type, it needs to accept parameters to know what to do with the action. (Example `to`, `from`, `subject`, `body` of an email). See the current built-in email action type for an example of the state-of-the-art validation.

    Technically, the value of this property should have a property named `validate()` which is a function that takes a params object to validate and returns a sanitized version of that object to pass to the execution function. Validation errors should be thrown from the `validate()` function and will be available as an error message | schema / validation function | | validate.config | Similar to params, a config may be required when creating an action (for example `host` and `port` for an email server). | schema / validation function | | validate.secrets | Similar to params, a secrets object may be required when creating an action (for example `user` and `password` for an email server). | schema / validation function | -| executor | This is where the code of an action type lives. This is a function gets called for generating an action from either alerting or manually by using the exposed function (see firing actions). For full details, see executor section below. | Function | +| executor | This is where the code of an action type lives. This is a function gets called for generating an action from either alerting or manually by using the exposed function (see firing actions). For full details, see executor section below. | Function | +| preSaveHook | This optional function is called before the connector saved object is saved. For full details, see hooks section below. | Function | +| postSaveHook | This optional function is called after the connector saved object is saved. For full details, see hooks section below. | Function | +| postDeleteHook | This optional function is called after the connector saved object is deleted. For full details, see hooks section below. | Function | | renderParameterTemplates | Optionally define a function to provide custom rendering for this action type. | Function | **Important** - The config object is persisted in ElasticSearch and updated via the ElasticSearch update document API. This API allows "partial updates" - and this can cause issues with the encryption used on specified properties. So, a `validate()` function should return values for all configuration properties, so that partial updates do not occur. Setting property values to `null` rather than `undefined`, or not including a property in the config object, is all you need to do to ensure partial updates won't occur. @@ -116,6 +119,71 @@ This is the primary function for an action type. Whenever the action needs to ru | services.savedObjectsClient | This is an instance of the saved objects client. This provides the ability to do CRUD on any saved objects within the same space the alert lives in.

    The scope of the saved objects client is tied to the user in context calling the execute API or the API key provided to the execute plugin function (only when security isenabled). | | services.log(tags, [data], [timestamp]) | Use this to create server logs. (This is the same function as server.log) | +### Hooks + +Hooks allow a connector implementation to be called during connector creation, update, and delete. When not using hooks, the connector implementation is not involved in creation, update and delete, except for the schema validation that happens for creation and update. Hooks can be used to force a create or update to fail, or run arbitrary code before and after update and create, and after delete. We don't have a need for a hook before delete at the moment, so that hook is currently not available. + +Hooks are passed the following parameters: + +```ts +interface PreSaveConnectorHookParams { + connectorId: string; + config: Config; + secrets: Secrets; + logger: Logger; + request: KibanaRequest; + services: HookServices; + isUpdate: boolean; +} + +interface PostSaveConnectorHookParams { + connectorId: string; + config: Config; + secrets: Secrets; + logger: Logger; + request: KibanaRequest; + services: HookServices; + isUpdate: boolean; + wasSuccessful: boolean; +} + +interface PostDeleteConnectorHookParams { + connectorId: string; + config: Config; + // secrets not provided, yet + logger: Logger; + request: KibanaRequest; + services: HookServices; +} +``` + +| parameter | description +| --------- | ----------- +| `connectorId` | The id of the connector. +| `config` | The connector's `config` object. +| `secrets` | The connector's `secrets` object. +| `logger` | A standard Kibana logger. +| `request` | The request causing this operation +| `services` | Common service objects, see below. +| `isUpdate` | For the `PreSave` and `PostSave` hooks, `isUpdate` is false for create operations, and true for update operations. +| `wasSuccessful` | For the `PostSave` hook, this indicates if the connector was persisted as a Saved Object successfully. + +The `services` object contains the following properties: + +| property | description +| --------- | ----------- +| `scopedClusterClient` | A standard `scopeClusterClient` object. + +The hooks are called just before, and just after, the Saved Object operation for the client methods is invoked. + +The `PostDelete` hook does not have a `wasSuccessful` property, as the hook is not called if the delete operation fails. The saved object will still exist. Only a successful call to delete the connector will cause the hook to run. + +The `PostSave` hook is useful if the `PreSave` hook is creating / modifying other resources. The `PreSave` hook is called just before the connector SO is actually created/updated, and of course that create/update could fail for some reason. In those cases, the `PostSave` hook is passed `wasSuccessful: false` and can "undo" any work it did in the `PreSave` hook. + +The `PreSave` hook can be used to cancel a create or update, by throwing an exception. The `PostSave` and `PostDelete` invocations will have thrown exceptions caught and logged to the Kibana log, and will not cancel the operation. + +When throwing an error in the `PreSave` hook, the Error's message will be used as the error failing the operation, so should include a human-readable description of what it was doing, along with any message from an underlying API that failed, if available. When an error is thrown from a `PreSave` hook, the `PostSave` hook will **NOT** be run. + ### Example The built-in email action type provides a good example of creating an action type with non-trivial configuration and params: diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts index 46e73f7bb3591..7f15dd6287d6b 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts @@ -113,6 +113,9 @@ const mockTaskManager = taskManagerMock.createSetup(); const configurationUtilities = actionsConfigMock.create(); const eventLogClient = eventLogClientMock.create(); const getEventLogClient = jest.fn(); +const preSaveHook = jest.fn(); +const postSaveHook = jest.fn(); +const postDeleteHook = jest.fn(); let actionsClient: ActionsClient; let mockedLicenseState: jest.Mocked; @@ -392,6 +395,8 @@ describe('create()', () => { params: { schema: schema.object({}) }, }, executor, + preSaveHook, + postSaveHook, }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce(savedObjectCreateResult); const result = await actionsClient.create({ @@ -428,6 +433,8 @@ describe('create()', () => { }, ] `); + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(postSaveHook).toHaveBeenCalledTimes(1); }); test('validates config', async () => { @@ -1973,6 +1980,33 @@ describe('getOAuthAccessToken()', () => { }); describe('delete()', () => { + beforeEach(() => { + actionTypeRegistry.register({ + id: 'my-action-delete', + name: 'My action type', + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + validate: { + config: { schema: schema.object({}) }, + secrets: { schema: schema.object({}) }, + params: { schema: schema.object({}) }, + }, + executor, + postDeleteHook: async (options) => postDeleteHook(options), + }); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ + id: '1', + type: 'action', + attributes: { + actionTypeId: 'my-action-delete', + isMissingSecrets: false, + config: {}, + secrets: {}, + }, + references: [], + }); + }); + describe('authorization', () => { test('ensures user is authorised to delete actions', async () => { await actionsClient.delete({ id: '1' }); @@ -2052,6 +2086,16 @@ describe('delete()', () => { `); }); + test('calls postDeleteHook', async () => { + const expectedResult = Symbol(); + unsecuredSavedObjectsClient.delete.mockResolvedValueOnce(expectedResult); + + const result = await actionsClient.delete({ id: '1' }); + expect(result).toEqual(expectedResult); + expect(unsecuredSavedObjectsClient.delete).toHaveBeenCalledTimes(1); + expect(postDeleteHook).toHaveBeenCalledTimes(1); + }); + it('throws when trying to delete a preconfigured connector', async () => { actionsClient = new ActionsClient({ logger, @@ -2250,6 +2294,8 @@ describe('update()', () => { params: { schema: schema.object({}) }, }, executor, + preSaveHook, + postSaveHook, }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', @@ -2315,6 +2361,9 @@ describe('update()', () => { "my-action", ] `); + + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(postSaveHook).toHaveBeenCalledTimes(1); }); test('updates an action with isMissingSecrets "true" (set true as the import result), to isMissingSecrets', async () => { diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.ts b/x-pack/plugins/actions/server/actions_client/actions_client.ts index 7e4d72faedaed..f485d82b2f120 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.ts @@ -43,6 +43,7 @@ import { validateConnector, ActionExecutionSource, parseDate, + tryCatch, } from '../lib'; import { ActionResult, @@ -50,6 +51,7 @@ import { InMemoryConnector, ActionTypeExecutorResult, ConnectorTokenClientContract, + HookServices, } from '../types'; import { PreconfiguredActionDisabledModificationError } from '../lib/errors/preconfigured_action_disabled_modification'; import { ExecuteOptions } from '../lib/action_executor'; @@ -246,6 +248,33 @@ export class ActionsClient { } this.context.actionTypeRegistry.ensureActionTypeEnabled(actionTypeId); + const hookServices: HookServices = { + scopedClusterClient: this.context.scopedClusterClient, + }; + + if (actionType.preSaveHook) { + try { + await actionType.preSaveHook({ + connectorId: id, + config, + secrets, + logger: this.context.logger, + request: this.context.request, + services: hookServices, + isUpdate: false, + }); + } catch (error) { + this.context.auditLogger?.log( + connectorAuditEvent({ + action: ConnectorAuditAction.CREATE, + savedObject: { type: 'action', id }, + error, + }) + ); + throw error; + } + } + this.context.auditLogger?.log( connectorAuditEvent({ action: ConnectorAuditAction.CREATE, @@ -254,18 +283,48 @@ export class ActionsClient { }) ); - const result = await this.context.unsecuredSavedObjectsClient.create( - 'action', - { - actionTypeId, - name, - isMissingSecrets: false, - config: validatedActionTypeConfig as SavedObjectAttributes, - secrets: validatedActionTypeSecrets as SavedObjectAttributes, - }, - { id } + const result = await tryCatch( + async () => + await this.context.unsecuredSavedObjectsClient.create( + 'action', + { + actionTypeId, + name, + isMissingSecrets: false, + config: validatedActionTypeConfig as SavedObjectAttributes, + secrets: validatedActionTypeSecrets as SavedObjectAttributes, + }, + { id } + ) ); + const wasSuccessful = !(result instanceof Error); + const label = `connectorId: "${id}"; type: ${actionTypeId}`; + const tags = ['post-save-hook', id]; + + if (actionType.postSaveHook) { + try { + await actionType.postSaveHook({ + connectorId: id, + config, + secrets, + logger: this.context.logger, + request: this.context.request, + services: hookServices, + isUpdate: false, + wasSuccessful, + }); + } catch (err) { + this.context.logger.error(`postSaveHook create error for ${label}: ${err.message}`, { + tags, + }); + } + } + + if (!wasSuccessful) { + throw result; + } + return { id: result.id, actionTypeId: result.attributes.actionTypeId, @@ -558,7 +617,36 @@ export class ActionsClient { ); } - return await this.context.unsecuredSavedObjectsClient.delete('action', id); + const rawAction = await this.context.unsecuredSavedObjectsClient.get('action', id); + const { + attributes: { actionTypeId, config }, + } = rawAction; + + const actionType = this.context.actionTypeRegistry.get(actionTypeId); + const result = await this.context.unsecuredSavedObjectsClient.delete('action', id); + + const hookServices: HookServices = { + scopedClusterClient: this.context.scopedClusterClient, + }; + + if (actionType.postDeleteHook) { + try { + await actionType.postDeleteHook({ + connectorId: id, + config, + logger: this.context.logger, + request: this.context.request, + services: hookServices, + }); + } catch (error) { + const tags = ['post-delete-hook', id]; + this.context.logger.error( + `The post delete hook failed for for connector "${id}": ${error.message}`, + { tags } + ); + } + } + return result; } private getSystemActionKibanaPrivileges(connectorId: string, params?: ExecuteOptions['params']) { diff --git a/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts b/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts new file mode 100644 index 0000000000000..7a1a0fb5e3d91 --- /dev/null +++ b/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts @@ -0,0 +1,385 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { omit } from 'lodash'; +import { schema } from '@kbn/config-schema'; +import { MockedLogger, loggerMock } from '@kbn/logging-mocks'; +import { ActionTypeRegistry, ActionTypeRegistryOpts } from '../action_type_registry'; +import { ActionsClient } from './actions_client'; +import { ExecutorType } from '../types'; +import { ActionExecutor, TaskRunnerFactory, ILicenseState } from '../lib'; +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { actionsConfigMock } from '../actions_config.mock'; +import { licenseStateMock } from '../lib/license_state.mock'; +import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; +import { + httpServerMock, + elasticsearchServiceMock, + savedObjectsClientMock, +} from '@kbn/core/server/mocks'; +import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; +import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; +import { actionExecutorMock } from '../lib/action_executor.mock'; +import { ActionsAuthorization } from '../authorization/actions_authorization'; +import { actionsAuthorizationMock } from '../authorization/actions_authorization.mock'; +import { connectorTokenClientMock } from '../lib/connector_token_client.mock'; +import { inMemoryMetricsMock } from '../monitoring/in_memory_metrics.mock'; + +jest.mock('uuid', () => ({ + v4: () => ConnectorSavedObject.id, +})); + +const kibanaIndices = ['.kibana']; +const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); +const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); +const actionExecutor = actionExecutorMock.create(); +const authorization = actionsAuthorizationMock.create(); +const ephemeralExecutionEnqueuer = jest.fn(); +const bulkExecutionEnqueuer = jest.fn(); +const request = httpServerMock.createKibanaRequest(); +const auditLogger = auditLoggerMock.create(); +const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); +const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); +const mockTaskManager = taskManagerMock.createSetup(); +const getEventLogClient = jest.fn(); +const preSaveHook = jest.fn(); +const postSaveHook = jest.fn(); +const postDeleteHook = jest.fn(); + +let actionsClient: ActionsClient; +let mockedLicenseState: jest.Mocked; +let actionTypeRegistry: ActionTypeRegistry; +let actionTypeRegistryParams: ActionTypeRegistryOpts; +const executor: ExecutorType<{}, {}, {}, void> = async (options) => { + return { status: 'ok', actionId: options.actionId }; +}; + +const ConnectorSavedObject = { + id: 'connector-id-uuid', + type: 'action', + attributes: { + actionTypeId: 'hooked-action-type', + isMissingSecrets: false, + name: 'Hooked Action', + config: { foo: 42 }, + secrets: { bar: 2001 }, + }, + references: [], +}; + +const CreateParms = { + action: { + name: ConnectorSavedObject.attributes.name, + actionTypeId: ConnectorSavedObject.attributes.actionTypeId, + config: ConnectorSavedObject.attributes.config, + secrets: ConnectorSavedObject.attributes.secrets, + }, +}; + +const UpdateParms = { + id: ConnectorSavedObject.id, + action: { + name: ConnectorSavedObject.attributes.name, + config: ConnectorSavedObject.attributes.config, + secrets: ConnectorSavedObject.attributes.secrets, + }, +}; + +const CoreHookParams = { + connectorId: ConnectorSavedObject.id, + config: ConnectorSavedObject.attributes.config, + secrets: ConnectorSavedObject.attributes.secrets, + request, + services: { + // this will be checked with a function test + scopedClusterClient: expect.any(Object), + }, +}; + +const connectorTokenClient = connectorTokenClientMock.create(); +const inMemoryMetrics = inMemoryMetricsMock.create(); + +let logger: MockedLogger; + +beforeEach(() => { + jest.resetAllMocks(); + logger = loggerMock.create(); + mockedLicenseState = licenseStateMock.create(); + + actionTypeRegistryParams = { + licensing: licensingMock.createSetup(), + taskManager: mockTaskManager, + taskRunnerFactory: new TaskRunnerFactory( + new ActionExecutor({ isESOCanEncrypt: true }), + inMemoryMetrics + ), + actionsConfigUtils: actionsConfigMock.create(), + licenseState: mockedLicenseState, + inMemoryConnectors: [], + }; + + actionTypeRegistry = new ActionTypeRegistry(actionTypeRegistryParams); + actionsClient = new ActionsClient({ + logger, + actionTypeRegistry, + unsecuredSavedObjectsClient, + scopedClusterClient, + kibanaIndices, + inMemoryConnectors: [], + actionExecutor, + ephemeralExecutionEnqueuer, + bulkExecutionEnqueuer, + request, + authorization: authorization as unknown as ActionsAuthorization, + auditLogger, + usageCounter: mockUsageCounter, + connectorTokenClient, + getEventLogClient, + }); + + actionTypeRegistry.register({ + id: 'hooked-action-type', + name: 'Hooked action type', + minimumLicenseRequired: 'gold', + supportedFeatureIds: ['alerting'], + validate: { + config: { schema: schema.object({ foo: schema.number() }) }, + secrets: { schema: schema.object({ bar: schema.number() }) }, + params: { schema: schema.object({}) }, + }, + executor, + preSaveHook, + postSaveHook, + postDeleteHook, + }); +}); + +describe('connector type hooks', () => { + describe('successful operation and successful hook', () => { + test('for create', async () => { + unsecuredSavedObjectsClient.create.mockResolvedValueOnce(ConnectorSavedObject); + const result = await actionsClient.create(CreateParms); + expect(result.id).toBe(ConnectorSavedObject.id); + + const preParams = { ...CoreHookParams, logger, isUpdate: false }; + const postParams = { ...preParams, wasSuccessful: true }; + + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(preSaveHook.mock.calls[0]).toStrictEqual([preParams]); + + expect(postSaveHook).toHaveBeenCalledTimes(1); + expect(postSaveHook.mock.calls[0]).toStrictEqual([postParams]); + }); + + test('for update', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(ConnectorSavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValueOnce(ConnectorSavedObject); + const result = await actionsClient.update(UpdateParms); + expect(result.id).toBe(ConnectorSavedObject.id); + + const preParams = { ...CoreHookParams, logger, isUpdate: true }; + const postParams = { ...preParams, wasSuccessful: true }; + + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(preSaveHook.mock.calls[0]).toStrictEqual([preParams]); + + expect(postSaveHook).toHaveBeenCalledTimes(1); + expect(postSaveHook.mock.calls[0]).toStrictEqual([postParams]); + }); + + test('for delete', async () => { + const expectedResult = Symbol(); + unsecuredSavedObjectsClient.delete.mockResolvedValueOnce(expectedResult); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(ConnectorSavedObject); + + const result = await actionsClient.delete({ id: ConnectorSavedObject.id }); + expect(result).toBe(expectedResult); + + const postParamsWithSecrets = { ...CoreHookParams, logger }; + const postParams = omit(postParamsWithSecrets, 'secrets'); + + expect(postDeleteHook).toHaveBeenCalledTimes(1); + expect(postDeleteHook.mock.calls[0]).toEqual([postParams]); + }); + }); + + describe('unsuccessful operation and successful hook', () => { + test('for create', async () => { + unsecuredSavedObjectsClient.create.mockRejectedValueOnce(new Error('OMG create')); + await expect(actionsClient.create(CreateParms)).rejects.toMatchInlineSnapshot( + `[Error: OMG create]` + ); + + const preParams = { ...CoreHookParams, logger, isUpdate: false }; + const postParams = { ...preParams, wasSuccessful: false }; + + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(preSaveHook.mock.calls[0]).toStrictEqual([preParams]); + + expect(postSaveHook).toHaveBeenCalledTimes(1); + expect(postSaveHook.mock.calls[0]).toStrictEqual([postParams]); + }); + + test('for update', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(ConnectorSavedObject); + unsecuredSavedObjectsClient.create.mockRejectedValueOnce(new Error('OMG update')); + await expect(actionsClient.update(UpdateParms)).rejects.toMatchInlineSnapshot( + `[Error: OMG update]` + ); + + const preParams = { ...CoreHookParams, logger, isUpdate: true }; + const postParams = { ...preParams, wasSuccessful: false }; + + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(preSaveHook.mock.calls[0]).toStrictEqual([preParams]); + + expect(postSaveHook).toHaveBeenCalledTimes(1); + expect(postSaveHook.mock.calls[0]).toStrictEqual([postParams]); + }); + + test('for delete', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(ConnectorSavedObject); + unsecuredSavedObjectsClient.delete.mockRejectedValueOnce(new Error('OMG delete')); + + await expect( + actionsClient.delete({ id: ConnectorSavedObject.id }) + ).rejects.toMatchInlineSnapshot(`[Error: OMG delete]`); + + expect(postDeleteHook).toHaveBeenCalledTimes(0); + }); + }); + + describe('successful operation and unsuccessful hook', () => { + test('for create pre hook', async () => { + preSaveHook.mockRejectedValueOnce(new Error('OMG create pre save')); + + await expect(actionsClient.create(CreateParms)).rejects.toMatchInlineSnapshot( + `[Error: OMG create pre save]` + ); + + const preParams = { ...CoreHookParams, logger, isUpdate: false }; + + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(preSaveHook.mock.calls[0]).toStrictEqual([preParams]); + + expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledTimes(0); + expect(postSaveHook).toHaveBeenCalledTimes(0); + }); + + test('for create post hook', async () => { + postSaveHook.mockRejectedValueOnce(new Error('OMG create post save')); + + unsecuredSavedObjectsClient.create.mockResolvedValueOnce(ConnectorSavedObject); + const result = await actionsClient.create(CreateParms); + expect(result.id).toBe(ConnectorSavedObject.id); + + const preParams = { ...CoreHookParams, logger, isUpdate: false }; + const postParams = { ...preParams, wasSuccessful: true }; + + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(preSaveHook.mock.calls[0]).toStrictEqual([preParams]); + + expect(postSaveHook).toHaveBeenCalledTimes(1); + expect(postSaveHook.mock.calls[0]).toStrictEqual([postParams]); + expect(logger.error).toHaveBeenCalledTimes(1); + expect(logger.error.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "postSaveHook create error for connectorId: \\"connector-id-uuid\\"; type: hooked-action-type: OMG create post save", + Object { + "tags": Array [ + "post-save-hook", + "connector-id-uuid", + ], + }, + ], + ] + `); + }); + + test('for update pre hook', async () => { + preSaveHook.mockRejectedValueOnce(new Error('OMG update pre save')); + + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(ConnectorSavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValueOnce(ConnectorSavedObject); + await expect(actionsClient.update(UpdateParms)).rejects.toMatchInlineSnapshot( + `[Error: OMG update pre save]` + ); + + const preParams = { ...CoreHookParams, logger, isUpdate: true }; + + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(preSaveHook.mock.calls[0]).toStrictEqual([preParams]); + + expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledTimes(0); + expect(postSaveHook).toHaveBeenCalledTimes(0); + }); + + test('for update post hook', async () => { + postSaveHook.mockRejectedValueOnce(new Error('OMG update post save')); + + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(ConnectorSavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValueOnce(ConnectorSavedObject); + const result = await actionsClient.update(UpdateParms); + expect(result.id).toBe(ConnectorSavedObject.id); + + const preParams = { ...CoreHookParams, logger, isUpdate: true }; + const postParams = { ...preParams, wasSuccessful: true }; + + expect(preSaveHook).toHaveBeenCalledTimes(1); + expect(preSaveHook.mock.calls[0]).toStrictEqual([preParams]); + + expect(postSaveHook).toHaveBeenCalledTimes(1); + expect(postSaveHook.mock.calls[0]).toStrictEqual([postParams]); + expect(logger.error).toHaveBeenCalledTimes(1); + expect(logger.error.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "postSaveHook update error for connectorId: \\"connector-id-uuid\\"; type: hooked-action-type: OMG update post save", + Object { + "tags": Array [ + "post-save-hook", + "connector-id-uuid", + ], + }, + ], + ] + `); + }); + + test('for delete post hook', async () => { + postDeleteHook.mockRejectedValueOnce(new Error('OMG delete post delete')); + + const expectedResult = Symbol(); + unsecuredSavedObjectsClient.delete.mockResolvedValueOnce(expectedResult); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(ConnectorSavedObject); + + const result = await actionsClient.delete({ id: ConnectorSavedObject.id }); + expect(result).toBe(expectedResult); + + const postParamsWithSecrets = { ...CoreHookParams, logger }; + const postParams = omit(postParamsWithSecrets, 'secrets'); + + expect(postDeleteHook).toHaveBeenCalledTimes(1); + expect(postDeleteHook.mock.calls[0]).toEqual([postParams]); + expect(logger.error).toHaveBeenCalledTimes(1); + expect(logger.error.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "The post delete hook failed for for connector \\"connector-id-uuid\\": OMG delete post delete", + Object { + "tags": Array [ + "post-delete-hook", + "connector-id-uuid", + ], + }, + ], + ] + `); + }); + }); +}); diff --git a/x-pack/plugins/actions/server/application/connector/methods/update/update.ts b/x-pack/plugins/actions/server/application/connector/methods/update/update.ts index 7baa099a29029..e22715c31d149 100644 --- a/x-pack/plugins/actions/server/application/connector/methods/update/update.ts +++ b/x-pack/plugins/actions/server/application/connector/methods/update/update.ts @@ -15,7 +15,8 @@ import { PreconfiguredActionDisabledModificationError } from '../../../../lib/er import { ConnectorAuditAction, connectorAuditEvent } from '../../../../lib/audit_events'; import { validateConfig, validateConnector, validateSecrets } from '../../../../lib'; import { isConnectorDeprecated } from '../../lib'; -import { RawAction } from '../../../../types'; +import { RawAction, HookServices } from '../../../../types'; +import { tryCatch } from '../../../../lib'; export async function update({ context, id, action }: ConnectorUpdateParams): Promise { try { @@ -75,6 +76,33 @@ export async function update({ context, id, action }: ConnectorUpdateParams): Pr context.actionTypeRegistry.ensureActionTypeEnabled(actionTypeId); + const hookServices: HookServices = { + scopedClusterClient: context.scopedClusterClient, + }; + + if (actionType.preSaveHook) { + try { + await actionType.preSaveHook({ + connectorId: id, + config, + secrets, + logger: context.logger, + request: context.request, + services: hookServices, + isUpdate: true, + }); + } catch (error) { + context.auditLogger?.log( + connectorAuditEvent({ + action: ConnectorAuditAction.UPDATE, + savedObject: { type: 'action', id }, + error, + }) + ); + throw error; + } + } + context.auditLogger?.log( connectorAuditEvent({ action: ConnectorAuditAction.UPDATE, @@ -83,27 +111,57 @@ export async function update({ context, id, action }: ConnectorUpdateParams): Pr }) ); - const result = await context.unsecuredSavedObjectsClient.create( - 'action', - { - ...attributes, - actionTypeId, - name, - isMissingSecrets: false, - config: validatedActionTypeConfig as SavedObjectAttributes, - secrets: validatedActionTypeSecrets as SavedObjectAttributes, - }, - omitBy( - { - id, - overwrite: true, - references, - version, - }, - isUndefined - ) + const result = await tryCatch( + async () => + await context.unsecuredSavedObjectsClient.create( + 'action', + { + ...attributes, + actionTypeId, + name, + isMissingSecrets: false, + config: validatedActionTypeConfig as SavedObjectAttributes, + secrets: validatedActionTypeSecrets as SavedObjectAttributes, + }, + omitBy( + { + id, + overwrite: true, + references, + version, + }, + isUndefined + ) + ) ); + const wasSuccessful = !(result instanceof Error); + const label = `connectorId: "${id}"; type: ${actionTypeId}`; + const tags = ['post-save-hook', id]; + + if (actionType.postSaveHook) { + try { + await actionType.postSaveHook({ + connectorId: id, + config, + secrets, + logger: context.logger, + request: context.request, + services: hookServices, + isUpdate: true, + wasSuccessful, + }); + } catch (err) { + context.logger.error(`postSaveHook update error for ${label}: ${err.message}`, { + tags, + }); + } + } + + if (!wasSuccessful) { + throw result; + } + try { await context.connectorTokenClient.deleteConnectorTokens({ connectorId: id }); } catch (e) { diff --git a/x-pack/plugins/actions/server/lib/index.ts b/x-pack/plugins/actions/server/lib/index.ts index 9b8d452f446a9..e13fb85008a84 100644 --- a/x-pack/plugins/actions/server/lib/index.ts +++ b/x-pack/plugins/actions/server/lib/index.ts @@ -38,3 +38,4 @@ export { export { parseDate } from './parse_date'; export type { RelatedSavedObjects } from './related_saved_objects'; export { getBasicAuthHeader, combineHeadersWithBasicAuthHeader } from './get_basic_auth_header'; +export { tryCatch } from './try_catch'; diff --git a/x-pack/plugins/actions/server/lib/try_catch.ts b/x-pack/plugins/actions/server/lib/try_catch.ts new file mode 100644 index 0000000000000..a9932601c8256 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/try_catch.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// functional version of try/catch, allows you to not have to use +// `let` vars initialied to `undefined` to capture the result value + +export async function tryCatch(fn: () => Promise): Promise { + try { + return await fn(); + } catch (err) { + return err; + } +} diff --git a/x-pack/plugins/actions/server/sub_action_framework/register.test.ts b/x-pack/plugins/actions/server/sub_action_framework/register.test.ts index a0e56c1a39b80..8ae7f3cf3350f 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/register.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/register.test.ts @@ -21,6 +21,9 @@ import { ServiceParams } from './types'; describe('Registration', () => { const renderedVariables = { body: '' }; const mockRenderParameterTemplates = jest.fn().mockReturnValue(renderedVariables); + const mockPreSaveHook = jest.fn(); + const mockPostSaveHook = jest.fn(); + const mockPostDeleteHook = jest.fn(); const connector = { id: '.test', @@ -47,7 +50,12 @@ describe('Registration', () => { it('registers the connector correctly', async () => { register({ actionTypeRegistry, - connector, + connector: { + ...connector, + preSaveHook: mockPreSaveHook, + postSaveHook: mockPostSaveHook, + postDeleteHook: mockPostDeleteHook, + }, configurationUtilities: mockedActionsConfig, logger, }); @@ -62,6 +70,9 @@ describe('Registration', () => { executor: expect.any(Function), getService: expect.any(Function), renderParameterTemplates: expect.any(Function), + preSaveHook: expect.any(Function), + postSaveHook: expect.any(Function), + postDeleteHook: expect.any(Function), }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/register.ts b/x-pack/plugins/actions/server/sub_action_framework/register.ts index dd05cc4e99967..04e7f0d9ea417 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/register.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/register.ts @@ -43,5 +43,8 @@ export const register = { /** @@ -76,6 +77,35 @@ export type Validators = Array< ConfigValidator | SecretsValidator >; +export interface PreSaveConnectorHookParams { + connectorId: string; + config: Config; + secrets: Secrets; + logger: Logger; + request: KibanaRequest; + services: HookServices; + isUpdate: boolean; +} + +export interface PostSaveConnectorHookParams { + connectorId: string; + config: Config; + secrets: Secrets; + logger: Logger; + request: KibanaRequest; + services: HookServices; + isUpdate: boolean; + wasSuccessful: boolean; +} + +export interface PostDeleteConnectorHookParams { + connectorId: string; + config: Config; + logger: Logger; + services: HookServices; + request: KibanaRequest; +} + export interface SubActionConnectorType { id: string; name: string; @@ -92,6 +122,9 @@ export interface SubActionConnectorType { getKibanaPrivileges?: (args?: { params?: { subAction: string; subActionParams: Record }; }) => string[]; + preSaveHook?: (params: PreSaveConnectorHookParams) => Promise; + postSaveHook?: (params: PostSaveConnectorHookParams) => Promise; + postDeleteHook?: (params: PostDeleteConnectorHookParams) => Promise; } export interface ExecutorParams extends ActionTypeParams { diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index 487e7630d40f9..d7c3497edc376 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -16,6 +16,7 @@ import { SavedObjectReference, Logger, ISavedObjectsRepository, + IScopedClusterClient, } from '@kbn/core/server'; import { AnySchema } from 'joi'; import { SubActionConnector } from './sub_action_framework/sub_action_connector'; @@ -57,6 +58,10 @@ export interface UnsecuredServices { connectorTokenClient: ConnectorTokenClient; } +export interface HookServices { + scopedClusterClient: IScopedClusterClient; +} + export interface ActionsApiRequestHandlerContext { getActionsClient: () => ActionsClient; listTypes: ActionTypeRegistry['list']; @@ -138,6 +143,44 @@ export type RenderParameterTemplates = ( actionId?: string ) => Params; +export interface PreSaveConnectorHookParams< + Config extends ActionTypeConfig = ActionTypeConfig, + Secrets extends ActionTypeSecrets = ActionTypeSecrets +> { + connectorId: string; + config: Config; + secrets: Secrets; + logger: Logger; + request: KibanaRequest; + services: HookServices; + isUpdate: boolean; +} + +export interface PostSaveConnectorHookParams< + Config extends ActionTypeConfig = ActionTypeConfig, + Secrets extends ActionTypeSecrets = ActionTypeSecrets +> { + connectorId: string; + config: Config; + secrets: Secrets; + logger: Logger; + request: KibanaRequest; + services: HookServices; + isUpdate: boolean; + wasSuccessful: boolean; +} + +export interface PostDeleteConnectorHookParams< + Config extends ActionTypeConfig = ActionTypeConfig, + Secrets extends ActionTypeSecrets = ActionTypeSecrets +> { + connectorId: string; + config: Config; + logger: Logger; + request: KibanaRequest; + services: HookServices; +} + export interface ActionType< Config extends ActionTypeConfig = ActionTypeConfig, Secrets extends ActionTypeSecrets = ActionTypeSecrets, @@ -171,6 +214,9 @@ export interface ActionType< renderParameterTemplates?: RenderParameterTemplates; executor: ExecutorType; getService?: (params: ServiceParams) => SubActionConnector; + preSaveHook?: (params: PreSaveConnectorHookParams) => Promise; + postSaveHook?: (params: PostSaveConnectorHookParams) => Promise; + postDeleteHook?: (params: PostDeleteConnectorHookParams) => Promise; } export interface RawAction extends Record { diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index fb0194b01be99..3ff3def3f4b70 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -77,6 +77,7 @@ const enabledActionTypes = [ 'test.system-action', 'test.system-action-kibana-privileges', 'test.system-action-connector-adapter', + 'test.connector-with-hooks', ]; export function createTestConfig(name: string, options: CreateTestConfigOptions) { diff --git a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/action_types.ts b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/action_types.ts index f6903da3c62bc..8d5caf79a4c89 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/action_types.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/action_types.ts @@ -76,6 +76,7 @@ export function defineActionTypes( actions.registerType(getNoAttemptsRateLimitedActionType()); actions.registerType(getAuthorizationActionType(core)); actions.registerType(getExcludedActionType()); + actions.registerType(getHookedActionType()); /** * System actions @@ -139,6 +140,96 @@ function getIndexRecordActionType() { return result; } +function getHookedActionType() { + const paramsSchema = schema.object({}); + type ParamsType = TypeOf; + const configSchema = schema.object({ + index: schema.string(), + source: schema.string(), + }); + type ConfigType = TypeOf; + const secretsSchema = schema.object({ + encrypted: schema.string(), + }); + type SecretsType = TypeOf; + const result: ActionType = { + id: 'test.connector-with-hooks', + name: 'Test: Connector with hooks', + minimumLicenseRequired: 'gold', + supportedFeatureIds: ['alerting'], + validate: { + params: { schema: paramsSchema }, + config: { schema: configSchema }, + secrets: { schema: secretsSchema }, + }, + async executor({ config, secrets, params, services, actionId }) { + return { status: 'ok', actionId }; + }, + async preSaveHook({ connectorId, config, secrets, services, isUpdate, logger }) { + const body = { + state: { + connectorId, + config, + secrets, + isUpdate, + }, + reference: 'pre-save', + source: config.source, + }; + logger.info(`running hook pre-save for ${JSON.stringify(body)}`); + await services.scopedClusterClient.asInternalUser.index({ + index: config.index, + refresh: 'wait_for', + body, + }); + }, + async postSaveHook({ + connectorId, + config, + secrets, + services, + logger, + isUpdate, + wasSuccessful, + }) { + const body = { + state: { + connectorId, + config, + secrets, + isUpdate, + wasSuccessful, + }, + reference: 'post-save', + source: config.source, + }; + logger.info(`running hook post-save for ${JSON.stringify(body)}`); + await services.scopedClusterClient.asInternalUser.index({ + index: config.index, + refresh: 'wait_for', + body, + }); + }, + async postDeleteHook({ connectorId, config, services, logger }) { + const body = { + state: { + connectorId, + config, + }, + reference: 'post-delete', + source: config.source, + }; + logger.info(`running hook post-delete for ${JSON.stringify(body)}`); + await services.scopedClusterClient.asInternalUser.index({ + index: config.index, + refresh: 'wait_for', + body, + }); + }, + }; + return result; +} + function getDelayedActionType() { const paramsSchema = schema.object({ delayInMs: schema.number({ defaultValue: 1000 }), diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/create.ts index 017fd3e45999b..e05a1ea9e0350 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/create.ts @@ -7,6 +7,7 @@ import { v4 as uuidv4 } from 'uuid'; import expect from '@kbn/expect'; +import { ESTestIndexTool, ES_TEST_INDEX_NAME } from '@kbn/alerting-api-integration-helpers'; import { UserAtSpaceScenarios } from '../../../scenarios'; import { checkAAD, getUrlPrefix, ObjectRemover } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -15,11 +16,21 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; export default function createActionTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); + const es = getService('es'); + const retry = getService('retry'); + const esTestIndexTool = new ESTestIndexTool(es, retry); describe('create', () => { const objectRemover = new ObjectRemover(supertest); - after(() => objectRemover.removeAll()); + before(async () => { + await esTestIndexTool.destroy(); + await esTestIndexTool.setup(); + }); + after(async () => { + await esTestIndexTool.destroy(); + await objectRemover.removeAll(); + }); for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; @@ -396,6 +407,74 @@ export default function createActionTests({ getService }: FtrProviderContext) { throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); } }); + + it('should handle save hooks appropriately', async () => { + const source = uuidv4(); + const encryptedValue = 'This value should be encrypted'; + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) + .auth(user.username, user.password) + .set('kbn-xsrf', 'foo') + .send({ + name: 'Hooked action', + connector_type_id: 'test.connector-with-hooks', + config: { + index: ES_TEST_INDEX_NAME, + source, + }, + secrets: { + encrypted: encryptedValue, + }, + }); + + const searchResult = await esTestIndexTool.search(source); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'global_read at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all at space2': + expect(response.statusCode).to.eql(403); + expect(searchResult.body.hits.hits.length).to.eql(0); + break; + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.statusCode).to.eql(200); + objectRemover.add(space.id, response.body.id, 'action', 'actions'); + + const refs: string[] = []; + for (const hit of searchResult.body.hits.hits) { + const doc = hit._source as any; + + const reference = doc.reference; + delete doc.reference; + refs.push(reference); + + if (reference === 'post-save') { + expect(doc.state.wasSuccessful).to.be(true); + delete doc.state.wasSuccessful; + } + + const expected = { + state: { + connectorId: response.body.id, + config: { index: ES_TEST_INDEX_NAME, source }, + secrets: { encrypted: encryptedValue }, + isUpdate: false, + }, + source, + }; + expect(doc).to.eql(expected); + } + + refs.sort(); + expect(refs).to.eql(['post-save', 'pre-save']); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); }); } }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/delete.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/delete.ts index b5b11036a3dfd..edb9821418f8d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/delete.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/delete.ts @@ -5,7 +5,9 @@ * 2.0. */ +import { v4 as uuidv4 } from 'uuid'; import expect from '@kbn/expect'; +import { ESTestIndexTool, ES_TEST_INDEX_NAME } from '@kbn/alerting-api-integration-helpers'; import { UserAtSpaceScenarios } from '../../../scenarios'; import { getUrlPrefix, ObjectRemover } from '../../../../common/lib'; @@ -15,11 +17,21 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; export default function deleteActionTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); + const es = getService('es'); + const retry = getService('retry'); + const esTestIndexTool = new ESTestIndexTool(es, retry); describe('delete', () => { const objectRemover = new ObjectRemover(supertest); - after(() => objectRemover.removeAll()); + before(async () => { + await esTestIndexTool.destroy(); + await esTestIndexTool.setup(); + }); + after(async () => { + await esTestIndexTool.destroy(); + await objectRemover.removeAll(); + }); for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; @@ -212,6 +224,77 @@ export default function deleteActionTests({ getService }: FtrProviderContext) { throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); } }); + + it('should handle delete hooks appropriately', async () => { + const source = uuidv4(); + const encryptedValue = 'This value should be encrypted'; + const { body: createdAction } = await supertest + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'Hooked action', + connector_type_id: 'test.connector-with-hooks', + config: { + index: ES_TEST_INDEX_NAME, + source, + }, + secrets: { + encrypted: encryptedValue, + }, + }) + .expect(200); + + // clear out docs from create + await esTestIndexTool.destroy(); + await esTestIndexTool.setup(); + + const response = await supertestWithoutAuth + .delete(`${getUrlPrefix(space.id)}/api/actions/connector/${createdAction.id}`) + .auth(user.username, user.password) + .set('kbn-xsrf', 'foo'); + + const searchResult = await esTestIndexTool.search(source); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'global_read at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all at space2': + expect(response.statusCode).to.eql(403); + expect(searchResult.body.hits.hits.length).to.eql(0); + objectRemover.add(space.id, createdAction.id, 'action', 'actions'); + break; + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.statusCode).to.eql(204); + + const refs: string[] = []; + for (const hit of searchResult.body.hits.hits) { + const doc = hit._source as any; + + const reference = doc.reference; + delete doc.reference; + refs.push(reference); + + const expected = { + state: { + connectorId: createdAction.id, + config: { index: ES_TEST_INDEX_NAME, source }, + }, + source, + }; + expect(doc).to.eql(expected); + } + + refs.sort(); + expect(refs).to.eql(['post-delete']); + break; + default: + objectRemover.add(space.id, createdAction.id, 'action', 'actions'); + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); }); } }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/update.ts index 7c3c00534f11d..cb9fe8a94c8c0 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/update.ts @@ -5,7 +5,10 @@ * 2.0. */ +import { v4 as uuidv4 } from 'uuid'; import expect from '@kbn/expect'; +import { ESTestIndexTool, ES_TEST_INDEX_NAME } from '@kbn/alerting-api-integration-helpers'; + import { UserAtSpaceScenarios } from '../../../scenarios'; import { checkAAD, getUrlPrefix, ObjectRemover } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -14,11 +17,21 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; export default function updateActionTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); + const es = getService('es'); + const retry = getService('retry'); + const esTestIndexTool = new ESTestIndexTool(es, retry); describe('update', () => { const objectRemover = new ObjectRemover(supertest); - after(() => objectRemover.removeAll()); + before(async () => { + await esTestIndexTool.destroy(); + await esTestIndexTool.setup(); + }); + after(async () => { + await esTestIndexTool.destroy(); + await objectRemover.removeAll(); + }); for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; @@ -430,6 +443,94 @@ export default function updateActionTests({ getService }: FtrProviderContext) { throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); } }); + + it('should handle save hooks appropriately', async () => { + const source = uuidv4(); + const encryptedValue = 'This value should be encrypted'; + + const { body: createdAction } = await supertest + .post(`${getUrlPrefix(space.id)}/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'Hooked action', + connector_type_id: 'test.connector-with-hooks', + config: { + index: ES_TEST_INDEX_NAME, + source, + }, + secrets: { + encrypted: encryptedValue, + }, + }) + .expect(200); + objectRemover.add(space.id, createdAction.id, 'action', 'actions'); + + // clear out docs from create + await esTestIndexTool.destroy(); + await esTestIndexTool.setup(); + + const response = await supertestWithoutAuth + .put(`${getUrlPrefix(space.id)}/api/actions/connector/${createdAction.id}`) + .auth(user.username, user.password) + .set('kbn-xsrf', 'foo') + .send({ + name: 'Hooked action', + config: { + index: ES_TEST_INDEX_NAME, + source, + }, + secrets: { + encrypted: encryptedValue, + }, + }); + + const searchResult = await esTestIndexTool.search(source); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'global_read at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all at space2': + expect(response.statusCode).to.eql(403); + expect(searchResult.body.hits.hits.length).to.eql(0); + break; + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.statusCode).to.eql(200); + + const refs: string[] = []; + for (const hit of searchResult.body.hits.hits) { + const doc = hit._source as any; + + const reference = doc.reference; + delete doc.reference; + refs.push(reference); + + if (reference === 'post-save') { + expect(doc.state.wasSuccessful).to.be(true); + delete doc.state.wasSuccessful; + } + + const expected = { + state: { + connectorId: response.body.id, + config: { index: ES_TEST_INDEX_NAME, source }, + secrets: { encrypted: encryptedValue }, + isUpdate: true, + }, + source, + }; + expect(doc).to.eql(expected); + } + + refs.sort(); + expect(refs).to.eql(['post-save', 'pre-save']); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); }); } }); From 83a701e837a7a84a86dcc8d359154f900f69676a Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Thu, 10 Oct 2024 00:07:31 +0200 Subject: [PATCH 096/110] [Epic] AI Insights + Assistant - Add "Other" option to the existing OpenAI Connector dropdown list (#8936) (#194831) --- .../output/kibana.serverless.staging.yaml | 1 + oas_docs/output/kibana.serverless.yaml | 1 + oas_docs/output/kibana.staging.yaml | 1 + oas_docs/output/kibana.yaml | 1 + ...sistant_api_2023_10_31.bundled.schema.yaml | 1 + ...sistant_api_2023_10_31.bundled.schema.yaml | 1 + .../conversations/common_attributes.gen.ts | 2 +- .../common_attributes.schema.yaml | 1 + .../impl/connectorland/helpers.tsx | 1 + .../server/usage/actions_telemetry.test.ts | 4 +- x-pack/plugins/actions/server/usage/types.ts | 1 + .../server/routes/utils.test.ts | 12 + .../elastic_assistant/server/routes/utils.ts | 26 +- .../plugins/search_playground/common/types.ts | 1 + .../public/hooks/use_llms_models.test.ts | 35 +- .../public/hooks/use_llms_models.ts | 17 +- .../public/hooks/use_load_connectors.test.ts | 16 + .../public/hooks/use_load_connectors.ts | 14 + .../server/lib/get_chat_params.test.ts | 37 ++ .../server/lib/get_chat_params.ts | 2 +- .../use_attack_discovery/helpers.ts | 1 + .../common/openai/constants.ts | 1 + .../stack_connectors/common/openai/schema.ts | 6 + .../lib/gen_ai/use_get_dashboard.test.ts | 1 + .../connector_types/openai/connector.test.tsx | 29 ++ .../connector_types/openai/connector.tsx | 10 + .../connector_types/openai/constants.tsx | 65 +++ .../connector_types/openai/params.test.tsx | 5 +- .../connector_types/openai/translations.ts | 4 + .../server/connector_types/openai/index.ts | 6 +- .../openai/lib/other_openai_utils.test.ts | 116 +++++ .../openai/lib/other_openai_utils.ts | 39 ++ .../connector_types/openai/lib/utils.test.ts | 43 ++ .../connector_types/openai/lib/utils.ts | 11 +- .../connector_types/openai/openai.test.ts | 428 ++++++++++++++++++ .../schema/xpack_plugins.json | 3 + .../tests/actions/connector_types/openai.ts | 4 +- 37 files changed, 915 insertions(+), 32 deletions(-) create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/openai/lib/other_openai_utils.test.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/openai/lib/other_openai_utils.ts diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index 69b783c6ccc44..20ab121c161bd 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -40891,6 +40891,7 @@ components: enum: - OpenAI - Azure OpenAI + - Other type: string Security_AI_Assistant_API_Reader: additionalProperties: true diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index 69b783c6ccc44..20ab121c161bd 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -40891,6 +40891,7 @@ components: enum: - OpenAI - Azure OpenAI + - Other type: string Security_AI_Assistant_API_Reader: additionalProperties: true diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index bc0828a44b619..6aa75efa5bd70 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -49452,6 +49452,7 @@ components: enum: - OpenAI - Azure OpenAI + - Other type: string Security_AI_Assistant_API_Reader: additionalProperties: true diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index bc0828a44b619..6aa75efa5bd70 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -49452,6 +49452,7 @@ components: enum: - OpenAI - Azure OpenAI + - Other type: string Security_AI_Assistant_API_Reader: additionalProperties: true diff --git a/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml index 1e070b75322d4..8f80e61c07040 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml @@ -1194,6 +1194,7 @@ components: enum: - OpenAI - Azure OpenAI + - Other type: string Reader: additionalProperties: true diff --git a/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml index e13d7a05af41f..97c18a2f77b6e 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml @@ -1194,6 +1194,7 @@ components: enum: - OpenAI - Azure OpenAI + - Other type: string Reader: additionalProperties: true diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts index 1ba701474b1f8..1dad26e1628db 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts @@ -46,7 +46,7 @@ export const Reader = z.object({}).catchall(z.unknown()); * Provider */ export type Provider = z.infer; -export const Provider = z.enum(['OpenAI', 'Azure OpenAI']); +export const Provider = z.enum(['OpenAI', 'Azure OpenAI', 'Other']); export type ProviderEnum = typeof Provider.enum; export const ProviderEnum = Provider.enum; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml index f6a8189182474..20423236f7423 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml @@ -34,6 +34,7 @@ components: enum: - OpenAI - Azure OpenAI + - Other MessageRole: type: string diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx index 2bbc74af5a45a..99550f1cafe75 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx @@ -18,6 +18,7 @@ import { PRECONFIGURED_CONNECTOR } from './translations'; enum OpenAiProviderType { OpenAi = 'OpenAI', AzureAi = 'Azure OpenAI', + Other = 'Other', } interface GenAiConfig { diff --git a/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts b/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts index b4f6d785584a4..26c37b36566e4 100644 --- a/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts +++ b/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts @@ -1025,15 +1025,17 @@ describe('actions telemetry', () => { '.d3security': 2, '.gen-ai__Azure OpenAI': 3, '.gen-ai__OpenAI': 1, + '.gen-ai__Other': 1, }; const { countByType, countGenAiProviderTypes } = getCounts(aggs); expect(countByType).toEqual({ __d3security: 2, - '__gen-ai': 4, + '__gen-ai': 5, }); expect(countGenAiProviderTypes).toEqual({ 'Azure OpenAI': 3, OpenAI: 1, + Other: 1, }); }); }); diff --git a/x-pack/plugins/actions/server/usage/types.ts b/x-pack/plugins/actions/server/usage/types.ts index d9fe796c2b4e0..6bdfe316c76e2 100644 --- a/x-pack/plugins/actions/server/usage/types.ts +++ b/x-pack/plugins/actions/server/usage/types.ts @@ -51,6 +51,7 @@ export const byGenAiProviderTypeSchema: MakeSchemaFrom['count_by_t // Known providers: ['Azure OpenAI']: { type: 'long' }, ['OpenAI']: { type: 'long' }, + ['Other']: { type: 'long' }, }; export const byServiceProviderTypeSchema: MakeSchemaFrom['count_active_email_connectors_by_service_type'] = diff --git a/x-pack/plugins/elastic_assistant/server/routes/utils.test.ts b/x-pack/plugins/elastic_assistant/server/routes/utils.test.ts index 3ca1b8edb5036..9a77e645686dd 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/utils.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/utils.test.ts @@ -65,5 +65,17 @@ describe('Utils', () => { const isOpenModel = isOpenSourceModel(connector); expect(isOpenModel).toEqual(true); }); + + it('should return `true` when apiProvider of OpenAiProviderType.Other is specified', async () => { + const connector = { + actionTypeId: '.gen-ai', + config: { + apiUrl: OPENAI_CHAT_URL, + apiProvider: OpenAiProviderType.Other, + }, + } as unknown as Connector; + const isOpenModel = isOpenSourceModel(connector); + expect(isOpenModel).toEqual(true); + }); }); }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/utils.ts b/x-pack/plugins/elastic_assistant/server/routes/utils.ts index ea05fc814ec69..0fb51c7364809 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/utils.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/utils.ts @@ -203,19 +203,25 @@ export const isOpenSourceModel = (connector?: Connector): boolean => { } const llmType = getLlmType(connector.actionTypeId); - const connectorApiUrl = connector.config?.apiUrl - ? (connector.config.apiUrl as string) - : undefined; + const isOpenAiType = llmType === 'openai'; + + if (!isOpenAiType) { + return false; + } const connectorApiProvider = connector.config?.apiProvider ? (connector.config?.apiProvider as OpenAiProviderType) : undefined; + if (connectorApiProvider === OpenAiProviderType.Other) { + return true; + } - const isOpenAiType = llmType === 'openai'; - const isOpenAI = - isOpenAiType && - (!connectorApiUrl || - connectorApiUrl === OPENAI_CHAT_URL || - connectorApiProvider === OpenAiProviderType.AzureAi); + const connectorApiUrl = connector.config?.apiUrl + ? (connector.config.apiUrl as string) + : undefined; - return isOpenAiType && !isOpenAI; + return ( + !!connectorApiUrl && + connectorApiUrl !== OPENAI_CHAT_URL && + connectorApiProvider !== OpenAiProviderType.AzureAi + ); }; diff --git a/x-pack/plugins/search_playground/common/types.ts b/x-pack/plugins/search_playground/common/types.ts index c239858b5b459..e2a0ae34c2ef3 100644 --- a/x-pack/plugins/search_playground/common/types.ts +++ b/x-pack/plugins/search_playground/common/types.ts @@ -57,6 +57,7 @@ export enum APIRoutes { export enum LLMs { openai = 'openai', openai_azure = 'openai_azure', + openai_other = 'openai_other', bedrock = 'bedrock', gemini = 'gemini', } diff --git a/x-pack/plugins/search_playground/public/hooks/use_llms_models.test.ts b/x-pack/plugins/search_playground/public/hooks/use_llms_models.test.ts index d661084306583..ebce3883a471b 100644 --- a/x-pack/plugins/search_playground/public/hooks/use_llms_models.test.ts +++ b/x-pack/plugins/search_playground/public/hooks/use_llms_models.test.ts @@ -15,9 +15,10 @@ jest.mock('./use_load_connectors', () => ({ })); const mockConnectors = [ - { id: 'connectorId1', title: 'OpenAI Connector', type: LLMs.openai }, - { id: 'connectorId2', title: 'OpenAI Azure Connector', type: LLMs.openai_azure }, - { id: 'connectorId2', title: 'Bedrock Connector', type: LLMs.bedrock }, + { id: 'connectorId1', name: 'OpenAI Connector', type: LLMs.openai }, + { id: 'connectorId2', name: 'OpenAI Azure Connector', type: LLMs.openai_azure }, + { id: 'connectorId2', name: 'Bedrock Connector', type: LLMs.bedrock }, + { id: 'connectorId3', name: 'OpenAI OSS Model Connector', type: LLMs.openai_other }, ]; const mockUseLoadConnectors = (data: any) => { (useLoadConnectors as jest.Mock).mockReturnValue({ data }); @@ -36,7 +37,7 @@ describe('useLLMsModels Hook', () => { expect(result.current).toEqual([ { connectorId: 'connectorId1', - connectorName: undefined, + connectorName: 'OpenAI Connector', connectorType: LLMs.openai, disabled: false, icon: expect.any(Function), @@ -48,7 +49,7 @@ describe('useLLMsModels Hook', () => { }, { connectorId: 'connectorId1', - connectorName: undefined, + connectorName: 'OpenAI Connector', connectorType: LLMs.openai, disabled: false, icon: expect.any(Function), @@ -60,7 +61,7 @@ describe('useLLMsModels Hook', () => { }, { connectorId: 'connectorId1', - connectorName: undefined, + connectorName: 'OpenAI Connector', connectorType: LLMs.openai, disabled: false, icon: expect.any(Function), @@ -72,19 +73,19 @@ describe('useLLMsModels Hook', () => { }, { connectorId: 'connectorId2', - connectorName: undefined, + connectorName: 'OpenAI Azure Connector', connectorType: LLMs.openai_azure, disabled: false, icon: expect.any(Function), - id: 'connectorId2Azure OpenAI ', - name: 'Azure OpenAI ', + id: 'connectorId2OpenAI Azure Connector (Azure OpenAI)', + name: 'OpenAI Azure Connector (Azure OpenAI)', showConnectorName: false, value: undefined, promptTokenLimit: undefined, }, { connectorId: 'connectorId2', - connectorName: undefined, + connectorName: 'Bedrock Connector', connectorType: LLMs.bedrock, disabled: false, icon: expect.any(Function), @@ -96,7 +97,7 @@ describe('useLLMsModels Hook', () => { }, { connectorId: 'connectorId2', - connectorName: undefined, + connectorName: 'Bedrock Connector', connectorType: LLMs.bedrock, disabled: false, icon: expect.any(Function), @@ -106,6 +107,18 @@ describe('useLLMsModels Hook', () => { value: 'anthropic.claude-3-5-sonnet-20240620-v1:0', promptTokenLimit: 200000, }, + { + connectorId: 'connectorId3', + connectorName: 'OpenAI OSS Model Connector', + connectorType: LLMs.openai_other, + disabled: false, + icon: expect.any(Function), + id: 'connectorId3OpenAI OSS Model Connector (OpenAI Compatible Service)', + name: 'OpenAI OSS Model Connector (OpenAI Compatible Service)', + showConnectorName: false, + value: undefined, + promptTokenLimit: undefined, + }, ]); }); diff --git a/x-pack/plugins/search_playground/public/hooks/use_llms_models.ts b/x-pack/plugins/search_playground/public/hooks/use_llms_models.ts index 7a9b01e085a6d..3d5cee7719f10 100644 --- a/x-pack/plugins/search_playground/public/hooks/use_llms_models.ts +++ b/x-pack/plugins/search_playground/public/hooks/use_llms_models.ts @@ -34,11 +34,22 @@ const mapLlmToModels: Record< }, [LLMs.openai_azure]: { icon: OpenAILogo, - getModels: (connectorName, includeName) => [ + getModels: (connectorName) => [ { label: i18n.translate('xpack.searchPlayground.openAIAzureModel', { - defaultMessage: 'Azure OpenAI {name}', - values: { name: includeName ? `(${connectorName})` : '' }, + defaultMessage: '{name} (Azure OpenAI)', + values: { name: connectorName }, + }), + }, + ], + }, + [LLMs.openai_other]: { + icon: OpenAILogo, + getModels: (connectorName) => [ + { + label: i18n.translate('xpack.searchPlayground.otherOpenAIModel', { + defaultMessage: '{name} (OpenAI Compatible Service)', + values: { name: connectorName }, }), }, ], diff --git a/x-pack/plugins/search_playground/public/hooks/use_load_connectors.test.ts b/x-pack/plugins/search_playground/public/hooks/use_load_connectors.test.ts index 3a68d91fd0246..eb2f36eb62e5f 100644 --- a/x-pack/plugins/search_playground/public/hooks/use_load_connectors.test.ts +++ b/x-pack/plugins/search_playground/public/hooks/use_load_connectors.test.ts @@ -71,6 +71,12 @@ describe('useLoadConnectors', () => { actionTypeId: '.bedrock', isMissingSecrets: false, }, + { + id: '5', + actionTypeId: '.gen-ai', + isMissingSecrets: false, + config: { apiProvider: OpenAiProviderType.Other }, + }, ]; mockedLoadConnectors.mockResolvedValue(connectors); @@ -106,6 +112,16 @@ describe('useLoadConnectors', () => { title: 'Bedrock', type: 'bedrock', }, + { + actionTypeId: '.gen-ai', + config: { + apiProvider: 'Other', + }, + id: '5', + isMissingSecrets: false, + title: 'OpenAI Other', + type: 'openai_other', + }, ]); }); }); diff --git a/x-pack/plugins/search_playground/public/hooks/use_load_connectors.ts b/x-pack/plugins/search_playground/public/hooks/use_load_connectors.ts index 94bb2da37b1ed..3d2a3e8c90b86 100644 --- a/x-pack/plugins/search_playground/public/hooks/use_load_connectors.ts +++ b/x-pack/plugins/search_playground/public/hooks/use_load_connectors.ts @@ -63,6 +63,20 @@ const connectorTypeToLLM: Array<{ type: LLMs.openai, }), }, + { + actionId: OPENAI_CONNECTOR_ID, + actionProvider: OpenAiProviderType.Other, + match: (connector) => + connector.actionTypeId === OPENAI_CONNECTOR_ID && + (connector as OpenAIConnector)?.config?.apiProvider === OpenAiProviderType.Other, + transform: (connector) => ({ + ...connector, + title: i18n.translate('xpack.searchPlayground.openAIOtherConnectorTitle', { + defaultMessage: 'OpenAI Other', + }), + type: LLMs.openai_other, + }), + }, { actionId: BEDROCK_CONNECTOR_ID, match: (connector) => connector.actionTypeId === BEDROCK_CONNECTOR_ID, diff --git a/x-pack/plugins/search_playground/server/lib/get_chat_params.test.ts b/x-pack/plugins/search_playground/server/lib/get_chat_params.test.ts index cbc696a50085e..614d00dc16e66 100644 --- a/x-pack/plugins/search_playground/server/lib/get_chat_params.test.ts +++ b/x-pack/plugins/search_playground/server/lib/get_chat_params.test.ts @@ -152,4 +152,41 @@ describe('getChatParams', () => { ) ).rejects.toThrow('Invalid connector id'); }); + + it('returns the correct chat model and uses the default model when not specified in the params', async () => { + mockActionsClient.get.mockResolvedValue({ + id: '2', + actionTypeId: OPENAI_CONNECTOR_ID, + config: { defaultModel: 'local' }, + }); + + const result = await getChatParams( + { + connectorId: '2', + prompt: 'How does it work?', + citations: false, + }, + { actions, request, logger } + ); + + expect(Prompt).toHaveBeenCalledWith('How does it work?', { + citations: false, + context: true, + type: 'openai', + }); + expect(QuestionRewritePrompt).toHaveBeenCalledWith({ + type: 'openai', + }); + expect(ActionsClientChatOpenAI).toHaveBeenCalledWith({ + logger: expect.anything(), + model: 'local', + connectorId: '2', + actionsClient: expect.anything(), + signal: expect.anything(), + traceId: 'test-uuid', + temperature: 0.2, + maxRetries: 0, + }); + expect(result.chatPrompt).toContain('How does it work?'); + }); }); diff --git a/x-pack/plugins/search_playground/server/lib/get_chat_params.ts b/x-pack/plugins/search_playground/server/lib/get_chat_params.ts index d2c4bb1afaa9d..34f902e0d1ca2 100644 --- a/x-pack/plugins/search_playground/server/lib/get_chat_params.ts +++ b/x-pack/plugins/search_playground/server/lib/get_chat_params.ts @@ -57,7 +57,7 @@ export const getChatParams = async ( actionsClient, logger, connectorId, - model, + model: model || connector?.config?.defaultModel, traceId: uuidv4(), signal: abortSignal, temperature: getDefaultArguments().temperature, diff --git a/x-pack/plugins/security_solution/public/attack_discovery/use_attack_discovery/helpers.ts b/x-pack/plugins/security_solution/public/attack_discovery/use_attack_discovery/helpers.ts index f800651985217..97eb132bdaaeb 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/use_attack_discovery/helpers.ts +++ b/x-pack/plugins/security_solution/public/attack_discovery/use_attack_discovery/helpers.ts @@ -18,6 +18,7 @@ import { isEmpty } from 'lodash/fp'; enum OpenAiProviderType { OpenAi = 'OpenAI', AzureAi = 'Azure OpenAI', + Other = 'Other', } interface GenAiConfig { diff --git a/x-pack/plugins/stack_connectors/common/openai/constants.ts b/x-pack/plugins/stack_connectors/common/openai/constants.ts index c57720d9847af..3d629360d03f3 100644 --- a/x-pack/plugins/stack_connectors/common/openai/constants.ts +++ b/x-pack/plugins/stack_connectors/common/openai/constants.ts @@ -27,6 +27,7 @@ export enum SUB_ACTION { export enum OpenAiProviderType { OpenAi = 'OpenAI', AzureAi = 'Azure OpenAI', + Other = 'Other', } export const DEFAULT_TIMEOUT_MS = 120000; diff --git a/x-pack/plugins/stack_connectors/common/openai/schema.ts b/x-pack/plugins/stack_connectors/common/openai/schema.ts index f62ee1f35174c..8a08da157b163 100644 --- a/x-pack/plugins/stack_connectors/common/openai/schema.ts +++ b/x-pack/plugins/stack_connectors/common/openai/schema.ts @@ -21,6 +21,12 @@ export const ConfigSchema = schema.oneOf([ defaultModel: schema.string({ defaultValue: DEFAULT_OPENAI_MODEL }), headers: schema.maybe(schema.recordOf(schema.string(), schema.string())), }), + schema.object({ + apiProvider: schema.oneOf([schema.literal(OpenAiProviderType.Other)]), + apiUrl: schema.string(), + defaultModel: schema.string(), + headers: schema.maybe(schema.recordOf(schema.string(), schema.string())), + }), ]); export const SecretsSchema = schema.object({ apiKey: schema.string() }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.test.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.test.ts index 8ca9b97292fa3..18bcdc6232792 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.test.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.test.ts @@ -53,6 +53,7 @@ describe('useGetDashboard', () => { it.each([ ['Azure OpenAI', 'openai'], ['OpenAI', 'openai'], + ['Other', 'openai'], ['Bedrock', 'bedrock'], ])( 'fetches the %p dashboard and sets the dashboard URL with %p', diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.test.tsx index 03d41dd01caa9..2c8eaf8a76257 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.test.tsx @@ -50,6 +50,17 @@ const azureConnector = { apiKey: 'thats-a-nice-looking-key', }, }; +const otherOpenAiConnector = { + ...openAiConnector, + config: { + apiUrl: 'https://localhost/oss-llm', + apiProvider: OpenAiProviderType.Other, + defaultModel: 'local-model', + }, + secrets: { + apiKey: 'thats-a-nice-looking-key', + }, +}; const navigateToUrl = jest.fn(); @@ -93,6 +104,24 @@ describe('ConnectorFields renders', () => { expect(getAllByTestId('azure-ai-api-keys-doc')[0]).toBeInTheDocument(); }); + test('other open ai connector fields are rendered', async () => { + const { getAllByTestId } = render( + + {}} /> + + ); + expect(getAllByTestId('config.apiUrl-input')[0]).toBeInTheDocument(); + expect(getAllByTestId('config.apiUrl-input')[0]).toHaveValue( + otherOpenAiConnector.config.apiUrl + ); + expect(getAllByTestId('config.apiProvider-select')[0]).toBeInTheDocument(); + expect(getAllByTestId('config.apiProvider-select')[0]).toHaveValue( + otherOpenAiConnector.config.apiProvider + ); + expect(getAllByTestId('other-ai-api-doc')[0]).toBeInTheDocument(); + expect(getAllByTestId('other-ai-api-keys-doc')[0]).toBeInTheDocument(); + }); + describe('Dashboard link', () => { it('Does not render if isEdit is false and dashboardUrl is defined', async () => { const { queryByTestId } = render( diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.tsx b/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.tsx index c940ad76e3643..27cbb9a4dac08 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.tsx @@ -24,6 +24,8 @@ import * as i18n from './translations'; import { azureAiConfig, azureAiSecrets, + otherOpenAiConfig, + otherOpenAiSecrets, openAiConfig, openAiSecrets, providerOptions, @@ -85,6 +87,14 @@ const ConnectorFields: React.FC = ({ readOnly, isEdi secretsFormSchema={azureAiSecrets} /> )} + {config != null && config.apiProvider === OpenAiProviderType.Other && ( + + )} {isEdit && ( + {`${i18n.OTHER_OPENAI} ${i18n.DOCUMENTATION}`} + + ), + }} + /> + ), + }, + { + id: 'defaultModel', + label: i18n.DEFAULT_MODEL_LABEL, + helpText: ( + + ), + }, +]; + export const openAiSecrets: SecretsFieldSchema[] = [ { id: 'apiKey', @@ -142,6 +177,31 @@ export const azureAiSecrets: SecretsFieldSchema[] = [ }, ]; +export const otherOpenAiSecrets: SecretsFieldSchema[] = [ + { + id: 'apiKey', + label: i18n.API_KEY_LABEL, + isPasswordField: true, + helpText: ( + + {`${i18n.OTHER_OPENAI} ${i18n.DOCUMENTATION}`} + + ), + }} + /> + ), + }, +]; + export const providerOptions = [ { value: OpenAiProviderType.OpenAi, @@ -153,4 +213,9 @@ export const providerOptions = [ text: i18n.AZURE_AI, label: i18n.AZURE_AI, }, + { + value: OpenAiProviderType.Other, + text: i18n.OTHER_OPENAI, + label: i18n.OTHER_OPENAI, + }, ]; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/params.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/openai/params.test.tsx index 09a2652ad8f1d..7539cc6bf6373 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/params.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/openai/params.test.tsx @@ -37,7 +37,7 @@ describe('Gen AI Params Fields renders', () => { expect(getByTestId('bodyJsonEditor')).toHaveProperty('value', '{"message": "test"}'); expect(getByTestId('bodyAddVariableButton')).toBeInTheDocument(); }); - test.each([OpenAiProviderType.OpenAi, OpenAiProviderType.AzureAi])( + test.each([OpenAiProviderType.OpenAi, OpenAiProviderType.AzureAi, OpenAiProviderType.Other])( 'useEffect handles the case when subAction and subActionParams are undefined and apiProvider is %p', (apiProvider) => { const actionParams = { @@ -79,6 +79,9 @@ describe('Gen AI Params Fields renders', () => { if (apiProvider === OpenAiProviderType.AzureAi) { expect(editAction).toHaveBeenCalledWith('subActionParams', { body: DEFAULT_BODY_AZURE }, 0); } + if (apiProvider === OpenAiProviderType.Other) { + expect(editAction).toHaveBeenCalledWith('subActionParams', { body: DEFAULT_BODY }, 0); + } } ); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/openai/translations.ts index 4c72866c6ece4..55815faac1c8e 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/openai/translations.ts @@ -47,6 +47,10 @@ export const AZURE_AI = i18n.translate('xpack.stackConnectors.components.genAi.a defaultMessage: 'Azure OpenAI', }); +export const OTHER_OPENAI = i18n.translate('xpack.stackConnectors.components.genAi.otherAi', { + defaultMessage: 'Other (OpenAI Compatible Service)', +}); + export const DOCUMENTATION = i18n.translate( 'xpack.stackConnectors.components.genAi.documentation', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/index.ts index f8a3a3d32ddb2..5bf0ba6c3a562 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/index.ts @@ -53,7 +53,11 @@ export const configValidator = (configObject: Config, validatorServices: Validat const { apiProvider } = configObject; - if (apiProvider !== OpenAiProviderType.OpenAi && apiProvider !== OpenAiProviderType.AzureAi) { + if ( + apiProvider !== OpenAiProviderType.OpenAi && + apiProvider !== OpenAiProviderType.AzureAi && + apiProvider !== OpenAiProviderType.Other + ) { throw new Error( `API Provider is not supported${ apiProvider && (apiProvider as OpenAiProviderType).length ? `: ${apiProvider}` : `` diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/other_openai_utils.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/other_openai_utils.test.ts new file mode 100644 index 0000000000000..33722314f5422 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/other_openai_utils.test.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { sanitizeRequest, getRequestWithStreamOption } from './other_openai_utils'; + +describe('Other (OpenAI Compatible Service) Utils', () => { + describe('sanitizeRequest', () => { + it('sets stream to false when stream is set to true in the body', () => { + const body = { + model: 'mistral', + stream: true, + messages: [ + { + role: 'user', + content: 'This is a test', + }, + ], + }; + + const sanitizedBodyString = sanitizeRequest(JSON.stringify(body)); + expect(sanitizedBodyString).toEqual( + `{\"model\":\"mistral\",\"stream\":false,\"messages\":[{\"role\":\"user\",\"content\":\"This is a test\"}]}` + ); + }); + + it('sets stream to false when stream is not defined in the body', () => { + const body = { + model: 'mistral', + messages: [ + { + role: 'user', + content: 'This is a test', + }, + ], + }; + + const sanitizedBodyString = sanitizeRequest(JSON.stringify(body)); + expect(sanitizedBodyString).toEqual( + `{\"model\":\"mistral\",\"messages\":[{\"role\":\"user\",\"content\":\"This is a test\"}],\"stream\":false}` + ); + }); + + it('sets stream to false when stream is set to false in the body', () => { + const body = { + model: 'mistral', + stream: false, + messages: [ + { + role: 'user', + content: 'This is a test', + }, + ], + }; + + const sanitizedBodyString = sanitizeRequest(JSON.stringify(body)); + expect(sanitizedBodyString).toEqual( + `{\"model\":\"mistral\",\"stream\":false,\"messages\":[{\"role\":\"user\",\"content\":\"This is a test\"}]}` + ); + }); + + it('does nothing when body is malformed JSON', () => { + const bodyString = `{\"model\":\"mistral\",\"messages\":[{\"role\":\"user\",\"content\":\"This is a test\"}],,}`; + + const sanitizedBodyString = sanitizeRequest(bodyString); + expect(sanitizedBodyString).toEqual(bodyString); + }); + }); + + describe('getRequestWithStreamOption', () => { + it('sets stream parameter when stream is not defined in the body', () => { + const body = { + model: 'mistral', + messages: [ + { + role: 'user', + content: 'This is a test', + }, + ], + }; + + const sanitizedBodyString = getRequestWithStreamOption(JSON.stringify(body), true); + expect(sanitizedBodyString).toEqual( + `{\"model\":\"mistral\",\"messages\":[{\"role\":\"user\",\"content\":\"This is a test\"}],\"stream\":true}` + ); + }); + + it('overrides stream parameter if defined in body', () => { + const body = { + model: 'mistral', + stream: true, + messages: [ + { + role: 'user', + content: 'This is a test', + }, + ], + }; + + const sanitizedBodyString = getRequestWithStreamOption(JSON.stringify(body), false); + expect(sanitizedBodyString).toEqual( + `{\"model\":\"mistral\",\"stream\":false,\"messages\":[{\"role\":\"user\",\"content\":\"This is a test\"}]}` + ); + }); + + it('does nothing when body is malformed JSON', () => { + const bodyString = `{\"model\":\"mistral\",\"messages\":[{\"role\":\"user\",\"content\":\"This is a test\"}],,}`; + + const sanitizedBodyString = getRequestWithStreamOption(bodyString, false); + expect(sanitizedBodyString).toEqual(bodyString); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/other_openai_utils.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/other_openai_utils.ts new file mode 100644 index 0000000000000..8288e0dba9ad1 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/other_openai_utils.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Sanitizes the Other (OpenAI Compatible Service) request body to set stream to false + * so users cannot specify a streaming response when the framework + * is not prepared to handle streaming + * + * The stream parameter is accepted in the ChatCompletion + * API and the Completion API only + */ +export const sanitizeRequest = (body: string): string => { + return getRequestWithStreamOption(body, false); +}; + +/** + * Intercepts the Other (OpenAI Compatible Service) request body to set the stream parameter + * + * The stream parameter is accepted in the ChatCompletion + * API and the Completion API only + */ +export const getRequestWithStreamOption = (body: string, stream: boolean): string => { + try { + const jsonBody = JSON.parse(body); + if (jsonBody) { + jsonBody.stream = stream; + } + + return JSON.stringify(jsonBody); + } catch (err) { + // swallow the error + } + + return body; +}; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/utils.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/utils.test.ts index 9dffaab3e5e00..142f3a319eeb6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/utils.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/utils.test.ts @@ -19,8 +19,14 @@ import { sanitizeRequest as azureAiSanitizeRequest, getRequestWithStreamOption as azureAiGetRequestWithStreamOption, } from './azure_openai_utils'; +import { + sanitizeRequest as otherOpenAiSanitizeRequest, + getRequestWithStreamOption as otherOpenAiGetRequestWithStreamOption, +} from './other_openai_utils'; + jest.mock('./openai_utils'); jest.mock('./azure_openai_utils'); +jest.mock('./other_openai_utils'); describe('Utils', () => { const azureAiUrl = @@ -38,6 +44,7 @@ describe('Utils', () => { describe('sanitizeRequest', () => { const mockOpenAiSanitizeRequest = openAiSanitizeRequest as jest.Mock; const mockAzureAiSanitizeRequest = azureAiSanitizeRequest as jest.Mock; + const mockOtherOpenAiSanitizeRequest = otherOpenAiSanitizeRequest as jest.Mock; beforeEach(() => { jest.clearAllMocks(); }); @@ -50,24 +57,36 @@ describe('Utils', () => { DEFAULT_OPENAI_MODEL ); expect(mockAzureAiSanitizeRequest).not.toHaveBeenCalled(); + expect(mockOtherOpenAiSanitizeRequest).not.toHaveBeenCalled(); + }); + + it('calls other_openai_utils sanitizeRequest when provider is Other OpenAi', () => { + sanitizeRequest(OpenAiProviderType.Other, OPENAI_CHAT_URL, bodyString, DEFAULT_OPENAI_MODEL); + expect(mockOtherOpenAiSanitizeRequest).toHaveBeenCalledWith(bodyString); + expect(mockOpenAiSanitizeRequest).not.toHaveBeenCalled(); + expect(mockAzureAiSanitizeRequest).not.toHaveBeenCalled(); }); it('calls azure_openai_utils sanitizeRequest when provider is AzureAi', () => { sanitizeRequest(OpenAiProviderType.AzureAi, azureAiUrl, bodyString); expect(mockAzureAiSanitizeRequest).toHaveBeenCalledWith(azureAiUrl, bodyString); expect(mockOpenAiSanitizeRequest).not.toHaveBeenCalled(); + expect(mockOtherOpenAiSanitizeRequest).not.toHaveBeenCalled(); }); it('does not call any helper fns when provider is unrecognized', () => { sanitizeRequest('foo', OPENAI_CHAT_URL, bodyString); expect(mockOpenAiSanitizeRequest).not.toHaveBeenCalled(); expect(mockAzureAiSanitizeRequest).not.toHaveBeenCalled(); + expect(mockOtherOpenAiSanitizeRequest).not.toHaveBeenCalled(); }); }); describe('getRequestWithStreamOption', () => { const mockOpenAiGetRequestWithStreamOption = openAiGetRequestWithStreamOption as jest.Mock; const mockAzureAiGetRequestWithStreamOption = azureAiGetRequestWithStreamOption as jest.Mock; + const mockOtherOpenAiGetRequestWithStreamOption = + otherOpenAiGetRequestWithStreamOption as jest.Mock; beforeEach(() => { jest.clearAllMocks(); }); @@ -88,6 +107,15 @@ describe('Utils', () => { DEFAULT_OPENAI_MODEL ); expect(mockAzureAiGetRequestWithStreamOption).not.toHaveBeenCalled(); + expect(mockOtherOpenAiGetRequestWithStreamOption).not.toHaveBeenCalled(); + }); + + it('calls other_openai_utils getRequestWithStreamOption when provider is Other OpenAi', () => { + getRequestWithStreamOption(OpenAiProviderType.Other, OPENAI_CHAT_URL, bodyString, true); + + expect(mockOtherOpenAiGetRequestWithStreamOption).toHaveBeenCalledWith(bodyString, true); + expect(mockOpenAiGetRequestWithStreamOption).not.toHaveBeenCalled(); + expect(mockAzureAiGetRequestWithStreamOption).not.toHaveBeenCalled(); }); it('calls azure_openai_utils getRequestWithStreamOption when provider is AzureAi', () => { @@ -99,6 +127,7 @@ describe('Utils', () => { true ); expect(mockOpenAiGetRequestWithStreamOption).not.toHaveBeenCalled(); + expect(mockOtherOpenAiGetRequestWithStreamOption).not.toHaveBeenCalled(); }); it('does not call any helper fns when provider is unrecognized', () => { @@ -110,6 +139,7 @@ describe('Utils', () => { ); expect(mockOpenAiGetRequestWithStreamOption).not.toHaveBeenCalled(); expect(mockAzureAiGetRequestWithStreamOption).not.toHaveBeenCalled(); + expect(mockOtherOpenAiGetRequestWithStreamOption).not.toHaveBeenCalled(); }); }); @@ -127,6 +157,19 @@ describe('Utils', () => { }); }); + it('returns correct axios options when provider is other openai and stream is false', () => { + expect(getAxiosOptions(OpenAiProviderType.Other, 'api-abc', false)).toEqual({ + headers: { Authorization: `Bearer api-abc`, ['content-type']: 'application/json' }, + }); + }); + + it('returns correct axios options when provider is other openai and stream is true', () => { + expect(getAxiosOptions(OpenAiProviderType.Other, 'api-abc', true)).toEqual({ + headers: { Authorization: `Bearer api-abc`, ['content-type']: 'application/json' }, + responseType: 'stream', + }); + }); + it('returns correct axios options when provider is azure openai and stream is false', () => { expect(getAxiosOptions(OpenAiProviderType.AzureAi, 'api-abc', false)).toEqual({ headers: { ['api-key']: `api-abc`, ['content-type']: 'application/json' }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/utils.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/utils.ts index 811dfd4ce63b4..3028433656503 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/utils.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/lib/utils.ts @@ -16,6 +16,10 @@ import { sanitizeRequest as azureAiSanitizeRequest, getRequestWithStreamOption as azureAiGetRequestWithStreamOption, } from './azure_openai_utils'; +import { + sanitizeRequest as otherOpenAiSanitizeRequest, + getRequestWithStreamOption as otherOpenAiGetRequestWithStreamOption, +} from './other_openai_utils'; export const sanitizeRequest = ( provider: string, @@ -28,6 +32,8 @@ export const sanitizeRequest = ( return openAiSanitizeRequest(url, body, defaultModel!); case OpenAiProviderType.AzureAi: return azureAiSanitizeRequest(url, body); + case OpenAiProviderType.Other: + return otherOpenAiSanitizeRequest(body); default: return body; } @@ -42,7 +48,7 @@ export function getRequestWithStreamOption( ): string; export function getRequestWithStreamOption( - provider: OpenAiProviderType.AzureAi, + provider: OpenAiProviderType.AzureAi | OpenAiProviderType.Other, url: string, body: string, stream: boolean @@ -68,6 +74,8 @@ export function getRequestWithStreamOption( return openAiGetRequestWithStreamOption(url, body, stream, defaultModel!); case OpenAiProviderType.AzureAi: return azureAiGetRequestWithStreamOption(url, body, stream); + case OpenAiProviderType.Other: + return otherOpenAiGetRequestWithStreamOption(body, stream); default: return body; } @@ -81,6 +89,7 @@ export const getAxiosOptions = ( const responseType = stream ? { responseType: 'stream' as ResponseType } : {}; switch (provider) { case OpenAiProviderType.OpenAi: + case OpenAiProviderType.Other: return { headers: { Authorization: `Bearer ${apiKey}`, ['content-type']: 'application/json' }, ...responseType, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts index 87dacaf4e6f17..1362b7610e2cd 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts @@ -20,6 +20,9 @@ import { RunActionResponseSchema, StreamingResponseSchema } from '../../../commo import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { PassThrough, Transform } from 'stream'; import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; + +const DEFAULT_OTHER_OPENAI_MODEL = 'local-model'; + jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); const mockTee = jest.fn(); @@ -713,6 +716,431 @@ describe('OpenAIConnector', () => { }); }); + describe('Other OpenAI', () => { + const connector = new OpenAIConnector({ + configurationUtilities: actionsConfigMock.create(), + connector: { id: '1', type: OPENAI_CONNECTOR_ID }, + config: { + apiUrl: 'http://localhost:1234/v1/chat/completions', + apiProvider: OpenAiProviderType.Other, + defaultModel: DEFAULT_OTHER_OPENAI_MODEL, + headers: { + 'X-My-Custom-Header': 'foo', + Authorization: 'override', + }, + }, + secrets: { apiKey: '123' }, + logger, + services: actionsMock.createServices(), + }); + + const sampleOpenAiBody = { + model: DEFAULT_OTHER_OPENAI_MODEL, + messages: [ + { + role: 'user', + content: 'Hello world', + }, + ], + }; + + beforeEach(() => { + // @ts-ignore + connector.request = mockRequest; + jest.clearAllMocks(); + }); + + describe('runApi', () => { + it('the Other OpenAI API call is successful with correct parameters', async () => { + const response = await connector.runApi( + { body: JSON.stringify(sampleOpenAiBody) }, + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + url: 'http://localhost:1234/v1/chat/completions', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OTHER_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + }, + connectorUsageCollector + ); + expect(response).toEqual(mockResponse.data); + }); + + it('overrides stream parameter if set in the body', async () => { + const body = { + model: 'llama-3.1', + messages: [ + { + role: 'user', + content: 'Hello world', + }, + ], + }; + const response = await connector.runApi( + { + body: JSON.stringify({ + ...body, + stream: true, + }), + }, + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + url: 'http://localhost:1234/v1/chat/completions', + data: JSON.stringify({ + ...body, + stream: false, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + }, + connectorUsageCollector + ); + expect(response).toEqual(mockResponse.data); + }); + + it('errors during API calls are properly handled', async () => { + // @ts-ignore + connector.request = mockError; + + await expect( + connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }, connectorUsageCollector) + ).rejects.toThrow('API Error'); + }); + }); + + describe('streamApi', () => { + it('the Other OpenAI API call is successful with correct parameters when stream = false', async () => { + const response = await connector.streamApi( + { + body: JSON.stringify(sampleOpenAiBody), + stream: false, + }, + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'http://localhost:1234/v1/chat/completions', + method: 'post', + responseSchema: RunActionResponseSchema, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + }, + connectorUsageCollector + ); + expect(response).toEqual(mockResponse.data); + }); + + it('the Other OpenAI API call is successful with correct parameters when stream = true', async () => { + const response = await connector.streamApi( + { + body: JSON.stringify(sampleOpenAiBody), + stream: true, + }, + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'http://localhost:1234/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + model: DEFAULT_OTHER_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + }, + connectorUsageCollector + ); + expect(response).toEqual({ + headers: { 'Content-Type': 'dont-compress-this' }, + ...mockResponse.data, + }); + }); + + it('overrides stream parameter if set in the body with explicit stream parameter', async () => { + const body = { + model: 'llama-3.1', + messages: [ + { + role: 'user', + content: 'Hello world', + }, + ], + }; + const response = await connector.streamApi( + { + body: JSON.stringify({ + ...body, + stream: false, + }), + stream: true, + }, + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'http://localhost:1234/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + ...body, + stream: true, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + }, + connectorUsageCollector + ); + expect(response).toEqual({ + headers: { 'Content-Type': 'dont-compress-this' }, + ...mockResponse.data, + }); + }); + + it('errors during API calls are properly handled', async () => { + // @ts-ignore + connector.request = mockError; + + await expect( + connector.streamApi( + { body: JSON.stringify(sampleOpenAiBody), stream: true }, + connectorUsageCollector + ) + ).rejects.toThrow('API Error'); + }); + }); + + describe('invokeStream', () => { + const mockStream = ( + dataToStream: string[] = [ + 'data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"My"}}]}\ndata: {"object":"chat.completion.chunk","choices":[{"delta":{"content":" new"}}]}', + ] + ) => { + const streamMock = createStreamMock(); + dataToStream.forEach((chunk) => { + streamMock.write(chunk); + }); + streamMock.complete(); + mockRequest = jest.fn().mockResolvedValue({ ...mockResponse, data: streamMock.transform }); + return mockRequest; + }; + beforeEach(() => { + // @ts-ignore + connector.request = mockStream(); + }); + + it('the API call is successful with correct request parameters', async () => { + await connector.invokeStream(sampleOpenAiBody, connectorUsageCollector); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'http://localhost:1234/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + }, + connectorUsageCollector + ); + }); + + it('signal is properly passed to streamApi', async () => { + const signal = jest.fn(); + await connector.invokeStream({ ...sampleOpenAiBody, signal }, connectorUsageCollector); + + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'http://localhost:1234/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + signal, + }, + connectorUsageCollector + ); + }); + + it('timeout is properly passed to streamApi', async () => { + const timeout = 180000; + await connector.invokeStream({ ...sampleOpenAiBody, timeout }, connectorUsageCollector); + + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'http://localhost:1234/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + timeout, + }, + connectorUsageCollector + ); + }); + + it('errors during API calls are properly handled', async () => { + // @ts-ignore + connector.request = mockError; + + await expect( + connector.invokeStream(sampleOpenAiBody, connectorUsageCollector) + ).rejects.toThrow('API Error'); + }); + + it('responds with a readable stream', async () => { + // @ts-ignore + connector.request = mockStream(); + const response = await connector.invokeStream(sampleOpenAiBody, connectorUsageCollector); + expect(response instanceof PassThrough).toEqual(true); + }); + }); + + describe('invokeAI', () => { + it('the API call is successful with correct parameters', async () => { + const response = await connector.invokeAI(sampleOpenAiBody, connectorUsageCollector); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + url: 'http://localhost:1234/v1/chat/completions', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OTHER_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + }, + connectorUsageCollector + ); + expect(response.message).toEqual(mockResponseString); + expect(response.usage.total_tokens).toEqual(9); + }); + + it('signal is properly passed to runApi', async () => { + const signal = jest.fn(); + await connector.invokeAI({ ...sampleOpenAiBody, signal }, connectorUsageCollector); + + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + url: 'http://localhost:1234/v1/chat/completions', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OTHER_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + signal, + }, + connectorUsageCollector + ); + }); + + it('timeout is properly passed to runApi', async () => { + const timeout = 180000; + await connector.invokeAI({ ...sampleOpenAiBody, timeout }, connectorUsageCollector); + + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + url: 'http://localhost:1234/v1/chat/completions', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OTHER_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + timeout, + }, + connectorUsageCollector + ); + }); + + it('errors during API calls are properly handled', async () => { + // @ts-ignore + connector.request = mockError; + + await expect(connector.invokeAI(sampleOpenAiBody, connectorUsageCollector)).rejects.toThrow( + 'API Error' + ); + }); + }); + }); + describe('AzureAI', () => { const connector = new OpenAIConnector({ configurationUtilities: actionsConfigMock.create(), diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 0de2cbd77db7b..0e5d4156d9760 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -73,6 +73,9 @@ }, "[OpenAI]": { "type": "long" + }, + "[Other]": { + "type": "long" } } }, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts index 05dfc61dd59e3..8a47b6a882456 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts @@ -147,7 +147,7 @@ export default function genAiTest({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'error validating action type config: types that failed validation:\n- [0.apiProvider]: expected at least one defined value but got [undefined]\n- [1.apiProvider]: expected at least one defined value but got [undefined]', + 'error validating action type config: types that failed validation:\n- [0.apiProvider]: expected at least one defined value but got [undefined]\n- [1.apiProvider]: expected at least one defined value but got [undefined]\n- [2.apiProvider]: expected at least one defined value but got [undefined]', }); }); }); @@ -168,7 +168,7 @@ export default function genAiTest({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'error validating action type config: types that failed validation:\n- [0.apiProvider]: expected value to equal [Azure OpenAI]\n- [1.apiUrl]: expected value of type [string] but got [undefined]', + 'error validating action type config: types that failed validation:\n- [0.apiProvider]: expected value to equal [Azure OpenAI]\n- [1.apiUrl]: expected value of type [string] but got [undefined]\n- [2.apiProvider]: expected value to equal [Other]', }); }); }); From d051743e6b4102323d4031113e35e90cdf9da512 Mon Sep 17 00:00:00 2001 From: Jon Date: Wed, 9 Oct 2024 18:29:09 -0500 Subject: [PATCH 097/110] [ci] Rebuild image after elasticsearch promotion (#195671) 1) After an elasticsearch image is promoted, this triggers a VM rebuild to update the snapshot cache 1) Moves elasticsearch builds to later in the day, when there's less activity. --- .../pipeline-resource-definitions/kibana-es-snapshots.yml | 8 ++++---- .buildkite/scripts/steps/es_snapshots/promote.sh | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml b/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml index 851862a613111..d386542fbdf0c 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml @@ -46,19 +46,19 @@ spec: access_level: MANAGE_BUILD_AND_READ schedules: Daily build (main): - cronline: 0 9 * * * America/New_York + cronline: 0 22 * * * America/New_York message: Daily build branch: main Daily build (8.x): - cronline: 0 9 * * * America/New_York + cronline: 0 22 * * * America/New_York message: Daily build branch: '8.x' Daily build (8.15): - cronline: 0 9 * * * America/New_York + cronline: 0 22 * * * America/New_York message: Daily build branch: '8.15' Daily build (7.17): - cronline: 0 9 * * * America/New_York + cronline: 0 22 * * * America/New_York message: Daily build branch: '7.17' tags: diff --git a/.buildkite/scripts/steps/es_snapshots/promote.sh b/.buildkite/scripts/steps/es_snapshots/promote.sh index cf52f5e9ff650..5654d7bd3b8d3 100755 --- a/.buildkite/scripts/steps/es_snapshots/promote.sh +++ b/.buildkite/scripts/steps/es_snapshots/promote.sh @@ -16,4 +16,12 @@ ts-node "$(dirname "${0}")/promote_manifest.ts" "$ES_SNAPSHOT_MANIFEST" if [[ "$BUILDKITE_BRANCH" == "main" ]]; then echo "--- Trigger agent packer cache pipeline" ts-node .buildkite/scripts/steps/trigger_pipeline.ts kibana-agent-packer-cache main + cat << EOF | buildkite-agent pipeline upload +steps: + - label: "Builds Kibana VM images for cache update" + trigger: ci-vm-images + build: + env: + IMAGES_CONFIG="kibana/images.yml" +EOF fi From 69ff471983a543c3052923e6b05385460079e45e Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Thu, 10 Oct 2024 01:49:36 +0200 Subject: [PATCH 098/110] [Security Solution][Notes] - limit visible text from note content on notes management page (#195296) --- .../notes/components/note_content.test.tsx | 28 +++++++ .../public/notes/components/note_content.tsx | 73 +++++++++++++++++++ .../public/notes/components/test_ids.ts | 2 + .../notes/pages/note_management_page.tsx | 2 + 4 files changed, 105 insertions(+) create mode 100644 x-pack/plugins/security_solution/public/notes/components/note_content.test.tsx create mode 100644 x-pack/plugins/security_solution/public/notes/components/note_content.tsx diff --git a/x-pack/plugins/security_solution/public/notes/components/note_content.test.tsx b/x-pack/plugins/security_solution/public/notes/components/note_content.test.tsx new file mode 100644 index 0000000000000..6cc9d33d886b7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/notes/components/note_content.test.tsx @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render } from '@testing-library/react'; +import React from 'react'; +import { NoteContent } from './note_content'; +import { NOTE_CONTENT_BUTTON_TEST_ID, NOTE_CONTENT_POPOVER_TEST_ID } from './test_ids'; + +const note = 'note-text'; + +describe('NoteContent', () => { + it('should render a note and the popover', () => { + const { getByTestId, getByText } = render(); + + const button = getByTestId(NOTE_CONTENT_BUTTON_TEST_ID); + + expect(button).toBeInTheDocument(); + expect(getByText(note)).toBeInTheDocument(); + + button.click(); + + expect(getByTestId(NOTE_CONTENT_POPOVER_TEST_ID)).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/notes/components/note_content.tsx b/x-pack/plugins/security_solution/public/notes/components/note_content.tsx new file mode 100644 index 0000000000000..ba8710e85c215 --- /dev/null +++ b/x-pack/plugins/security_solution/public/notes/components/note_content.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo, useCallback, useMemo, useState } from 'react'; +import { EuiButtonEmpty, EuiMarkdownFormat, EuiPopover, useEuiTheme } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { css } from '@emotion/react'; +import { NOTE_CONTENT_BUTTON_TEST_ID, NOTE_CONTENT_POPOVER_TEST_ID } from './test_ids'; + +const OPEN_POPOVER = i18n.translate('xpack.securitySolution.notes.expandRow.buttonLabel', { + defaultMessage: 'Expand', +}); + +export interface NoteContentProps { + /** + * The note content to display + */ + note: string; +} + +/** + * Renders the note content to be displayed in the notes management table. + * The content is truncated with an expand button to show the full content within the row. + */ +export const NoteContent = memo(({ note }: NoteContentProps) => { + const { euiTheme } = useEuiTheme(); + + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const togglePopover = useCallback(() => setIsPopoverOpen((value) => !value), []); + const closePopover = useCallback(() => setIsPopoverOpen(false), []); + + const button = useMemo( + () => ( + + {note} + + ), + [euiTheme.size.l, note, togglePopover] + ); + + return ( + + + {note} + + + ); +}); + +NoteContent.displayName = 'NoteContent'; diff --git a/x-pack/plugins/security_solution/public/notes/components/test_ids.ts b/x-pack/plugins/security_solution/public/notes/components/test_ids.ts index 6c63a43f365ac..ac4eeb1948748 100644 --- a/x-pack/plugins/security_solution/public/notes/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/notes/components/test_ids.ts @@ -17,3 +17,5 @@ export const DELETE_NOTE_BUTTON_TEST_ID = `${PREFIX}DeleteNotesButton` as const; export const OPEN_TIMELINE_BUTTON_TEST_ID = `${PREFIX}OpenTimelineButton` as const; export const OPEN_FLYOUT_BUTTON_TEST_ID = `${PREFIX}OpenFlyoutButton` as const; export const TIMELINE_DESCRIPTION_COMMENT_TEST_ID = `${PREFIX}TimelineDescriptionComment` as const; +export const NOTE_CONTENT_BUTTON_TEST_ID = `${PREFIX}NoteContentButton` as const; +export const NOTE_CONTENT_POPOVER_TEST_ID = `${PREFIX}NoteContentPopover` as const; diff --git a/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx b/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx index 9c2900ca4d599..2b7f0f690532c 100644 --- a/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx +++ b/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx @@ -44,6 +44,7 @@ import { DeleteConfirmModal } from '../components/delete_confirm_modal'; import * as i18n from './translations'; import { OpenFlyoutButtonIcon } from '../components/open_flyout_button'; import { OpenTimelineButtonIcon } from '../components/open_timeline_button'; +import { NoteContent } from '../components/note_content'; const columns: Array> = [ { @@ -94,6 +95,7 @@ const columns: Array> = [ { field: 'note', name: i18n.NOTE_CONTENT_COLUMN, + render: (note: Note['note']) => <>{note && }, }, { field: 'created', From 65ed9899de2733ec7017ef7277bd24723131684a Mon Sep 17 00:00:00 2001 From: Yara Tercero Date: Wed, 9 Oct 2024 17:14:03 -0700 Subject: [PATCH 099/110] [Detection Engine] Remove technical preview for certain rule types of alert suppression (#195425) ## Summary GA-ing alert suppression for IM rule, ML rule, Threshold rule, ES|QL rule and New Terms rule. Thanks to @vitaliidm for setting up the groundwork to easily update which rules GA. Rules that remain in technical preview are: EQL. --- .../common/detection_engine/constants.ts | 10 +++++++++- .../common/detection_engine/utils.test.ts | 10 +++++----- .../components/step_define_rule/translations.tsx | 8 ++++---- x-pack/plugins/translations/translations/fr-FR.json | 2 -- x-pack/plugins/translations/translations/ja-JP.json | 2 -- x-pack/plugins/translations/translations/zh-CN.json | 2 -- .../indicator_match_rule_suppression.cy.ts | 4 ---- .../indicator_match_rule_suppression_ess_basic.cy.ts | 4 ---- .../machine_learning_rule_suppression.cy.ts | 7 ------- .../detection_engine/rule_edit/esql_rule.cy.ts | 4 ---- .../rule_edit/indicator_match_rule.cy.ts | 4 ---- .../rule_edit/machine_learning_rule.cy.ts | 4 ---- .../detection_engine/rule_edit/threshold_rule.cy.ts | 3 --- 13 files changed, 18 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/constants.ts b/x-pack/plugins/security_solution/common/detection_engine/constants.ts index 7057e3c8b3091..270af1a91cf46 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/constants.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/constants.ts @@ -51,4 +51,12 @@ export const SUPPRESSIBLE_ALERT_RULES: Type[] = [ 'machine_learning', ]; -export const SUPPRESSIBLE_ALERT_RULES_GA: Type[] = ['saved_query', 'query']; +export const SUPPRESSIBLE_ALERT_RULES_GA: Type[] = [ + 'threshold', + 'esql', + 'saved_query', + 'query', + 'new_terms', + 'threat_match', + 'machine_learning', +]; diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.test.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.test.ts index a4db006a67463..be0b6ce9c2927 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.test.ts @@ -250,14 +250,14 @@ describe('Alert Suppression Rules', () => { test('should return true for rule type suppression in global availability', () => { expect(isSuppressionRuleInGA('saved_query')).toBe(true); expect(isSuppressionRuleInGA('query')).toBe(true); + expect(isSuppressionRuleInGA('esql')).toBe(true); + expect(isSuppressionRuleInGA('threshold')).toBe(true); + expect(isSuppressionRuleInGA('threat_match')).toBe(true); + expect(isSuppressionRuleInGA('new_terms')).toBe(true); + expect(isSuppressionRuleInGA('machine_learning')).toBe(true); }); test('should return false for rule type suppression in tech preview', () => { - expect(isSuppressionRuleInGA('machine_learning')).toBe(false); - expect(isSuppressionRuleInGA('esql')).toBe(false); - expect(isSuppressionRuleInGA('threshold')).toBe(false); - expect(isSuppressionRuleInGA('threat_match')).toBe(false); - expect(isSuppressionRuleInGA('new_terms')).toBe(false); expect(isSuppressionRuleInGA('eql')).toBe(false); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/translations.tsx index 7d7bb9c4a9253..b212aa7c67dd4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/translations.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/translations.tsx @@ -205,15 +205,15 @@ export const THRESHOLD_SUPPRESSION_PER_RULE_EXECUTION_WARNING = i18n.translate( export const getEnableThresholdSuppressionLabel = (fields: string[] | undefined) => fields?.length ? ( {fields.join(', ')} }} /> ) : ( i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.enableThresholdSuppressionLabel', + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.ga.enableThresholdSuppressionLabel', { - defaultMessage: 'Suppress alerts (Technical Preview)', + defaultMessage: 'Suppress alerts', } ) ); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 9aa58bd4f5286..c6f8753f75b9e 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -36129,8 +36129,6 @@ "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.customThreatQueryFieldRequiredEmptyError": "Toutes les correspondances requièrent un champ et un champ d'index des menaces.", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.customThreatQueryFieldRequiredError": "Au moins une correspondance d'indicateur est requise.", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.dataViewSelectorFieldRequired": "Veuillez sélectionner une vue des données ou un modèle d'index disponible.", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.enableThresholdSuppressionForFieldsLabel": "Supprimer les alertes par champs sélectionnés : {fieldsString} (version d'évaluation technique)", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.enableThresholdSuppressionLabel": "Supprimer les alertes (version d'évaluation technique)", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.EqlQueryBarLabel": "Requête EQL", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlQueryFieldRequiredError": "Une requête EQL est requise.", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlSequenceSuppressionDisableText": "La suppression n'est pas prise en charge pour les requêtes de séquence EQL.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 72afb1947e928..19a01d7325113 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -35873,8 +35873,6 @@ "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.customThreatQueryFieldRequiredEmptyError": "すべての一致には、フィールドと脅威インデックスフィールドの両方が必要です。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.customThreatQueryFieldRequiredError": "1 つ以上のインジケーター一致が必要です。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.dataViewSelectorFieldRequired": "使用可能なデータビューまたはインデックスパターンを選択してください。", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.enableThresholdSuppressionForFieldsLabel": "選択したフィールドでアラートを非表示:{fieldsString}(テクニカルプレビュー)", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.enableThresholdSuppressionLabel": "アラートを抑制(テクニカルプレビュー)", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.EqlQueryBarLabel": "EQL クエリ", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlQueryFieldRequiredError": "EQLクエリは必須です。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlSequenceSuppressionDisableText": "EQLシーケンスクエリでは抑制はサポートされていません。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index c27a5241e5a33..30ac0196e8993 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -35917,8 +35917,6 @@ "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.customThreatQueryFieldRequiredEmptyError": "所有匹配项都需要字段和威胁索引字段。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.customThreatQueryFieldRequiredError": "至少需要一个指标匹配。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.dataViewSelectorFieldRequired": "请选择可用的数据视图或索引模式。", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.enableThresholdSuppressionForFieldsLabel": "选定字段阻止告警:{fieldsString}(技术预览)", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.enableThresholdSuppressionLabel": "阻止告警(技术预览)", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.EqlQueryBarLabel": "EQL 查询", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlQueryFieldRequiredError": "EQL 查询必填。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlSequenceSuppressionDisableText": "EQL 序列查询不支持阻止。", diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule_suppression.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule_suppression.cy.ts index 42fb37184da1c..d0539683e5a64 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule_suppression.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule_suppression.cy.ts @@ -12,7 +12,6 @@ import { SUPPRESS_FOR_DETAILS, SUPPRESS_BY_DETAILS, SUPPRESS_MISSING_FIELD, - DETAILS_TITLE, } from '../../../../screens/rule_details'; import { @@ -67,9 +66,6 @@ describe( 'have.text', 'Suppress and group alerts for events with missing fields' ); - - // suppression functionality should be under Tech Preview - cy.contains(DETAILS_TITLE, SUPPRESS_FOR_DETAILS).contains('Technical Preview'); }); fillAboutRuleMinimumAndContinue(rule); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule_suppression_ess_basic.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule_suppression_ess_basic.cy.ts index dd3c086224e49..6223ac017281d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule_suppression_ess_basic.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule_suppression_ess_basic.cy.ts @@ -9,7 +9,6 @@ import { getNewThreatIndicatorRule } from '../../../../objects/rule'; import { SUPPRESS_FOR_DETAILS, - DETAILS_TITLE, SUPPRESS_BY_DETAILS, SUPPRESS_MISSING_FIELD, DEFINITION_DETAILS, @@ -62,9 +61,6 @@ describe( 'have.text', 'Do not suppress alerts for events with missing fields' ); - - // suppression functionality should be under Tech Preview - cy.contains(DETAILS_TITLE, SUPPRESS_FOR_DETAILS).contains('Technical Preview'); }); // Platinum license is required for configuration to apply diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/machine_learning_rule_suppression.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/machine_learning_rule_suppression.cy.ts index c38a6ef43150a..45ccc2c5aba8d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/machine_learning_rule_suppression.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/machine_learning_rule_suppression.cy.ts @@ -13,7 +13,6 @@ import { } from '../../../../screens/create_new_rule'; import { DEFINITION_DETAILS, - DETAILS_TITLE, SUPPRESS_BY_DETAILS, SUPPRESS_FOR_DETAILS, SUPPRESS_MISSING_FIELD, @@ -129,9 +128,6 @@ describe( 'have.text', 'Suppress and group alerts for events with missing fields' ); - - // suppression functionality should be under Tech Preview - cy.contains(DETAILS_TITLE, SUPPRESS_FOR_DETAILS).contains('Technical Preview'); }); fillAboutRuleMinimumAndContinue(mlRule); @@ -163,9 +159,6 @@ describe( 'have.text', 'Do not suppress alerts for events with missing fields' ); - - // suppression functionality should be under Tech Preview - cy.contains(DETAILS_TITLE, SUPPRESS_FOR_DETAILS).contains('Technical Preview'); }); fillAboutRuleMinimumAndContinue(mlRule); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/esql_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/esql_rule.cy.ts index 511ea42c06767..9fa45987407f0 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/esql_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/esql_rule.cy.ts @@ -14,7 +14,6 @@ import { DEFINITION_DETAILS, SUPPRESS_MISSING_FIELD, SUPPRESS_BY_DETAILS, - DETAILS_TITLE, } from '../../../../screens/rule_details'; import { @@ -191,9 +190,6 @@ describe( 'have.text', 'Suppress and group alerts for events with missing fields' ); - - // suppression functionality should be under Tech Preview - cy.contains(DETAILS_TITLE, SUPPRESS_FOR_DETAILS).contains('Technical Preview'); }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/indicator_match_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/indicator_match_rule.cy.ts index 62d9a95398797..fe616f6ba1969 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/indicator_match_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/indicator_match_rule.cy.ts @@ -9,7 +9,6 @@ import { getNewThreatIndicatorRule } from '../../../../objects/rule'; import { SUPPRESS_FOR_DETAILS, - DETAILS_TITLE, SUPPRESS_BY_DETAILS, SUPPRESS_MISSING_FIELD, DEFINITION_DETAILS, @@ -81,9 +80,6 @@ describe( 'have.text', 'Suppress and group alerts for events with missing fields' ); - - // suppression functionality should be under Tech Preview - cy.contains(DETAILS_TITLE, SUPPRESS_FOR_DETAILS).contains('Technical Preview'); }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/machine_learning_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/machine_learning_rule.cy.ts index e89e4b6afb817..7410d9fefae6d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/machine_learning_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/machine_learning_rule.cy.ts @@ -13,7 +13,6 @@ import { } from '../../../../screens/create_new_rule'; import { DEFINITION_DETAILS, - DETAILS_TITLE, SUPPRESS_BY_DETAILS, SUPPRESS_FOR_DETAILS, SUPPRESS_MISSING_FIELD, @@ -88,9 +87,6 @@ describe( 'have.text', 'Suppress and group alerts for events with missing fields' ); - - // suppression functionality should be under Tech Preview - cy.contains(DETAILS_TITLE, SUPPRESS_FOR_DETAILS).contains('Technical Preview'); }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/threshold_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/threshold_rule.cy.ts index 8d4bdf2d34976..dcc35a9e00080 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/threshold_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/threshold_rule.cy.ts @@ -9,7 +9,6 @@ import { getNewThresholdRule } from '../../../../objects/rule'; import { SUPPRESS_FOR_DETAILS, - DETAILS_TITLE, SUPPRESS_BY_DETAILS, SUPPRESS_MISSING_FIELD, } from '../../../../screens/rule_details'; @@ -63,8 +62,6 @@ describe( // ensure typed interval is displayed on details page getDetails(SUPPRESS_FOR_DETAILS).should('have.text', '60m'); - // suppression functionality should be under Tech Preview - cy.contains(DETAILS_TITLE, SUPPRESS_FOR_DETAILS).contains('Technical Preview'); // the rest of suppress properties do not exist for threshold rule assertDetailsNotExist(SUPPRESS_BY_DETAILS); From b51ba0a27c852f967b922130d01ac7cf2ec11d64 Mon Sep 17 00:00:00 2001 From: Paulo Silva Date: Wed, 9 Oct 2024 17:36:33 -0700 Subject: [PATCH 100/110] fix flaky test with timestamp (#195681) ## Summary It fixes the flaky test raised on #195634 by adding the possibility to pass the timestamp to the function. That helps to eliminate flakiness, by passing the same `currentTimestamp` to both the test and the function. Also, it's a simpler approach that doesn't require mocking global objects or using Jest's fake timers, keeping your test straightforward and easy to understand. --- .../create_detection_rule_from_vulnerability.test.ts | 2 +- .../utils/create_detection_rule_from_vulnerability.ts | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts index 209ec81168271..7dd0982cc58b5 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts @@ -89,7 +89,7 @@ describe('CreateDetectionRuleFromVulnerability', () => { } as Vulnerability; const currentTimestamp = new Date().toISOString(); - const query = generateVulnerabilitiesRuleQuery(mockVulnerability); + const query = generateVulnerabilitiesRuleQuery(mockVulnerability, currentTimestamp); expect(query).toEqual( `vulnerability.id: "CVE-2024-00005" AND event.ingested >= "${currentTimestamp}"` ); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts index b723c60f9ee3d..804e89fad61d8 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts @@ -53,10 +53,11 @@ export const getVulnerabilityRuleName = (vulnerability: Vulnerability) => { }); }; -export const generateVulnerabilitiesRuleQuery = (vulnerability: Vulnerability) => { - const currentTimestamp = new Date().toISOString(); - - return `vulnerability.id: "${vulnerability.id}" AND event.ingested >= "${currentTimestamp}"`; +export const generateVulnerabilitiesRuleQuery = ( + vulnerability: Vulnerability, + startTimestamp = new Date().toISOString() +) => { + return `vulnerability.id: "${vulnerability.id}" AND event.ingested >= "${startTimestamp}"`; }; const CSP_RULE_TAG = 'Cloud Security'; From 447617e2be18cbf8fdd495cb4b9570921b7fd467 Mon Sep 17 00:00:00 2001 From: Jiawei Wu <74562234+JiaweiWu@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:01:58 -0700 Subject: [PATCH 101/110] [ResponseOps][Flapping] Add Rule Specific Flapping Form to New Rule Form Page (#194516) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Depends on: https://github.com/elastic/kibana/pull/194086 Designs: https://www.figma.com/design/eTr6WsKzhSLcQ24AlgrY8R/Flapping-per-Rule--%3E-%23294?node-id=5265-29867&node-type=frame&t=1VfgdlcjkSHmpbje-0 Adds the rule specific flapping form to the new rule form page. ## To test: 1. change `IS_RULE_SPECIFIC_FLAPPING_ENABLED` to true 2. run `yarn start --run-examples` 3. assert the new flapping UI exists by going to developer examples -> create/edit rule Screenshot 2024-09-30 at 11 43 16 PM ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine --- packages/kbn-alerting-types/index.ts | 1 + packages/kbn-alerting-types/rule_settings.ts | 46 ++ .../fetch_flapping_settings.test.ts | 44 ++ .../fetch_flapping_settings.ts | 21 + .../apis/fetch_flapping_settings/index.ts | 10 + ...ansform_flapping_settings_response.test.ts | 36 ++ .../transform_flapping_settings_response.ts | 29 ++ .../src/common/constants/rule_flapping.ts | 11 + .../use_fetch_flapping_settings.test.tsx | 106 +++++ .../hooks/use_fetch_flapping_settings.ts | 43 ++ .../src/rule_form/create_rule_form.tsx | 3 + .../src/rule_form/edit_rule_form.tsx | 3 + .../hooks/use_load_dependencies.test.tsx | 20 + .../rule_form/hooks/use_load_dependencies.ts | 18 + .../rule_definition/rule_definition.test.tsx | 133 ++++++ .../rule_definition/rule_definition.tsx | 62 ++- .../src/rule_form/translations.ts | 15 + .../src/rule_form/types.ts | 4 +- .../rule_settings_flapping_form.tsx | 318 +++++++++++++ .../rule_settings_flapping_message.tsx | 31 +- .../rule_settings_flapping_title_tooltip.tsx | 140 ++++++ .../plugins/alerting/common/rules_settings.ts | 50 +-- .../rules_settings_flapping_form_section.tsx | 1 + .../rules_settings_link.test.tsx | 12 +- .../rules_settings_modal.test.tsx | 18 +- .../rules_setting/rules_settings_modal.tsx | 6 +- .../hooks/use_get_flapping_settings.ts | 41 -- .../lib/rule_api/get_flapping_settings.ts | 28 -- .../sections/rule_form/rule_add.test.tsx | 4 +- .../sections/rule_form/rule_add.tsx | 2 +- .../sections/rule_form/rule_edit.test.tsx | 4 +- .../sections/rule_form/rule_edit.tsx | 2 +- .../sections/rule_form/rule_form.test.tsx | 4 +- .../sections/rule_form/rule_form.tsx | 9 +- .../rule_form_advanced_options.test.tsx | 8 +- .../rule_form/rule_form_advanced_options.tsx | 416 +----------------- .../public/common/constants/index.ts | 3 - 37 files changed, 1162 insertions(+), 540 deletions(-) create mode 100644 packages/kbn-alerting-types/rule_settings.ts create mode 100644 packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/fetch_flapping_settings.test.ts create mode 100644 packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/fetch_flapping_settings.ts create mode 100644 packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/index.ts create mode 100644 packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/transform_flapping_settings_response.test.ts create mode 100644 packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/transform_flapping_settings_response.ts create mode 100644 packages/kbn-alerts-ui-shared/src/common/constants/rule_flapping.ts create mode 100644 packages/kbn-alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings.test.tsx create mode 100644 packages/kbn-alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings.ts create mode 100644 packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_form.tsx create mode 100644 packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_title_tooltip.tsx delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_flapping_settings.ts delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_flapping_settings.ts diff --git a/packages/kbn-alerting-types/index.ts b/packages/kbn-alerting-types/index.ts index 0a930e6a9319c..b2288900a1248 100644 --- a/packages/kbn-alerting-types/index.ts +++ b/packages/kbn-alerting-types/index.ts @@ -18,4 +18,5 @@ export * from './r_rule_types'; export * from './rule_notify_when_type'; export * from './rule_type_types'; export * from './rule_types'; +export * from './rule_settings'; export * from './search_strategy_types'; diff --git a/packages/kbn-alerting-types/rule_settings.ts b/packages/kbn-alerting-types/rule_settings.ts new file mode 100644 index 0000000000000..b25ad201c2dc0 --- /dev/null +++ b/packages/kbn-alerting-types/rule_settings.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export interface RulesSettingsModificationMetadata { + createdBy: string | null; + updatedBy: string | null; + createdAt: string; + updatedAt: string; +} + +export interface RulesSettingsFlappingProperties { + enabled: boolean; + lookBackWindow: number; + statusChangeThreshold: number; +} + +export interface RuleSpecificFlappingProperties { + lookBackWindow: number; + statusChangeThreshold: number; +} + +export type RulesSettingsFlapping = RulesSettingsFlappingProperties & + RulesSettingsModificationMetadata; + +export interface RulesSettingsQueryDelayProperties { + delay: number; +} + +export type RulesSettingsQueryDelay = RulesSettingsQueryDelayProperties & + RulesSettingsModificationMetadata; + +export interface RulesSettingsProperties { + flapping?: RulesSettingsFlappingProperties; + queryDelay?: RulesSettingsQueryDelayProperties; +} + +export interface RulesSettings { + flapping?: RulesSettingsFlapping; + queryDelay?: RulesSettingsQueryDelay; +} diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/fetch_flapping_settings.test.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/fetch_flapping_settings.test.ts new file mode 100644 index 0000000000000..d5feaa731335a --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/fetch_flapping_settings.test.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { httpServiceMock } from '@kbn/core/public/mocks'; +import { fetchFlappingSettings } from './fetch_flapping_settings'; + +const http = httpServiceMock.createStartContract(); + +describe('fetchFlappingSettings', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + test('should call fetch rule flapping API', async () => { + const now = new Date().toISOString(); + http.get.mockResolvedValue({ + created_by: 'test', + updated_by: 'test', + created_at: now, + updated_at: now, + enabled: true, + look_back_window: 20, + status_change_threshold: 20, + }); + + const result = await fetchFlappingSettings({ http }); + + expect(result).toEqual({ + createdBy: 'test', + updatedBy: 'test', + createdAt: now, + updatedAt: now, + enabled: true, + lookBackWindow: 20, + statusChangeThreshold: 20, + }); + }); +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/fetch_flapping_settings.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/fetch_flapping_settings.ts new file mode 100644 index 0000000000000..6ad702ebc945e --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/fetch_flapping_settings.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { HttpSetup } from '@kbn/core/public'; +import { AsApiContract } from '@kbn/actions-types'; +import { RulesSettingsFlapping } from '@kbn/alerting-types'; +import { INTERNAL_BASE_ALERTING_API_PATH } from '../../constants'; +import { transformFlappingSettingsResponse } from './transform_flapping_settings_response'; + +export const fetchFlappingSettings = async ({ http }: { http: HttpSetup }) => { + const res = await http.get>( + `${INTERNAL_BASE_ALERTING_API_PATH}/rules/settings/_flapping` + ); + return transformFlappingSettingsResponse(res); +}; diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/index.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/index.ts new file mode 100644 index 0000000000000..68ff193255403 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export * from './fetch_flapping_settings'; diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/transform_flapping_settings_response.test.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/transform_flapping_settings_response.test.ts new file mode 100644 index 0000000000000..e53d133f6838b --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/transform_flapping_settings_response.test.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { transformFlappingSettingsResponse } from './transform_flapping_settings_response'; + +describe('transformFlappingSettingsResponse', () => { + test('should transform flapping settings response', () => { + const now = new Date().toISOString(); + + const result = transformFlappingSettingsResponse({ + created_by: 'test', + updated_by: 'test', + created_at: now, + updated_at: now, + enabled: true, + look_back_window: 20, + status_change_threshold: 20, + }); + + expect(result).toEqual({ + createdBy: 'test', + updatedBy: 'test', + createdAt: now, + updatedAt: now, + enabled: true, + lookBackWindow: 20, + statusChangeThreshold: 20, + }); + }); +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/transform_flapping_settings_response.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/transform_flapping_settings_response.ts new file mode 100644 index 0000000000000..a628829927a3b --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_flapping_settings/transform_flapping_settings_response.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { AsApiContract } from '@kbn/actions-types'; +import { RulesSettingsFlapping } from '@kbn/alerting-types'; + +export const transformFlappingSettingsResponse = ({ + look_back_window: lookBackWindow, + status_change_threshold: statusChangeThreshold, + created_at: createdAt, + created_by: createdBy, + updated_at: updatedAt, + updated_by: updatedBy, + ...rest +}: AsApiContract): RulesSettingsFlapping => ({ + ...rest, + lookBackWindow, + statusChangeThreshold, + createdAt, + createdBy, + updatedAt, + updatedBy, +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/constants/rule_flapping.ts b/packages/kbn-alerts-ui-shared/src/common/constants/rule_flapping.ts new file mode 100644 index 0000000000000..49ea5a63b3fca --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/constants/rule_flapping.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +// Feature flag for frontend rule specific flapping in rule flyout +export const IS_RULE_SPECIFIC_FLAPPING_ENABLED = false; diff --git a/packages/kbn-alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings.test.tsx b/packages/kbn-alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings.test.tsx new file mode 100644 index 0000000000000..10e1869b9e64c --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings.test.tsx @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React, { FunctionComponent } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { renderHook } from '@testing-library/react-hooks'; +import { testQueryClientConfig } from '../test_utils/test_query_client_config'; +import { useFetchFlappingSettings } from './use_fetch_flapping_settings'; +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; + +const queryClient = new QueryClient(testQueryClientConfig); + +const wrapper: FunctionComponent> = ({ children }) => ( + {children} +); + +const http = httpServiceMock.createStartContract(); + +const now = new Date().toISOString(); + +describe('useFetchFlappingSettings', () => { + beforeEach(() => { + http.get.mockResolvedValue({ + created_by: 'test', + updated_by: 'test', + created_at: now, + updated_at: now, + enabled: true, + look_back_window: 20, + status_change_threshold: 20, + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + queryClient.clear(); + }); + + test('should call fetchFlappingSettings with the correct parameters', async () => { + const { result, waitFor } = renderHook( + () => useFetchFlappingSettings({ http, enabled: true }), + { + wrapper, + } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(result.current.data).toEqual({ + createdAt: now, + createdBy: 'test', + updatedAt: now, + updatedBy: 'test', + enabled: true, + lookBackWindow: 20, + statusChangeThreshold: 20, + }); + }); + + test('should not call fetchFlappingSettings if enabled is false', async () => { + const { result, waitFor } = renderHook( + () => useFetchFlappingSettings({ http, enabled: false }), + { + wrapper, + } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(http.get).not.toHaveBeenCalled(); + }); + + test('should call onSuccess when the fetching was successful', async () => { + const onSuccessMock = jest.fn(); + const { result, waitFor } = renderHook( + () => useFetchFlappingSettings({ http, enabled: true, onSuccess: onSuccessMock }), + { + wrapper, + } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(onSuccessMock).toHaveBeenCalledWith({ + createdAt: now, + createdBy: 'test', + updatedAt: now, + updatedBy: 'test', + enabled: true, + lookBackWindow: 20, + statusChangeThreshold: 20, + }); + }); +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings.ts b/packages/kbn-alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings.ts new file mode 100644 index 0000000000000..6b72c2fea734b --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { useQuery } from '@tanstack/react-query'; +import { HttpStart } from '@kbn/core-http-browser'; +import { RulesSettingsFlapping } from '@kbn/alerting-types/rule_settings'; +import { fetchFlappingSettings } from '../apis/fetch_flapping_settings'; + +interface UseFetchFlappingSettingsProps { + http: HttpStart; + enabled: boolean; + onSuccess?: (settings: RulesSettingsFlapping) => void; +} + +export const useFetchFlappingSettings = (props: UseFetchFlappingSettingsProps) => { + const { http, enabled, onSuccess } = props; + + const queryFn = () => { + return fetchFlappingSettings({ http }); + }; + + const { data, isFetching, isError, isLoadingError, isLoading, isInitialLoading } = useQuery({ + queryKey: ['fetchFlappingSettings'], + queryFn, + onSuccess, + enabled, + refetchOnWindowFocus: false, + retry: false, + }); + + return { + isInitialLoading, + isLoading: isLoading || isFetching, + isError: isError || isLoadingError, + data, + }; +}; diff --git a/packages/kbn-alerts-ui-shared/src/rule_form/create_rule_form.tsx b/packages/kbn-alerts-ui-shared/src/rule_form/create_rule_form.tsx index 71aeb2bcaab77..fc96ae214a7a8 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_form/create_rule_form.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_form/create_rule_form.tsx @@ -92,6 +92,7 @@ export const CreateRuleForm = (props: CreateRuleFormProps) => { connectors, connectorTypes, aadTemplateFields, + flappingSettings, } = useLoadDependencies({ http, toasts: notifications.toasts, @@ -117,6 +118,7 @@ export const CreateRuleForm = (props: CreateRuleFormProps) => { actions: newFormData.actions, notifyWhen: newFormData.notifyWhen, alertDelay: newFormData.alertDelay, + flapping: newFormData.flapping, }, }); }, @@ -173,6 +175,7 @@ export const CreateRuleForm = (props: CreateRuleFormProps) => { selectedRuleTypeModel: ruleTypeModel, selectedRuleType: ruleType, validConsumers, + flappingSettings, canShowConsumerSelection, showMustacheAutocompleteSwitch, multiConsumerSelection: getInitialMultiConsumer({ diff --git a/packages/kbn-alerts-ui-shared/src/rule_form/edit_rule_form.tsx b/packages/kbn-alerts-ui-shared/src/rule_form/edit_rule_form.tsx index 5091444276873..6e92b94cc2e0d 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_form/edit_rule_form.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_form/edit_rule_form.tsx @@ -69,6 +69,7 @@ export const EditRuleForm = (props: EditRuleFormProps) => { connectors, connectorTypes, aadTemplateFields, + flappingSettings, } = useLoadDependencies({ http, toasts: notifications.toasts, @@ -89,6 +90,7 @@ export const EditRuleForm = (props: EditRuleFormProps) => { actions: newFormData.actions, notifyWhen: newFormData.notifyWhen, alertDelay: newFormData.alertDelay, + flapping: newFormData.flapping, }, }); }, @@ -160,6 +162,7 @@ export const EditRuleForm = (props: EditRuleFormProps) => { minimumScheduleInterval: uiConfig?.minimumScheduleInterval, selectedRuleType: ruleType, selectedRuleTypeModel: ruleTypeModel, + flappingSettings, showMustacheAutocompleteSwitch, }} > diff --git a/packages/kbn-alerts-ui-shared/src/rule_form/hooks/use_load_dependencies.test.tsx b/packages/kbn-alerts-ui-shared/src/rule_form/hooks/use_load_dependencies.test.tsx index 263c9e2118056..9d2ce3b6f1211 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_form/hooks/use_load_dependencies.test.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_form/hooks/use_load_dependencies.test.tsx @@ -50,6 +50,10 @@ jest.mock('../utils/get_authorized_rule_types', () => ({ getAvailableRuleTypes: jest.fn(), })); +jest.mock('../../common/hooks/use_fetch_flapping_settings', () => ({ + useFetchFlappingSettings: jest.fn(), +})); + const { useLoadUiConfig } = jest.requireMock('../../common/hooks/use_load_ui_config'); const { useHealthCheck } = jest.requireMock('../../common/hooks/use_health_check'); const { useResolveRule } = jest.requireMock('../../common/hooks/use_resolve_rule'); @@ -60,6 +64,9 @@ const { useLoadRuleTypeAadTemplateField } = jest.requireMock( ); const { useLoadRuleTypesQuery } = jest.requireMock('../../common/hooks/use_load_rule_types_query'); const { getAvailableRuleTypes } = jest.requireMock('../utils/get_authorized_rule_types'); +const { useFetchFlappingSettings } = jest.requireMock( + '../../common/hooks/use_fetch_flapping_settings' +); const uiConfigMock = { isUsingSecurity: true, @@ -103,6 +110,15 @@ useResolveRule.mockReturnValue({ data: ruleMock, }); +useFetchFlappingSettings.mockReturnValue({ + isLoading: false, + isInitialLoading: false, + data: { + lookBackWindow: 20, + statusChangeThreshold: 20, + }, +}); + const indexThresholdRuleType = { enabledInLicense: true, recoveryActionGroup: { @@ -260,6 +276,10 @@ describe('useLoadDependencies', () => { uiConfig: uiConfigMock, healthCheckError: null, fetchedFormData: ruleMock, + flappingSettings: { + lookBackWindow: 20, + statusChangeThreshold: 20, + }, connectors: [mockConnector], connectorTypes: [mockConnectorType], aadTemplateFields: [mockAadTemplateField], diff --git a/packages/kbn-alerts-ui-shared/src/rule_form/hooks/use_load_dependencies.ts b/packages/kbn-alerts-ui-shared/src/rule_form/hooks/use_load_dependencies.ts index da59e85a933a1..5e0c52b1089ba 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_form/hooks/use_load_dependencies.ts +++ b/packages/kbn-alerts-ui-shared/src/rule_form/hooks/use_load_dependencies.ts @@ -22,6 +22,8 @@ import { } from '../../common/hooks'; import { getAvailableRuleTypes } from '../utils'; import { RuleTypeRegistryContract } from '../../common'; +import { useFetchFlappingSettings } from '../../common/hooks/use_fetch_flapping_settings'; +import { IS_RULE_SPECIFIC_FLAPPING_ENABLED } from '../../common/constants/rule_flapping'; import { useLoadRuleTypeAadTemplateField } from '../../common/hooks/use_load_rule_type_aad_template_fields'; export interface UseLoadDependencies { @@ -81,6 +83,15 @@ export const useLoadDependencies = (props: UseLoadDependencies) => { filteredRuleTypes, }); + const { + data: flappingSettings, + isLoading: isLoadingFlappingSettings, + isInitialLoading: isInitialLoadingFlappingSettings, + } = useFetchFlappingSettings({ + http, + enabled: IS_RULE_SPECIFIC_FLAPPING_ENABLED, + }); + const { data: connectors = [], isLoading: isLoadingConnectors, @@ -144,6 +155,7 @@ export const useLoadDependencies = (props: UseLoadDependencies) => { isLoadingUiConfig || isLoadingHealthCheck || isLoadingRuleTypes || + isLoadingFlappingSettings || isLoadingConnectors || isLoadingConnectorTypes || isLoadingAadtemplateFields @@ -156,6 +168,7 @@ export const useLoadDependencies = (props: UseLoadDependencies) => { isLoadingHealthCheck || isLoadingRule || isLoadingRuleTypes || + isLoadingFlappingSettings || isLoadingConnectors || isLoadingConnectorTypes || isLoadingAadtemplateFields @@ -166,6 +179,7 @@ export const useLoadDependencies = (props: UseLoadDependencies) => { isLoadingHealthCheck, isLoadingRule, isLoadingRuleTypes, + isLoadingFlappingSettings, isLoadingConnectors, isLoadingConnectorTypes, isLoadingAadtemplateFields, @@ -178,6 +192,7 @@ export const useLoadDependencies = (props: UseLoadDependencies) => { isInitialLoadingUiConfig || isInitialLoadingHealthCheck || isInitialLoadingRuleTypes || + isInitialLoadingFlappingSettings || isInitialLoadingConnectors || isInitialLoadingConnectorTypes || isInitialLoadingAadTemplateField @@ -190,6 +205,7 @@ export const useLoadDependencies = (props: UseLoadDependencies) => { isInitialLoadingHealthCheck || isInitialLoadingRule || isInitialLoadingRuleTypes || + isInitialLoadingFlappingSettings || isInitialLoadingConnectors || isInitialLoadingConnectorTypes || isInitialLoadingAadTemplateField @@ -200,6 +216,7 @@ export const useLoadDependencies = (props: UseLoadDependencies) => { isInitialLoadingHealthCheck, isInitialLoadingRule, isInitialLoadingRuleTypes, + isInitialLoadingFlappingSettings, isInitialLoadingConnectors, isInitialLoadingConnectorTypes, isInitialLoadingAadTemplateField, @@ -213,6 +230,7 @@ export const useLoadDependencies = (props: UseLoadDependencies) => { uiConfig, healthCheckError, fetchedFormData, + flappingSettings, connectors, connectorTypes, aadTemplateFields, diff --git a/packages/kbn-alerts-ui-shared/src/rule_form/rule_definition/rule_definition.test.tsx b/packages/kbn-alerts-ui-shared/src/rule_form/rule_definition/rule_definition.test.tsx index 01f9f39e9d086..b91148c220844 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_form/rule_definition/rule_definition.test.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_form/rule_definition/rule_definition.test.tsx @@ -19,12 +19,37 @@ import type { DocLinksStart } from '@kbn/core-doc-links-browser'; import { RuleDefinition } from './rule_definition'; import { RuleType } from '@kbn/alerting-types'; import { RuleTypeModel } from '../../common/types'; +import { RuleSettingsFlappingFormProps } from '../../rule_settings/rule_settings_flapping_form'; +import { ALERT_FLAPPING_DETECTION_TITLE } from '../translations'; +import userEvent from '@testing-library/user-event'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; jest.mock('../hooks', () => ({ useRuleFormState: jest.fn(), useRuleFormDispatch: jest.fn(), })); +jest.mock('../../common/constants/rule_flapping', () => ({ + IS_RULE_SPECIFIC_FLAPPING_ENABLED: true, +})); + +jest.mock('../../rule_settings/rule_settings_flapping_form', () => ({ + RuleSettingsFlappingForm: (props: RuleSettingsFlappingFormProps) => ( +

    + +
    + ), +})); + const ruleType = { id: '.es-query', name: 'Test', @@ -73,6 +98,13 @@ const plugins = { dataViews: {} as DataViewsPublicPluginStart, unifiedSearch: {} as UnifiedSearchPublicPluginStart, docLinks: {} as DocLinksStart, + application: { + capabilities: { + rulesSettings: { + writeFlappingSettingsUI: true, + }, + }, + }, }; const { useRuleFormState, useRuleFormDispatch } = jest.requireMock('../hooks'); @@ -279,4 +311,105 @@ describe('Rule Definition', () => { }, }); }); + + test('should render rule flapping settings correctly', () => { + useRuleFormState.mockReturnValue({ + plugins, + formData: { + id: 'test-id', + params: {}, + schedule: { + interval: '1m', + }, + alertDelay: { + active: 5, + }, + notifyWhen: null, + consumer: 'stackAlerts', + }, + selectedRuleType: ruleType, + selectedRuleTypeModel: ruleModel, + canShowConsumerSelection: true, + validConsumers: ['logs', 'stackAlerts'], + }); + + render(); + + expect(screen.getByText(ALERT_FLAPPING_DETECTION_TITLE)).toBeInTheDocument(); + expect(screen.getByTestId('ruleSettingsFlappingForm')).toBeInTheDocument(); + }); + + test('should allow flapping to be changed', async () => { + useRuleFormState.mockReturnValue({ + plugins, + formData: { + id: 'test-id', + params: {}, + schedule: { + interval: '1m', + }, + alertDelay: { + active: 5, + }, + notifyWhen: null, + consumer: 'stackAlerts', + }, + selectedRuleType: ruleType, + selectedRuleTypeModel: ruleModel, + canShowConsumerSelection: true, + validConsumers: ['logs', 'stackAlerts'], + }); + + render(); + + await userEvent.click(screen.getByText('onFlappingChange')); + expect(mockOnChange).toHaveBeenCalledWith({ + payload: { + property: 'flapping', + value: { + lookBackWindow: 15, + statusChangeThreshold: 15, + }, + }, + type: 'setRuleProperty', + }); + }); + + test('should open and close flapping popover when button icon is clicked', async () => { + useRuleFormState.mockReturnValue({ + plugins, + formData: { + id: 'test-id', + params: {}, + schedule: { + interval: '1m', + }, + alertDelay: { + active: 5, + }, + notifyWhen: null, + consumer: 'stackAlerts', + }, + selectedRuleType: ruleType, + selectedRuleTypeModel: ruleModel, + canShowConsumerSelection: true, + validConsumers: ['logs', 'stackAlerts'], + }); + + render( + + + + ); + + expect(screen.queryByTestId('ruleSettingsFlappingTooltipTitle')).not.toBeInTheDocument(); + + await userEvent.click(screen.getByTestId('ruleSettingsFlappingTitleTooltipButton')); + + expect(screen.queryByTestId('ruleSettingsFlappingTooltipTitle')).toBeInTheDocument(); + + await userEvent.click(screen.getByTestId('ruleSettingsFlappingTitleTooltipButton')); + + expect(screen.queryByTestId('ruleSettingsFlappingTooltipTitle')).not.toBeVisible(); + }); }); diff --git a/packages/kbn-alerts-ui-shared/src/rule_form/rule_definition/rule_definition.tsx b/packages/kbn-alerts-ui-shared/src/rule_form/rule_definition/rule_definition.tsx index fe4812436144a..3b404edc5d029 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_form/rule_definition/rule_definition.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_form/rule_definition/rule_definition.tsx @@ -25,6 +25,7 @@ import { useEuiTheme, COLOR_MODES_STANDARD, } from '@elastic/eui'; +import { RuleSpecificFlappingProperties } from '@kbn/alerting-types'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { AlertConsumers } from '@kbn/rule-data-utils'; import { @@ -39,6 +40,8 @@ import { ADVANCED_OPTIONS_TITLE, ALERT_DELAY_DESCRIPTION_TEXT, ALERT_DELAY_HELP_TEXT, + ALERT_FLAPPING_DETECTION_TITLE, + ALERT_FLAPPING_DETECTION_DESCRIPTION, } from '../translations'; import { RuleAlertDelay } from './rule_alert_delay'; import { RuleConsumerSelection } from './rule_consumer_selection'; @@ -46,6 +49,9 @@ import { RuleSchedule } from './rule_schedule'; import { useRuleFormState, useRuleFormDispatch } from '../hooks'; import { MULTI_CONSUMER_RULE_TYPE_IDS } from '../constants'; import { getAuthorizedConsumers } from '../utils'; +import { RuleSettingsFlappingTitleTooltip } from '../../rule_settings/rule_settings_flapping_title_tooltip'; +import { RuleSettingsFlappingForm } from '../../rule_settings/rule_settings_flapping_form'; +import { IS_RULE_SPECIFIC_FLAPPING_ENABLED } from '../../common/constants/rule_flapping'; export const RuleDefinition = () => { const { @@ -58,17 +64,26 @@ export const RuleDefinition = () => { selectedRuleTypeModel, validConsumers, canShowConsumerSelection = false, + flappingSettings, } = useRuleFormState(); const { colorMode } = useEuiTheme(); const dispatch = useRuleFormDispatch(); - const { charts, data, dataViews, unifiedSearch, docLinks } = plugins; + const { charts, data, dataViews, unifiedSearch, docLinks, application } = plugins; - const { params, schedule, notifyWhen } = formData; + const { + capabilities: { rulesSettings }, + } = application; + + const { writeFlappingSettingsUI } = rulesSettings || {}; + + const { params, schedule, notifyWhen, flapping } = formData; const [isAdvancedOptionsVisible, setIsAdvancedOptionsVisible] = useState(false); + const [isFlappingPopoverOpen, setIsFlappingPopoverOpen] = useState(false); + const authorizedConsumers = useMemo(() => { if (!validConsumers?.length) { return []; @@ -143,6 +158,19 @@ export const RuleDefinition = () => { [dispatch] ); + const onSetFlapping = useCallback( + (value: RuleSpecificFlappingProperties | null) => { + dispatch({ + type: 'setRuleProperty', + payload: { + property: 'flapping', + value, + }, + }); + }, + [dispatch] + ); + return ( @@ -243,7 +271,10 @@ export const RuleDefinition = () => { { + setIsAdvancedOptionsVisible(isOpen); + setIsFlappingPopoverOpen(false); + }} initialIsOpen={isAdvancedOptionsVisible} buttonProps={{ 'data-test-subj': 'advancedOptionsAccordionButton', @@ -274,6 +305,31 @@ export const RuleDefinition = () => { > + {IS_RULE_SPECIFIC_FLAPPING_ENABLED && ( + {ALERT_FLAPPING_DETECTION_TITLE}} + description={ + +

    + {ALERT_FLAPPING_DETECTION_DESCRIPTION} + +

    +
    + } + > + +
    + )}
    diff --git a/packages/kbn-alerts-ui-shared/src/rule_form/translations.ts b/packages/kbn-alerts-ui-shared/src/rule_form/translations.ts index e7b060dce9831..20e87c66f10f4 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_form/translations.ts +++ b/packages/kbn-alerts-ui-shared/src/rule_form/translations.ts @@ -85,6 +85,21 @@ export const ALERT_DELAY_TITLE_PREFIX = i18n.translate( } ); +export const ALERT_FLAPPING_DETECTION_TITLE = i18n.translate( + 'alertsUIShared.ruleForm.ruleDefinition.alertFlappingDetectionTitle', + { + defaultMessage: 'Alert flapping detection', + } +); + +export const ALERT_FLAPPING_DETECTION_DESCRIPTION = i18n.translate( + 'alertsUIShared.ruleForm.ruleDefinition.alertFlappingDetectionDescription', + { + defaultMessage: + 'Detect alerts that switch quickly between active and recovered states and reduce unwanted noise for these flapping alerts', + } +); + export const SCHEDULE_TITLE_PREFIX = i18n.translate( 'alertsUIShared.ruleForm.ruleSchedule.scheduleTitlePrefix', { diff --git a/packages/kbn-alerts-ui-shared/src/rule_form/types.ts b/packages/kbn-alerts-ui-shared/src/rule_form/types.ts index ac81f45de19e6..d33c74da528db 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_form/types.ts +++ b/packages/kbn-alerts-ui-shared/src/rule_form/types.ts @@ -20,7 +20,7 @@ import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/ import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import { RuleCreationValidConsumer } from '@kbn/rule-data-utils'; import { ActionType } from '@kbn/actions-types'; -import { ActionVariable } from '@kbn/alerting-types'; +import { ActionVariable, RulesSettingsFlapping } from '@kbn/alerting-types'; import { ActionConnector, ActionTypeRegistryContract, @@ -46,6 +46,7 @@ export interface RuleFormData { alertDelay?: Rule['alertDelay']; notifyWhen?: Rule['notifyWhen']; ruleTypeId?: Rule['ruleTypeId']; + flapping?: Rule['flapping']; } export interface RuleFormPlugins { @@ -83,6 +84,7 @@ export interface RuleFormState { minimumScheduleInterval?: MinimumScheduleInterval; canShowConsumerSelection?: boolean; validConsumers?: RuleCreationValidConsumer[]; + flappingSettings?: RulesSettingsFlapping; } export type InitialRule = Partial & diff --git a/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_form.tsx b/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_form.tsx new file mode 100644 index 0000000000000..99f64f0a3977f --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_form.tsx @@ -0,0 +1,318 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React, { useCallback, useMemo, useRef, useState } from 'react'; +import { + EuiBadge, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiLink, + EuiPopover, + EuiSpacer, + EuiSplitPanel, + EuiSwitch, + EuiText, + EuiOutsideClickDetector, + useEuiTheme, + useIsWithinMinBreakpoint, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { RuleSpecificFlappingProperties, RulesSettingsFlapping } from '@kbn/alerting-types'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { RuleSettingsFlappingMessage } from './rule_settings_flapping_message'; +import { RuleSettingsFlappingInputs } from './rule_settings_flapping_inputs'; + +const flappingLabel = i18n.translate('alertsUIShared.ruleSettingsFlappingForm.flappingLabel', { + defaultMessage: 'Flapping Detection', +}); + +const flappingOnLabel = i18n.translate('alertsUIShared.ruleSettingsFlappingForm.onLabel', { + defaultMessage: 'ON', +}); + +const flappingOffLabel = i18n.translate('alertsUIShared.ruleSettingsFlappingForm.offLabel', { + defaultMessage: 'OFF', +}); + +const flappingOverrideLabel = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingForm.overrideLabel', + { + defaultMessage: 'Custom', + } +); + +const flappingOffContentRules = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingForm.flappingOffContentRules', + { + defaultMessage: 'Rules', + } +); + +const flappingOffContentSettings = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingForm.flappingOffContentSettings', + { + defaultMessage: 'Settings', + } +); + +const flappingExternalLinkLabel = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingForm.flappingExternalLinkLabel', + { + defaultMessage: "What's this?", + } +); + +const flappingOverrideConfiguration = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingForm.flappingOverrideConfiguration', + { + defaultMessage: 'Customize Configuration', + } +); + +const clampFlappingValues = (flapping: RuleSpecificFlappingProperties) => { + return { + ...flapping, + statusChangeThreshold: Math.min(flapping.lookBackWindow, flapping.statusChangeThreshold), + }; +}; + +export interface RuleSettingsFlappingFormProps { + flappingSettings?: RuleSpecificFlappingProperties | null; + spaceFlappingSettings?: RulesSettingsFlapping; + canWriteFlappingSettingsUI: boolean; + onFlappingChange: (value: RuleSpecificFlappingProperties | null) => void; +} + +export const RuleSettingsFlappingForm = (props: RuleSettingsFlappingFormProps) => { + const { flappingSettings, spaceFlappingSettings, canWriteFlappingSettingsUI, onFlappingChange } = + props; + + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const cachedFlappingSettings = useRef(); + + const isDesktop = useIsWithinMinBreakpoint('xl'); + + const { euiTheme } = useEuiTheme(); + + const onFlappingToggle = useCallback(() => { + if (!spaceFlappingSettings) { + return; + } + if (flappingSettings) { + cachedFlappingSettings.current = flappingSettings; + return onFlappingChange(null); + } + const initialFlappingSettings = cachedFlappingSettings.current || spaceFlappingSettings; + onFlappingChange({ + lookBackWindow: initialFlappingSettings.lookBackWindow, + statusChangeThreshold: initialFlappingSettings.statusChangeThreshold, + }); + }, [spaceFlappingSettings, flappingSettings, onFlappingChange]); + + const internalOnFlappingChange = useCallback( + (flapping: RuleSpecificFlappingProperties) => { + const clampedValue = clampFlappingValues(flapping); + onFlappingChange(clampedValue); + cachedFlappingSettings.current = clampedValue; + }, + [onFlappingChange] + ); + + const onLookBackWindowChange = useCallback( + (value: number) => { + if (!flappingSettings) { + return; + } + internalOnFlappingChange({ + ...flappingSettings, + lookBackWindow: value, + }); + }, + [flappingSettings, internalOnFlappingChange] + ); + + const onStatusChangeThresholdChange = useCallback( + (value: number) => { + if (!flappingSettings) { + return; + } + internalOnFlappingChange({ + ...flappingSettings, + statusChangeThreshold: value, + }); + }, + [flappingSettings, internalOnFlappingChange] + ); + + const flappingOffTooltip = useMemo(() => { + if (!spaceFlappingSettings) { + return null; + } + const { enabled } = spaceFlappingSettings; + if (enabled) { + return null; + } + + if (canWriteFlappingSettingsUI) { + return ( + setIsPopoverOpen(false)}> + setIsPopoverOpen(!isPopoverOpen)} + /> + } + > + + {flappingOffContentRules}, + settings: {flappingOffContentSettings}, + }} + /> + + + + ); + } + // TODO: Add the external doc link here! + return ( + + {flappingExternalLinkLabel} + + ); + }, [canWriteFlappingSettingsUI, isPopoverOpen, spaceFlappingSettings]); + + const flappingFormHeader = useMemo(() => { + if (!spaceFlappingSettings) { + return null; + } + const { enabled } = spaceFlappingSettings; + + return ( + + + + + {flappingLabel} + + + {enabled ? flappingOnLabel : flappingOffLabel} + + {flappingSettings && enabled && ( + {flappingOverrideLabel} + )} + + + {enabled && ( + + )} + {flappingOffTooltip} + + + {flappingSettings && enabled && ( + <> + + + + )} + + ); + }, [ + isDesktop, + euiTheme, + spaceFlappingSettings, + flappingSettings, + flappingOffTooltip, + onFlappingToggle, + ]); + + const flappingFormBody = useMemo(() => { + if (!flappingSettings) { + return null; + } + if (!spaceFlappingSettings?.enabled) { + return null; + } + return ( + + + + ); + }, [ + flappingSettings, + spaceFlappingSettings, + onLookBackWindowChange, + onStatusChangeThresholdChange, + ]); + + const flappingFormMessage = useMemo(() => { + if (!spaceFlappingSettings || !spaceFlappingSettings.enabled) { + return null; + } + const settingsToUse = flappingSettings || spaceFlappingSettings; + return ( + + + + ); + }, [spaceFlappingSettings, flappingSettings, euiTheme]); + + return ( + + + + {flappingFormHeader} + {flappingFormBody} + + + {flappingFormMessage} + + ); +}; diff --git a/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_message.tsx b/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_message.tsx index b7c8681ef221b..d6d488e08f0c1 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_message.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_message.tsx @@ -37,21 +37,34 @@ export const flappingOffMessage = i18n.translate( export interface RuleSettingsFlappingMessageProps { lookBackWindow: number; statusChangeThreshold: number; + isUsingRuleSpecificFlapping: boolean; } export const RuleSettingsFlappingMessage = (props: RuleSettingsFlappingMessageProps) => { - const { lookBackWindow, statusChangeThreshold } = props; + const { lookBackWindow, statusChangeThreshold, isUsingRuleSpecificFlapping } = props; return ( - {getLookBackWindowLabelRuleRuns(lookBackWindow)}, - statusChangeThreshold: {getStatusChangeThresholdRuleRuns(statusChangeThreshold)}, - }} - /> + {!isUsingRuleSpecificFlapping && ( + {getLookBackWindowLabelRuleRuns(lookBackWindow)}, + statusChangeThreshold: {getStatusChangeThresholdRuleRuns(statusChangeThreshold)}, + }} + /> + )} + {isUsingRuleSpecificFlapping && ( + {getLookBackWindowLabelRuleRuns(lookBackWindow)}, + statusChangeThreshold: {getStatusChangeThresholdRuleRuns(statusChangeThreshold)}, + }} + /> + )} ); }; diff --git a/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_title_tooltip.tsx b/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_title_tooltip.tsx new file mode 100644 index 0000000000000..2a5cc4186013d --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/rule_settings/rule_settings_flapping_title_tooltip.tsx @@ -0,0 +1,140 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { + EuiButtonIcon, + EuiPopover, + EuiPopoverProps, + EuiPopoverTitle, + EuiSpacer, + EuiText, + EuiOutsideClickDetector, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; + +const tooltipTitle = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingTitleTooltip.tooltipTitle', + { + defaultMessage: 'Alert flapping detection', + } +); + +const flappingTitlePopoverFlappingDetection = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopoverFlappingDetection', + { + defaultMessage: 'flapping detection', + } +); + +const flappingTitlePopoverAlertStatus = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopoverAlertStatus', + { + defaultMessage: 'alert status change threshold', + } +); + +const flappingTitlePopoverLookBack = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopoverLookBack', + { + defaultMessage: 'rule run look back window', + } +); + +const flappingOffContentRules = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingOffContentRules', + { + defaultMessage: 'Rules', + } +); + +const flappingOffContentSettings = i18n.translate( + 'alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingOffContentSettings', + { + defaultMessage: 'Settings', + } +); + +interface RuleSettingsFlappingTitleTooltipProps { + isOpen: boolean; + setIsPopoverOpen: (isOpen: boolean) => void; + anchorPosition?: EuiPopoverProps['anchorPosition']; +} + +export const RuleSettingsFlappingTitleTooltip = (props: RuleSettingsFlappingTitleTooltipProps) => { + const { isOpen, setIsPopoverOpen, anchorPosition = 'leftCenter' } = props; + + return ( + setIsPopoverOpen(false)}> + setIsPopoverOpen(!isOpen)} + /> + } + > + + {tooltipTitle} + + + {flappingTitlePopoverFlappingDetection}, + }} + /> + + + + {flappingTitlePopoverAlertStatus}, + }} + /> + + + + {flappingTitlePopoverLookBack}, + }} + /> + + + + {flappingOffContentRules}, + settings: {flappingOffContentSettings}, + }} + /> + + + + ); +}; diff --git a/x-pack/plugins/alerting/common/rules_settings.ts b/x-pack/plugins/alerting/common/rules_settings.ts index 2a4162ca2c5d3..6dcfd377eeb7c 100644 --- a/x-pack/plugins/alerting/common/rules_settings.ts +++ b/x-pack/plugins/alerting/common/rules_settings.ts @@ -5,38 +5,28 @@ * 2.0. */ -export interface RulesSettingsModificationMetadata { - createdBy: string | null; - updatedBy: string | null; - createdAt: string; - updatedAt: string; -} +import type { + RulesSettingsFlappingProperties, + RulesSettingsQueryDelayProperties, +} from '@kbn/alerting-types'; -export interface RulesSettingsFlappingProperties { - enabled: boolean; - lookBackWindow: number; - statusChangeThreshold: number; -} +export { + MIN_LOOK_BACK_WINDOW, + MAX_LOOK_BACK_WINDOW, + MIN_STATUS_CHANGE_THRESHOLD, + MAX_STATUS_CHANGE_THRESHOLD, +} from '@kbn/alerting-types/flapping/latest'; -export type RulesSettingsFlapping = RulesSettingsFlappingProperties & - RulesSettingsModificationMetadata; - -export interface RulesSettingsQueryDelayProperties { - delay: number; -} - -export type RulesSettingsQueryDelay = RulesSettingsQueryDelayProperties & - RulesSettingsModificationMetadata; - -export interface RulesSettingsProperties { - flapping?: RulesSettingsFlappingProperties; - queryDelay?: RulesSettingsQueryDelayProperties; -} - -export interface RulesSettings { - flapping?: RulesSettingsFlapping; - queryDelay?: RulesSettingsQueryDelay; -} +export type { + RulesSettingsModificationMetadata, + RulesSettingsFlappingProperties, + RulesSettingsQueryDelayProperties, + RuleSpecificFlappingProperties, + RulesSettingsFlapping, + RulesSettingsQueryDelay, + RulesSettingsProperties, + RulesSettings, +} from '@kbn/alerting-types'; export const MIN_QUERY_DELAY = 0; export const MAX_QUERY_DELAY = 60; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/flapping/rules_settings_flapping_form_section.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/flapping/rules_settings_flapping_form_section.tsx index a78658044a192..1b38eede40e68 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/flapping/rules_settings_flapping_form_section.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/flapping/rules_settings_flapping_form_section.tsx @@ -82,6 +82,7 @@ export const RulesSettingsFlappingFormSection = memo( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_link.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_link.test.tsx index 8d32eb2c9940c..e1cdf5a8ee150 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_link.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_link.test.tsx @@ -14,12 +14,12 @@ import { coreMock } from '@kbn/core/public/mocks'; import { RulesSettingsFlapping, RulesSettingsQueryDelay } from '@kbn/alerting-plugin/common'; import { RulesSettingsLink } from './rules_settings_link'; import { useKibana } from '../../../common/lib/kibana'; -import { getFlappingSettings } from '../../lib/rule_api/get_flapping_settings'; +import { fetchFlappingSettings } from '@kbn/alerts-ui-shared/src/common/apis/fetch_flapping_settings'; import { getQueryDelaySettings } from '../../lib/rule_api/get_query_delay_settings'; jest.mock('../../../common/lib/kibana'); -jest.mock('../../lib/rule_api/get_flapping_settings', () => ({ - getFlappingSettings: jest.fn(), +jest.mock('@kbn/alerts-ui-shared/src/common/apis/fetch_flapping_settings', () => ({ + fetchFlappingSettings: jest.fn(), })); jest.mock('../../lib/rule_api/get_query_delay_settings', () => ({ getQueryDelaySettings: jest.fn(), @@ -38,8 +38,8 @@ const useKibanaMock = useKibana as jest.Mocked; const mocks = coreMock.createSetup(); -const getFlappingSettingsMock = getFlappingSettings as unknown as jest.MockedFunction< - typeof getFlappingSettings +const fetchFlappingSettingsMock = fetchFlappingSettings as unknown as jest.MockedFunction< + typeof fetchFlappingSettings >; const getQueryDelaySettingsMock = getQueryDelaySettings as unknown as jest.MockedFunction< typeof getQueryDelaySettings @@ -88,7 +88,7 @@ describe('rules_settings_link', () => { readQueryDelaySettingsUI: true, }, }; - getFlappingSettingsMock.mockResolvedValue(mockFlappingSetting); + fetchFlappingSettingsMock.mockResolvedValue(mockFlappingSetting); getQueryDelaySettingsMock.mockResolvedValue(mockQueryDelaySetting); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_modal.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_modal.test.tsx index 592705b56984d..1dea8bdf88a6e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_modal.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_modal.test.tsx @@ -15,14 +15,14 @@ import { IToasts } from '@kbn/core/public'; import { RulesSettingsFlapping, RulesSettingsQueryDelay } from '@kbn/alerting-plugin/common'; import { RulesSettingsModal, RulesSettingsModalProps } from './rules_settings_modal'; import { useKibana } from '../../../common/lib/kibana'; -import { getFlappingSettings } from '../../lib/rule_api/get_flapping_settings'; +import { fetchFlappingSettings } from '@kbn/alerts-ui-shared/src/common/apis/fetch_flapping_settings'; import { updateFlappingSettings } from '../../lib/rule_api/update_flapping_settings'; import { getQueryDelaySettings } from '../../lib/rule_api/get_query_delay_settings'; import { updateQueryDelaySettings } from '../../lib/rule_api/update_query_delay_settings'; jest.mock('../../../common/lib/kibana'); -jest.mock('../../lib/rule_api/get_flapping_settings', () => ({ - getFlappingSettings: jest.fn(), +jest.mock('@kbn/alerts-ui-shared/src/common/apis/fetch_flapping_settings', () => ({ + fetchFlappingSettings: jest.fn(), })); jest.mock('../../lib/rule_api/update_flapping_settings', () => ({ updateFlappingSettings: jest.fn(), @@ -47,8 +47,8 @@ const useKibanaMock = useKibana as jest.Mocked; const mocks = coreMock.createSetup(); -const getFlappingSettingsMock = getFlappingSettings as unknown as jest.MockedFunction< - typeof getFlappingSettings +const fetchFlappingSettingsMock = fetchFlappingSettings as unknown as jest.MockedFunction< + typeof fetchFlappingSettings >; const updateFlappingSettingsMock = updateFlappingSettings as unknown as jest.MockedFunction< typeof updateFlappingSettings @@ -142,7 +142,7 @@ describe('rules_settings_modal', () => { useKibanaMock().services.isServerless = true; - getFlappingSettingsMock.mockResolvedValue(mockFlappingSetting); + fetchFlappingSettingsMock.mockResolvedValue(mockFlappingSetting); updateFlappingSettingsMock.mockResolvedValue(mockFlappingSetting); getQueryDelaySettingsMock.mockResolvedValue(mockQueryDelaySetting); updateQueryDelaySettingsMock.mockResolvedValue(mockQueryDelaySetting); @@ -156,7 +156,7 @@ describe('rules_settings_modal', () => { test('renders flapping settings correctly', async () => { const result = render(); - expect(getFlappingSettingsMock).toHaveBeenCalledTimes(1); + expect(fetchFlappingSettingsMock).toHaveBeenCalledTimes(1); await waitForModalLoad(); expect( result.getByTestId('rulesSettingsFlappingEnableSwitch').getAttribute('aria-checked') @@ -204,7 +204,7 @@ describe('rules_settings_modal', () => { test('reset flapping settings to initial state on cancel without triggering another server reload', async () => { const result = render(); - expect(getFlappingSettingsMock).toHaveBeenCalledTimes(1); + expect(fetchFlappingSettingsMock).toHaveBeenCalledTimes(1); expect(getQueryDelaySettingsMock).toHaveBeenCalledTimes(1); await waitForModalLoad(); @@ -228,7 +228,7 @@ describe('rules_settings_modal', () => { expect(lookBackWindowInput.getAttribute('value')).toBe('10'); expect(statusChangeThresholdInput.getAttribute('value')).toBe('10'); - expect(getFlappingSettingsMock).toHaveBeenCalledTimes(1); + expect(fetchFlappingSettingsMock).toHaveBeenCalledTimes(1); expect(getQueryDelaySettingsMock).toHaveBeenCalledTimes(1); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_modal.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_modal.tsx index 4431f05975906..09828e067369b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_modal.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/rules_setting/rules_settings_modal.tsx @@ -26,8 +26,8 @@ import { EuiSpacer, EuiEmptyPrompt, } from '@elastic/eui'; +import { useFetchFlappingSettings } from '@kbn/alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings'; import { useKibana } from '../../../common/lib/kibana'; -import { useGetFlappingSettings } from '../../hooks/use_get_flapping_settings'; import { RulesSettingsFlappingSection } from './flapping/rules_settings_flapping_section'; import { RulesSettingsQueryDelaySection } from './query_delay/rules_settings_query_delay_section'; import { useGetQueryDelaySettings } from '../../hooks/use_get_query_delay_settings'; @@ -93,6 +93,7 @@ export const RulesSettingsModal = memo((props: RulesSettingsModalProps) => { const { application: { capabilities }, isServerless, + http, } = useKibana().services; const { rulesSettings: { @@ -109,7 +110,8 @@ export const RulesSettingsModal = memo((props: RulesSettingsModalProps) => { const [queryDelaySettings, hasQueryDelayChanged, setQueryDelaySettings, resetQueryDelaySettings] = useResettableState(); - const { isLoading: isFlappingLoading, isError: hasFlappingError } = useGetFlappingSettings({ + const { isLoading: isFlappingLoading, isError: hasFlappingError } = useFetchFlappingSettings({ + http, enabled: isVisible, onSuccess: (fetchedSettings) => { if (!flappingSettings) { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_flapping_settings.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_flapping_settings.ts deleted file mode 100644 index 26b9fdcaeb1c2..0000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_flapping_settings.ts +++ /dev/null @@ -1,41 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useQuery } from '@tanstack/react-query'; -import { RulesSettingsFlapping } from '@kbn/alerting-plugin/common'; -import { useKibana } from '../../common/lib/kibana'; -import { getFlappingSettings } from '../lib/rule_api/get_flapping_settings'; - -interface UseGetFlappingSettingsProps { - enabled: boolean; - onSuccess?: (settings: RulesSettingsFlapping) => void; -} - -export const useGetFlappingSettings = (props: UseGetFlappingSettingsProps) => { - const { enabled, onSuccess } = props; - const { http } = useKibana().services; - - const queryFn = () => { - return getFlappingSettings({ http }); - }; - - const { data, isFetching, isError, isLoadingError, isLoading, isInitialLoading } = useQuery({ - queryKey: ['getFlappingSettings'], - queryFn, - onSuccess, - enabled, - refetchOnWindowFocus: false, - retry: false, - }); - - return { - isInitialLoading, - isLoading: isLoading || isFetching, - isError: isError || isLoadingError, - data, - }; -}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_flapping_settings.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_flapping_settings.ts deleted file mode 100644 index 931b1037ef729..0000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_flapping_settings.ts +++ /dev/null @@ -1,28 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { HttpSetup } from '@kbn/core/public'; -import { AsApiContract, RewriteRequestCase } from '@kbn/actions-plugin/common'; -import { RulesSettingsFlapping } from '@kbn/alerting-plugin/common'; -import { INTERNAL_BASE_ALERTING_API_PATH } from '../../constants'; - -const rewriteBodyRes: RewriteRequestCase = ({ - look_back_window: lookBackWindow, - status_change_threshold: statusChangeThreshold, - ...rest -}: any) => ({ - ...rest, - lookBackWindow, - statusChangeThreshold, -}); - -export const getFlappingSettings = async ({ http }: { http: HttpSetup }) => { - const res = await http.get>( - `${INTERNAL_BASE_ALERTING_API_PATH}/rules/settings/_flapping` - ); - return rewriteBodyRes(res); -}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx index af8bda5704b0f..c7b2876d83d84 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx @@ -67,8 +67,8 @@ jest.mock('../../lib/action_connector_api', () => ({ loadAllActions: jest.fn(), })); -jest.mock('../../lib/rule_api/get_flapping_settings', () => ({ - getFlappingSettings: jest.fn().mockResolvedValue({ +jest.mock('@kbn/alerts-ui-shared/src/common/apis/fetch_flapping_settings', () => ({ + fetchFlappingSettings: jest.fn().mockResolvedValue({ lookBackWindow: 20, statusChangeThreshold: 20, }), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx index 8657248a29df3..ccdca1bd1250d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx @@ -14,6 +14,7 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import { parseRuleCircuitBreakerErrorMessage } from '@kbn/alerting-plugin/common'; import { createRule, CreateRuleBody } from '@kbn/alerts-ui-shared/src/common/apis/create_rule'; import { fetchUiConfig as triggersActionsUiConfig } from '@kbn/alerts-ui-shared/src/common/apis/fetch_ui_config'; +import { IS_RULE_SPECIFIC_FLAPPING_ENABLED } from '@kbn/alerts-ui-shared/src/common/constants/rule_flapping'; import { Rule, RuleTypeParams, @@ -37,7 +38,6 @@ import { hasShowActionsCapability } from '../../lib/capabilities'; import RuleAddFooter from './rule_add_footer'; import { HealthContextProvider } from '../../context/health_context'; import { useKibana } from '../../../common/lib/kibana'; -import { IS_RULE_SPECIFIC_FLAPPING_ENABLED } from '../../../common/constants'; import { hasRuleChanged, haveRuleParamsChanged } from './has_rule_changed'; import { getRuleWithInvalidatedFields } from '../../lib/value_validators'; import { DEFAULT_RULE_INTERVAL, MULTI_CONSUMER_RULE_TYPE_IDS } from '../../constants'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx index 331b10505a5d7..243236d7f6b93 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx @@ -63,8 +63,8 @@ jest.mock('@kbn/alerts-ui-shared/src/common/apis/fetch_ui_health_status', () => fetchUiHealthStatus: jest.fn(() => ({ isRulesAvailable: true })), })); -jest.mock('../../lib/rule_api/get_flapping_settings', () => ({ - getFlappingSettings: jest.fn().mockResolvedValue({ +jest.mock('@kbn/alerts-ui-shared/src/common/apis/fetch_flapping_settings', () => ({ + fetchFlappingSettings: jest.fn().mockResolvedValue({ lookBackWindow: 20, statusChangeThreshold: 20, }), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx index 72eab243ad0c8..a24fd0eec2eb1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx @@ -30,7 +30,7 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import { parseRuleCircuitBreakerErrorMessage } from '@kbn/alerting-plugin/common'; import { updateRule } from '@kbn/alerts-ui-shared/src/common/apis/update_rule'; import { fetchUiConfig as triggersActionsUiConfig } from '@kbn/alerts-ui-shared/src/common/apis/fetch_ui_config'; -import { IS_RULE_SPECIFIC_FLAPPING_ENABLED } from '../../../common/constants'; +import { IS_RULE_SPECIFIC_FLAPPING_ENABLED } from '@kbn/alerts-ui-shared/src/common/constants/rule_flapping'; import { Rule, RuleFlyoutCloseReason, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx index 38ee1c73ac40b..17bdcc92997ca 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx @@ -71,8 +71,8 @@ jest.mock('../../lib/capabilities', () => ({ hasShowActionsCapability: jest.fn(() => true), hasExecuteActionsCapability: jest.fn(() => true), })); -jest.mock('../../lib/rule_api/get_flapping_settings', () => ({ - getFlappingSettings: jest.fn().mockResolvedValue({ +jest.mock('@kbn/alerts-ui-shared/src/common/apis/fetch_flapping_settings', () => ({ + fetchFlappingSettings: jest.fn().mockResolvedValue({ lookBackWindow: 20, statusChangeThreshold: 20, }), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx index c3f79c3458374..665dd93325c2b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx @@ -62,9 +62,11 @@ import { isActionGroupDisabledForActionTypeId, RuleActionAlertsFilterProperty, RuleActionKey, + Flapping, } from '@kbn/alerting-plugin/common'; import { AlertingConnectorFeatureId } from '@kbn/actions-plugin/common'; import { AlertConsumers } from '@kbn/rule-data-utils'; +import { IS_RULE_SPECIFIC_FLAPPING_ENABLED } from '@kbn/alerts-ui-shared/src/common/constants/rule_flapping'; import { RuleReducerAction, InitialRule } from './rule_reducer'; import { RuleTypeModel, @@ -91,10 +93,7 @@ import { ruleTypeGroupCompare, ruleTypeUngroupedCompare, } from '../../lib/rule_type_compare'; -import { - IS_RULE_SPECIFIC_FLAPPING_ENABLED, - VIEW_LICENSE_OPTIONS_LINK, -} from '../../../common/constants'; +import { VIEW_LICENSE_OPTIONS_LINK } from '../../../common/constants'; import { MULTI_CONSUMER_RULE_TYPE_IDS } from '../../constants'; import { SectionLoading } from '../../components/section_loading'; import { RuleFormConsumerSelection, VALID_CONSUMERS } from './rule_form_consumer_selection'; @@ -882,7 +881,7 @@ export const RuleForm = ({ alertDelay={alertDelay} flappingSettings={rule.flapping} onAlertDelayChange={onAlertDelayChange} - onFlappingChange={(flapping) => setRuleProperty('flapping', flapping)} + onFlappingChange={(flapping) => setRuleProperty('flapping', flapping as Flapping)} enabledFlapping={IS_RULE_SPECIFIC_FLAPPING_ENABLED} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.test.tsx index f6534f7451405..25c6de0225edb 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.test.tsx @@ -88,7 +88,7 @@ describe('ruleFormAdvancedOptions', () => { expect(screen.getByTestId('ruleFormAdvancedOptionsOverrideSwitch')).not.toBeChecked(); expect(screen.queryByText('Custom')).not.toBeInTheDocument(); expect(screen.getByTestId('ruleSettingsFlappingMessage')).toHaveTextContent( - 'An alert is flapping if it changes status at least 3 times in the last 10 rule runs.' + 'All rules (in this space) detect an alert is flapping when it changes status at least 3 times in the last 10 rule runs.' ); await userEvent.click(screen.getByTestId('ruleFormAdvancedOptionsOverrideSwitch')); @@ -121,7 +121,7 @@ describe('ruleFormAdvancedOptions', () => { expect(screen.getByTestId('lookBackWindowRangeInput')).toHaveValue('6'); expect(screen.getByTestId('statusChangeThresholdRangeInput')).toHaveValue('4'); expect(screen.getByTestId('ruleSettingsFlappingMessage')).toHaveTextContent( - 'An alert is flapping if it changes status at least 4 times in the last 6 rule runs.' + 'This rule detects an alert is flapping if it changes status at least 4 times in the last 6 rule runs.' ); await userEvent.click(screen.getByTestId('ruleFormAdvancedOptionsOverrideSwitch')); @@ -157,6 +157,10 @@ describe('ruleFormAdvancedOptions', () => { expect(screen.queryByText('Custom')).not.toBeInTheDocument(); expect(screen.queryByTestId('ruleFormAdvancedOptionsOverrideSwitch')).not.toBeInTheDocument(); expect(screen.queryByTestId('ruleSettingsFlappingMessage')).not.toBeInTheDocument(); + + await userEvent.click(screen.getByTestId('ruleSettingsFlappingFormTooltipButton')); + + expect(screen.getByTestId('ruleSettingsFlappingFormTooltipContent')).toBeInTheDocument(); }); test('should allow for flapping inputs to be modified', async () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.tsx index ca6e17451c1aa..00ad6186d58e8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_advanced_options.tsx @@ -5,36 +5,21 @@ * 2.0. */ -import React, { useCallback, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { - EuiBadge, EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip, EuiPanel, - EuiSwitch, - EuiText, - useIsWithinMinBreakpoint, - useEuiTheme, - EuiHorizontalRule, - EuiSpacer, - EuiSplitPanel, EuiLoadingSpinner, - EuiLink, - EuiButtonIcon, - EuiPopover, - EuiPopoverTitle, - EuiOutsideClickDetector, } from '@elastic/eui'; -import { RuleSettingsFlappingInputs } from '@kbn/alerts-ui-shared/src/rule_settings/rule_settings_flapping_inputs'; -import { RuleSettingsFlappingMessage } from '@kbn/alerts-ui-shared/src/rule_settings/rule_settings_flapping_message'; -import { Rule } from '@kbn/alerts-ui-shared'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { Flapping } from '@kbn/alerting-plugin/common'; -import { useGetFlappingSettings } from '../../hooks/use_get_flapping_settings'; +import { RuleSpecificFlappingProperties } from '@kbn/alerting-types/rule_settings'; +import { RuleSettingsFlappingForm } from '@kbn/alerts-ui-shared/src/rule_settings/rule_settings_flapping_form'; +import { RuleSettingsFlappingTitleTooltip } from '@kbn/alerts-ui-shared/src/rule_settings/rule_settings_flapping_title_tooltip'; +import { useFetchFlappingSettings } from '@kbn/alerts-ui-shared/src/common/hooks/use_fetch_flapping_settings'; import { useKibana } from '../../../common/lib/kibana'; const alertDelayFormRowLabel = i18n.translate( @@ -66,45 +51,6 @@ const alertDelayAppendLabel = i18n.translate( } ); -const flappingLabel = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.flappingLabel', - { - defaultMessage: 'Flapping Detection', - } -); - -const flappingOnLabel = i18n.translate('xpack.triggersActionsUI.ruleFormAdvancedOptions.onLabel', { - defaultMessage: 'ON', -}); - -const flappingOffLabel = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.offLabel', - { - defaultMessage: 'OFF', - } -); - -const flappingOverrideLabel = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.overrideLabel', - { - defaultMessage: 'Custom', - } -); - -const flappingOverrideConfiguration = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.flappingOverrideConfiguration', - { - defaultMessage: 'Override Configuration', - } -); - -const flappingExternalLinkLabel = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.flappingExternalLinkLabel', - { - defaultMessage: "What's this?", - } -); - const flappingFormRowLabel = i18n.translate( 'xpack.triggersActionsUI.sections.ruleForm.flappingLabel', { @@ -112,58 +58,13 @@ const flappingFormRowLabel = i18n.translate( } ); -const flappingOffContentRules = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.flappingOffContentRules', - { - defaultMessage: 'Rules', - } -); - -const flappingOffContentSettings = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.flappingOffContentSettings', - { - defaultMessage: 'Settings', - } -); - -const flappingTitlePopoverFlappingDetection = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.flappingTitlePopoverFlappingDetection', - { - defaultMessage: 'flapping detection', - } -); - -const flappingTitlePopoverAlertStatus = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.flappingTitlePopoverAlertStatus', - { - defaultMessage: 'alert status change threshold', - } -); - -const flappingTitlePopoverLookBack = i18n.translate( - 'xpack.triggersActionsUI.ruleFormAdvancedOptions.flappingTitlePopoverLookBack', - { - defaultMessage: 'rule run look back window', - } -); - -const clampFlappingValues = (flapping: Rule['flapping']) => { - if (!flapping) { - return; - } - return { - ...flapping, - statusChangeThreshold: Math.min(flapping.lookBackWindow, flapping.statusChangeThreshold), - }; -}; - const INTEGER_REGEX = /^[1-9][0-9]*$/; export interface RuleFormAdvancedOptionsProps { alertDelay?: number; - flappingSettings?: Flapping | null; + flappingSettings?: RuleSpecificFlappingProperties | null; onAlertDelayChange: (value: string) => void; - onFlappingChange: (value: Flapping | null) => void; + onFlappingChange: (value: RuleSpecificFlappingProperties | null) => void; enabledFlapping?: boolean; } @@ -180,20 +81,15 @@ export const RuleFormAdvancedOptions = (props: RuleFormAdvancedOptionsProps) => application: { capabilities: { rulesSettings }, }, + http, } = useKibana().services; - const { writeFlappingSettingsUI = false } = rulesSettings || {}; + const { writeFlappingSettingsUI } = rulesSettings || {}; - const [isFlappingOffPopoverOpen, setIsFlappingOffPopoverOpen] = useState(false); const [isFlappingTitlePopoverOpen, setIsFlappingTitlePopoverOpen] = useState(false); - const cachedFlappingSettings = useRef(); - - const isDesktop = useIsWithinMinBreakpoint('xl'); - - const { euiTheme } = useEuiTheme(); - - const { data: spaceFlappingSettings, isInitialLoading } = useGetFlappingSettings({ + const { data: spaceFlappingSettings, isInitialLoading } = useFetchFlappingSettings({ + http, enabled: enabledFlapping, }); @@ -207,274 +103,6 @@ export const RuleFormAdvancedOptions = (props: RuleFormAdvancedOptionsProps) => [onAlertDelayChange] ); - const internalOnFlappingChange = useCallback( - (flapping: Flapping) => { - const clampedValue = clampFlappingValues(flapping); - if (!clampedValue) { - return; - } - onFlappingChange(clampedValue); - cachedFlappingSettings.current = clampedValue; - }, - [onFlappingChange] - ); - - const onLookBackWindowChange = useCallback( - (value: number) => { - if (!flappingSettings) { - return; - } - internalOnFlappingChange({ - ...flappingSettings, - lookBackWindow: value, - }); - }, - [flappingSettings, internalOnFlappingChange] - ); - - const onStatusChangeThresholdChange = useCallback( - (value: number) => { - if (!flappingSettings) { - return; - } - internalOnFlappingChange({ - ...flappingSettings, - statusChangeThreshold: value, - }); - }, - [flappingSettings, internalOnFlappingChange] - ); - - const onFlappingToggle = useCallback(() => { - if (!spaceFlappingSettings) { - return; - } - if (flappingSettings) { - cachedFlappingSettings.current = flappingSettings; - return onFlappingChange(null); - } - const initialFlappingSettings = cachedFlappingSettings.current || spaceFlappingSettings; - onFlappingChange({ - lookBackWindow: initialFlappingSettings.lookBackWindow, - statusChangeThreshold: initialFlappingSettings.statusChangeThreshold, - }); - }, [spaceFlappingSettings, flappingSettings, onFlappingChange]); - - const flappingTitleTooltip = useMemo(() => { - return ( - setIsFlappingTitlePopoverOpen(false)}> - setIsFlappingTitlePopoverOpen(!isFlappingTitlePopoverOpen)} - /> - } - > - Alert flapping detection - - {flappingTitlePopoverFlappingDetection}, - }} - /> - - - - {flappingTitlePopoverAlertStatus}, - }} - /> - - - - {flappingTitlePopoverLookBack}, - }} - /> - - - - {flappingOffContentRules}, - settings: {flappingOffContentSettings}, - }} - /> - - - - ); - }, [isFlappingTitlePopoverOpen]); - - const flappingOffTooltip = useMemo(() => { - if (!spaceFlappingSettings) { - return null; - } - const { enabled } = spaceFlappingSettings; - if (enabled) { - return null; - } - - if (writeFlappingSettingsUI) { - return ( - setIsFlappingOffPopoverOpen(false)}> - setIsFlappingOffPopoverOpen(!isFlappingOffPopoverOpen)} - /> - } - > - - {flappingOffContentRules}, - settings: {flappingOffContentSettings}, - }} - /> - - - - ); - } - // TODO: Add the external doc link here! - return ( - - {flappingExternalLinkLabel} - - ); - }, [writeFlappingSettingsUI, isFlappingOffPopoverOpen, spaceFlappingSettings]); - - const flappingFormHeader = useMemo(() => { - if (!spaceFlappingSettings) { - return null; - } - const { enabled } = spaceFlappingSettings; - - return ( - - - - - {flappingLabel} - - - {enabled ? flappingOnLabel : flappingOffLabel} - - {flappingSettings && enabled && ( - {flappingOverrideLabel} - )} - - - {enabled && ( - - )} - {flappingOffTooltip} - - - {flappingSettings && enabled && ( - <> - - - - )} - - ); - }, [ - isDesktop, - euiTheme, - spaceFlappingSettings, - flappingSettings, - flappingOffTooltip, - onFlappingToggle, - ]); - - const flappingFormBody = useMemo(() => { - if (!spaceFlappingSettings || !spaceFlappingSettings.enabled) { - return null; - } - if (!flappingSettings) { - return null; - } - return ( - - - - ); - }, [ - flappingSettings, - spaceFlappingSettings, - onLookBackWindowChange, - onStatusChangeThresholdChange, - ]); - - const flappingFormMessage = useMemo(() => { - if (!spaceFlappingSettings || !spaceFlappingSettings.enabled) { - return null; - } - const settingsToUse = flappingSettings || spaceFlappingSettings; - return ( - - - - ); - }, [spaceFlappingSettings, flappingSettings, euiTheme]); - return ( @@ -512,21 +140,23 @@ export const RuleFormAdvancedOptions = (props: RuleFormAdvancedOptionsProps) => label={ {flappingFormRowLabel} - {flappingTitleTooltip} + + + } data-test-subj="alertFlappingFormRow" display="rowCompressed" > - - - - {flappingFormHeader} - {flappingFormBody} - - - {flappingFormMessage} - + )} diff --git a/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts b/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts index 2d6548062eed9..ca87ba3522042 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts @@ -25,9 +25,6 @@ export { I18N_WEEKDAY_OPTIONS_DDD, } from '@kbn/alerts-ui-shared/src/common/constants/i18n_weekdays'; -// Feature flag for frontend rule specific flapping in rule flyout -export const IS_RULE_SPECIFIC_FLAPPING_ENABLED = false; - export const builtInComparators: { [key: string]: Comparator } = { [COMPARATORS.GREATER_THAN]: { text: i18n.translate('xpack.triggersActionsUI.common.constants.comparators.isAboveLabel', { From 8ebd79326634417c1d4f469747ca6c2ddb3f5999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Thu, 10 Oct 2024 09:15:46 +0200 Subject: [PATCH 102/110] [Usage counters] Use `refresh=false` (#195619) --- .../server/usage_counters/saved_objects.test.ts | 1 + .../usage_collection/server/usage_counters/saved_objects.ts | 1 + .../server/usage_counters/usage_counters_service.test.ts | 2 ++ 3 files changed, 4 insertions(+) diff --git a/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts b/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts index ebced92622779..927869b6d0f89 100644 --- a/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts +++ b/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts @@ -80,6 +80,7 @@ describe('storeCounter', () => { ], Object { "namespace": "default", + "refresh": false, "upsertAttributes": Object { "counterName": "b", "counterType": "c", diff --git a/src/plugins/usage_collection/server/usage_counters/saved_objects.ts b/src/plugins/usage_collection/server/usage_counters/saved_objects.ts index 9c4e2832946e6..d5f49016e5296 100644 --- a/src/plugins/usage_collection/server/usage_counters/saved_objects.ts +++ b/src/plugins/usage_collection/server/usage_counters/saved_objects.ts @@ -122,6 +122,7 @@ export const storeCounter = async ({ metric, soRepository }: StoreCounterParams) counterType, source, }, + refresh: false, } ); }; diff --git a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.test.ts b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.test.ts index 6128b643918a1..1041cfb5ce36f 100644 --- a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.test.ts +++ b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.test.ts @@ -157,6 +157,7 @@ describe('UsageCountersService', () => { }, ], Object { + "refresh": false, "upsertAttributes": Object { "counterName": "counterA", "counterType": "count", @@ -175,6 +176,7 @@ describe('UsageCountersService', () => { }, ], Object { + "refresh": false, "upsertAttributes": Object { "counterName": "counterB", "counterType": "count", From 72c76f9ac9c43365bcfb70903c9d848012260291 Mon Sep 17 00:00:00 2001 From: Artem Shelkovnikov Date: Thu, 10 Oct 2024 09:34:17 +0200 Subject: [PATCH 103/110] Update configuration on changes in category/advanced configurations in configView (#195567) ## Closes https://github.com/elastic/search-team/issues/6557 ## Summary Fixes a known bug for Network Drive connector (as this feature is only used in it). The problem happens when there are Rich Configurable Fields that are marked as "advanced" and depend on certain fields - in some cases this field will not be shown until the page is fully reloaded. Criteria that makes the bug happen: 1. Have some RCFs that are marked as "advanced": https://github.com/elastic/connectors/blob/main/connectors/sources/network_drive.py#L405-L414. (`"ui_restrictions": ["advanced"]`) 2. Make it so that this RCF depends on another field, and by default is hidden - for example this field depends on a field "OS" that has "Windows" and "Linux" as available options and Windows is default, but this RCF depends on it being "Linux" 3. Try satisfying the dependency and see if the RCF is displayed - it won't be, unless you save the form and reload it The problem happens because for changes in "advanced" section the configuration is not updated, so the view that's rendered still thinks that the dependency is not satisfied and the field should not be rendered Before: https://github.com/user-attachments/assets/51f9f8b0-a57a-4d96-a183-6dbbd36a919e After: https://github.com/user-attachments/assets/be32f434-0810-4345-bc4e-dc82f617705c ### Checklist - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../connector_configuration_form.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/kbn-search-connectors/components/configuration/connector_configuration_form.tsx b/packages/kbn-search-connectors/components/configuration/connector_configuration_form.tsx index e70754d5e09e8..f7e619f407f12 100644 --- a/packages/kbn-search-connectors/components/configuration/connector_configuration_form.tsx +++ b/packages/kbn-search-connectors/components/configuration/connector_configuration_form.tsx @@ -109,6 +109,15 @@ export const ConnectorConfigurationForm: React.FC = items={category.configEntries} hasDocumentLevelSecurityEnabled={hasDocumentLevelSecurity} setConfigEntry={(key, value) => { + const entry = localConfig[key]; + if (entry && !isCategoryEntry(entry)) { + const newConfiguration: ConnectorConfiguration = { + ...localConfig, + [key]: { ...entry, value }, + }; + setLocalConfig(newConfiguration); + } + const categories = configView.categories; categories[index] = { ...categories[index], [key]: value }; setConfigView({ @@ -136,6 +145,15 @@ export const ConnectorConfigurationForm: React.FC = items={configView.advancedConfigurations} hasDocumentLevelSecurityEnabled={hasDocumentLevelSecurity} setConfigEntry={(key, value) => { + const entry = localConfig[key]; + if (entry && !isCategoryEntry(entry)) { + const newConfiguration: ConnectorConfiguration = { + ...localConfig, + [key]: { ...entry, value }, + }; + setLocalConfig(newConfiguration); + } + setConfigView({ ...configView, advancedConfigurations: configView.advancedConfigurations.map((config) => From f687ce2ba34a500522907b76add4327c16ad1bec Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Thu, 10 Oct 2024 09:06:33 +0100 Subject: [PATCH 104/110] [Security Solution][Detection Engine] adds EBT telemetry for rule preview (#194326) ## Summary - adds basic EBT telemetry for rule preview ### To test Use Discover Data View in staging to see reported events: https://telemetry-v2-staging.elastic.dev/s/securitysolution/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:now-28h,to:now))&_a=(columns:!(properties.ruleType,properties.loggedRequestsEnabled),filters:!(),index:security-solution-ebt-kibana-browser,interval:auto,query:(language:kuery,query:'event_type%20:%20%22Preview%20rule%22'),sort:!(!(timestamp,desc))) Note, there is a few hours delay from event reported locally to be stored on staging host --- .../public/common/lib/telemetry/constants.ts | 1 + .../telemetry/events/preview_rule/index.ts | 29 +++++++++++++++++++ .../telemetry/events/preview_rule/types.ts | 20 +++++++++++++ .../lib/telemetry/events/telemetry_events.ts | 2 ++ .../lib/telemetry/telemetry_client.mock.ts | 1 + .../common/lib/telemetry/telemetry_client.ts | 5 ++++ .../public/common/lib/telemetry/types.ts | 7 +++++ .../rule_preview/use_preview_rule.ts | 18 ++++++++++-- ...ecurity_solution_ebt_kibana_browser.ndjson | 4 +-- 9 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/index.ts create mode 100644 x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/types.ts diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts index f42f77f19a0f9..5126d75178f5f 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts @@ -86,6 +86,7 @@ export enum TelemetryEventTypes { EventLogShowSourceEventDateRange = 'Event Log -> Show Source -> Event Date Range', OpenNoteInExpandableFlyoutClicked = 'Open Note In Expandable Flyout Clicked', AddNoteFromExpandableFlyoutClicked = 'Add Note From Expandable Flyout Clicked', + PreviewRule = 'Preview rule', } export enum ML_JOB_TELEMETRY_STATUS { diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/index.ts new file mode 100644 index 0000000000000..12d721c45e2c0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { TelemetryEvent } from '../../types'; +import { TelemetryEventTypes } from '../../constants'; + +export const previewRuleEvent: TelemetryEvent = { + eventType: TelemetryEventTypes.PreviewRule, + schema: { + ruleType: { + type: 'keyword', + _meta: { + description: 'Rule type', + optional: false, + }, + }, + loggedRequestsEnabled: { + type: 'boolean', + _meta: { + description: 'shows if preview executed with enabled logged requests', + optional: false, + }, + }, + }, +}; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/types.ts new file mode 100644 index 0000000000000..e5523080088fc --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/types.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; + +import type { RootSchema } from '@kbn/core/public'; +import type { TelemetryEventTypes } from '../../constants'; + +export interface PreviewRuleParams { + ruleType: Type; + loggedRequestsEnabled: boolean; +} + +export interface PreviewRuleTelemetryEvent { + eventType: TelemetryEventTypes.PreviewRule; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts index d1f9502346a04..a0328099b9ff7 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts @@ -48,6 +48,7 @@ import { addNoteFromExpandableFlyoutClickedEvent, openNoteInExpandableFlyoutClickedEvent, } from './notes'; +import { previewRuleEvent } from './preview_rule'; const mlJobUpdateEvent: TelemetryEvent = { eventType: TelemetryEventTypes.MLJobUpdate, @@ -192,4 +193,5 @@ export const telemetryEvents = [ eventLogShowSourceEventDateRangeEvent, openNoteInExpandableFlyoutClickedEvent, addNoteFromExpandableFlyoutClickedEvent, + previewRuleEvent, ]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts index 02342cb4257be..98d6aa64bb9cb 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts @@ -42,4 +42,5 @@ export const createTelemetryClientMock = (): jest.Mocked = reportManualRuleRunOpenModal: jest.fn(), reportOpenNoteInExpandableFlyoutClicked: jest.fn(), reportAddNoteFromExpandableFlyoutClicked: jest.fn(), + reportPreviewRule: jest.fn(), }); diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts index 0023064adac69..e09f0a3c2eb66 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts @@ -44,6 +44,7 @@ import type { ReportManualRuleRunOpenModalParams, ReportEventLogShowSourceEventDateRangeParams, ReportEventLogFilterByRunTypeParams, + PreviewRuleParams, } from './types'; import { TelemetryEventTypes } from './constants'; @@ -211,4 +212,8 @@ export class TelemetryClient implements TelemetryClientStart { ) => { this.analytics.reportEvent(TelemetryEventTypes.AddNoteFromExpandableFlyoutClicked, params); }; + + public reportPreviewRule = (params: PreviewRuleParams) => { + this.analytics.reportEvent(TelemetryEventTypes.PreviewRule, params); + }; } diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts index 49c78dc50feeb..55b91837a2585 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts @@ -72,6 +72,7 @@ import type { NotesTelemetryEvents, OpenNoteInExpandableFlyoutClickedParams, } from './events/notes/types'; +import type { PreviewRuleParams, PreviewRuleTelemetryEvent } from './events/preview_rule/types'; export * from './events/ai_assistant/types'; export * from './events/alerts_grouping/types'; @@ -91,6 +92,7 @@ export type { export * from './events/document_details/types'; export * from './events/manual_rule_run/types'; export * from './events/event_log/types'; +export * from './events/preview_rule/types'; export interface TelemetryServiceSetupParams { analytics: AnalyticsServiceSetup; @@ -136,6 +138,7 @@ export type TelemetryEventParams = | OnboardingHubStepLinkClickedParams | ReportManualRuleRunTelemetryEventParams | ReportEventLogTelemetryEventParams + | PreviewRuleParams | NotesTelemetryEventParams; export interface TelemetryClientStart { @@ -194,6 +197,9 @@ export interface TelemetryClientStart { // new notes reportOpenNoteInExpandableFlyoutClicked(params: OpenNoteInExpandableFlyoutClickedParams): void; reportAddNoteFromExpandableFlyoutClicked(params: AddNoteFromExpandableFlyoutClickedParams): void; + + // preview rule + reportPreviewRule(params: PreviewRuleParams): void; } export type TelemetryEvent = @@ -221,4 +227,5 @@ export type TelemetryEvent = | OnboardingHubTelemetryEvent | ManualRuleRunTelemetryEvent | EventLogTelemetryEvent + | PreviewRuleTelemetryEvent | NotesTelemetryEvents; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/use_preview_rule.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/use_preview_rule.ts index 05c3b9fe10299..018e2602aa170 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/use_preview_rule.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/use_preview_rule.ts @@ -12,7 +12,7 @@ import type { RuleCreateProps, RulePreviewResponse, } from '../../../../../common/api/detection_engine'; - +import { useKibana } from '../../../../common/lib/kibana'; import { previewRule } from '../../../rule_management/api/api'; import { transformOutput } from '../../../../detections/containers/detection_engine/rules/transforms'; import type { TimeframePreviewOptions } from '../../../../detections/pages/detection_engine/rules/types'; @@ -37,6 +37,7 @@ export const usePreviewRule = ({ const [isLoading, setIsLoading] = useState(false); const { addError } = useAppToasts(); const { invocationCount, interval, from } = usePreviewInvocationCount({ timeframeOptions }); + const { telemetry } = useKibana().services; const timeframeEnd = useMemo( () => timeframeOptions.timeframeEnd.toISOString(), @@ -57,6 +58,10 @@ export const usePreviewRule = ({ const createPreviewId = async () => { if (rule != null) { try { + telemetry.reportPreviewRule({ + loggedRequestsEnabled: enableLoggedRequests ?? false, + ruleType: rule.type, + }); setIsLoading(true); const previewRuleResponse = await previewRule({ rule: { @@ -90,7 +95,16 @@ export const usePreviewRule = ({ isSubscribed = false; abortCtrl.abort(); }; - }, [rule, addError, invocationCount, from, interval, timeframeEnd, enableLoggedRequests]); + }, [ + rule, + addError, + invocationCount, + from, + interval, + timeframeEnd, + enableLoggedRequests, + telemetry, + ]); return { isLoading, response, rule, setRule }; }; diff --git a/x-pack/plugins/security_solution/scripts/telemetry/saved_objects/security_solution_ebt_kibana_browser.ndjson b/x-pack/plugins/security_solution/scripts/telemetry/saved_objects/security_solution_ebt_kibana_browser.ndjson index be4eb8f1e7785..f0df277ff5223 100644 --- a/x-pack/plugins/security_solution/scripts/telemetry/saved_objects/security_solution_ebt_kibana_browser.ndjson +++ b/x-pack/plugins/security_solution/scripts/telemetry/saved_objects/security_solution_ebt_kibana_browser.ndjson @@ -1,2 +1,2 @@ -{"attributes":{"allowHidden":false,"fieldAttrs":"{\"properties.groupingId\":{\"count\":1},\"properties.target\":{\"count\":1},\"properties.groupName\":{\"count\":2},\"properties.metadata.telemetry.component\":{\"count\":2},\"properties.unallowedMappingFields\":{\"count\":2},\"properties.unallowedValueFields\":{\"count\":1},\"context.labels.serverless\":{\"count\":4},\"properties.tableId\":{\"count\":1},\"properties.groupNumber\":{\"count\":1},\"properties.groupByField\":{\"count\":4},\"properties.status\":{\"count\":1},\"properties.conversationId\":{\"count\":17},\"properties.invokedBy\":{\"count\":7},\"properties.role\":{\"count\":3},\"properties.isEnabledKnowledgeBase\":{\"count\":1},\"properties.isEnabledRAGAlerts\":{\"count\":1},\"properties.promptTitle\":{\"count\":3},\"properties.fieldName\":{\"count\":1},\"properties.actionId\":{\"count\":1},\"properties.displayName\":{\"count\":1},\"properties.batchId\":{\"count\":8},\"properties.indexId\":{\"count\":1},\"properties.indexName\":{\"count\":2},\"properties.numberOfIndices\":{\"count\":1},\"properties.timeConsumedMs\":{\"count\":1},\"properties.ecsVersion\":{\"count\":1},\"properties.errorCount\":{\"count\":1},\"properties.numberOfIncompatibleFields\":{\"count\":1},\"properties.numberOfDocuments\":{\"count\":1},\"properties.sizeInBytes\":{\"count\":4},\"properties.isCheckAll\":{\"count\":5},\"properties.ilmPhase\":{\"count\":2},\"properties.title\":{\"count\":1},\"properties.location\":{\"count\":1},\"context.applicationId\":{\"count\":6},\"context.cloudId\":{\"count\":6},\"context.cluster_name\":{\"count\":13},\"context.cluster_uuid\":{\"count\":28},\"context.cluster_version\":{\"count\":2},\"context.license_type\":{\"count\":1},\"context.page\":{\"count\":8},\"context.pageName\":{\"count\":6},\"context.page_title\":{\"count\":1},\"context.page_url\":{\"count\":1},\"context.session_id\":{\"count\":2},\"event_type\":{\"count\":36},\"properties\":{\"count\":8},\"properties.pattern\":{\"count\":2},\"peoperties.indexName\":{\"count\":1},\"properties.stepId\":{},\"properties.trigger\":{},\"properties.stepLinkId\":{},\"properties.originStepId\":{},\"properties.durationMs\":{},\"properties.isOpen\":{},\"properties.actionTypeId\":{},\"properties.model\":{},\"properties.provider\":{},\"properties.assistantStreamingEnabled\":{},\"properties.alertsContextCount\":{},\"properties.alertsCount\":{},\"properties.configuredAlertsCount\":{},\"properties.entity\":{},\"properties.selectedSeverity\":{},\"properties.file.size\":{},\"properties.processing.startTime\":{},\"properties.processing.endTime\":{},\"properties.processing.tookMs\":{},\"properties.stats.validLines\":{},\"properties.stats.invalidLines\":{},\"properties.stats.totalLines\":{},\"properties.valid\":{},\"properties.errorCode\":{},\"properties.action\":{},\"properties.quantity\":{},\"properties.jobId\":{},\"properties.isElasticJob\":{},\"properties.moduleId\":{},\"properties.errorMessage\":{},\"properties.count\":{},\"properties.numberOfIndicesChecked\":{},\"properties.numberOfSameFamily\":{},\"properties.numberOfFields\":{},\"properties.numberOfEcsFields\":{},\"properties.numberOfCustomFields\":{},\"properties.panel\":{},\"properties.tabId\":{}}","fieldFormatMap":"{}","fields":"[]","name":"security-solution-ebt-kibana-browser","runtimeFieldMap":"{\"properties.groupingId\":{\"type\":\"keyword\"},\"properties.target\":{\"type\":\"keyword\"},\"property.stackByField\":{\"type\":\"keyword\"},\"properties.groupName\":{\"type\":\"keyword\"},\"context.prebuiltRulesPackageVersion\":{\"type\":\"keyword\"},\"properties.metadata.telemetry.component\":{\"type\":\"keyword\"},\"properties.unallowedMappingFields\":{\"type\":\"keyword\"},\"properties.unallowedValueFields\":{\"type\":\"keyword\"},\"context.labels.serverless\":{\"type\":\"keyword\"},\"properties.resourceAccessed\":{\"type\":\"keyword\"},\"properties.resultCount\":{\"type\":\"long\"},\"properties.responseTime\":{\"type\":\"long\"},\"day_of_week\":{\"type\":\"keyword\",\"script\":{\"source\":\"emit(doc['timestamp'].value.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault()))\"}},\"properties.isOpen\":{\"type\":\"boolean\"},\"properties.tableId\":{\"type\":\"keyword\"},\"properties.groupNumber\":{\"type\":\"long\"},\"properties.groupByField\":{\"type\":\"keyword\"},\"properties.status\":{\"type\":\"keyword\"},\"properties.conversationId\":{\"type\":\"keyword\"},\"properties.invokedBy\":{\"type\":\"keyword\"},\"properties.role\":{\"type\":\"keyword\"},\"properties.isEnabledKnowledgeBase\":{\"type\":\"boolean\"},\"properties.isEnabledRAGAlerts\":{\"type\":\"boolean\"},\"properties.actionTypeId\":{\"type\":\"keyword\"},\"properties.model\":{\"type\":\"keyword\"},\"properties.provider\":{\"type\":\"keyword\"},\"properties.promptTitle\":{\"type\":\"keyword\"},\"properties.assistantStreamingEnabled\":{\"type\":\"boolean\"},\"properties.durationMs\":{\"type\":\"long\"},\"properties.alertsContextCount\":{\"type\":\"long\"},\"properties.alertsCount\":{\"type\":\"long\"},\"properties.configuredAlertsCount\":{\"type\":\"long\"},\"properties.entity\":{\"type\":\"keyword\"},\"properties.selectedSeverity\":{\"type\":\"keyword\"},\"properties.file.size\":{\"type\":\"long\"},\"properties.processing.startTime\":{\"type\":\"date\"},\"properties.processing.endTime\":{\"type\":\"date\"},\"properties.processing.tookMs\":{\"type\":\"long\"},\"properties.stats.validLines\":{\"type\":\"long\"},\"properties.stats.invalidLines\":{\"type\":\"long\"},\"properties.stats.totalLines\":{\"type\":\"long\"},\"properties.valid\":{\"type\":\"boolean\"},\"properties.errorCode\":{\"type\":\"keyword\"},\"properties.action\":{\"type\":\"keyword\"},\"properties.quantity\":{\"type\":\"long\"},\"properties.jobId\":{\"type\":\"keyword\"},\"properties.isElasticJob\":{\"type\":\"boolean\"},\"properties.moduleId\":{\"type\":\"keyword\"},\"properties.errorMessage\":{\"type\":\"keyword\"},\"properties.fieldName\":{\"type\":\"keyword\"},\"properties.actionId\":{\"type\":\"keyword\"},\"properties.displayName\":{\"type\":\"keyword\"},\"properties.count\":{\"type\":\"long\"},\"properties.batchId\":{\"type\":\"keyword\"},\"properties.indexId\":{\"type\":\"keyword\"},\"properties.indexName\":{\"type\":\"keyword\"},\"properties.numberOfIndices\":{\"type\":\"long\"},\"properties.numberOfIndicesChecked\":{\"type\":\"long\"},\"properties.numberOfSameFamily\":{\"type\":\"long\"},\"properties.timeConsumedMs\":{\"type\":\"long\"},\"properties.ecsVersion\":{\"type\":\"keyword\"},\"properties.errorCount\":{\"type\":\"long\"},\"properties.numberOfFields\":{\"type\":\"long\"},\"properties.numberOfIncompatibleFields\":{\"type\":\"long\"},\"properties.numberOfEcsFields\":{\"type\":\"long\"},\"properties.numberOfCustomFields\":{\"type\":\"long\"},\"properties.numberOfDocuments\":{\"type\":\"long\"},\"properties.sizeInBytes\":{\"type\":\"long\"},\"properties.isCheckAll\":{\"type\":\"boolean\"},\"properties.ilmPhase\":{\"type\":\"keyword\"},\"properties.title\":{\"type\":\"keyword\"},\"properties.location\":{\"type\":\"keyword\"},\"properties.panel\":{\"type\":\"keyword\"},\"properties.tabId\":{\"type\":\"keyword\"},\"properties.stepId\":{\"type\":\"keyword\"},\"properties.trigger\":{\"type\":\"keyword\"},\"properties.originStepId\":{\"type\":\"keyword\"},\"properties.stepLinkId\":{\"type\":\"keyword\"}}","sourceFilters":"[]","timeFieldName":"timestamp","title":"ebt-kibana-browser","typeMeta":"{}"},"coreMigrationVersion":"8.8.0","created_at":"2024-05-30T16:12:33.003Z","id":"security-solution-ebt-kibana-browser","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2024-05-30T16:52:03.990Z","version":"WzMwNTU0LDVd"} -{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} +{"attributes":{"allowHidden":false,"fieldAttrs":"{\"properties.groupingId\":{\"count\":1},\"properties.target\":{\"count\":1},\"properties.groupName\":{\"count\":2},\"properties.metadata.telemetry.component\":{\"count\":2},\"properties.unallowedMappingFields\":{\"count\":2},\"properties.unallowedValueFields\":{\"count\":1},\"context.labels.serverless\":{\"count\":4},\"properties.isEnabledRAGAlerts\":{\"count\":1},\"properties.tableId\":{\"count\":1},\"properties.groupNumber\":{\"count\":1},\"properties.groupByField\":{\"count\":4},\"properties.status\":{\"count\":1},\"properties.conversationId\":{\"count\":17},\"properties.invokedBy\":{\"count\":7},\"properties.role\":{\"count\":3},\"properties.isEnabledKnowledgeBase\":{\"count\":1},\"properties.promptTitle\":{\"count\":3},\"properties.fieldName\":{\"count\":1},\"properties.actionId\":{\"count\":1},\"properties.displayName\":{\"count\":1},\"properties.batchId\":{\"count\":8},\"properties.indexId\":{\"count\":1},\"properties.indexName\":{\"count\":2},\"properties.numberOfIndices\":{\"count\":1},\"properties.timeConsumedMs\":{\"count\":1},\"properties.ecsVersion\":{\"count\":1},\"properties.errorCount\":{\"count\":1},\"properties.numberOfIncompatibleFields\":{\"count\":1},\"properties.numberOfDocuments\":{\"count\":1},\"properties.sizeInBytes\":{\"count\":4},\"properties.isCheckAll\":{\"count\":5},\"properties.ilmPhase\":{\"count\":2},\"properties.title\":{\"count\":1},\"properties.location\":{\"count\":1},\"context.applicationId\":{\"count\":6},\"context.cloudId\":{\"count\":6},\"context.cluster_name\":{\"count\":13},\"context.cluster_uuid\":{\"count\":28},\"context.cluster_version\":{\"count\":2},\"context.license_type\":{\"count\":1},\"context.page\":{\"count\":8},\"context.pageName\":{\"count\":6},\"context.page_title\":{\"count\":1},\"context.page_url\":{\"count\":1},\"context.session_id\":{\"count\":2},\"event_type\":{\"count\":36},\"properties\":{\"count\":8},\"properties.pattern\":{\"count\":2},\"peoperties.indexName\":{\"count\":1},\"properties.stepId\":{},\"properties.trigger\":{},\"properties.stepLinkId\":{},\"properties.originStepId\":{},\"properties.durationMs\":{},\"properties.isOpen\":{},\"properties.actionTypeId\":{},\"properties.model\":{},\"properties.provider\":{},\"properties.assistantStreamingEnabled\":{},\"properties.alertsContextCount\":{},\"properties.alertsCount\":{},\"properties.configuredAlertsCount\":{},\"properties.entity\":{},\"properties.selectedSeverity\":{},\"properties.file.size\":{},\"properties.processing.startTime\":{},\"properties.processing.endTime\":{},\"properties.processing.tookMs\":{},\"properties.stats.validLines\":{},\"properties.stats.invalidLines\":{},\"properties.stats.totalLines\":{},\"properties.valid\":{},\"properties.errorCode\":{},\"properties.action\":{},\"properties.quantity\":{},\"properties.jobId\":{},\"properties.isElasticJob\":{},\"properties.moduleId\":{},\"properties.errorMessage\":{},\"properties.count\":{},\"properties.numberOfIndicesChecked\":{},\"properties.numberOfSameFamily\":{},\"properties.numberOfFields\":{},\"properties.numberOfEcsFields\":{},\"properties.numberOfCustomFields\":{},\"properties.panel\":{},\"properties.tabId\":{},\"properties.totalTasks\":{},\"properties.completedTasks\":{},\"properties.errorTasks\":{},\"properties.rangeInMs\":{},\"properties.type\":{},\"properties.runType\":{},\"properties.isVisible\":{},\"properties.alertsCountUpdated\":{},\"properties.rulesCount\":{},\"properties.isRelatedToATimeline\":{},\"propeties.loggedRequestsEnabled\":{},\"properties.ruleType\":{},\"properties.loggedRequestsEnabled\":{}}","fieldFormatMap":"{}","fields":"[]","name":"security-solution-ebt-kibana-browser","runtimeFieldMap":"{\"properties.groupingId\":{\"type\":\"keyword\"},\"properties.target\":{\"type\":\"keyword\"},\"property.stackByField\":{\"type\":\"keyword\"},\"properties.groupName\":{\"type\":\"keyword\"},\"context.prebuiltRulesPackageVersion\":{\"type\":\"keyword\"},\"properties.metadata.telemetry.component\":{\"type\":\"keyword\"},\"properties.unallowedMappingFields\":{\"type\":\"keyword\"},\"properties.unallowedValueFields\":{\"type\":\"keyword\"},\"context.labels.serverless\":{\"type\":\"keyword\"},\"properties.resourceAccessed\":{\"type\":\"keyword\"},\"properties.resultCount\":{\"type\":\"long\"},\"properties.responseTime\":{\"type\":\"long\"},\"day_of_week\":{\"type\":\"keyword\",\"script\":{\"source\":\"emit(doc['timestamp'].value.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault()))\"}},\"properties.isEnabledRAGAlerts\":{\"type\":\"boolean\"},\"properties.durationMs\":{\"type\":\"long\"},\"properties.alertsContextCount\":{\"type\":\"long\"},\"properties.alertsCount\":{\"type\":\"long\"},\"properties.configuredAlertsCount\":{\"type\":\"long\"},\"properties.runType\":{\"type\":\"keyword\"},\"properties.isOpen\":{\"type\":\"boolean\"},\"properties.tableId\":{\"type\":\"keyword\"},\"properties.groupNumber\":{\"type\":\"long\"},\"properties.groupByField\":{\"type\":\"keyword\"},\"properties.status\":{\"type\":\"keyword\"},\"properties.conversationId\":{\"type\":\"keyword\"},\"properties.invokedBy\":{\"type\":\"keyword\"},\"properties.role\":{\"type\":\"keyword\"},\"properties.actionTypeId\":{\"type\":\"keyword\"},\"properties.model\":{\"type\":\"keyword\"},\"properties.provider\":{\"type\":\"keyword\"},\"properties.isEnabledKnowledgeBase\":{\"type\":\"boolean\"},\"properties.promptTitle\":{\"type\":\"keyword\"},\"properties.alertsCountUpdated\":{\"type\":\"boolean\"},\"properties.assistantStreamingEnabled\":{\"type\":\"boolean\"},\"properties.entity\":{\"type\":\"keyword\"},\"properties.selectedSeverity\":{\"type\":\"keyword\"},\"properties.file.size\":{\"type\":\"long\"},\"properties.processing.startTime\":{\"type\":\"date\"},\"properties.processing.endTime\":{\"type\":\"date\"},\"properties.processing.tookMs\":{\"type\":\"long\"},\"properties.stats.validLines\":{\"type\":\"long\"},\"properties.stats.invalidLines\":{\"type\":\"long\"},\"properties.stats.totalLines\":{\"type\":\"long\"},\"properties.valid\":{\"type\":\"boolean\"},\"properties.errorCode\":{\"type\":\"keyword\"},\"properties.action\":{\"type\":\"keyword\"},\"properties.quantity\":{\"type\":\"long\"},\"properties.jobId\":{\"type\":\"keyword\"},\"properties.isElasticJob\":{\"type\":\"boolean\"},\"properties.moduleId\":{\"type\":\"keyword\"},\"properties.errorMessage\":{\"type\":\"keyword\"},\"properties.fieldName\":{\"type\":\"keyword\"},\"properties.actionId\":{\"type\":\"keyword\"},\"properties.displayName\":{\"type\":\"keyword\"},\"properties.count\":{\"type\":\"long\"},\"properties.batchId\":{\"type\":\"keyword\"},\"properties.indexId\":{\"type\":\"keyword\"},\"properties.indexName\":{\"type\":\"keyword\"},\"properties.numberOfIndices\":{\"type\":\"long\"},\"properties.numberOfIndicesChecked\":{\"type\":\"long\"},\"properties.numberOfSameFamily\":{\"type\":\"long\"},\"properties.timeConsumedMs\":{\"type\":\"long\"},\"properties.ecsVersion\":{\"type\":\"keyword\"},\"properties.errorCount\":{\"type\":\"long\"},\"properties.numberOfFields\":{\"type\":\"long\"},\"properties.numberOfIncompatibleFields\":{\"type\":\"long\"},\"properties.numberOfEcsFields\":{\"type\":\"long\"},\"properties.numberOfCustomFields\":{\"type\":\"long\"},\"properties.numberOfDocuments\":{\"type\":\"long\"},\"properties.sizeInBytes\":{\"type\":\"long\"},\"properties.isCheckAll\":{\"type\":\"boolean\"},\"properties.ilmPhase\":{\"type\":\"keyword\"},\"properties.title\":{\"type\":\"keyword\"},\"properties.location\":{\"type\":\"keyword\"},\"properties.panel\":{\"type\":\"keyword\"},\"properties.tabId\":{\"type\":\"keyword\"},\"properties.stepId\":{\"type\":\"keyword\"},\"properties.trigger\":{\"type\":\"keyword\"},\"properties.originStepId\":{\"type\":\"keyword\"},\"properties.stepLinkId\":{\"type\":\"keyword\"},\"properties.totalTasks\":{\"type\":\"long\"},\"properties.completedTasks\":{\"type\":\"long\"},\"properties.errorTasks\":{\"type\":\"long\"},\"properties.rangeInMs\":{\"type\":\"long\"},\"properties.rulesCount\":{\"type\":\"long\"},\"properties.type\":{\"type\":\"keyword\"},\"properties.isVisible\":{\"type\":\"boolean\"},\"properties.isRelatedToATimeline\":{\"type\":\"boolean\"},\"properties.ruleType\":{\"type\":\"keyword\"},\"properties.loggedRequestsEnabled\":{\"type\":\"boolean\"}}","sourceFilters":"[]","timeFieldName":"timestamp","title":"ebt-kibana-browser","typeMeta":"{}"},"coreMigrationVersion":"8.8.0","created_at":"2024-05-30T16:12:33.003Z","id":"security-solution-ebt-kibana-browser","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2024-10-09T14:55:41.854Z","version":"WzUyMTQ4LDld"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file From a481da68e58cb20d6407c9866c1511717addfdb0 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Oct 2024 10:53:59 +0200 Subject: [PATCH 105/110] [HTTP] Copy array returned by `getRoutes` (#195647) ## Summary Small follow up based on https://github.com/elastic/kibana/pull/192675#discussion_r1793601519 --- .../core/http/core-http-router-server-internal/src/router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/http/core-http-router-server-internal/src/router.ts b/packages/core/http/core-http-router-server-internal/src/router.ts index 1a74e27910c1a..bb99de64581be 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.ts @@ -240,7 +240,7 @@ export class Router !route.isVersioned); } - return this.routes; + return [...this.routes]; } public handleLegacyErrors = wrapErrors; From dbc0e6f085d73206a9c4efd38a29bfa4bf045029 Mon Sep 17 00:00:00 2001 From: Elena Shostak <165678770+elena-shostak@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:05:01 +0200 Subject: [PATCH 106/110] [CodeQL] Added env vars for code scanning data ingestion (#195712) ## Summary Added env vars for code scanning data ingestion. --- .github/workflows/codeql.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e16dbcb261807..e80b3b2c73463 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -73,7 +73,9 @@ jobs: env: GITHUB_TOKEN: ${{secrets.KIBANAMACHINE_TOKEN}} SLACK_TOKEN: ${{secrets.CODE_SCANNING_SLACK_TOKEN}} - CODEQL_BRANCHES: 7.17,8.x,main + CODE_SCANNING_ES_HOST: ${{secrets.CODE_SCANNING_ES_HOST}} + CODE_SCANNING_ES_API_KEY: ${{secrets.CODE_SCANNING_ES_API_KEY}} + CODE_SCANNING_BRANCHES: 7.17,8.x,main run: | npm ci --omit=dev node codeql-alert From d44d3543fb71858de5b09e04f3a538bd8cb0bf5b Mon Sep 17 00:00:00 2001 From: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:19:28 +0200 Subject: [PATCH 107/110] [ML] Fix Anomaly Swim Lane Embeddable not updating properly on query change (#195090) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fix for: [#194579](https://github.com/elastic/kibana/issues/194579) In Anomaly Explorer, we do not limit the query size, as it is based on a constant value of `1000`. However, we did limit the query for the embeddable by setting the size to the value of the previous query cardinality. After discussing with @darnautov, we couldn't identify any potential regressions from removing this check. Includes fix for issue mentioned in: [#2397303538](https://github.com/elastic/kibana/pull/195090#issuecomment-2397303538) When querying from a pagination page other than page 1, we didn’t reset the `fromPage` value, which prevented the query from returning results. Before: https://github.com/user-attachments/assets/80476a0c-8fcc-40f7-8cac-04ecfb01d614 After: https://github.com/user-attachments/assets/f55e20fd-b1a4-446e-b16a-b1a6069bf63c https://github.com/user-attachments/assets/d31cb47d-cd13-4b3c-b6f9-c0ee60d3a370 --- .../anomaly_swimlane_embeddable_factory.tsx | 19 ++++++++++++++++++- .../initialize_swim_lane_data_fetcher.ts | 10 ++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx index 34390075f927b..464b5bd196675 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx @@ -18,6 +18,7 @@ import { apiHasExecutionContext, apiHasParentApi, apiPublishesTimeRange, + fetch$, initializeTimeRange, initializeTitles, useBatchedPublishingSubjects, @@ -26,7 +27,8 @@ import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import React, { useCallback, useState } from 'react'; import useUnmount from 'react-use/lib/useUnmount'; import type { Observable } from 'rxjs'; -import { BehaviorSubject, combineLatest, map, of, Subscription } from 'rxjs'; +import { BehaviorSubject, combineLatest, distinctUntilChanged, map, of, Subscription } from 'rxjs'; +import fastIsEqual from 'fast-deep-equal'; import type { AnomalySwimlaneEmbeddableServices } from '..'; import { ANOMALY_SWIMLANE_EMBEDDABLE_TYPE } from '..'; import type { MlDependencies } from '../../application/app'; @@ -235,6 +237,21 @@ export const getAnomalySwimLaneEmbeddableFactory = ( anomalySwimLaneServices ); + subscriptions.add( + fetch$(api) + .pipe( + map((fetchContext) => ({ + query: fetchContext.query, + filters: fetchContext.filters, + timeRange: fetchContext.timeRange, + })), + distinctUntilChanged(fastIsEqual) + ) + .subscribe(() => { + api.updatePagination({ fromPage: 1 }); + }) + ); + const onRenderComplete = () => {}; return { diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/initialize_swim_lane_data_fetcher.ts b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/initialize_swim_lane_data_fetcher.ts index 268a17fca4a81..be678af02a65b 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/initialize_swim_lane_data_fetcher.ts +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/initialize_swim_lane_data_fetcher.ts @@ -6,7 +6,7 @@ */ import type { estypes } from '@elastic/elasticsearch'; -import type { TimeRange } from '@kbn/es-query'; +import { type TimeRange } from '@kbn/es-query'; import type { PublishesUnifiedSearch } from '@kbn/presentation-publishing'; import { BehaviorSubject, @@ -29,7 +29,6 @@ import { SWIMLANE_TYPE, } from '../../application/explorer/explorer_constants'; import type { OverallSwimlaneData } from '../../application/explorer/explorer_utils'; -import { isViewBySwimLaneData } from '../../application/explorer/swimlane_container'; import { CONTROLLED_BY_SWIM_LANE_FILTER } from '../../ui_actions/constants'; import { getJobsObservable } from '../common/get_jobs_observable'; import { processFilters } from '../common/process_filters'; @@ -114,12 +113,7 @@ export const initializeSwimLaneDataFetcher = ( const { earliest, latest } = overallSwimlaneData; if (overallSwimlaneData && swimlaneType === SWIMLANE_TYPE.VIEW_BY) { - const swimlaneData = swimLaneData$.value; - - let swimLaneLimit = ANOMALY_SWIM_LANE_HARD_LIMIT; - if (isViewBySwimLaneData(swimlaneData) && viewBy === swimlaneData.fieldName) { - swimLaneLimit = swimlaneData.cardinality; - } + const swimLaneLimit = ANOMALY_SWIM_LANE_HARD_LIMIT; return from( anomalyTimelineService.loadViewBySwimlane( From 7a30154fdfc109a87b69d429bb2252cf5499d5b9 Mon Sep 17 00:00:00 2001 From: kosabogi <105062005+kosabogi@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:27:03 +0200 Subject: [PATCH 108/110] [Search landing page] Update search landing page list with new links (#194656) ### Overview This PR updates the search landing page by refreshing the existing list with new links. ### Related issue https://github.com/elastic/search-docs-team/issues/200 --------- Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com> --- docs/search/index.asciidoc | 78 +++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/docs/search/index.asciidoc b/docs/search/index.asciidoc index f046330ac13e9..ab4b007800da4 100644 --- a/docs/search/index.asciidoc +++ b/docs/search/index.asciidoc @@ -9,8 +9,8 @@ The *Search* space in {kib} comprises the following features: * <> * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-application-overview.html[Search Applications] * https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-overview.html[Behavioral Analytics] -* Inference Endpoints UI -* AI Assistant for Search +* <> +* <> * Persistent Dev Tools <> [float] @@ -19,53 +19,53 @@ The *Search* space in {kib} comprises the following features: The Search solution and use case is made up of many tools and features across the {stack}. As a result, the release notes for your features of interest might live in different Elastic docs. -// Use the following table to find links to the appropriate documentation, API references (if applicable), and release notes. +Use the following table to find links to the appropriate documentation, API references (if applicable), and release notes. -// [options="header"] -// |=== -// | Name | API reference | Documentation | Release notes +[options="header"] +|=== +| Name | API reference | Documentation | Release notes -// | Connectors -// | link:https://example.com/connectors/api[API reference] -// | link:https://example.com/connectors/docs[Documentation] -// | link:https://example.com/connectors/notes[Release notes] +| Connectors +| {ref}/connector-apis.html[API reference] +| {ref}/es-connectors.html[Elastic Connectors] +| {ref}/es-connectors-release-notes.html[Elasticsearch guide] -// | Web crawler -// | link:https://example.com/web_crawlers/api[API reference] -// | link:https://example.com/web_crawlers/docs[Documentation] -// | link:https://example.com/web_crawlers/notes[Release notes] +| Web crawler +| N/A +| {enterprise-search-ref}/crawler.html[Documentation] +| {enterprise-search-ref}/changelog.html[Enterprise Search Guide] -// | Playground -// | link:https://example.com/playground/api[API reference] -// | link:https://example.com/playground/docs[Documentation] -// | link:https://example.com/playground/notes[Release notes] +| Playground +| N/A +| {kibana-ref}/playground.html[Documentation] +| {kibana-ref}/release-notes.html[Kibana guide] -// | Search Applications -// | link:https://example.com/search_apps/api[API reference] -// | link:https://example.com/search_apps/docs[Documentation] -// | link:https://example.com/search_apps/notes[Release notes] +| Search Applications +| {ref}/search-application-apis.html[API reference] +| {enterprise-search-ref}/app-search-workplace-search.html[Documentation] +| {ref}/es-release-notes.html[Elasticsearch guide] -// | Behavioral Analytics -// | link:https://example.com/behavioral_analytics/api[API reference] -// | link:https://example.com/behavioral_analytics/docs[Documentation] -// | link:https://example.com/behavioral_analytics/notes[Release notes] +| Behavioral Analytics +| {ref}/behavioral-analytics-apis.html[API reference] +| {ref}/behavioral-analytics-start.html[Documentation] +| {ref}/es-release-notes.html[Elasticsearch guide] -// | Inference Endpoints -// | link:https://example.com/inference_endpoints/api[API reference] -// | link:https://example.com/inference_endpoints/docs[Documentation] -// | link:https://example.com/inference_endpoints/notes[Release notes] +| Inference Endpoints +| {ref}/inference-apis.html[API reference] +| {kibana-ref}/inference-endpoints.html[Documentation] +| {ref}/es-release-notes.html[Elasticsearch guide] -// | Console -// | link:https://example.com/console/api[API reference] -// | link:https://example.com/console/docs[Documentation] -// | link:https://example.com/console/notes[Release notes] +| Console +| N/A +| {kibana-ref}/console-kibana.html[Documentation] +| {kibana-ref}/release-notes.html[Kibana guide] -// | Search UI -// | link:https://www.elastic.co/docs/current/search-ui/api/architecture[API reference] -// | link:https://www.elastic.co/docs/current/search-ui/overview[Documentation] -// | link:https://example.com/search_ui/notes[Release notes] +| Search UI +| https://www.elastic.co/docs/current/search-ui/api/architecture[API reference] +| https://www.elastic.co/docs/current/search-ui[Documentation] +| https://www.elastic.co/docs/current/search-ui[Search UI] -// |=== +|=== include::search-connection-details.asciidoc[] include::playground/index.asciidoc[] From c9200332ffe13e1df7225f023fa493f415ab429f Mon Sep 17 00:00:00 2001 From: Bharat Pasupula <123897612+bhapas@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:31:30 +0200 Subject: [PATCH 109/110] [Automatic Import] Add Cypress tests for Automatic Import UI flow (#194948) ## Summary Adds Cypress functional UI tests for different flows in Automatic Import. - Relates [#192684](https://github.com/elastic/kibana/issues/192684) ### RBAC tests #### Create Integration Landing Page - Fleet `read` Integrations `all` -- No access - Fleet `read` Integrations `read` -- No access - Fleet `read` Integrations `read` -- No access - Fleet `all` Integrations `all` -- Access #### Create Integration Assistant Page - Fleet/integrations `all` Actions `read` [ `show` `execute` ] -- Execute with existing connectors - Fleet/integrations `all` Actions `all` [ `show` `execute` `save` `delete` ] -- Create new connector / execute existing ones. ### Create Integration UI Flow - NDJSON example - Create an integration using Automatic Import with NDJSON samples https://github.com/user-attachments/assets/9ab4cfc2-f058-4491-a280-6b86bcc5c9ce --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../e2e/integrations_automatic_import.cy.ts | 115 ++++ ...ileges_integrations_automatic_import.cy.ts | 159 ++++++ .../fleet/cypress/fixtures/teleport.ndjson | 1 + .../screens/integrations_automatic_import.ts | 35 ++ .../cypress/tasks/api_calls/connectors.ts | 88 +++ .../cypress/tasks/api_calls/graph_results.ts | 531 ++++++++++++++++++ .../plugins/fleet/cypress/tasks/privileges.ts | 113 +++- x-pack/plugins/fleet/cypress/tsconfig.json | 1 + .../missing_privileges_description.tsx | 2 +- .../success_section/success_section.tsx | 14 +- .../steps/connector_step/connector_setup.tsx | 5 +- .../create_integration_landing.tsx | 5 +- .../integration_assistant_card.tsx | 5 +- .../integration_builder/readme_files.ts | 15 +- .../server/templates/build_readme.md.njk | 2 +- .../{readme.njk => description_readme.njk} | 0 .../server/templates/package_readme.md.njk | 2 +- 17 files changed, 1081 insertions(+), 12 deletions(-) create mode 100644 x-pack/plugins/fleet/cypress/e2e/integrations_automatic_import.cy.ts create mode 100644 x-pack/plugins/fleet/cypress/e2e/privileges_integrations_automatic_import.cy.ts create mode 100644 x-pack/plugins/fleet/cypress/fixtures/teleport.ndjson create mode 100644 x-pack/plugins/fleet/cypress/screens/integrations_automatic_import.ts create mode 100644 x-pack/plugins/fleet/cypress/tasks/api_calls/connectors.ts create mode 100644 x-pack/plugins/fleet/cypress/tasks/api_calls/graph_results.ts rename x-pack/plugins/integration_assistant/server/templates/{readme.njk => description_readme.njk} (100%) diff --git a/x-pack/plugins/fleet/cypress/e2e/integrations_automatic_import.cy.ts b/x-pack/plugins/fleet/cypress/e2e/integrations_automatic_import.cy.ts new file mode 100644 index 0000000000000..e2454cb1dcf77 --- /dev/null +++ b/x-pack/plugins/fleet/cypress/e2e/integrations_automatic_import.cy.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { deleteIntegrations } from '../tasks/integrations'; +import { + UPLOAD_PACKAGE_LINK, + ASSISTANT_BUTTON, + TECH_PREVIEW_BADGE, + CREATE_INTEGRATION_LANDING_PAGE, + BUTTON_FOOTER_NEXT, + INTEGRATION_TITLE_INPUT, + INTEGRATION_DESCRIPTION_INPUT, + DATASTREAM_TITLE_INPUT, + DATASTREAM_DESCRIPTION_INPUT, + DATASTREAM_NAME_INPUT, + DATA_COLLECTION_METHOD_INPUT, + LOGS_SAMPLE_FILE_PICKER, + EDIT_PIPELINE_BUTTON, + SAVE_PIPELINE_BUTTON, + VIEW_INTEGRATION_BUTTON, + INTEGRATION_SUCCESS_SECTION, + SAVE_ZIP_BUTTON, +} from '../screens/integrations_automatic_import'; +import { cleanupAgentPolicies } from '../tasks/cleanup'; +import { login, logout } from '../tasks/login'; +import { createBedrockConnector, deleteConnectors } from '../tasks/api_calls/connectors'; +import { + ecsResultsForJson, + categorizationResultsForJson, + relatedResultsForJson, +} from '../tasks/api_calls/graph_results'; + +describe('Add Integration - Automatic Import', () => { + beforeEach(() => { + login(); + + cleanupAgentPolicies(); + deleteIntegrations(); + + // Create a mock connector + deleteConnectors(); + createBedrockConnector(); + // Mock API Responses + cy.intercept('POST', '/api/integration_assistant/ecs', { + statusCode: 200, + body: { + results: ecsResultsForJson, + }, + }); + cy.intercept('POST', '/api/integration_assistant/categorization', { + statusCode: 200, + body: { + results: categorizationResultsForJson, + }, + }); + cy.intercept('POST', '/api/integration_assistant/related', { + statusCode: 200, + body: { + results: relatedResultsForJson, + }, + }); + }); + + afterEach(() => { + deleteConnectors(); + cleanupAgentPolicies(); + deleteIntegrations(); + logout(); + }); + + it('should create an integration', () => { + cy.visit(CREATE_INTEGRATION_LANDING_PAGE); + + cy.getBySel(ASSISTANT_BUTTON).should('exist'); + cy.getBySel(UPLOAD_PACKAGE_LINK).should('exist'); + cy.getBySel(TECH_PREVIEW_BADGE).should('exist'); + + // Create Integration Assistant Page + cy.getBySel(ASSISTANT_BUTTON).click(); + cy.getBySel(BUTTON_FOOTER_NEXT).click(); + + // Integration details Page + cy.getBySel(INTEGRATION_TITLE_INPUT).type('Test Integration'); + cy.getBySel(INTEGRATION_DESCRIPTION_INPUT).type('Test Integration Description'); + cy.getBySel(BUTTON_FOOTER_NEXT).click(); + + // Datastream details page + cy.getBySel(DATASTREAM_TITLE_INPUT).type('Audit'); + cy.getBySel(DATASTREAM_DESCRIPTION_INPUT).type('Test Datastream Description'); + cy.getBySel(DATASTREAM_NAME_INPUT).type('audit'); + cy.getBySel(DATA_COLLECTION_METHOD_INPUT).type('file stream'); + cy.get('body').click(0, 0); + + // Select sample logs file and Analyze logs + cy.fixture('teleport.ndjson', null).as('myFixture'); + cy.getBySel(LOGS_SAMPLE_FILE_PICKER).selectFile('@myFixture'); + cy.getBySel(BUTTON_FOOTER_NEXT).click(); + + // Edit Pipeline + cy.getBySel(EDIT_PIPELINE_BUTTON).click(); + cy.getBySel(SAVE_PIPELINE_BUTTON).click(); + + // Deploy + cy.getBySel(BUTTON_FOOTER_NEXT).click(); + cy.getBySel(INTEGRATION_SUCCESS_SECTION).should('exist'); + cy.getBySel(SAVE_ZIP_BUTTON).should('exist'); + + // View Integration + cy.getBySel(VIEW_INTEGRATION_BUTTON).click(); + }); +}); diff --git a/x-pack/plugins/fleet/cypress/e2e/privileges_integrations_automatic_import.cy.ts b/x-pack/plugins/fleet/cypress/e2e/privileges_integrations_automatic_import.cy.ts new file mode 100644 index 0000000000000..29eaab7eaca0a --- /dev/null +++ b/x-pack/plugins/fleet/cypress/e2e/privileges_integrations_automatic_import.cy.ts @@ -0,0 +1,159 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { User } from '../tasks/privileges'; +import { + deleteUsersAndRoles, + getIntegrationsAutoImportRole, + createUsersAndRoles, + AutomaticImportConnectorNoneUser, + AutomaticImportConnectorNoneRole, + AutomaticImportConnectorAllUser, + AutomaticImportConnectorAllRole, + AutomaticImportConnectorReadUser, + AutomaticImportConnectorReadRole, +} from '../tasks/privileges'; +import { login, loginWithUserAndWaitForPage, logout } from '../tasks/login'; +import { + ASSISTANT_BUTTON, + CONNECTOR_BEDROCK, + CONNECTOR_GEMINI, + CONNECTOR_OPENAI, + CREATE_INTEGRATION_ASSISTANT, + CREATE_INTEGRATION_LANDING_PAGE, + CREATE_INTEGRATION_UPLOAD, + MISSING_PRIVILEGES, + UPLOAD_PACKAGE_LINK, +} from '../screens/integrations_automatic_import'; + +describe('When the user does not have enough previleges for Integrations', () => { + const runs = [ + { fleetRole: 'read', integrationsRole: 'read' }, + { fleetRole: 'read', integrationsRole: 'all' }, + { fleetRole: 'all', integrationsRole: 'read' }, + ]; + + runs.forEach(function (run) { + describe(`When the user has '${run.fleetRole}' role for fleet and '${run.integrationsRole}' role for Integrations`, () => { + const automaticImportIntegrRole = getIntegrationsAutoImportRole({ + fleetv2: [run.fleetRole], // fleet + fleet: [run.integrationsRole], // integrations + }); + const AutomaticImportIntegrUser: User = { + username: 'automatic_import_integrations_read_user', + password: 'password', + roles: [automaticImportIntegrRole.name], + }; + + before(() => { + createUsersAndRoles([AutomaticImportIntegrUser], [automaticImportIntegrRole]); + }); + + beforeEach(() => { + login(); + }); + + afterEach(() => { + logout(); + }); + + after(() => { + deleteUsersAndRoles([AutomaticImportIntegrUser], [automaticImportIntegrRole]); + }); + + it('Create Assistant is not accessible if user has read role in integrations', () => { + loginWithUserAndWaitForPage(CREATE_INTEGRATION_ASSISTANT, AutomaticImportIntegrUser); + cy.getBySel(MISSING_PRIVILEGES).should('exist'); + }); + + it('Create upload is not accessible if user has read role in integrations', () => { + loginWithUserAndWaitForPage(CREATE_INTEGRATION_UPLOAD, AutomaticImportIntegrUser); + cy.getBySel(MISSING_PRIVILEGES).should('exist'); + }); + }); + }); +}); + +describe('When the user has All permissions for Integrations and No permissions for actions', () => { + before(() => { + createUsersAndRoles([AutomaticImportConnectorNoneUser], [AutomaticImportConnectorNoneRole]); + }); + + beforeEach(() => { + login(); + }); + + afterEach(() => { + logout(); + }); + + after(() => { + deleteUsersAndRoles([AutomaticImportConnectorNoneUser], [AutomaticImportConnectorNoneRole]); + }); + + it('Create Assistant is not accessible but upload is accessible', () => { + loginWithUserAndWaitForPage(CREATE_INTEGRATION_LANDING_PAGE, AutomaticImportConnectorNoneUser); + cy.getBySel(ASSISTANT_BUTTON).should('not.exist'); + cy.getBySel(UPLOAD_PACKAGE_LINK).should('exist'); + }); +}); + +describe('When the user has All permissions for Integrations and read permissions for actions', () => { + before(() => { + createUsersAndRoles([AutomaticImportConnectorReadUser], [AutomaticImportConnectorReadRole]); + }); + + beforeEach(() => { + login(); + }); + + afterEach(() => { + logout(); + }); + + after(() => { + deleteUsersAndRoles([AutomaticImportConnectorReadUser], [AutomaticImportConnectorReadRole]); + }); + + it('Create Assistant is not accessible but upload is accessible', () => { + loginWithUserAndWaitForPage(CREATE_INTEGRATION_LANDING_PAGE, AutomaticImportConnectorReadUser); + cy.getBySel(ASSISTANT_BUTTON).should('exist'); + cy.getBySel(UPLOAD_PACKAGE_LINK).should('exist'); + }); + + it('Create Assistant is accessible but execute connector is not accessible', () => { + loginWithUserAndWaitForPage(CREATE_INTEGRATION_ASSISTANT, AutomaticImportConnectorReadUser); + cy.getBySel(CONNECTOR_BEDROCK).should('not.exist'); + cy.getBySel(CONNECTOR_OPENAI).should('not.exist'); + cy.getBySel(CONNECTOR_GEMINI).should('not.exist'); + }); +}); + +describe('When the user has All permissions for Integrations and All permissions for actions', () => { + before(() => { + createUsersAndRoles([AutomaticImportConnectorAllUser], [AutomaticImportConnectorAllRole]); + }); + + beforeEach(() => { + login(); + }); + + afterEach(() => { + logout(); + }); + + after(() => { + deleteUsersAndRoles([AutomaticImportConnectorAllUser], [AutomaticImportConnectorAllRole]); + }); + + it('Create Assistant is not accessible but upload is accessible', () => { + loginWithUserAndWaitForPage(CREATE_INTEGRATION_ASSISTANT, AutomaticImportConnectorAllUser); + cy.getBySel(CONNECTOR_BEDROCK).should('exist'); + cy.getBySel(CONNECTOR_OPENAI).should('exist'); + cy.getBySel(CONNECTOR_GEMINI).should('exist'); + }); +}); diff --git a/x-pack/plugins/fleet/cypress/fixtures/teleport.ndjson b/x-pack/plugins/fleet/cypress/fixtures/teleport.ndjson new file mode 100644 index 0000000000000..82774ac2297d6 --- /dev/null +++ b/x-pack/plugins/fleet/cypress/fixtures/teleport.ndjson @@ -0,0 +1 @@ +{"ei":0,"event":"cert.create","uid":"efd326fc-dd13-4df8-acef-3102c2d717d3","code":"TC000I","time":"2024-02-24T06:56:50.648137154Z"} \ No newline at end of file diff --git a/x-pack/plugins/fleet/cypress/screens/integrations_automatic_import.ts b/x-pack/plugins/fleet/cypress/screens/integrations_automatic_import.ts new file mode 100644 index 0000000000000..e549f88294a3b --- /dev/null +++ b/x-pack/plugins/fleet/cypress/screens/integrations_automatic_import.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const UPLOAD_PACKAGE_LINK = 'uploadPackageLink'; +export const ASSISTANT_BUTTON = 'assistantButton'; +export const TECH_PREVIEW_BADGE = 'techPreviewBadge'; +export const MISSING_PRIVILEGES = 'missingPrivilegesCallOut'; + +export const CONNECTOR_BEDROCK = 'actionType-.bedrock'; +export const CONNECTOR_OPENAI = 'actionType-.gen-ai'; +export const CONNECTOR_GEMINI = 'actionType-.gemini'; + +export const BUTTON_FOOTER_NEXT = 'buttonsFooter-nextButton'; + +export const INTEGRATION_TITLE_INPUT = 'integrationTitleInput'; +export const INTEGRATION_DESCRIPTION_INPUT = 'integrationDescriptionInput'; +export const DATASTREAM_TITLE_INPUT = 'dataStreamTitleInput'; +export const DATASTREAM_DESCRIPTION_INPUT = 'dataStreamDescriptionInput'; +export const DATASTREAM_NAME_INPUT = 'dataStreamNameInput'; +export const DATA_COLLECTION_METHOD_INPUT = 'dataCollectionMethodInput'; +export const LOGS_SAMPLE_FILE_PICKER = 'logsSampleFilePicker'; + +export const EDIT_PIPELINE_BUTTON = 'editPipelineButton'; +export const SAVE_PIPELINE_BUTTON = 'savePipelineButton'; +export const VIEW_INTEGRATION_BUTTON = 'viewIntegrationButton'; +export const INTEGRATION_SUCCESS_SECTION = 'integrationSuccessSection'; +export const SAVE_ZIP_BUTTON = 'saveZipButton'; + +export const CREATE_INTEGRATION_LANDING_PAGE = '/app/integrations/create'; +export const CREATE_INTEGRATION_ASSISTANT = '/app/integrations/create/assistant'; +export const CREATE_INTEGRATION_UPLOAD = '/app/integrations/create/upload'; diff --git a/x-pack/plugins/fleet/cypress/tasks/api_calls/connectors.ts b/x-pack/plugins/fleet/cypress/tasks/api_calls/connectors.ts new file mode 100644 index 0000000000000..230fdcd124562 --- /dev/null +++ b/x-pack/plugins/fleet/cypress/tasks/api_calls/connectors.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AllConnectorsResponse } from '@kbn/actions-plugin/common/routes/connector/response'; + +import { v4 as uuidv4 } from 'uuid'; + +import { API_AUTH, COMMON_API_HEADERS } from '../common'; + +export const bedrockId = uuidv4(); +export const azureId = uuidv4(); + +// Replaces request - adds baseline authentication + global headers +export const request = ({ + headers, + ...options +}: Partial): Cypress.Chainable> => { + return cy.request({ + auth: API_AUTH, + headers: { ...COMMON_API_HEADERS, ...headers }, + ...options, + }); +}; +export const INTERNAL_CLOUD_CONNECTORS = ['Elastic-Cloud-SMTP']; + +export const getConnectors = () => + request({ + method: 'GET', + url: 'api/actions/connectors', + }); + +export const createConnector = (connector: Record, id: string) => + cy.request({ + method: 'POST', + url: `/api/actions/connector/${id}`, + body: connector, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, + }); + +export const deleteConnectors = () => { + getConnectors().then(($response) => { + if ($response.body.length > 0) { + const ids = $response.body.map((connector) => { + return connector.id; + }); + ids.forEach((id) => { + if (!INTERNAL_CLOUD_CONNECTORS.includes(id)) { + request({ + method: 'DELETE', + url: `api/actions/connector/${id}`, + }); + } + }); + } + }); +}; + +export const azureConnectorAPIPayload = { + connector_type_id: '.gen-ai', + secrets: { + apiKey: '123', + }, + config: { + apiUrl: + 'https://goodurl.com/openai/deployments/good-gpt4o/chat/completions?api-version=2024-02-15-preview', + apiProvider: 'Azure OpenAI', + }, + name: 'Azure OpenAI cypress test e2e connector', +}; + +export const bedrockConnectorAPIPayload = { + connector_type_id: '.bedrock', + secrets: { + accessKey: '123', + secret: '123', + }, + config: { + apiUrl: 'https://bedrock.com', + }, + name: 'Bedrock cypress test e2e connector', +}; + +export const createAzureConnector = () => createConnector(azureConnectorAPIPayload, azureId); +export const createBedrockConnector = () => createConnector(bedrockConnectorAPIPayload, bedrockId); diff --git a/x-pack/plugins/fleet/cypress/tasks/api_calls/graph_results.ts b/x-pack/plugins/fleet/cypress/tasks/api_calls/graph_results.ts new file mode 100644 index 0000000000000..3276b6ecf055f --- /dev/null +++ b/x-pack/plugins/fleet/cypress/tasks/api_calls/graph_results.ts @@ -0,0 +1,531 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const ecsResultsForJson = { + mapping: { + teleport2: { + audit: { + ei: null, + event: { + target: 'event.action', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + uid: { + target: 'event.id', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + code: { + target: 'event.code', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + }, + }, + }, + pipeline: { + description: 'Pipeline to process teleport2 audit logs', + processors: [ + { + set: { + field: 'ecs.version', + tag: 'set_ecs_version', + value: '8.11.0', + }, + }, + { + remove: { + field: 'message', + ignore_missing: true, + tag: 'remove_message', + }, + }, + { + json: { + field: 'event.original', + tag: 'json_original', + target_field: 'teleport2.audit', + }, + }, + { + rename: { + field: 'teleport2.audit.event', + target_field: 'event.action', + ignore_missing: true, + }, + }, + { + script: { + description: 'Ensures the date processor does not receive an array value.', + tag: 'script_convert_array_to_string', + lang: 'painless', + source: + 'if (ctx.teleport2?.audit?.time != null &&\n ctx.teleport2.audit.time instanceof ArrayList){\n ctx.teleport2.audit.time = ctx.teleport2.audit.time[0];\n}\n', + }, + }, + { + date: { + field: 'teleport2.audit.time', + target_field: 'event.start', + formats: ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'", 'ISO8601'], + tag: 'date_processor_teleport2.audit.time', + if: 'ctx.teleport2?.audit?.time != null', + }, + }, + { + set: { + field: 'event.kind', + value: 'pipeline_error', + }, + }, + ], + }, +}; + +export const categorizationResultsForJson = { + docs: [ + { + ecs: { + version: '8.11.0', + }, + teleport2: { + audit: { + cert_type: 'user', + time: '2024-02-24T06:56:50.648137154Z', + ei: 0, + identity: { + expires: '2024-02-24T06:56:50.648137154Z', + traits: { + logins: ['root', 'ubuntu', 'ec2-user'], + }, + private_key_policy: 'none', + teleport_cluster: 'teleport.com', + prev_identity_expires: '0001-01-01T00:00:00Z', + route_to_cluster: 'teleport.com', + logins: ['root', 'ubuntu', 'ec2-user', '-teleport-internal-join'], + }, + }, + }, + organization: { + name: 'teleport.com', + }, + source: { + ip: '1.2.3.4', + }, + event: { + code: 'TC000I', + start: '2024-02-24T06:56:50.648Z', + action: 'cert.create', + end: '0001-01-01T00:00:00.000Z', + id: 'efd326fc-dd13-4df8-acef-3102c2d717d3', + category: ['iam', 'authentication'], + type: ['creation', 'start'], + }, + user: { + name: 'teleport-admin', + changes: { + name: '2024-02-24T06:56:50.648Z', + }, + roles: ['access', 'editor'], + }, + tags: [ + '_geoip_database_unavailable_GeoLite2-City.mmdb', + '_geoip_database_unavailable_GeoLite2-ASN.mmdb', + '_geoip_database_unavailable_GeoLite2-City.mmdb', + '_geoip_database_unavailable_GeoLite2-ASN.mmdb', + ], + }, + ], + pipeline: { + description: 'Pipeline to process teleport2 audit logs', + processors: [ + { + set: { + field: 'ecs.version', + tag: 'set_ecs_version', + value: '8.11.0', + }, + }, + { + remove: { + field: 'message', + ignore_missing: true, + tag: 'remove_message', + }, + }, + { + json: { + field: 'event.original', + tag: 'json_original', + target_field: 'teleport2.audit', + }, + }, + { + rename: { + field: 'teleport2.audit.event', + target_field: 'event.action', + ignore_missing: true, + }, + }, + { + script: { + description: 'Ensures the date processor does not receive an array value.', + tag: 'script_convert_array_to_string', + lang: 'painless', + source: + 'if (ctx.teleport2?.audit?.time != null &&\n ctx.teleport2.audit.time instanceof ArrayList){\n ctx.teleport2.audit.time = ctx.teleport2.audit.time[0];\n}\n', + }, + }, + { + date: { + field: 'teleport2.audit.time', + target_field: 'event.start', + formats: ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'", 'ISO8601'], + tag: 'date_processor_teleport2.audit.time', + if: 'ctx.teleport2?.audit?.time != null', + }, + }, + { + set: { + field: 'event.kind', + value: 'pipeline_error', + }, + }, + ], + }, +}; + +export const relatedResultsForJson = { + docs: [ + { + ecs: { + version: '8.11.0', + }, + related: { + user: ['teleport-admin'], + ip: ['1.2.3.4'], + }, + teleport2: { + audit: { + cert_type: 'user', + time: '2024-02-24T06:56:50.648137154Z', + ei: 0, + identity: { + expires: '2024-02-24T06:56:50.648137154Z', + traits: { + logins: ['root', 'ubuntu', 'ec2-user'], + }, + private_key_policy: 'none', + teleport_cluster: 'teleport.com', + prev_identity_expires: '0001-01-01T00:00:00Z', + route_to_cluster: 'teleport.com', + logins: ['root', 'ubuntu', 'ec2-user', '-teleport-internal-join'], + }, + }, + }, + organization: { + name: 'teleport.com', + }, + source: { + ip: '1.2.3.4', + }, + event: { + code: 'TC000I', + start: '2024-02-24T06:56:50.648Z', + action: 'cert.create', + end: '0001-01-01T00:00:00.000Z', + id: 'efd326fc-dd13-4df8-acef-3102c2d717d3', + category: ['iam', 'authentication'], + type: ['creation', 'start'], + }, + user: { + name: 'teleport-admin', + changes: { + name: '2024-02-24T06:56:50.648Z', + }, + roles: ['access', 'editor'], + }, + tags: [ + '_geoip_database_unavailable_GeoLite2-City.mmdb', + '_geoip_database_unavailable_GeoLite2-ASN.mmdb', + '_geoip_database_unavailable_GeoLite2-City.mmdb', + '_geoip_database_unavailable_GeoLite2-ASN.mmdb', + ], + }, + ], + pipeline: { + description: 'Pipeline to process teleport2 audit logs', + processors: [ + { + set: { + tag: 'set_ecs_version', + field: 'ecs.version', + value: '8.11.0', + }, + }, + { + set: { + tag: 'copy_original_message', + field: 'originalMessage', + copy_from: 'message', + }, + }, + { + rename: { + ignore_missing: true, + if: 'ctx.event?.original == null', + tag: 'rename_message', + field: 'originalMessage', + target_field: 'event.original', + }, + }, + { + rename: { + ignore_missing: true, + field: 'teleport2.audit.user', + target_field: 'user.name', + }, + }, + { + rename: { + ignore_missing: true, + field: 'teleport2.audit.login', + target_field: 'user.id', + }, + }, + { + rename: { + ignore_missing: true, + field: 'teleport2.audit.server_hostname', + target_field: 'destination.domain', + }, + }, + { + rename: { + ignore_missing: true, + field: 'teleport2.audit.addr.remote', + target_field: 'source.address', + }, + }, + { + rename: { + ignore_missing: true, + field: 'teleport2.audit.proto', + target_field: 'network.protocol', + }, + }, + { + script: { + tag: 'script_drop_null_empty_values', + description: 'Drops null/empty values recursively.', + lang: 'painless', + source: + 'boolean dropEmptyFields(Object object) {\n if (object == null || object == "") {\n return true;\n } else if (object instanceof Map) {\n ((Map) object).values().removeIf(value -> dropEmptyFields(value));\n return (((Map) object).size() == 0);\n } else if (object instanceof List) {\n ((List) object).removeIf(value -> dropEmptyFields(value));\n return (((List) object).length == 0);\n }\n return false;\n}\ndropEmptyFields(ctx);\n', + }, + }, + { + geoip: { + ignore_missing: true, + tag: 'geoip_source_ip', + field: 'source.ip', + target_field: 'source.geo', + }, + }, + { + geoip: { + ignore_missing: true, + tag: 'geoip_source_asn', + database_file: 'GeoLite2-ASN.mmdb', + field: 'source.ip', + target_field: 'source.as', + properties: ['asn', 'organization_name'], + }, + }, + { + rename: { + ignore_missing: true, + tag: 'rename_source_as_asn', + field: 'source.as.asn', + target_field: 'source.as.number', + }, + }, + { + rename: { + ignore_missing: true, + tag: 'rename_source_as_organization_name', + field: 'source.as.organization_name', + target_field: 'source.as.organization.name', + }, + }, + { + geoip: { + ignore_missing: true, + tag: 'geoip_destination_ip', + field: 'destination.ip', + target_field: 'destination.geo', + }, + }, + { + geoip: { + ignore_missing: true, + tag: 'geoip_destination_asn', + database_file: 'GeoLite2-ASN.mmdb', + field: 'destination.ip', + target_field: 'destination.as', + properties: ['asn', 'organization_name'], + }, + }, + { + rename: { + ignore_missing: true, + tag: 'rename_destination_as_asn', + field: 'destination.as.asn', + target_field: 'destination.as.number', + }, + }, + { + rename: { + ignore_missing: true, + tag: 'rename_destination_as_organization_name', + field: 'destination.as.organization_name', + target_field: 'destination.as.organization.name', + }, + }, + { + append: { + if: "ctx.event?.action == 'cert.create'", + field: 'event.category', + value: ['iam'], + allow_duplicates: false, + }, + }, + { + append: { + if: "ctx.event?.action == 'cert.create'", + field: 'event.type', + value: ['creation'], + allow_duplicates: false, + }, + }, + { + append: { + if: "ctx.event?.action == 'cert.create'", + field: 'event.category', + value: ['authentication'], + allow_duplicates: false, + }, + }, + { + append: { + if: "ctx.event?.action == 'cert.create'", + field: 'event.type', + value: ['start'], + allow_duplicates: false, + }, + }, + { + append: { + if: "ctx.event?.action == 'session.start'", + field: 'event.category', + value: ['session'], + allow_duplicates: false, + }, + }, + { + append: { + if: "ctx.event?.action == 'session.start'", + field: 'event.type', + value: ['start'], + allow_duplicates: false, + }, + }, + { + append: { + if: "ctx.network?.protocol == 'ssh'", + field: 'event.category', + value: ['network'], + allow_duplicates: false, + }, + }, + { + append: { + if: "ctx.network?.protocol == 'ssh'", + field: 'event.type', + value: ['connection', 'start'], + allow_duplicates: false, + }, + }, + { + append: { + field: 'related.ip', + value: '{{{source.ip}}}', + if: 'ctx.source?.ip != null', + allow_duplicates: false, + }, + }, + { + append: { + field: 'related.user', + value: '{{{user.name}}}', + if: 'ctx.user?.name != null', + allow_duplicates: false, + }, + }, + { + append: { + field: 'related.hosts', + value: '{{{destination.domain}}}', + if: 'ctx.destination?.domain != null', + allow_duplicates: false, + }, + }, + { + append: { + field: 'related.user', + value: '{{{user.id}}}', + if: 'ctx.user?.id != null', + allow_duplicates: false, + }, + }, + { + remove: { + ignore_missing: true, + tag: 'remove_fields', + field: ['teleport2.audit.identity.client_ip'], + }, + }, + { + remove: { + ignore_failure: true, + ignore_missing: true, + if: 'ctx?.tags == null || !(ctx.tags.contains("preserve_original_event"))', + tag: 'remove_original_event', + field: 'event.original', + }, + }, + ], + on_failure: [ + { + append: { + field: 'error.message', + value: + 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}', + }, + }, + { + set: { + field: 'event.kind', + value: 'pipeline_error', + }, + }, + ], + }, +}; diff --git a/x-pack/plugins/fleet/cypress/tasks/privileges.ts b/x-pack/plugins/fleet/cypress/tasks/privileges.ts index 214bd0f14e6e6..876b88ac9d5b5 100644 --- a/x-pack/plugins/fleet/cypress/tasks/privileges.ts +++ b/x-pack/plugins/fleet/cypress/tasks/privileges.ts @@ -8,7 +8,7 @@ import { request } from './common'; import { constructUrlWithUser, getEnvAuth } from './login'; -interface User { +export interface User { username: string; password: string; description?: string; @@ -193,6 +193,117 @@ export const FleetNoneIntegrAllUser: User = { roles: [FleetNoneIntegrAllRole.name], }; +export const getIntegrationsAutoImportRole = (feature: FeaturesPrivileges): Role => ({ + name: 'automatic_import_integrations_read_role', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + cluster: ['manage_service_account'], + }, + kibana: [ + { + feature, + spaces: ['*'], + }, + ], + }, +}); + +export const AutomaticImportConnectorNoneRole: Role = { + name: 'automatic_import_connectors_none_role', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + cluster: ['manage_service_account'], + }, + kibana: [ + { + feature: { + fleetv2: ['all'], + fleet: ['all'], + actions: ['none'], + }, + spaces: ['*'], + }, + ], + }, +}; +export const AutomaticImportConnectorNoneUser: User = { + username: 'automatic_import_connectors_none_user', + password: 'password', + roles: [AutomaticImportConnectorNoneRole.name], +}; + +export const AutomaticImportConnectorReadRole: Role = { + name: 'automatic_import_connectors_read_role', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + cluster: ['manage_service_account'], + }, + kibana: [ + { + feature: { + fleetv2: ['all'], + fleet: ['all'], + actions: ['read'], + }, + spaces: ['*'], + }, + ], + }, +}; +export const AutomaticImportConnectorReadUser: User = { + username: 'automatic_import_connectors_read_user', + password: 'password', + roles: [AutomaticImportConnectorReadRole.name], +}; + +export const AutomaticImportConnectorAllRole: Role = { + name: 'automatic_import_connectors_all_role', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + cluster: ['manage_service_account'], + }, + kibana: [ + { + feature: { + fleetv2: ['all'], + fleet: ['all'], + actions: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; +export const AutomaticImportConnectorAllUser: User = { + username: 'automatic_import_connectors_all_user', + password: 'password', + roles: [AutomaticImportConnectorAllRole.name], +}; + export const BuiltInEditorUser: User = { username: 'editor_user', password: 'password', diff --git a/x-pack/plugins/fleet/cypress/tsconfig.json b/x-pack/plugins/fleet/cypress/tsconfig.json index ee3dd7cd1e246..6d1433482b1c2 100644 --- a/x-pack/plugins/fleet/cypress/tsconfig.json +++ b/x-pack/plugins/fleet/cypress/tsconfig.json @@ -29,5 +29,6 @@ "force": true }, "@kbn/rison", + "@kbn/actions-plugin", ] } diff --git a/x-pack/plugins/integration_assistant/public/common/components/authorization/missing_privileges_description.tsx b/x-pack/plugins/integration_assistant/public/common/components/authorization/missing_privileges_description.tsx index 15365aeb3a08e..ccc65a2e49f0e 100644 --- a/x-pack/plugins/integration_assistant/public/common/components/authorization/missing_privileges_description.tsx +++ b/x-pack/plugins/integration_assistant/public/common/components/authorization/missing_privileges_description.tsx @@ -13,7 +13,7 @@ type MissingPrivilegesDescriptionProps = Partial; export const MissingPrivilegesDescription = React.memo( ({ canCreateIntegrations, canCreateConnectors, canExecuteConnectors }) => { return ( - + {i18n.PRIVILEGES_REQUIRED_TITLE} diff --git a/x-pack/plugins/integration_assistant/public/common/components/success_section/success_section.tsx b/x-pack/plugins/integration_assistant/public/common/components/success_section/success_section.tsx index 62df4a8f98660..08da1329770cd 100644 --- a/x-pack/plugins/integration_assistant/public/common/components/success_section/success_section.tsx +++ b/x-pack/plugins/integration_assistant/public/common/components/success_section/success_section.tsx @@ -35,7 +35,13 @@ export const SuccessSection = React.memo(({ integrationName return ( - + (({ integrationName icon={} title={i18n.VIEW_INTEGRATION_TITLE} description={i18n.VIEW_INTEGRATION_DESCRIPTION} - footer={{i18n.VIEW_INTEGRATION_BUTTON}} + footer={ + + {i18n.VIEW_INTEGRATION_BUTTON} + + } /> diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_setup.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_setup.tsx index 8715f42eb8f58..e85481378f4dd 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_setup.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_setup.tsx @@ -104,10 +104,13 @@ export const ConnectorSetup = React.memo( size="xl" color="text" type={actionTypeRegistry.get(actionType.id).iconClass} + data-test-subj="connectorActionId" /> - {actionType.name} + + {actionType.name} + diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_landing/create_integration_landing.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_landing/create_integration_landing.tsx index 39cbd2cea1026..71706625f636f 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_landing/create_integration_landing.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_landing/create_integration_landing.tsx @@ -54,7 +54,10 @@ export const CreateIntegrationLanding = React.memo(() => { defaultMessage="If you have an existing integration package, {link}" values={{ link: ( - navigate(Page.upload)}> + navigate(Page.upload)} + data-test-subj="uploadPackageLink" + > { tooltipContent={i18n.TECH_PREVIEW_TOOLTIP} size="s" color="hollow" + data-test-subj="techPreviewBadge" /> @@ -64,7 +65,9 @@ export const IntegrationAssistantCard = React.memo(() => { {canExecuteConnectors ? ( - navigate(Page.assistant)}>{i18n.ASSISTANT_BUTTON} + navigate(Page.assistant)} data-test-subj="assistantButton"> + {i18n.ASSISTANT_BUTTON} + ) : ( {i18n.ASSISTANT_BUTTON} diff --git a/x-pack/plugins/integration_assistant/server/integration_builder/readme_files.ts b/x-pack/plugins/integration_assistant/server/integration_builder/readme_files.ts index 163b2b04b52f9..5467a1549cea2 100644 --- a/x-pack/plugins/integration_assistant/server/integration_builder/readme_files.ts +++ b/x-pack/plugins/integration_assistant/server/integration_builder/readme_files.ts @@ -5,7 +5,7 @@ * 2.0. */ -import nunjucks from 'nunjucks'; +import { Environment, FileSystemLoader } from 'nunjucks'; import { join as joinPath } from 'path'; import { createSync, ensureDirSync } from '../util'; @@ -17,6 +17,8 @@ export function createReadme(packageDir: string, integrationName: string, fields function createPackageReadme(packageDir: string, integrationName: string, fields: object[]) { const dirPath = joinPath(packageDir, 'docs/'); + // The readme nunjucks template files should be named in the format `somename_readme.md.njk` and not just `readme.md.njk` + // since any file with `readme.*` pattern is skipped in build process in buildkite. createReadmeFile(dirPath, 'package_readme.md.njk', integrationName, fields); } @@ -33,10 +35,17 @@ function createReadmeFile( ) { ensureDirSync(targetDir); - const template = nunjucks.render(templateName, { + const templatesPath = joinPath(__dirname, '../templates'); + const env = new Environment(new FileSystemLoader(templatesPath), { + autoescape: false, + }); + + const template = env.getTemplate(templateName); + + const renderedTemplate = template.render({ package_name: integrationName, fields, }); - createSync(joinPath(targetDir, 'README.md'), template); + createSync(joinPath(targetDir, 'README.md'), renderedTemplate); } diff --git a/x-pack/plugins/integration_assistant/server/templates/build_readme.md.njk b/x-pack/plugins/integration_assistant/server/templates/build_readme.md.njk index e23fa4af9efe8..1b58e55aebd37 100644 --- a/x-pack/plugins/integration_assistant/server/templates/build_readme.md.njk +++ b/x-pack/plugins/integration_assistant/server/templates/build_readme.md.njk @@ -1,4 +1,4 @@ -{% include "readme.njk" %} +{% include "./description_readme.njk" %} {% for data_stream in fields %} ### {{ data_stream.datastream }} diff --git a/x-pack/plugins/integration_assistant/server/templates/readme.njk b/x-pack/plugins/integration_assistant/server/templates/description_readme.njk similarity index 100% rename from x-pack/plugins/integration_assistant/server/templates/readme.njk rename to x-pack/plugins/integration_assistant/server/templates/description_readme.njk diff --git a/x-pack/plugins/integration_assistant/server/templates/package_readme.md.njk b/x-pack/plugins/integration_assistant/server/templates/package_readme.md.njk index b47e3491b5bc2..bd56aba5ac1e5 100644 --- a/x-pack/plugins/integration_assistant/server/templates/package_readme.md.njk +++ b/x-pack/plugins/integration_assistant/server/templates/package_readme.md.njk @@ -1,4 +1,4 @@ -{% include "readme.njk" %} +{% include "./description_readme.njk" %} {% for data_stream in fields %} ### {{ data_stream.datastream }} From 4d54cfe2bc3d28d238bc3d56186692081a5d5a9c Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Thu, 10 Oct 2024 12:44:56 +0300 Subject: [PATCH 110/110] [Security Solution] Add upgrade prebuilt rule flyout layout details (#195166) **Addresses:** https://github.com/elastic/kibana/issues/171520 **Design:** [Figma](https://www.figma.com/file/gLHm8LpTtSkAUQHrkG3RHU/%5B8.7%5D-%5BRules%5D-Rule-Immutability%2FCustomization?type=design&node-id=3903%3A88369&mode=design&t=rMjxtGjBNKbCjedE-1) (internal) ## Summary This PR extends prebuilt rule flyout layout with design details including field state, rule state callout and little UI fixes. ## Screenshots image image image --- .../comparison_side/comparison_side.tsx | 21 ++++-- .../comparison_side_help_info.tsx | 43 +++++++++++ .../comparison_side/translations.ts | 7 ++ .../field_upgrade_conflicts_resolver.tsx | 10 ++- ...ield_upgrade_conflicts_resolver_header.tsx | 16 +++-- .../field_upgrade_state_info.tsx | 55 ++++++++++++++ .../field_upgrade_state_info/index.ts | 8 +++ .../field_upgrade_state_info/translations.tsx | 60 ++++++++++++++++ .../components/rule_upgrade_callout/index.ts | 8 +++ .../rule_upgrade_callout.tsx | 71 +++++++++++++++++++ .../rule_upgrade_callout/translations.tsx | 58 +++++++++++++++ .../rule_upgrade_conflicts_resolver.tsx | 3 +- .../components/rule_upgrade_info_bar.tsx | 2 +- .../components/translations.tsx | 30 ++++---- .../three_way_diff/final_side/final_side.tsx | 4 +- .../three_way_diff/final_side/translations.ts | 6 +- .../rule_upgrade_conflicts_resolver_tab.tsx | 5 +- .../field_upgrade_state.ts | 12 ++++ .../fields_upgrade_state.ts | 10 +++ .../model/prebuilt_rule_upgrade/index.ts | 12 ++++ .../rule_upgrade_state.ts | 27 +++++++ .../rules_upgrade_state.ts | 11 +++ .../set_rule_field_resolved_value.ts | 16 +++++ .../upgrade_prebuilt_rules_table.tsx | 2 +- .../upgrade_prebuilt_rules_table_buttons.tsx | 2 +- .../upgrade_prebuilt_rules_table_context.tsx | 2 +- .../use_prebuilt_rules_upgrade_state.ts | 60 ++++++++++------ ...e_upgrade_prebuilt_rules_table_columns.tsx | 2 +- 28 files changed, 504 insertions(+), 59 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/field_upgrade_state_info.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/index.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/translations.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/index.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/rule_upgrade_callout.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/translations.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/field_upgrade_state.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/fields_upgrade_state.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/index.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rules_upgrade_state.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/set_rule_field_resolved_value.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.tsx index 9ef207b0bb998..2592469beaabb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.tsx @@ -6,6 +6,7 @@ */ import React, { useState } from 'react'; +import { EuiFlexGroup, EuiTitle } from '@elastic/eui'; import { VersionsPicker } from '../versions_picker/versions_picker'; import type { Version } from '../versions_picker/constants'; import { SelectedVersions } from '../versions_picker/constants'; @@ -17,6 +18,8 @@ import type { import { getSubfieldChanges } from './get_subfield_changes'; import { SubfieldChanges } from './subfield_changes'; import { SideHeader } from '../components/side_header'; +import { ComparisonSideHelpInfo } from './comparison_side_help_info'; +import * as i18n from './translations'; interface ComparisonSideProps { fieldName: FieldName; @@ -43,11 +46,19 @@ export function ComparisonSide({ return ( <> - + + +

    + {i18n.TITLE} + +

    +
    + +
    diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx new file mode 100644 index 0000000000000..a2b7e1a360150 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { useToggle } from 'react-use'; +import { EuiPopover, EuiText, EuiButtonIcon } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +/** + * Theme doesn't expose width variables. Using provided size variables will require + * multiplying it by another magic constant. + * + * 320px width looks + * like a [commonly used width in EUI](https://github.com/search?q=repo%3Aelastic%2Feui%20320&type=code). + */ +const POPOVER_WIDTH = 320; + +export function ComparisonSideHelpInfo(): JSX.Element { + const [isPopoverOpen, togglePopover] = useToggle(false); + + const button = ( + + ); + + return ( + + + + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/translations.ts index d60c78646b5ad..8208892ac298d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/translations.ts @@ -7,6 +7,13 @@ import { i18n } from '@kbn/i18n'; +export const TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.comparisonSide.title', + { + defaultMessage: 'Diff view', + } +); + export const NO_CHANGES = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.upgradeRules.comparisonSide.noChangesLabel', { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver.tsx index eeafddfc21f03..a750c163814a0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver.tsx @@ -16,18 +16,21 @@ import type { ThreeWayDiff, } from '../../../../../../../common/api/detection_engine'; import { ThreeWayDiffConflict } from '../../../../../../../common/api/detection_engine'; +import type { FieldUpgradeState } from '../../../../model/prebuilt_rule_upgrade'; import { ComparisonSide } from '../comparison_side/comparison_side'; import { FinalSide } from '../final_side/final_side'; import { FieldUpgradeConflictsResolverHeader } from './field_upgrade_conflicts_resolver_header'; interface FieldUpgradeConflictsResolverProps { fieldName: FieldName; + fieldUpgradeState: FieldUpgradeState; fieldThreeWayDiff: RuleFieldsDiff[FieldName]; finalDiffableRule: DiffableRule; } export function FieldUpgradeConflictsResolver({ fieldName, + fieldUpgradeState, fieldThreeWayDiff, finalDiffableRule, }: FieldUpgradeConflictsResolverProps): JSX.Element { @@ -37,7 +40,12 @@ export function FieldUpgradeConflictsResolver } + header={ + + } initialIsOpen={hasConflict} data-test-subj="ruleUpgradePerFieldDiff" > diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver_header.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver_header.tsx index 2821a0a179b91..a096f025873a5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver_header.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver_header.tsx @@ -7,19 +7,27 @@ import React from 'react'; import { camelCase, startCase } from 'lodash'; -import { EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiTitle } from '@elastic/eui'; import { fieldToDisplayNameMap } from '../../diff_components/translations'; +import type { FieldUpgradeState } from '../../../../model/prebuilt_rule_upgrade'; +import { FieldUpgradeStateInfo } from './field_upgrade_state_info'; interface FieldUpgradeConflictsResolverHeaderProps { fieldName: string; + fieldUpgradeState: FieldUpgradeState; } export function FieldUpgradeConflictsResolverHeader({ fieldName, + fieldUpgradeState, }: FieldUpgradeConflictsResolverHeaderProps): JSX.Element { return ( - -
    {fieldToDisplayNameMap[fieldName] ?? startCase(camelCase(fieldName))}
    -
    + + +
    {fieldToDisplayNameMap[fieldName] ?? startCase(camelCase(fieldName))}
    +
    + + +
    ); } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/field_upgrade_state_info.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/field_upgrade_state_info.tsx new file mode 100644 index 0000000000000..c49fc18e2c6ba --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/field_upgrade_state_info.tsx @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiIcon, EuiText } from '@elastic/eui'; +import { FieldUpgradeState } from '../../../../../model/prebuilt_rule_upgrade'; +import * as i18n from './translations'; + +interface FieldUpgradeStateInfoProps { + state: FieldUpgradeState; +} + +export function FieldUpgradeStateInfo({ state }: FieldUpgradeStateInfoProps): JSX.Element { + switch (state) { + case FieldUpgradeState.Accepted: + return ( + <> + + +  {i18n.UPDATE_ACCEPTED} + {i18n.SEPARATOR} + {i18n.UPDATE_ACCEPTED_DESCRIPTION} + + + ); + + case FieldUpgradeState.SolvableConflict: + return ( + <> + + +  {i18n.SOLVABLE_CONFLICT} + {i18n.SEPARATOR} + {i18n.SOLVABLE_CONFLICT_DESCRIPTION} + + + ); + + case FieldUpgradeState.NonSolvableConflict: + return ( + <> + + +  {i18n.NON_SOLVABLE_CONFLICT} + {i18n.SEPARATOR} + {i18n.NON_SOLVABLE_CONFLICT_DESCRIPTION} + + + ); + } +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/index.ts new file mode 100644 index 0000000000000..69915cc64cdcc --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './field_upgrade_state_info'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/translations.tsx new file mode 100644 index 0000000000000..36349b5029a87 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/translations.tsx @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const UPDATE_ACCEPTED = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAccepted', + { + defaultMessage: 'Update accepted', + } +); + +export const UPDATE_ACCEPTED_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAcceptedDescription', + { + defaultMessage: + 'You can still make changes, please review/accept all other conflicts before updating the rule.', + } +); + +export const SOLVABLE_CONFLICT = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.solvableConflict', + { + defaultMessage: 'Solved conflict', + } +); + +export const SOLVABLE_CONFLICT_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.solvableConflictDescription', + { + defaultMessage: + 'We have suggested an update for this modified field, please review before accepting.', + } +); + +export const NON_SOLVABLE_CONFLICT = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflict', + { + defaultMessage: 'Solved conflict', + } +); + +export const NON_SOLVABLE_CONFLICT_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflictDescription', + { + defaultMessage: + 'We have suggested an update for this modified field, please review before accepting.', + } +); + +export const SEPARATOR = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.separator', + { + defaultMessage: ' - ', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/index.ts new file mode 100644 index 0000000000000..75ff48ff541a1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './rule_upgrade_callout'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/rule_upgrade_callout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/rule_upgrade_callout.tsx new file mode 100644 index 0000000000000..852ab0c91c58e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/rule_upgrade_callout.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { EuiCallOut } from '@elastic/eui'; +import type { RuleUpgradeState } from '../../../../../model/prebuilt_rule_upgrade'; +import { FieldUpgradeState } from '../../../../../model/prebuilt_rule_upgrade'; +import * as i18n from './translations'; + +interface RuleUpgradeCalloutProps { + ruleUpgradeState: RuleUpgradeState; +} + +export function RuleUpgradeCallout({ ruleUpgradeState }: RuleUpgradeCalloutProps): JSX.Element { + const fieldsUpgradeState = ruleUpgradeState.fieldsUpgradeState; + const { numOfNonSolvableConflicts, numOfSolvableConflicts } = useMemo(() => { + let numOfFieldsWithNonSolvableConflicts = 0; + let numOfFieldsWithSolvableConflicts = 0; + + for (const fieldName of Object.keys(fieldsUpgradeState)) { + if (fieldsUpgradeState[fieldName] === FieldUpgradeState.NonSolvableConflict) { + numOfFieldsWithNonSolvableConflicts++; + } + + if (fieldsUpgradeState[fieldName] === FieldUpgradeState.SolvableConflict) { + numOfFieldsWithSolvableConflicts++; + } + } + + return { + numOfNonSolvableConflicts: numOfFieldsWithNonSolvableConflicts, + numOfSolvableConflicts: numOfFieldsWithSolvableConflicts, + }; + }, [fieldsUpgradeState]); + + if (numOfNonSolvableConflicts > 0) { + return ( + +

    {i18n.RULE_HAS_NON_SOLVABLE_CONFLICTS_DESCRIPTION}

    +
    + ); + } + + if (numOfSolvableConflicts > 0) { + return ( + +

    {i18n.RULE_HAS_SOLVABLE_CONFLICTS_DESCRIPTION}

    +
    + ); + } + + return ( + +

    {i18n.RULE_IS_READY_FOR_UPGRADE_DESCRIPTION}

    +
    + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/translations.tsx new file mode 100644 index 0000000000000..be9ee761388d0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/translations.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const RULE_HAS_NON_SOLVABLE_CONFLICTS = (count: number) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflicts', + { + values: { count }, + defaultMessage: + '{count} of the fields has a unsolved conflict. Please review and modify accordingly.', + } + ); + +export const RULE_HAS_NON_SOLVABLE_CONFLICTS_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflictsDescription', + { + defaultMessage: + 'Please provide an input for the unsolved conflict. You can also keep the current without the updates, or accept the Elastic update but lose your modifications.', + } +); + +export const RULE_HAS_SOLVABLE_CONFLICTS = (count: number) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflicts', + { + values: { count }, + defaultMessage: + '{count} of the fields has an update conflict, please review the suggested update being updating.', + } + ); + +export const RULE_HAS_SOLVABLE_CONFLICTS_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflictsDescription', + { + defaultMessage: + 'Please review the suggested updated version before accepting the update. You can edit and then save the field if you wish to change it.', + } +); + +export const RULE_IS_READY_FOR_UPGRADE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgrade', + { + defaultMessage: 'The update is ready to be applied.', + } +); + +export const RULE_IS_READY_FOR_UPGRADE_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgradeDescription', + { + defaultMessage: 'All conflicts have now been reviewed and solved please update the rule.', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_conflicts_resolver.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_conflicts_resolver.tsx index 57af1b340c776..f60af70c808f5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_conflicts_resolver.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_conflicts_resolver.tsx @@ -9,7 +9,7 @@ import React from 'react'; import type { RuleUpgradeState, SetRuleFieldResolvedValueFn, -} from '../../../../../rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state'; +} from '../../../../model/prebuilt_rule_upgrade'; import { FieldUpgradeConflictsResolver } from './field_upgrade_conflicts_resolver'; interface RuleUpgradeConflictsResolverProps { @@ -31,6 +31,7 @@ export function RuleUpgradeConflictsResolver({ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_info_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_info_bar.tsx index 7ecde8059cc2f..970f04f383274 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_info_bar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_info_bar.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import type { RuleUpgradeState } from '../../../../../rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state'; +import type { RuleUpgradeState } from '../../../../model/prebuilt_rule_upgrade'; import { UtilityBar, UtilityBarGroup, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/translations.tsx index 620b3ac1c0ba8..27172cb98755c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/translations.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/translations.tsx @@ -11,23 +11,21 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; -export const NUM_OF_FIELDS_WITH_UPDATES = (count: number) => - i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.diffTab.fieldsWithUpdates', - { - values: { count }, - defaultMessage: 'Upgrade has {count} {count, plural, one {field} other {fields}}', - } - ); +export const NUM_OF_FIELDS_WITH_UPDATES = (count: number) => ( + {count} }} + /> +); -export const NUM_OF_CONFLICTS = (count: number) => - i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.diffTab.numOfConflicts', - { - values: { count }, - defaultMessage: '{count} {count, plural, one {conflict} other {conflicts}}', - } - ); +export const NUM_OF_CONFLICTS = (count: number) => ( + {count} }} + /> +); const UPGRADE_RULES_DOCS_LINK = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.upgradeRules.updateYourRulesDocsLink', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side.tsx index 0685d064b32d0..83190015ebc6d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side.tsx @@ -22,9 +22,9 @@ export function FinalSide({ fieldName, finalDiffableRule }: FinalSideProps): JSX return ( <> - +

    - {i18n.UPGRADED_VERSION} + {i18n.FINAL_UPDATE}

    diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/translations.ts index aa9b4885a964d..8f6a10b5681be 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/translations.ts @@ -7,9 +7,9 @@ import { i18n } from '@kbn/i18n'; -export const UPGRADED_VERSION = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradedVersion', +export const FINAL_UPDATE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.finalUpdate', { - defaultMessage: 'Upgraded version', + defaultMessage: 'Final update', } ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab.tsx index 10823b8045c96..547cd23c7e86e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab.tsx @@ -10,9 +10,10 @@ import { EuiSpacer } from '@elastic/eui'; import type { RuleUpgradeState, SetRuleFieldResolvedValueFn, -} from '../../../../rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state'; +} from '../../../model/prebuilt_rule_upgrade'; import { RuleUpgradeInfoBar } from './components/rule_upgrade_info_bar'; import { RuleUpgradeConflictsResolver } from './components/rule_upgrade_conflicts_resolver'; +import { RuleUpgradeCallout } from './components/rule_upgrade_callout'; interface RuleUpgradeConflictsResolverTabProps { ruleUpgradeState: RuleUpgradeState; @@ -28,6 +29,8 @@ export function RuleUpgradeConflictsResolverTab({ + + ; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/index.ts new file mode 100644 index 0000000000000..57ee30f308f08 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './field_upgrade_state'; +export * from './fields_upgrade_state'; +export * from './rule_upgrade_state'; +export * from './rules_upgrade_state'; +export * from './set_rule_field_resolved_value'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state.ts new file mode 100644 index 0000000000000..0c72361bb29dc --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + type DiffableRule, + type RuleUpgradeInfoForReview, +} from '../../../../../common/api/detection_engine'; +import type { FieldsUpgradeState } from './fields_upgrade_state'; + +export interface RuleUpgradeState extends RuleUpgradeInfoForReview { + /** + * Rule containing desired values users expect to see in the upgraded rule. + */ + finalRule: DiffableRule; + /** + * Indicates whether there are conflicts blocking rule upgrading. + */ + hasUnresolvedConflicts: boolean; + /** + * Stores a record of field names mapped to field upgrade state. + */ + fieldsUpgradeState: FieldsUpgradeState; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rules_upgrade_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rules_upgrade_state.ts new file mode 100644 index 0000000000000..66709ec34653e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rules_upgrade_state.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RuleSignatureId } from '../../../../../common/api/detection_engine'; +import type { RuleUpgradeState } from './rule_upgrade_state'; + +export type RulesUpgradeState = Record; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/set_rule_field_resolved_value.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/set_rule_field_resolved_value.ts new file mode 100644 index 0000000000000..c4bb65f162394 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/set_rule_field_resolved_value.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DiffableAllFields, RuleObjectId } from '../../../../../common/api/detection_engine'; + +export type SetRuleFieldResolvedValueFn< + FieldName extends keyof DiffableAllFields = keyof DiffableAllFields +> = (params: { + ruleId: RuleObjectId; + fieldName: FieldName; + resolvedValue: DiffableAllFields[FieldName]; +}) => void; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx index 16ba012313f34..2437a5e87866d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx @@ -16,6 +16,7 @@ import { EuiSkeletonTitle, } from '@elastic/eui'; import React, { useMemo, useState } from 'react'; +import type { RuleUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade'; import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; import { RULES_TABLE_INITIAL_PAGE_SIZE, RULES_TABLE_PAGE_SIZE_OPTIONS } from '../constants'; import { RulesChangelogLink } from '../rules_changelog_link'; @@ -23,7 +24,6 @@ import { UpgradePrebuiltRulesTableButtons } from './upgrade_prebuilt_rules_table import { useUpgradePrebuiltRulesTableContext } from './upgrade_prebuilt_rules_table_context'; import { UpgradePrebuiltRulesTableFilters } from './upgrade_prebuilt_rules_table_filters'; import { useUpgradePrebuiltRulesTableColumns } from './use_upgrade_prebuilt_rules_table_columns'; -import type { RuleUpgradeState } from './use_prebuilt_rules_upgrade_state'; const NO_ITEMS_MESSAGE = ( ; -export type SetRuleFieldResolvedValueFn< - FieldName extends keyof DiffableAllFields = keyof DiffableAllFields -> = (params: { - ruleId: RuleObjectId; - fieldName: FieldName; - resolvedValue: DiffableAllFields[FieldName]; -}) => void; - type RuleResolvedConflicts = Partial; type RulesResolvedConflicts = Record; @@ -70,6 +55,10 @@ export function usePrebuiltRulesUpgradeState( ruleUpgradeInfo, rulesResolvedConflicts[ruleUpgradeInfo.rule_id] ?? {} ), + fieldsUpgradeState: calcFieldsState( + ruleUpgradeInfo.diff.fields, + rulesResolvedConflicts[ruleUpgradeInfo.rule_id] ?? {} + ), hasUnresolvedConflicts: getUnacceptedConflictsCount( ruleUpgradeInfo.diff.fields, @@ -113,6 +102,35 @@ function convertRuleFieldsDiffToDiffable( return mergeVersionRule; } +function calcFieldsState( + ruleFieldsDiff: FieldsDiff>, + ruleResolvedConflicts: RuleResolvedConflicts +): FieldsUpgradeState { + const fieldsState: FieldsUpgradeState = {}; + + for (const fieldName of Object.keys(ruleFieldsDiff)) { + switch (ruleFieldsDiff[fieldName].conflict) { + case ThreeWayDiffConflict.NONE: + fieldsState[fieldName] = FieldUpgradeState.Accepted; + break; + + case ThreeWayDiffConflict.SOLVABLE: + fieldsState[fieldName] = FieldUpgradeState.SolvableConflict; + break; + + case ThreeWayDiffConflict.NON_SOLVABLE: + fieldsState[fieldName] = FieldUpgradeState.NonSolvableConflict; + break; + } + } + + for (const fieldName of Object.keys(ruleResolvedConflicts)) { + fieldsState[fieldName] = FieldUpgradeState.Accepted; + } + + return fieldsState; +} + function getUnacceptedConflictsCount( ruleFieldsDiff: FieldsDiff>, ruleResolvedConflicts: RuleResolvedConflicts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx index e7267007d2348..09009c98c2858 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx @@ -8,6 +8,7 @@ import type { EuiBasicTableColumn } from '@elastic/eui'; import { EuiBadge, EuiButtonEmpty, EuiLink, EuiLoadingSpinner, EuiText } from '@elastic/eui'; import React, { useMemo } from 'react'; +import type { RuleUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state'; import { RulesTableEmptyColumnName } from '../rules_table_empty_column_name'; import { SHOW_RELATED_INTEGRATIONS_SETTING } from '../../../../../../common/constants'; import type { RuleSignatureId } from '../../../../../../common/api/detection_engine/model/rule_schema'; @@ -22,7 +23,6 @@ import type { Rule } from '../../../../rule_management/logic'; import { getNormalizedSeverity } from '../helpers'; import type { UpgradePrebuiltRulesTableActions } from './upgrade_prebuilt_rules_table_context'; import { useUpgradePrebuiltRulesTableContext } from './upgrade_prebuilt_rules_table_context'; -import type { RuleUpgradeState } from './use_prebuilt_rules_upgrade_state'; export type TableColumn = EuiBasicTableColumn;