diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_index_pattern_fields.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_index_pattern_fields.ts deleted file mode 100644 index 5aedb92219da6..0000000000000 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_index_pattern_fields.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 { FieldSpec } from '@kbn/data-views-plugin/common'; -import { useQuery } from '@tanstack/react-query'; -import { useKibana } from '../../utils/kibana_react'; - -export interface UseFetchIndexPatternFieldsResponse { - isLoading: boolean; - isSuccess: boolean; - isError: boolean; - data: FieldSpec[] | undefined; -} - -export function useFetchIndexPatternFields( - indexPattern?: string -): UseFetchIndexPatternFieldsResponse { - const { dataViews } = useKibana().services; - - const { isLoading, isError, isSuccess, data } = useQuery({ - queryKey: ['fetchIndexPatternFields', indexPattern], - queryFn: async ({ signal }) => { - if (!indexPattern) { - return []; - } - try { - return await dataViews.getFieldsForWildcard({ pattern: indexPattern, allowNoIndex: true }); - } catch (error) { - throw new Error(`Something went wrong. Error: ${error}`); - } - }, - retry: false, - refetchOnWindowFocus: false, - enabled: Boolean(indexPattern), - }); - - return { isLoading, isError, isSuccess, data }; -} diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx index 78afcc71cae58..ade6cc5c32008 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx @@ -5,18 +5,16 @@ * 2.0. */ -import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React, { useEffect } from 'react'; import { useFormContext } from 'react-hook-form'; -import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; +import { useCreateDataView } from '../../../../hooks/use_create_data_view'; +import { GroupByField } from '../common/group_by_field'; import { useFetchApmIndex } from '../../../../hooks/slo/use_fetch_apm_indices'; -import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { CreateSLOForm } from '../../types'; import { FieldSelector } from '../apm_common/field_selector'; import { DataPreviewChart } from '../common/data_preview_chart'; -import { IndexFieldSelector } from '../common/index_field_selector'; import { QueryBuilder } from '../common/query_builder'; export function ApmAvailabilityIndicatorTypeForm() { @@ -28,15 +26,10 @@ export function ApmAvailabilityIndicatorTypeForm() { setValue('indicator.params.index', apmIndex); } }, [setValue, apmIndex]); - const timestampField = watch('indicator.params.timestampField'); - const groupByField = watch('groupBy'); - const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = - useFetchIndexPatternFields(apmIndex); - - const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = - useFetchGroupByCardinality(apmIndex, timestampField, groupByField); - const groupByFields = indexFields.filter((field) => field.aggregatable); + const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({ + indexPatternString: apmIndex, + }); return ( @@ -140,42 +133,7 @@ export function ApmAvailabilityIndicatorTypeForm() { - - {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { - defaultMessage: 'Group by', - })}{' '} - - - } - placeholder={i18n.translate('xpack.observability.slo.sloEdit.groupBy.placeholder', { - defaultMessage: 'Select an optional field to group by', - })} - isLoading={!!apmIndex && isIndexFieldsLoading} - isDisabled={!apmIndex} - /> - - {!isGroupByCardinalityLoading && !!groupByCardinality && ( - - )} + diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx index dcb4be69d272d..b93596458a437 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx @@ -5,25 +5,16 @@ * 2.0. */ -import { - EuiCallOut, - EuiFieldNumber, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiIconTip, -} from '@elastic/eui'; +import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React, { useEffect } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; +import { GroupByField } from '../common/group_by_field'; +import { useCreateDataView } from '../../../../hooks/use_create_data_view'; import { useFetchApmIndex } from '../../../../hooks/slo/use_fetch_apm_indices'; -import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { CreateSLOForm } from '../../types'; import { FieldSelector } from '../apm_common/field_selector'; import { DataPreviewChart } from '../common/data_preview_chart'; -import { IndexFieldSelector } from '../common/index_field_selector'; import { QueryBuilder } from '../common/query_builder'; export function ApmLatencyIndicatorTypeForm() { @@ -36,15 +27,9 @@ export function ApmLatencyIndicatorTypeForm() { } }, [setValue, apmIndex]); - const timestampField = watch('indicator.params.timestampField'); - const groupByField = watch('groupBy'); - - const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = - useFetchIndexPatternFields(apmIndex); - - const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = - useFetchGroupByCardinality(apmIndex, timestampField, groupByField); - const groupByFields = indexFields.filter((field) => field.aggregatable); + const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({ + indexPatternString: apmIndex, + }); return ( @@ -191,42 +176,7 @@ export function ApmLatencyIndicatorTypeForm() { - - {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { - defaultMessage: 'Group by', - })}{' '} - - - } - placeholder={i18n.translate('xpack.observability.slo.sloEdit.groupBy.placeholder', { - defaultMessage: 'Select an optional field to group by', - })} - isLoading={!!apmIndex && isIndexFieldsLoading} - isDisabled={!apmIndex} - /> - - {!isGroupByCardinalityLoading && !!groupByCardinality && ( - - )} + diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/common/group_by_field.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/common/group_by_field.tsx new file mode 100644 index 0000000000000..103e3dc3c93b8 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/common/group_by_field.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 { ALL_VALUE } from '@kbn/slo-schema'; +import { i18n } from '@kbn/i18n'; +import { EuiCallOut, EuiIconTip } from '@elastic/eui'; +import React from 'react'; +import { DataView } from '@kbn/data-views-plugin/common'; +import { useFormContext } from 'react-hook-form'; +import { OptionalText } from './optional_text'; +import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; +import { CreateSLOForm } from '../../types'; +import { IndexFieldSelector } from './index_field_selector'; + +export function GroupByField({ dataView, isLoading }: { dataView?: DataView; isLoading: boolean }) { + const { watch } = useFormContext(); + + const groupByFields = dataView?.fields?.filter((field) => field.aggregatable) ?? []; + const index = watch('indicator.params.index'); + const timestampField = watch('indicator.params.timestampField'); + const groupByField = watch('groupBy'); + + const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = + useFetchGroupByCardinality(index, timestampField, groupByField); + + return ( + <> + + {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { + defaultMessage: 'Group by', + })}{' '} + + + } + labelAppend={} + placeholder={i18n.translate('xpack.observability.slo.sloEdit.groupBy.placeholder', { + defaultMessage: 'Select an optional field to group by', + })} + isLoading={!!index && isLoading} + isDisabled={!index} + /> + {!isGroupByCardinalityLoading && !!groupByCardinality && ( + + )} + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx index 46d4af15de628..aa5b663f75770 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx @@ -21,11 +21,13 @@ interface Props { isLoading: boolean; isRequired?: boolean; defaultValue?: string; + labelAppend?: ReactNode; } export function IndexFieldSelector({ indexFields, name, label, + labelAppend, placeholder, isDisabled, isLoading, @@ -41,7 +43,7 @@ export function IndexFieldSelector({ return ( - + + {i18n.translate('xpack.observability.slo.sloEdit.optionalLabel', { + defaultMessage: 'Optional', + })} + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/common/query_builder.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/common/query_builder.tsx index db451234b6e31..0bd66f7881820 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/common/query_builder.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/common/query_builder.tsx @@ -11,6 +11,7 @@ import { Controller, FieldPath, useFormContext } from 'react-hook-form'; import { useCreateDataView } from '../../../../hooks/use_create_data_view'; import { useKibana } from '../../../../utils/kibana_react'; import { CreateSLOForm } from '../../types'; +import { OptionalText } from './optional_text'; export interface Props { dataTestSubj: string; @@ -54,6 +55,7 @@ export function QueryBuilder({ label ) } + labelAppend={!required ? : undefined} isInvalid={getFieldState(name).invalid} fullWidth > @@ -62,14 +64,12 @@ export function QueryBuilder({ name={name} control={control} rules={{ - required: Boolean(required), + required: Boolean(required) && Boolean(dataView), }} render={({ field, fieldState }) => ( (); const index = watch('indicator.params.index'); - const timestampField = watch('indicator.params.timestampField'); - const groupByField = watch('groupBy'); const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({ indexPatternString: index, }); const timestampFields = dataView?.fields?.filter((field) => field.type === 'date') ?? []; - const groupByFields = dataView?.fields?.filter((field) => field.aggregatable) ?? []; - - const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = - useFetchGroupByCardinality(index, timestampField, groupByField); return ( @@ -142,42 +135,7 @@ export function CustomKqlIndicatorTypeForm() { /> - - {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { - defaultMessage: 'Group by', - })}{' '} - - - } - placeholder={i18n.translate('xpack.observability.slo.sloEdit.groupBy.placeholder', { - defaultMessage: 'Select an optional field to group by', - })} - isLoading={!!index && isIndexFieldsLoading} - isDisabled={!index} - /> - - {!isGroupByCardinalityLoading && !!groupByCardinality && ( - - )} + diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx index 2db17479ffd2d..b40a7cd43227a 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx @@ -6,7 +6,6 @@ */ import { - EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -16,11 +15,10 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React from 'react'; import { useFormContext } from 'react-hook-form'; -import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; -import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; +import { GroupByField } from '../common/group_by_field'; +import { useCreateDataView } from '../../../../hooks/use_create_data_view'; import { CreateSLOForm } from '../../types'; import { DataPreviewChart } from '../common/data_preview_chart'; import { IndexFieldSelector } from '../common/index_field_selector'; @@ -35,17 +33,13 @@ const SUPPORTED_METRIC_FIELD_TYPES = ['number', 'histogram']; export function CustomMetricIndicatorTypeForm() { const { watch } = useFormContext(); const index = watch('indicator.params.index'); - const timestampField = watch('indicator.params.timestampField'); - const groupByField = watch('groupBy'); - const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = - useFetchIndexPatternFields(index); - const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = - useFetchGroupByCardinality(index, timestampField, groupByField); + const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({ + indexPatternString: index, + }); - const timestampFields = indexFields.filter((field) => field.type === 'date'); - const groupByFields = indexFields.filter((field) => field.aggregatable); - const metricFields = indexFields.filter((field) => + const timestampFields = dataView?.fields.filter((field) => field.type === 'date'); + const metricFields = dataView?.fields.filter((field) => SUPPORTED_METRIC_FIELD_TYPES.includes(field.type) ); @@ -67,7 +61,7 @@ export function CustomMetricIndicatorTypeForm() { @@ -150,7 +144,7 @@ export function CustomMetricIndicatorTypeForm() { @@ -159,42 +153,7 @@ export function CustomMetricIndicatorTypeForm() { - - {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { - defaultMessage: 'Group by', - })}{' '} - - - } - placeholder={i18n.translate('xpack.observability.slo.sloEdit.groupBy.placeholder', { - defaultMessage: 'Select an optional field to group by', - })} - isLoading={!!index && isIndexFieldsLoading} - isDisabled={!index} - /> - - {!isGroupByCardinalityLoading && !!groupByCardinality && ( - - )} + diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx index 992547dc2802f..9abe0828b6695 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx @@ -6,7 +6,6 @@ */ import { - EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -16,11 +15,10 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React from 'react'; import { useFormContext } from 'react-hook-form'; -import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; -import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; +import { useCreateDataView } from '../../../../hooks/use_create_data_view'; +import { GroupByField } from '../common/group_by_field'; import { CreateSLOForm } from '../../types'; import { DataPreviewChart } from '../common/data_preview_chart'; import { IndexFieldSelector } from '../common/index_field_selector'; @@ -31,17 +29,13 @@ import { HistogramIndicator } from './histogram_indicator'; export function HistogramIndicatorTypeForm() { const { watch } = useFormContext(); const index = watch('indicator.params.index'); - const timestampField = watch('indicator.params.timestampField'); - const groupByField = watch('groupBy'); - const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = - useFetchIndexPatternFields(index); - const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = - useFetchGroupByCardinality(index, timestampField, groupByField); + const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({ + indexPatternString: index, + }); - const histogramFields = indexFields.filter((field) => field.type === 'histogram'); - const timestampFields = indexFields.filter((field) => field.type === 'date'); - const groupByFields = indexFields.filter((field) => field.aggregatable); + const histogramFields = dataView?.fields.filter((field) => field.type === 'histogram'); + const timestampFields = dataView?.fields.filter((field) => field.type === 'date'); return ( <> @@ -61,7 +55,7 @@ export function HistogramIndicatorTypeForm() { @@ -137,7 +131,7 @@ export function HistogramIndicatorTypeForm() { @@ -145,42 +139,7 @@ export function HistogramIndicatorTypeForm() { - - {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { - defaultMessage: 'Group by', - })}{' '} - - - } - placeholder={i18n.translate('xpack.observability.slo.sloEdit.groupBy.placeholder', { - defaultMessage: 'Select an optional field to group by', - })} - isLoading={!!index && isIndexFieldsLoading} - isDisabled={!index} - /> - - {!isGroupByCardinalityLoading && !!groupByCardinality && ( - - )} + diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/slo_edit_form_description_section.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/slo_edit_form_description_section.tsx index 6b7c25f57025e..8e4e2f26ea19a 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/slo_edit_form_description_section.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/slo_edit_form_description_section.tsx @@ -19,6 +19,7 @@ import { import { i18n } from '@kbn/i18n'; import React from 'react'; import { Controller, useFormContext } from 'react-hook-form'; +import { OptionalText } from './common/optional_text'; import { CreateSLOForm } from '../types'; import { maxWidth } from './slo_edit_form'; @@ -74,6 +75,7 @@ export function SloEditFormDescriptionSection() { label={i18n.translate('xpack.observability.slo.sloEdit.description.sloDescription', { defaultMessage: 'Description', })} + labelAppend={} > (); const index = watch('indicator.params.index'); - const timestampField = watch('indicator.params.timestampField'); - const groupByField = watch('groupBy'); - const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = - useFetchIndexPatternFields(index); - const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = - useFetchGroupByCardinality(index, timestampField, groupByField); + const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({ + indexPatternString: index, + }); - const timestampFields = indexFields.filter((field) => field.type === 'date'); - const groupByFields = indexFields.filter((field) => field.aggregatable); + const timestampFields = dataView?.fields.filter((field) => field.type === 'date'); const { uiSettings } = useKibana().services; const threshold = watch('indicator.params.metric.threshold'); const comparator = watch('indicator.params.metric.comparator'); @@ -69,7 +63,7 @@ export function TimesliceMetricIndicatorTypeForm() { - + - - {i18n.translate('xpack.observability.slo.sloEdit.groupBy.label', { - defaultMessage: 'Group by', - })}{' '} - - - } - placeholder={i18n.translate('xpack.observability.slo.sloEdit.groupBy.placeholder', { - defaultMessage: 'Select an optional field to group by', - })} - isLoading={!!index && isIndexFieldsLoading} - isDisabled={!index} - /> - - {!isGroupByCardinalityLoading && !!groupByCardinality && ( - - )} + { isLoading: false, data: ['some-index', 'index-2'], }); - useFetchIndexPatternFieldsMock.mockReturnValue({ - isLoading: false, - data: [ - { name: 'field', type: 'date', aggregatable: false, searchable: false }, - { name: 'field_text', type: 'text', aggregatable: true, searchable: true }, - ], - }); useCreateSloMock.mockReturnValue({ isLoading: false,