mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[ML] Fix query bar autocompletion for ML and AIOps embeddables (#164485)
This commit is contained in:
parent
fb0d022758
commit
5d5ac37e9e
6 changed files with 116 additions and 73 deletions
|
@ -58,12 +58,31 @@ export class EmbeddableChangePointChart extends AbstractEmbeddable<
|
|||
|
||||
private node?: HTMLElement;
|
||||
|
||||
// Need to defer embeddable load in order to resolve data views
|
||||
deferEmbeddableLoad = true;
|
||||
|
||||
constructor(
|
||||
private readonly deps: EmbeddableChangePointChartDeps,
|
||||
initialInput: EmbeddableChangePointChartInput,
|
||||
parent?: IContainer
|
||||
) {
|
||||
super(initialInput, { defaultTitle: initialInput.title }, parent);
|
||||
|
||||
this.initOutput().finally(() => this.setInitializationFinished());
|
||||
}
|
||||
|
||||
private async initOutput() {
|
||||
const {
|
||||
data: { dataViews: dataViewsService },
|
||||
} = this.deps;
|
||||
|
||||
const { dataViewId } = this.getInput();
|
||||
|
||||
const dataView = await dataViewsService.get(dataViewId);
|
||||
|
||||
this.updateOutput({
|
||||
indexPatterns: [dataView],
|
||||
});
|
||||
}
|
||||
|
||||
public reportsEmbeddableLoad() {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { type Observable } from 'rxjs';
|
||||
import React, { FC, useCallback, useEffect, useMemo } from 'react';
|
||||
import React, { FC, useEffect, useMemo } from 'react';
|
||||
import { useTimefilter } from '@kbn/ml-date-picker';
|
||||
import { css } from '@emotion/react';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
|
@ -21,11 +21,7 @@ import type {
|
|||
} from './embeddable_change_point_chart';
|
||||
import { EmbeddableChangePointChartProps } from './embeddable_change_point_chart_component';
|
||||
import { FilterQueryContextProvider, useFilerQueryUpdates } from '../hooks/use_filters_query';
|
||||
import {
|
||||
DataSourceContextProvider,
|
||||
type DataSourceContextProviderProps,
|
||||
useDataSource,
|
||||
} from '../hooks/use_data_source';
|
||||
import { DataSourceContextProvider, useDataSource } from '../hooks/use_data_source';
|
||||
import { useAiopsAppContext } from '../hooks/use_aiops_app_context';
|
||||
import { useTimeBuckets } from '../hooks/use_time_buckets';
|
||||
import { createMergedEsQuery } from '../application/utils/search_utils';
|
||||
|
@ -59,16 +55,9 @@ export const EmbeddableInputTracker: FC<EmbeddableInputTrackerProps> = ({
|
|||
}) => {
|
||||
const input = useObservable(input$, initialInput);
|
||||
|
||||
const onChange = useCallback<Exclude<DataSourceContextProviderProps['onChange'], undefined>>(
|
||||
({ dataViews }) => {
|
||||
onOutputChange({ indexPatterns: dataViews });
|
||||
},
|
||||
[onOutputChange]
|
||||
);
|
||||
|
||||
return (
|
||||
<ReloadContextProvider reload$={reload$}>
|
||||
<DataSourceContextProvider dataViewId={input.dataViewId} onChange={onChange}>
|
||||
<DataSourceContextProvider dataViewId={input.dataViewId}>
|
||||
<FilterQueryContextProvider timeRange={input.timeRange}>
|
||||
<ChartGridEmbeddableWrapper
|
||||
timeRange={input.timeRange}
|
||||
|
|
|
@ -11,8 +11,7 @@ import { CoreStart } from '@kbn/core/public';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { Subject } from 'rxjs';
|
||||
import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import { Embeddable, IContainer } from '@kbn/embeddable-plugin/public';
|
||||
import type { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { IContainer } from '@kbn/embeddable-plugin/public';
|
||||
import { EmbeddableAnomalyChartsContainer } from './embeddable_anomaly_charts_container_lazy';
|
||||
import type { JobId } from '../../../common/types/anomaly_detection_jobs';
|
||||
import type { MlDependencies } from '../../application/app';
|
||||
|
@ -23,6 +22,8 @@ import {
|
|||
AnomalyChartsServices,
|
||||
} from '..';
|
||||
import { EmbeddableLoading } from '../common/components/embeddable_loading_fallback';
|
||||
import { AnomalyDetectionEmbeddable } from '../common/anomaly_detection_embeddable';
|
||||
|
||||
export const getDefaultExplorerChartsPanelTitle = (jobIds: JobId[]) =>
|
||||
i18n.translate('xpack.ml.anomalyChartsEmbeddable.title', {
|
||||
defaultMessage: 'ML anomaly charts for {jobIds}',
|
||||
|
@ -31,7 +32,7 @@ export const getDefaultExplorerChartsPanelTitle = (jobIds: JobId[]) =>
|
|||
|
||||
export type IAnomalyChartsEmbeddable = typeof AnomalyChartsEmbeddable;
|
||||
|
||||
export class AnomalyChartsEmbeddable extends Embeddable<
|
||||
export class AnomalyChartsEmbeddable extends AnomalyDetectionEmbeddable<
|
||||
AnomalyChartsEmbeddableInput,
|
||||
AnomalyChartsEmbeddableOutput
|
||||
> {
|
||||
|
@ -44,52 +45,7 @@ export class AnomalyChartsEmbeddable extends Embeddable<
|
|||
public services: [CoreStart, MlDependencies, AnomalyChartsServices],
|
||||
parent?: IContainer
|
||||
) {
|
||||
super(
|
||||
initialInput,
|
||||
{
|
||||
defaultTitle: initialInput.title,
|
||||
defaultDescription: initialInput.description,
|
||||
},
|
||||
parent
|
||||
);
|
||||
this.initializeOutput(initialInput);
|
||||
}
|
||||
|
||||
private async initializeOutput(initialInput: AnomalyChartsEmbeddableInput) {
|
||||
const { anomalyExplorerService } = this.services[2];
|
||||
const { jobIds } = initialInput;
|
||||
|
||||
try {
|
||||
const jobs = await anomalyExplorerService.getCombinedJobs(jobIds);
|
||||
const dataViewsService = this.services[1].data.dataViews;
|
||||
|
||||
// First get list of unique indices from the selected jobs
|
||||
const indices = new Set(jobs.map((j) => j.datafeed_config.indices).flat());
|
||||
// Then find the data view assuming the data view title matches the index name
|
||||
const indexPatterns: Record<string, DataView> = {};
|
||||
for (const indexName of indices) {
|
||||
const response = await dataViewsService.find(`"${indexName}"`);
|
||||
|
||||
const indexPattern = response.find(
|
||||
(obj) => obj.title.toLowerCase() === indexName.toLowerCase()
|
||||
);
|
||||
if (indexPattern !== undefined) {
|
||||
indexPatterns[indexPattern.id!] = indexPattern;
|
||||
}
|
||||
}
|
||||
|
||||
this.updateOutput({
|
||||
...this.getOutput(),
|
||||
indexPatterns: Object.values(indexPatterns),
|
||||
});
|
||||
} catch (e) {
|
||||
// Unable to find and load data view but we can ignore the error
|
||||
// as we only load it to support the filter & query bar
|
||||
// the visualizations should still work correctly
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Unable to load data views for ${jobIds}`, e);
|
||||
}
|
||||
super(initialInput, services[2].anomalyDetectorService, services[1].data.dataViews, parent);
|
||||
}
|
||||
|
||||
public onLoading() {
|
||||
|
|
|
@ -11,7 +11,7 @@ import { CoreStart } from '@kbn/core/public';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { Subject } from 'rxjs';
|
||||
import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import { Embeddable, IContainer } from '@kbn/embeddable-plugin/public';
|
||||
import { IContainer } from '@kbn/embeddable-plugin/public';
|
||||
import { EmbeddableSwimLaneContainer } from './embeddable_swim_lane_container_lazy';
|
||||
import type { JobId } from '../../../common/types/anomaly_detection_jobs';
|
||||
import type { MlDependencies } from '../../application/app';
|
||||
|
@ -23,6 +23,7 @@ import {
|
|||
AnomalySwimlaneServices,
|
||||
} from '..';
|
||||
import { EmbeddableLoading } from '../common/components/embeddable_loading_fallback';
|
||||
import { AnomalyDetectionEmbeddable } from '../common/anomaly_detection_embeddable';
|
||||
|
||||
export const getDefaultSwimlanePanelTitle = (jobIds: JobId[]) =>
|
||||
i18n.translate('xpack.ml.swimlaneEmbeddable.title', {
|
||||
|
@ -32,7 +33,7 @@ export const getDefaultSwimlanePanelTitle = (jobIds: JobId[]) =>
|
|||
|
||||
export type IAnomalySwimlaneEmbeddable = typeof AnomalySwimlaneEmbeddable;
|
||||
|
||||
export class AnomalySwimlaneEmbeddable extends Embeddable<
|
||||
export class AnomalySwimlaneEmbeddable extends AnomalyDetectionEmbeddable<
|
||||
AnomalySwimlaneEmbeddableInput,
|
||||
AnomalySwimlaneEmbeddableOutput
|
||||
> {
|
||||
|
@ -45,14 +46,7 @@ export class AnomalySwimlaneEmbeddable extends Embeddable<
|
|||
public services: [CoreStart, MlDependencies, AnomalySwimlaneServices],
|
||||
parent?: IContainer
|
||||
) {
|
||||
super(
|
||||
initialInput,
|
||||
{
|
||||
defaultTitle: initialInput.title,
|
||||
defaultDescription: initialInput.description,
|
||||
},
|
||||
parent
|
||||
);
|
||||
super(initialInput, services[2].anomalyDetectorService, services[1].data.dataViews, parent);
|
||||
}
|
||||
|
||||
public reportsEmbeddableLoad() {
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 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 {
|
||||
Embeddable,
|
||||
type EmbeddableInput,
|
||||
type EmbeddableOutput,
|
||||
type IContainer,
|
||||
} from '@kbn/embeddable-plugin/public';
|
||||
import { type DataView } from '@kbn/data-views-plugin/common';
|
||||
import { type DataViewsContract } from '@kbn/data-views-plugin/public';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { type AnomalyDetectorService } from '../../application/services/anomaly_detector_service';
|
||||
|
||||
export type CommonInput = { jobIds: string[] } & EmbeddableInput;
|
||||
|
||||
export type CommonOutput = { indexPatterns?: DataView[] } & EmbeddableOutput;
|
||||
|
||||
export abstract class AnomalyDetectionEmbeddable<
|
||||
Input extends CommonInput,
|
||||
Output extends CommonOutput
|
||||
> extends Embeddable<Input, Output> {
|
||||
// Need to defer embeddable load in order to resolve data views
|
||||
deferEmbeddableLoad = true;
|
||||
|
||||
protected constructor(
|
||||
initialInput: Input,
|
||||
private anomalyDetectorService: AnomalyDetectorService,
|
||||
private dataViewsService: DataViewsContract,
|
||||
parent?: IContainer
|
||||
) {
|
||||
super(
|
||||
initialInput,
|
||||
{
|
||||
defaultTitle: initialInput.title,
|
||||
defaultDescription: initialInput.description,
|
||||
} as Output,
|
||||
parent
|
||||
);
|
||||
|
||||
this.initializeOutput(initialInput).finally(() => {
|
||||
this.setInitializationFinished();
|
||||
});
|
||||
}
|
||||
|
||||
protected async initializeOutput(initialInput: CommonInput) {
|
||||
const { jobIds } = initialInput;
|
||||
|
||||
try {
|
||||
const jobs = await firstValueFrom(this.anomalyDetectorService.getJobs$(jobIds));
|
||||
|
||||
// First get list of unique indices from the selected jobs
|
||||
const indices = new Set(jobs.map((j) => j.datafeed_config!.indices).flat());
|
||||
// Then find the data view assuming the data view title matches the index name
|
||||
const indexPatterns: Record<string, DataView> = {};
|
||||
for (const indexName of indices) {
|
||||
const response = await this.dataViewsService.find(`"${indexName}"`);
|
||||
const indexPattern = response.find((obj) =>
|
||||
obj.getIndexPattern().toLowerCase().includes(indexName.toLowerCase())
|
||||
);
|
||||
|
||||
if (indexPattern !== undefined) {
|
||||
indexPatterns[indexPattern.id!] = indexPattern;
|
||||
}
|
||||
}
|
||||
|
||||
this.updateOutput({
|
||||
...this.getOutput(),
|
||||
indexPatterns: Object.values(indexPatterns),
|
||||
});
|
||||
} catch (e) {
|
||||
// Unable to find and load data view but we can ignore the error
|
||||
// as we only load it to support the filter & query bar
|
||||
// the visualizations should still work correctly
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Unable to load data views for ${jobIds}`, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,6 +58,7 @@ export interface AnomalySwimlaneEmbeddableCustomOutput {
|
|||
perPage?: number;
|
||||
fromPage?: number;
|
||||
interval?: number;
|
||||
indexPatterns?: DataView[];
|
||||
}
|
||||
|
||||
export type AnomalySwimlaneEmbeddableOutput = EmbeddableOutput &
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue