mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
# 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\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\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\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:
parent
71c6761a06
commit
a6087390bc
25 changed files with 493 additions and 16 deletions
|
@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -116,6 +116,7 @@ test('generates metric chart config', async () => {
|
|||
"query": Object {
|
||||
"esql": "from test | count=count() by @timestamp, category",
|
||||
},
|
||||
"timeField": undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -108,6 +108,7 @@ test('generates metric chart config', async () => {
|
|||
"query": Object {
|
||||
"esql": "from test | count=count()",
|
||||
},
|
||||
"timeField": undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -115,6 +115,7 @@ test('generates metric chart config', async () => {
|
|||
"query": Object {
|
||||
"esql": "from test | count=count() by @timestamp, category",
|
||||
},
|
||||
"timeField": undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -107,6 +107,7 @@ test('generates region map chart config', async () => {
|
|||
"query": Object {
|
||||
"esql": "from test | count=count() by category",
|
||||
},
|
||||
"timeField": undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -107,6 +107,7 @@ test('generates table config', async () => {
|
|||
"query": Object {
|
||||
"esql": "from test | count=count() by category",
|
||||
},
|
||||
"timeField": undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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'),
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
|
|
|
@ -125,6 +125,7 @@ test('generates xy chart config', async () => {
|
|||
"query": Object {
|
||||
"esql": "from test | count=count() by @timestamp",
|
||||
},
|
||||
"timeField": undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
@ -208,6 +208,7 @@ describe('buildDatasourceStates', () => {
|
|||
"query": Object {
|
||||
"esql": "from test | limit 10",
|
||||
},
|
||||
"timeField": undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
"usageCollection",
|
||||
"taskManager",
|
||||
"serverless",
|
||||
"noDataPage"
|
||||
"noDataPage",
|
||||
"observabilityAIAssistant"
|
||||
],
|
||||
"requiredBundles": [
|
||||
"kibanaReact",
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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]);
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
};
|
|
@ -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 }
|
||||
: {};
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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/**/*"]
|
||||
}
|
||||
|
|
|
@ -26,5 +26,5 @@ export function createScreenContextAction<
|
|||
return {
|
||||
...definition,
|
||||
respond,
|
||||
};
|
||||
} as ScreenContextActionDefinition<unknown>;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue