mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
chore(slo): improve SLO form index selector field (#168726)
This commit is contained in:
parent
9cc7b8cda5
commit
ad82e98220
9 changed files with 109 additions and 132 deletions
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 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 { UseFetchDataViewsResponse } from '../use_fetch_data_views';
|
||||
|
||||
export const useFetchDataViews = (): UseFetchDataViewsResponse => {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
isSuccess: true,
|
||||
data: Array(20)
|
||||
.fill(0)
|
||||
.map((_, i) => ({
|
||||
title: `dataview-${i}`,
|
||||
type: 'foo',
|
||||
getName: () => `dataview-${i}`,
|
||||
getIndexPattern: () => `.index-pattern-dataview-${i}`,
|
||||
})) as DataView[],
|
||||
};
|
||||
};
|
|
@ -60,21 +60,17 @@ export function useFetchSloList({
|
|||
{
|
||||
queryKey: sloKeys.list({ kqlQuery, page, sortBy, sortDirection }),
|
||||
queryFn: async ({ signal }) => {
|
||||
try {
|
||||
const response = await http.get<FindSLOResponse>(`/api/observability/slos`, {
|
||||
query: {
|
||||
...(kqlQuery && { kqlQuery }),
|
||||
...(sortBy && { sortBy }),
|
||||
...(sortDirection && { sortDirection }),
|
||||
...(page && { page }),
|
||||
},
|
||||
signal,
|
||||
});
|
||||
const response = await http.get<FindSLOResponse>(`/api/observability/slos`, {
|
||||
query: {
|
||||
...(kqlQuery && { kqlQuery }),
|
||||
...(sortBy && { sortBy }),
|
||||
...(sortDirection && { sortDirection }),
|
||||
...(page && { page }),
|
||||
},
|
||||
signal,
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
return response;
|
||||
},
|
||||
keepPreviousData: true,
|
||||
refetchOnWindowFocus: false,
|
||||
|
|
|
@ -5,12 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
QueryObserverResult,
|
||||
RefetchOptions,
|
||||
RefetchQueryFilters,
|
||||
useQuery,
|
||||
} from '@tanstack/react-query';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { useKibana } from '../utils/kibana_react';
|
||||
|
||||
|
@ -19,9 +14,6 @@ export interface UseFetchDataViewsResponse {
|
|||
isSuccess: boolean;
|
||||
isError: boolean;
|
||||
data: DataView[] | undefined;
|
||||
refetch: <TPageData>(
|
||||
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
|
||||
) => Promise<QueryObserverResult<DataView[], unknown>>;
|
||||
}
|
||||
|
||||
interface Params {
|
||||
|
@ -33,16 +25,15 @@ export function useFetchDataViews({ name = '', size = 10 }: Params): UseFetchDat
|
|||
const { dataViews } = useKibana().services;
|
||||
const search = name.endsWith('*') ? name : `${name}*`;
|
||||
|
||||
const { isLoading, isError, isSuccess, data, refetch } = useQuery({
|
||||
const { isLoading, isError, isSuccess, data } = useQuery({
|
||||
queryKey: ['fetchDataViews', search],
|
||||
queryFn: async () => {
|
||||
try {
|
||||
return await dataViews.find(search, size);
|
||||
} catch (error) {
|
||||
throw new Error(`Something went wrong. Error: ${error}`);
|
||||
}
|
||||
return dataViews.find(search, size);
|
||||
},
|
||||
retry: false,
|
||||
keepPreviousData: true,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
return { isLoading, isError, isSuccess, data, refetch };
|
||||
return { isLoading, isError, isSuccess, data };
|
||||
}
|
||||
|
|
|
@ -32,18 +32,15 @@ export function useFetchIndices({ search }: Params): UseFetchIndicesResponse {
|
|||
queryKey: ['fetchIndices', search],
|
||||
queryFn: async () => {
|
||||
const searchPattern = search?.endsWith('*') ? search : `${search}*`;
|
||||
try {
|
||||
const response = await http.get<ResolveIndexReponse>(
|
||||
`/internal/index-pattern-management/resolve_index/${searchPattern}`
|
||||
);
|
||||
return response.indices.map((index) => index.name);
|
||||
} catch (error) {
|
||||
throw new Error(`Something went wrong. Error: ${error}`);
|
||||
}
|
||||
const response = await http.get<ResolveIndexReponse>(
|
||||
`/internal/index-pattern-management/resolve_index/${searchPattern}`
|
||||
);
|
||||
return response.indices.map((index) => index.name);
|
||||
},
|
||||
retry: false,
|
||||
enabled: Boolean(search),
|
||||
refetchOnWindowFocus: false,
|
||||
keepPreviousData: true,
|
||||
});
|
||||
|
||||
return { isLoading, isError, isSuccess, data };
|
||||
|
|
|
@ -15,7 +15,7 @@ import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants';
|
|||
|
||||
export default {
|
||||
component: Component,
|
||||
title: 'app/SLO/EditPage/CustomKQL/IndexSelection',
|
||||
title: 'app/SLO/EditPage/Common/IndexSelection',
|
||||
decorators: [KibanaReactStorybookDecorator],
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui';
|
|||
import { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { debounce } from 'lodash';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { useFetchDataViews } from '../../../../hooks/use_fetch_data_views';
|
||||
import { useFetchIndices } from '../../../../hooks/use_fetch_indices';
|
||||
|
@ -22,10 +22,7 @@ interface Option {
|
|||
|
||||
export function IndexSelection() {
|
||||
const { control, getFieldState } = useFormContext<CreateSLOForm>();
|
||||
|
||||
const [searchValue, setSearchValue] = useState<string>('');
|
||||
const [dataViewOptions, setDataViewOptions] = useState<Option[]>([]);
|
||||
const [indexPatternOption, setIndexPatternOption] = useState<Option | undefined>();
|
||||
|
||||
const { isLoading: isIndicesLoading, data: indices = [] } = useFetchIndices({
|
||||
search: searchValue,
|
||||
|
@ -34,54 +31,19 @@ export function IndexSelection() {
|
|||
name: searchValue,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (dataViews.length > 0) {
|
||||
setDataViewOptions(createDataViewOptions(dataViews));
|
||||
}
|
||||
}, [dataViews]);
|
||||
const options: Option[] = [];
|
||||
if (!isDataViewsLoading && dataViews.length > 0) {
|
||||
options.push(createDataViewsOption(dataViews));
|
||||
}
|
||||
if (!isIndicesLoading && !!searchValue) {
|
||||
options.push(createIndexPatternOption(searchValue, indices));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (indices.length === 0) {
|
||||
setIndexPatternOption(undefined);
|
||||
} else if (!!searchValue) {
|
||||
const searchPattern = searchValue.endsWith('*') ? searchValue : `${searchValue}*`;
|
||||
const onSearchChange = debounce((value: string) => setSearchValue(value), 300);
|
||||
|
||||
setIndexPatternOption({
|
||||
label: i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.customKql.indexSelection.indexPatternLabel',
|
||||
{ defaultMessage: 'Use the index pattern' }
|
||||
),
|
||||
options: [
|
||||
{
|
||||
value: searchPattern,
|
||||
label: i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.customKql.indexSelection.indexPatternFoundLabel',
|
||||
{
|
||||
defaultMessage:
|
||||
'{searchPattern} (match {num, plural, one {# index} other {# indices}})',
|
||||
values: {
|
||||
searchPattern,
|
||||
num: indices.length,
|
||||
},
|
||||
}
|
||||
),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}, [indices.length, searchValue]);
|
||||
|
||||
const onDataViewSearchChange = useMemo(
|
||||
() => debounce((value: string) => setSearchValue(value), 300),
|
||||
[]
|
||||
);
|
||||
|
||||
const placeholder = i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.customKql.indexSelection.placeholder',
|
||||
{
|
||||
defaultMessage: 'Select a Data View or use an index pattern',
|
||||
}
|
||||
);
|
||||
const placeholder = i18n.translate('xpack.observability.slo.sloEdit.indexSelection.placeholder', {
|
||||
defaultMessage: 'Select an index pattern',
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiFormRow
|
||||
|
@ -90,9 +52,7 @@ export function IndexSelection() {
|
|||
})}
|
||||
helpText={i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.customKql.indexSelection.helpText',
|
||||
{
|
||||
defaultMessage: 'Use * to broaden your query.',
|
||||
}
|
||||
{ defaultMessage: 'Use * to broaden your query.' }
|
||||
)}
|
||||
isInvalid={getFieldState('indicator.params.index').invalid}
|
||||
>
|
||||
|
@ -110,6 +70,7 @@ export function IndexSelection() {
|
|||
isClearable
|
||||
isInvalid={fieldState.invalid}
|
||||
isLoading={isIndicesLoading && isDataViewsLoading}
|
||||
placeholder={placeholder}
|
||||
onChange={(selected: EuiComboBoxOptionOption[]) => {
|
||||
if (selected.length) {
|
||||
return field.onChange(selected[0].value);
|
||||
|
@ -117,13 +78,18 @@ export function IndexSelection() {
|
|||
|
||||
field.onChange('');
|
||||
}}
|
||||
onSearchChange={onDataViewSearchChange}
|
||||
options={
|
||||
indexPatternOption ? [...dataViewOptions, indexPatternOption] : dataViewOptions
|
||||
}
|
||||
placeholder={placeholder}
|
||||
options={options}
|
||||
onSearchChange={onSearchChange}
|
||||
selectedOptions={
|
||||
!!field.value ? [findSelectedIndexPattern(dataViews, field.value)] : []
|
||||
!!field.value
|
||||
? [
|
||||
{
|
||||
value: field.value,
|
||||
label: field.value,
|
||||
'data-test-subj': 'indexSelectionSelectedValue',
|
||||
},
|
||||
]
|
||||
: []
|
||||
}
|
||||
singleSelection
|
||||
/>
|
||||
|
@ -133,42 +99,50 @@ export function IndexSelection() {
|
|||
);
|
||||
}
|
||||
|
||||
function findSelectedIndexPattern(dataViews: DataView[], indexPattern: string) {
|
||||
const selectedDataView = dataViews.find((view) => view.getIndexPattern() === indexPattern);
|
||||
if (selectedDataView) {
|
||||
return {
|
||||
value: selectedDataView.getIndexPattern(),
|
||||
label: createDataViewLabel(selectedDataView),
|
||||
'data-test-subj': 'indexSelectionSelectedValue',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
value: indexPattern,
|
||||
label: indexPattern,
|
||||
'data-test-subj': 'indexSelectionSelectedValue',
|
||||
};
|
||||
}
|
||||
|
||||
function createDataViewLabel(dataView: DataView) {
|
||||
return `${dataView.getName()} (${dataView.getIndexPattern()})`;
|
||||
}
|
||||
|
||||
function createDataViewOptions(dataViews: DataView[]): Option[] {
|
||||
const options = [];
|
||||
|
||||
options.push({
|
||||
label: i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.customKql.indexSelection.dataViewOptionsLabel',
|
||||
{ defaultMessage: 'Select an existing Data View' }
|
||||
),
|
||||
function createDataViewsOption(dataViews: DataView[]): Option {
|
||||
return {
|
||||
label: i18n.translate('xpack.observability.slo.sloEdit.indexSelection.dataViewOptionsLabel', {
|
||||
defaultMessage: 'Select an index pattern from an existing Data View',
|
||||
}),
|
||||
options: dataViews
|
||||
.map((view) => ({
|
||||
label: createDataViewLabel(view),
|
||||
value: view.getIndexPattern(),
|
||||
}))
|
||||
.sort((a, b) => String(a.label).localeCompare(b.label)),
|
||||
});
|
||||
|
||||
return options;
|
||||
};
|
||||
}
|
||||
|
||||
function createIndexPatternOption(searchValue: string, indices: string[]): Option {
|
||||
const indexPattern = searchValue.endsWith('*') ? searchValue : `${searchValue}*`;
|
||||
const hasMatchingIndices = indices.length > 0;
|
||||
|
||||
return {
|
||||
label: i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.customKql.indexSelection.indexPatternLabel',
|
||||
{ defaultMessage: 'Use the index pattern' }
|
||||
),
|
||||
options: [
|
||||
{
|
||||
value: indexPattern,
|
||||
label: hasMatchingIndices
|
||||
? i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.customKql.indexSelection.indexPatternFoundLabel',
|
||||
{
|
||||
defaultMessage:
|
||||
'{searchPattern} (match {num, plural, one {# index} other {# indices}})',
|
||||
values: { searchPattern: indexPattern, num: indices.length },
|
||||
}
|
||||
)
|
||||
: i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.indexSelection.indexPatternNoMatchLabel',
|
||||
{ defaultMessage: '{searchPattern}', values: { searchPattern: indexPattern } }
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27273,11 +27273,9 @@
|
|||
"xpack.observability.slo.sloEdit.createAlert.ruleName": "Règle d'alerte de taux d'avancement du SLO",
|
||||
"xpack.observability.slo.sloEdit.createAlert.title": "Créer",
|
||||
"xpack.observability.slo.sloEdit.createSloButton": "Créer un SLO",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.dataViewOptionsLabel": "Sélectionner une vue de données existante",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.helpText": "Utilisez le caractère * pour élargir votre recherche.",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.indexPatternLabel": "Utiliser le modèle d'indexation",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.label": "Index",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.placeholder": "Sélectionner une vue de données ou utiliser un modèle d’indexation",
|
||||
"xpack.observability.slo.sloEdit.dataPreviewChart.xTitle": "Dernière heure",
|
||||
"xpack.observability.slo.sloEdit.dataPreviewChart.yTitle": "SLI",
|
||||
"xpack.observability.slo.sloEdit.definition.sliType": "Choisir le type de SLI",
|
||||
|
|
|
@ -27273,11 +27273,9 @@
|
|||
"xpack.observability.slo.sloEdit.createAlert.ruleName": "SLOバーンレートアラートルール",
|
||||
"xpack.observability.slo.sloEdit.createAlert.title": "作成",
|
||||
"xpack.observability.slo.sloEdit.createSloButton": "SLOの作成",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.dataViewOptionsLabel": "既存のデータビューを選択",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.helpText": "* で検索クエリの範囲を広げます。",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.indexPatternLabel": "インデックスパターンを使用",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.label": "インデックス",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.placeholder": "データビューを選択するか、インデックスパターンを使用してください。",
|
||||
"xpack.observability.slo.sloEdit.dataPreviewChart.xTitle": "過去 1 時間",
|
||||
"xpack.observability.slo.sloEdit.dataPreviewChart.yTitle": "SLI",
|
||||
"xpack.observability.slo.sloEdit.definition.sliType": "SLIタイプを選択",
|
||||
|
|
|
@ -27271,11 +27271,9 @@
|
|||
"xpack.observability.slo.sloEdit.createAlert.ruleName": "SLO 消耗速度告警规则",
|
||||
"xpack.observability.slo.sloEdit.createAlert.title": "创建",
|
||||
"xpack.observability.slo.sloEdit.createSloButton": "创建 SLO",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.dataViewOptionsLabel": "选择现有数据视图",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.helpText": "使用 * 可扩大您的查询范围。",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.indexPatternLabel": "使用索引模式",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.label": "索引",
|
||||
"xpack.observability.slo.sloEdit.customKql.indexSelection.placeholder": "选择数据视图或使用索引模式",
|
||||
"xpack.observability.slo.sloEdit.dataPreviewChart.xTitle": "过去一小时",
|
||||
"xpack.observability.slo.sloEdit.dataPreviewChart.yTitle": "SLI",
|
||||
"xpack.observability.slo.sloEdit.definition.sliType": "选择 SLI 类型",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue