[8.15] [AI Assistant] Add to dashboard (#179329) (#187827)

# Backport

This will backport the following commits from `main` to `8.15`:
- [[AI Assistant] Add to dashboard
(#179329)](https://github.com/elastic/kibana/pull/179329)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Dario
Gieselaar","email":"dario.gieselaar@elastic.co"},"sourceCommit":{"committedDate":"2024-07-09T07:31:54Z","message":"[AI
Assistant] Add to dashboard (#179329)\n\nAdds a new functionality in the
AI assistant when in dashboards. If the\r\nusers ask for a question
which will generate a query then then can use\r\nprompts like:\r\n\r\n-
`Create a visualization from this query and add this to a
dashboard`\r\n- `Create a metric from this query and add this to a
dashboard`\r\n-
....\r\n\r\n\r\n![meow](3092f006-13ce-4565-b9d3-c6ad407afb31)\r\n\r\n\r\n###
How it works\r\n- It uses the existing functionality of the assistant to
create an ES|QL\r\nquery (if the generated query is wrong is not part of
this PR)\r\n- The LLM returns the query to the new `add_to_dashboard`
function and\r\nwith the chart type (if the user has added the
preference) and the\r\nconfiguration needed for the ConfigBuilder it
creates a Lens embeddable\r\nand adds it to the dashboard.\r\n\r\n###
How to test\r\n- Go to advanced settings, find the `Observability AI
Assistant scope`\r\nsetting and change to Everywhere\r\n- Go to a
dahsboard (existing or new)\r\n- Ask a question to the AI such as `I
want the 95th percentile of ...\r\nfrom ... index` or `I want the median
of butes from the\r\nkibana_sample_data_logs grouped by the top 5
destinations`\r\n- After the ES|QL query has been generated correctly
ask AI to create a\r\nchart from this query and add this to the
dashboard\r\n\r\n\r\n### important note\r\nAs this is the first real
consumer of the build api for ES|QL I have\r\nfixed and various bugs I
discovered in the api.\r\n\r\n---------\r\n\r\nCo-authored-by: Stratoula
Kalafateli <stratoula1@gmail.com>\r\nCo-authored-by: Stratoula
Kalafateli <efstratia.kalafateli@elastic.co>\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"4013f608c1872b75f4f5601889a478b985479859","branchLabelMapping":{"^v8.16.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","backport:prev-minor","Team:Obs
AI
Assistant","Feature:ES|QL","ci:project-deploy-observability","apm:review","v8.15.0","v8.16.0"],"title":"[AI
Assistant] Add to
dashboard","number":179329,"url":"https://github.com/elastic/kibana/pull/179329","mergeCommit":{"message":"[AI
Assistant] Add to dashboard (#179329)\n\nAdds a new functionality in the
AI assistant when in dashboards. If the\r\nusers ask for a question
which will generate a query then then can use\r\nprompts like:\r\n\r\n-
`Create a visualization from this query and add this to a
dashboard`\r\n- `Create a metric from this query and add this to a
dashboard`\r\n-
....\r\n\r\n\r\n![meow](3092f006-13ce-4565-b9d3-c6ad407afb31)\r\n\r\n\r\n###
How it works\r\n- It uses the existing functionality of the assistant to
create an ES|QL\r\nquery (if the generated query is wrong is not part of
this PR)\r\n- The LLM returns the query to the new `add_to_dashboard`
function and\r\nwith the chart type (if the user has added the
preference) and the\r\nconfiguration needed for the ConfigBuilder it
creates a Lens embeddable\r\nand adds it to the dashboard.\r\n\r\n###
How to test\r\n- Go to advanced settings, find the `Observability AI
Assistant scope`\r\nsetting and change to Everywhere\r\n- Go to a
dahsboard (existing or new)\r\n- Ask a question to the AI such as `I
want the 95th percentile of ...\r\nfrom ... index` or `I want the median
of butes from the\r\nkibana_sample_data_logs grouped by the top 5
destinations`\r\n- After the ES|QL query has been generated correctly
ask AI to create a\r\nchart from this query and add this to the
dashboard\r\n\r\n\r\n### important note\r\nAs this is the first real
consumer of the build api for ES|QL I have\r\nfixed and various bugs I
discovered in the api.\r\n\r\n---------\r\n\r\nCo-authored-by: Stratoula
Kalafateli <stratoula1@gmail.com>\r\nCo-authored-by: Stratoula
Kalafateli <efstratia.kalafateli@elastic.co>\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"4013f608c1872b75f4f5601889a478b985479859"}},"sourceBranch":"main","suggestedTargetBranches":["8.15"],"targetPullRequestStates":[{"branch":"8.15","label":"v8.15.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/179329","number":179329,"mergeCommit":{"message":"[AI
Assistant] Add to dashboard (#179329)\n\nAdds a new functionality in the
AI assistant when in dashboards. If the\r\nusers ask for a question
which will generate a query then then can use\r\nprompts like:\r\n\r\n-
`Create a visualization from this query and add this to a
dashboard`\r\n- `Create a metric from this query and add this to a
dashboard`\r\n-
....\r\n\r\n\r\n![meow](3092f006-13ce-4565-b9d3-c6ad407afb31)\r\n\r\n\r\n###
How it works\r\n- It uses the existing functionality of the assistant to
create an ES|QL\r\nquery (if the generated query is wrong is not part of
this PR)\r\n- The LLM returns the query to the new `add_to_dashboard`
function and\r\nwith the chart type (if the user has added the
preference) and the\r\nconfiguration needed for the ConfigBuilder it
creates a Lens embeddable\r\nand adds it to the dashboard.\r\n\r\n###
How to test\r\n- Go to advanced settings, find the `Observability AI
Assistant scope`\r\nsetting and change to Everywhere\r\n- Go to a
dahsboard (existing or new)\r\n- Ask a question to the AI such as `I
want the 95th percentile of ...\r\nfrom ... index` or `I want the median
of butes from the\r\nkibana_sample_data_logs grouped by the top 5
destinations`\r\n- After the ES|QL query has been generated correctly
ask AI to create a\r\nchart from this query and add this to the
dashboard\r\n\r\n\r\n### important note\r\nAs this is the first real
consumer of the build api for ES|QL I have\r\nfixed and various bugs I
discovered in the api.\r\n\r\n---------\r\n\r\nCo-authored-by: Stratoula
Kalafateli <stratoula1@gmail.com>\r\nCo-authored-by: Stratoula
Kalafateli <efstratia.kalafateli@elastic.co>\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"4013f608c1872b75f4f5601889a478b985479859"}}]}]
BACKPORT-->

Co-authored-by: Dario Gieselaar <dario.gieselaar@elastic.co>
This commit is contained in:
Kibana Machine 2024-07-09 10:49:07 +02:00 committed by GitHub
parent 71c6761a06
commit a6087390bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 493 additions and 16 deletions

View file

@ -98,6 +98,7 @@ test('generates gauge chart config', async () => {
"query": Object {
"esql": "from test | count=count()",
},
"timeField": undefined,
},
},
},
@ -189,6 +190,7 @@ test('generates gauge chart config with goal and max', async () => {
"query": Object {
"esql": "from test | count=count() | eval max=1000 | eval goal=500",
},
"timeField": undefined,
},
},
},

View file

@ -116,6 +116,7 @@ test('generates metric chart config', async () => {
"query": Object {
"esql": "from test | count=count() by @timestamp, category",
},
"timeField": undefined,
},
},
},

View file

@ -108,6 +108,7 @@ test('generates metric chart config', async () => {
"query": Object {
"esql": "from test | count=count()",
},
"timeField": undefined,
},
},
},

View file

@ -115,6 +115,7 @@ test('generates metric chart config', async () => {
"query": Object {
"esql": "from test | count=count() by @timestamp, category",
},
"timeField": undefined,
},
},
},

View file

@ -107,6 +107,7 @@ test('generates region map chart config', async () => {
"query": Object {
"esql": "from test | count=count() by category",
},
"timeField": undefined,
},
},
},

View file

@ -107,6 +107,7 @@ test('generates table config', async () => {
"query": Object {
"esql": "from test | count=count() by category",
},
"timeField": undefined,
},
},
},

View file

@ -107,6 +107,7 @@ test('generates tag cloud chart config', async () => {
"query": Object {
"esql": "from test | count=count() by category",
},
"timeField": undefined,
},
},
},
@ -123,8 +124,8 @@ test('generates tag cloud chart config', async () => {
"minFontSize": 12,
"orientation": "single",
"showLabel": true,
"tagAccessor": "category",
"valueAccessor": "count",
"tagAccessor": "metric_formula_accessor_breakdown",
"valueAccessor": "metric_formula_accessor",
},
},
"title": "test",

View file

@ -18,7 +18,6 @@ import {
buildDatasourceStates,
buildReferences,
getAdhocDataviews,
isFormulaDataset,
mapToFormula,
} from '../utils';
import { getBreakdownColumn, getFormulaColumn, getValueColumn } from '../columns';
@ -31,18 +30,17 @@ function getAccessorName(type: 'breakdown') {
function buildVisualizationState(config: LensTagCloudConfig): TagcloudState {
const layer = config;
const isFormula = isFormulaDataset(config.dataset) || isFormulaDataset(layer.dataset);
return {
layerId: DEFAULT_LAYER_ID,
valueAccessor: !isFormula ? layer.value : ACCESSOR,
valueAccessor: ACCESSOR,
maxFontSize: 72,
minFontSize: 12,
orientation: 'single',
showLabel: true,
...(layer.breakdown
? {
tagAccessor: !isFormula ? (layer.breakdown as string) : getAccessorName('breakdown'),
tagAccessor: getAccessorName('breakdown'),
}
: {}),
};

View file

@ -125,6 +125,7 @@ test('generates xy chart config', async () => {
"query": Object {
"esql": "from test | count=count() by @timestamp",
},
"timeField": undefined,
},
},
},

View file

@ -49,7 +49,7 @@ export class LensConfigBuilder {
async build(
config: LensConfig,
options: LensConfigOptions = {}
): Promise<LensAttributes | LensEmbeddableInput | undefined> {
): Promise<LensAttributes | LensEmbeddableInput> {
const { chartType } = config;
const chartConfig = await this.charts[chartType](config as any, {
formulaAPI: this.formulaAPI,
@ -74,6 +74,6 @@ export class LensConfigBuilder {
} as LensEmbeddableInput;
}
return chartState;
return chartState as LensAttributes;
}
}

View file

@ -7,7 +7,7 @@
*/
import type { FormulaPublicApi, TypedLensByValueInput } from '@kbn/lens-plugin/public';
import type { Filter, Query } from '@kbn/es-query';
import type { AggregateQuery, Filter, Query } from '@kbn/es-query';
import type { Datatable } from '@kbn/expressions-plugin/common';
import { DataViewsCommon } from './config_builder';
@ -95,7 +95,7 @@ export interface LensConfigOptions {
/** optional time range override */
timeRange?: TimeRange;
filters?: Filter[];
query?: Query;
query?: Query | AggregateQuery;
}
export interface LensAxisTitleVisibilityConfig {
@ -208,9 +208,9 @@ export type LensRegionMapConfig = Identity<
export interface LensMosaicConfigBase {
chartType: 'mosaic';
/** field name to apply breakdown based on field type or full breakdown configuration */
breakdown: LensBreakdownConfig;
breakdown: LensBreakdownConfig[];
/** field name to apply breakdown based on field type or full breakdown configuration */
xAxis: LensBreakdownConfig;
xAxis?: LensBreakdownConfig;
}
export type LensMosaicConfig = Identity<LensBaseConfig & LensBaseLayer & LensMosaicConfigBase>;
@ -228,7 +228,7 @@ export type LensTableConfig = Identity<LensBaseConfig & LensBaseLayer & LensTabl
export interface LensHeatmapConfigBase {
chartType: 'heatmap';
/** field name to apply breakdown based on field type or full breakdown configuration */
breakdown: LensBreakdownConfig;
breakdown?: LensBreakdownConfig;
xAxis: LensBreakdownConfig;
legend?: Identity<LensLegendConfig>;
}

View file

@ -208,6 +208,7 @@ describe('buildDatasourceStates', () => {
"query": Object {
"esql": "from test | limit 10",
},
"timeField": undefined,
},
},
},

View file

@ -200,6 +200,7 @@ function buildDatasourceStatesLayer(
const newLayer = {
index: dataView!.id!,
query: { esql: (dataset as LensESQLDataset).esql } as AggregateQuery,
timeField: dataView!.timeFieldName,
columns,
allColumns: columns,
};

View file

@ -34,7 +34,8 @@
"usageCollection",
"taskManager",
"serverless",
"noDataPage"
"noDataPage",
"observabilityAIAssistant"
],
"requiredBundles": [
"kibanaReact",

View file

@ -42,6 +42,7 @@ import { loadDashboardHistoryLocationState } from './locator/load_dashboard_hist
import type { DashboardCreationOptions } from '../dashboard_container/embeddable/dashboard_container_factory';
import { DashboardTopNav } from '../dashboard_top_nav';
import { DashboardTabTitleSetter } from './tab_title_setter/dashboard_tab_title_setter';
import { useObservabilityAIAssistantContext } from './hooks/use_observability_ai_assistant_context';
export interface DashboardAppProps {
history: History;
@ -82,13 +83,21 @@ export function DashboardApp({
embeddable: { getStateTransfer },
notifications: { toasts },
settings: { uiSettings },
data: { search },
data: { search, dataViews },
customBranding,
share: { url },
observabilityAIAssistant,
} = pluginServices.getServices();
const showPlainSpinner = useObservable(customBranding.hasCustomBranding$, false);
const { scopedHistory: getScopedHistory } = useDashboardMountContext();
useObservabilityAIAssistantContext({
observabilityAIAssistant: observabilityAIAssistant.start,
dashboardAPI,
search,
dataViews,
});
useExecutionContext(executionContext, {
type: 'application',
page: 'app',

View file

@ -0,0 +1,386 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
import { useEffect } from 'react';
import type { Embeddable } from '@kbn/embeddable-plugin/public';
import { getESQLQueryColumns } from '@kbn/esql-utils';
import type { ISearchStart } from '@kbn/data-plugin/public';
import {
LensConfigBuilder,
type LensConfig,
type LensMetricConfig,
type LensPieConfig,
type LensGaugeConfig,
type LensXYConfig,
type LensHeatmapConfig,
type LensMosaicConfig,
type LensRegionMapConfig,
type LensTableConfig,
type LensTagCloudConfig,
type LensTreeMapConfig,
LensDataset,
} from '@kbn/lens-embeddable-utils/config_builder';
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import { LensEmbeddableInput } from '@kbn/lens-plugin/public';
import type { AwaitingDashboardAPI } from '../../dashboard_container';
const chartTypes = [
'xy',
'pie',
'heatmap',
'metric',
'gauge',
'donut',
'mosaic',
'regionmap',
'table',
'tagcloud',
'treemap',
] as const;
export function useObservabilityAIAssistantContext({
observabilityAIAssistant,
dashboardAPI,
search,
dataViews,
}: {
observabilityAIAssistant: ObservabilityAIAssistantPublicStart | undefined;
dashboardAPI: AwaitingDashboardAPI;
search: ISearchStart;
dataViews: DataViewsPublicPluginStart;
}) {
useEffect(() => {
if (!observabilityAIAssistant) {
return;
}
const {
service: { setScreenContext },
createScreenContextAction,
} = observabilityAIAssistant;
return setScreenContext({
screenDescription:
'The user is looking at the dashboard app. Here they can add visualizations to a dashboard and save them',
actions: dashboardAPI
? [
createScreenContextAction(
{
name: 'add_to_dashboard',
description:
'Add an ES|QL visualization to the current dashboard. Pick a single chart type, and based on the chart type, the corresponding key for `layers`. E.g., when you select type:metric, fill in only layers.metric.',
parameters: {
type: 'object',
properties: {
esql: {
type: 'object',
properties: {
query: {
type: 'string',
description:
'The ES|QL query for this visualization. Use the "query" function to generate ES|QL first and then add it here.',
},
},
required: ['query'],
},
type: {
type: 'string',
description: 'The type of chart',
enum: chartTypes,
},
layers: {
type: 'object',
properties: {
xy: {
type: 'object',
properties: {
xAxis: {
type: 'string',
},
yAxis: {
type: 'string',
},
type: {
type: 'string',
enum: ['line', 'bar', 'area'],
},
},
},
donut: {
type: 'object',
properties: {
breakdown: {
type: 'string',
},
},
},
metric: {
type: 'object',
},
gauge: {
type: 'object',
},
pie: {
type: 'object',
properties: {
breakdown: {
type: 'string',
},
},
},
heatmap: {
type: 'object',
properties: {
xAxis: {
type: 'string',
},
breakdown: {
type: 'string',
},
},
required: ['xAxis'],
},
mosaic: {
type: 'object',
properties: {
breakdown: {
type: 'string',
},
},
required: ['breakdown'],
},
regionmap: {
type: 'object',
properties: {
breakdown: {
type: 'string',
},
},
required: ['breakdown'],
},
table: {
type: 'object',
},
tagcloud: {
type: 'object',
properties: {
breakdown: {
type: 'string',
},
},
required: ['breakdown'],
},
treemap: {
type: 'object',
properties: {
breakdown: {
type: 'string',
},
},
},
},
},
title: {
type: 'string',
description: 'An optional title for the visualization.',
},
},
required: ['esql', 'type'],
} as const,
},
async ({ args, signal }) => {
const {
title = '',
type: chartType = 'xy',
layers,
esql: { query },
} = args;
const [columns] = await Promise.all([
getESQLQueryColumns({
esqlQuery: query,
search: search.search,
signal,
}),
]);
const configBuilder = new LensConfigBuilder(dataViews);
let config: LensConfig;
const firstMetricColumn = columns.find(
(column) => column.meta.type === 'number'
)?.id;
const dataset: LensDataset = {
esql: query,
};
switch (chartType) {
default:
case 'xy':
const xyConfig: LensXYConfig = {
chartType: 'xy',
layers: [
{
seriesType: layers?.xy?.type || 'line',
type: 'series',
xAxis: layers?.xy?.xAxis || '@timestamp',
yAxis: [
{
value: layers?.xy?.yAxis || firstMetricColumn!,
},
],
},
],
dataset,
title,
};
config = xyConfig;
break;
case 'donut':
const donutConfig: LensPieConfig = {
chartType,
title,
value: firstMetricColumn!,
breakdown: [layers?.donut?.breakdown!],
dataset,
};
config = donutConfig;
break;
case 'pie':
const pieConfig: LensPieConfig = {
chartType,
title,
value: firstMetricColumn!,
breakdown: [layers?.pie?.breakdown!],
dataset,
};
config = pieConfig;
break;
case 'metric':
const metricConfig: LensMetricConfig = {
chartType,
title,
value: firstMetricColumn!,
dataset,
};
config = metricConfig;
break;
case 'gauge':
const gaugeConfig: LensGaugeConfig = {
chartType,
title,
value: firstMetricColumn!,
dataset,
};
config = gaugeConfig;
break;
case 'heatmap':
const heatmapConfig: LensHeatmapConfig = {
chartType,
title,
value: firstMetricColumn!,
breakdown: layers?.heatmap?.breakdown,
xAxis: layers?.heatmap?.xAxis || '@timestamp',
dataset,
};
config = heatmapConfig;
break;
case 'mosaic':
const mosaicConfig: LensMosaicConfig = {
chartType,
title,
value: firstMetricColumn!,
breakdown: [layers?.mosaic?.breakdown || '@timestamp'],
dataset,
};
config = mosaicConfig;
break;
case 'regionmap':
const regionMapConfig: LensRegionMapConfig = {
chartType,
title,
value: firstMetricColumn!,
breakdown: layers?.regionmap?.breakdown!,
dataset,
};
config = regionMapConfig;
break;
case 'table':
const tableConfig: LensTableConfig = {
chartType,
title,
value: firstMetricColumn!,
dataset,
};
config = tableConfig;
break;
case 'tagcloud':
const tagCloudConfig: LensTagCloudConfig = {
chartType,
title,
value: firstMetricColumn!,
breakdown: layers?.tagcloud?.breakdown!,
dataset,
};
config = tagCloudConfig;
break;
case 'treemap':
const treeMapConfig: LensTreeMapConfig = {
chartType,
title,
value: firstMetricColumn!,
breakdown: [layers?.treemap?.breakdown || '@timestamp'],
dataset,
};
config = treeMapConfig;
break;
}
const embeddableInput = (await configBuilder.build(config, {
embeddable: true,
query: dataset,
})) as LensEmbeddableInput;
return dashboardAPI
.addNewPanel<Embeddable>({
panelType: 'lens',
initialState: embeddableInput,
})
.then(() => {
return {
content: 'Visualization successfully added to dashboard',
};
})
.catch((error) => {
return {
content: {
error,
},
};
});
}
),
]
: [],
});
}, [observabilityAIAssistant, dashboardAPI, search, dataViews]);
}

View file

@ -52,6 +52,10 @@ import type { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding
import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public';
import type { ServerlessPluginStart } from '@kbn/serverless/public';
import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public';
import type {
ObservabilityAIAssistantPublicSetup,
ObservabilityAIAssistantPublicStart,
} from '@kbn/observability-ai-assistant-plugin/public';
import { CustomBrandingStart } from '@kbn/core-custom-branding-browser';
import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public';
@ -87,6 +91,7 @@ export interface DashboardSetupDependencies {
uiActions: UiActionsSetup;
urlForwarding: UrlForwardingSetup;
unifiedSearch: UnifiedSearchPublicPluginStart;
observabilityAIAssistant?: ObservabilityAIAssistantPublicSetup;
}
export interface DashboardStartDependencies {
@ -110,6 +115,7 @@ export interface DashboardStartDependencies {
customBranding: CustomBrandingStart;
serverless?: ServerlessPluginStart;
noDataPage?: NoDataPagePluginStart;
observabilityAIAssistant?: ObservabilityAIAssistantPublicStart;
}
export interface DashboardSetup {

View file

@ -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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock';
import { ObservabilityAIAssistantService } from './types';
type ObservabilityAIAssistantServiceFactory = PluginServiceFactory<ObservabilityAIAssistantService>;
export const observabilityAIAssistantServiceStubFactory: ObservabilityAIAssistantServiceFactory =
() => {
const pluginMock = observabilityAIAssistantPluginMock.createStartContract();
return {
start: pluginMock,
};
};

View file

@ -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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
import type { DashboardStartDependencies } from '../../plugin';
import type { ObservabilityAIAssistantService } from './types';
export type ObservabilityAIAssistantServiceFactory = KibanaPluginServiceFactory<
ObservabilityAIAssistantService,
DashboardStartDependencies
>;
export const observabilityAIAssistantServiceFactory: ObservabilityAIAssistantServiceFactory = ({
startPlugins,
}) => {
return startPlugins.observabilityAIAssistant
? { start: startPlugins.observabilityAIAssistant }
: {};
};

View file

@ -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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
export interface ObservabilityAIAssistantService {
start?: ObservabilityAIAssistantPublicStart;
}

View file

@ -44,6 +44,7 @@ import { savedObjectsManagementServiceFactory } from './saved_objects_management
import { contentManagementServiceFactory } from './content_management/content_management_service.stub';
import { serverlessServiceFactory } from './serverless/serverless_service.stub';
import { userProfileServiceFactory } from './user_profile/user_profile_service.stub';
import { observabilityAIAssistantServiceStubFactory } from './observability_ai_assistant/observability_ai_assistant_service.stub';
import { noDataPageServiceFactory } from './no_data_page/no_data_page_service.stub';
import { uiActionsServiceFactory } from './ui_actions/ui_actions_service.stub';
@ -80,6 +81,7 @@ export const providers: PluginServiceProviders<DashboardServices> = {
noDataPage: new PluginServiceProvider(noDataPageServiceFactory),
uiActions: new PluginServiceProvider(uiActionsServiceFactory),
userProfile: new PluginServiceProvider(userProfileServiceFactory),
observabilityAIAssistant: new PluginServiceProvider(observabilityAIAssistantServiceStubFactory),
};
export const registry = new PluginServiceRegistry<DashboardServices>(providers);

View file

@ -46,6 +46,7 @@ import { contentManagementServiceFactory } from './content_management/content_ma
import { serverlessServiceFactory } from './serverless/serverless_service';
import { noDataPageServiceFactory } from './no_data_page/no_data_page_service';
import { uiActionsServiceFactory } from './ui_actions/ui_actions_service';
import { observabilityAIAssistantServiceFactory } from './observability_ai_assistant/observability_ai_assistant_service';
import { userProfileServiceFactory } from './user_profile/user_profile_service';
const providers: PluginServiceProviders<DashboardServices, DashboardPluginServiceParams> = {
@ -93,6 +94,7 @@ const providers: PluginServiceProviders<DashboardServices, DashboardPluginServic
serverless: new PluginServiceProvider(serverlessServiceFactory),
noDataPage: new PluginServiceProvider(noDataPageServiceFactory),
uiActions: new PluginServiceProvider(uiActionsServiceFactory),
observabilityAIAssistant: new PluginServiceProvider(observabilityAIAssistantServiceFactory),
userProfile: new PluginServiceProvider(userProfileServiceFactory),
};

View file

@ -41,6 +41,7 @@ import { DashboardVisualizationsService } from './visualizations/types';
import { DashboardServerlessService } from './serverless/types';
import { NoDataPageService } from './no_data_page/types';
import { DashboardUiActionsService } from './ui_actions/types';
import { ObservabilityAIAssistantService } from './observability_ai_assistant/types';
import { DashboardUserProfileService } from './user_profile/types';
export type DashboardPluginServiceParams = KibanaPluginServiceParams<DashboardStartDependencies> & {
@ -79,5 +80,6 @@ export interface DashboardServices {
serverless: DashboardServerlessService; // TODO: make this optional in follow up
noDataPage: NoDataPageService;
uiActions: DashboardUiActionsService;
observabilityAIAssistant: ObservabilityAIAssistantService; // TODO: make this optional in follow up
userProfile: DashboardUserProfileService;
}

View file

@ -79,6 +79,10 @@
"@kbn/core-user-profile-browser-mocks",
"@kbn/react-kibana-context-render",
"@kbn/core-i18n-browser-mocks",
"@kbn/observability-ai-assistant-plugin",
"@kbn/esql-utils",
"@kbn/lens-embeddable-utils",
"@kbn/lens-plugin",
],
"exclude": ["target/**/*"]
}

View file

@ -26,5 +26,5 @@ export function createScreenContextAction<
return {
...definition,
respond,
};
} as ScreenContextActionDefinition<unknown>;
}