Skip to content

Commit

Permalink
use saved data view
Browse files Browse the repository at this point in the history
  • Loading branch information
shahzad31 committed Feb 21, 2024
1 parent fdebc68 commit c54d750
Show file tree
Hide file tree
Showing 35 changed files with 384 additions and 208 deletions.
6 changes: 6 additions & 0 deletions x-pack/packages/kbn-slo-schema/src/schema/indicators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const apmTransactionDurationIndicatorSchema = t.type({
}),
t.partial({
filter: querySchema,
dataViewId: t.string,
}),
]),
});
Expand All @@ -39,6 +40,7 @@ const apmTransactionErrorRateIndicatorSchema = t.type({
}),
t.partial({
filter: querySchema,
dataViewId: t.string,
}),
]),
});
Expand All @@ -55,6 +57,7 @@ const kqlCustomIndicatorSchema = t.type({
}),
t.partial({
filter: querySchema,
dataViewId: t.string,
}),
]),
});
Expand Down Expand Up @@ -132,6 +135,7 @@ const timesliceMetricIndicatorSchema = t.type({
}),
t.partial({
filter: querySchema,
dataViewId: t.string,
}),
]),
});
Expand Down Expand Up @@ -173,6 +177,7 @@ const metricCustomIndicatorSchema = t.type({
}),
t.partial({
filter: querySchema,
dataViewId: t.string,
}),
]),
});
Expand Down Expand Up @@ -218,6 +223,7 @@ const histogramIndicatorSchema = t.type({
}),
t.partial({
filter: querySchema,
dataViewId: t.string,
}),
]),
});
Expand Down
33 changes: 11 additions & 22 deletions x-pack/plugins/observability/public/hooks/use_create_data_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,28 @@
* 2.0.
*/

import { useEffect, useState } from 'react';
import { DataView } from '@kbn/data-views-plugin/common';
import { useFetcher } from '@kbn/observability-shared-plugin/public';
import { useKibana } from '../utils/kibana_react';

interface UseCreateDataViewProps {
indexPatternString: string | undefined;
indexPatternString?: string;
dataViewId?: string;
}

export function useCreateDataView({ indexPatternString }: UseCreateDataViewProps) {
export function useCreateDataView({ indexPatternString, dataViewId }: UseCreateDataViewProps) {
const { dataViews } = useKibana().services;

const [stateDataView, setStateDataView] = useState<DataView | undefined>();
const [isLoading, setIsLoading] = useState<boolean>(false);

useEffect(() => {
const createDataView = () =>
dataViews.create({
const { data: dataView, loading } = useFetcher(() => {
if (dataViewId) {
return dataViews.get(dataViewId);
} else if (indexPatternString) {
return dataViews.create({
id: `${indexPatternString}-id`,
title: indexPatternString,
allowNoIndex: true,
});

if (indexPatternString) {
setIsLoading(true);
createDataView()
.then((value) => {
setStateDataView(value);
})
.finally(() => {
setIsLoading(false);
});
}
}, [indexPatternString, dataViews]);
}, [dataViewId, dataViews, indexPatternString]);

return { dataView: stateDataView, loading: isLoading };
return { dataView, loading: Boolean(loading) };
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { DataPreviewChart } from '../common/data_preview_chart';
import { QueryBuilder } from '../common/query_builder';

export function ApmAvailabilityIndicatorTypeForm() {
const { watch, setValue } = useFormContext<CreateSLOForm>();
const { setValue } = useFormContext<CreateSLOForm>();
const { data: apmIndex } = useFetchApmIndex();

useEffect(() => {
Expand Down Expand Up @@ -109,7 +109,7 @@ export function ApmAvailabilityIndicatorTypeForm() {
<EuiFlexItem>
<QueryBuilder
dataTestSubj="apmLatencyFilterInput"
indexPatternString={watch('indicator.params.index')}
dataView={dataView}
label={i18n.translate('xpack.observability.slo.sloEdit.apmLatency.filter', {
defaultMessage: 'Query filter',
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { DataPreviewChart } from '../common/data_preview_chart';
import { QueryBuilder } from '../common/query_builder';

export function ApmLatencyIndicatorTypeForm() {
const { control, watch, getFieldState, setValue } = useFormContext<CreateSLOForm>();
const { control, getFieldState, setValue } = useFormContext<CreateSLOForm>();
const { data: apmIndex } = useFetchApmIndex();

useEffect(() => {
Expand Down Expand Up @@ -152,7 +152,7 @@ export function ApmLatencyIndicatorTypeForm() {
<EuiFlexItem>
<QueryBuilder
dataTestSubj="apmLatencyFilterInput"
indexPatternString={watch('indicator.params.index')}
dataView={dataView}
label={i18n.translate('xpack.observability.slo.sloEdit.apmLatency.filter', {
defaultMessage: 'Query filter',
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ import { Controller, FieldPath, useFormContext } from 'react-hook-form';
import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query';
import styled from 'styled-components';
import { kqlQuerySchema } from '@kbn/slo-schema';
import { DataView } from '@kbn/data-views-plugin/common';
import { observabilityAppId } from '../../../../../common';
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;
indexPatternString: string | undefined;
dataView?: DataView;
dataViewId?: string;
label: string;
name: FieldPath<CreateSLOForm>;
placeholder: string;
Expand All @@ -29,12 +30,12 @@ export interface Props {

export function QueryBuilder({
dataTestSubj,
indexPatternString,
label,
name,
placeholder,
required,
tooltip,
dataView,
}: Props) {
const {
unifiedSearch: {
Expand All @@ -44,10 +45,6 @@ export function QueryBuilder({

const { control, getFieldState } = useFormContext<CreateSLOForm>();

const { dataView } = useCreateDataView({
indexPatternString,
});

return (
<EuiFormRow
label={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,28 @@
import { EuiFormRow } from '@elastic/eui';
import { DataView } from '@kbn/data-views-plugin/public';
import { i18n } from '@kbn/i18n';
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { DataViewPicker } from '@kbn/unified-search-plugin/public';
import { useKibana } from '../../../../utils/kibana_react';
import { ObservabilityPublicPluginsStart } from '../../../..';
import { useFetchDataViews } from '../../../../hooks/use_fetch_data_views';
import { CreateSLOForm } from '../../types';

export const DATA_VIEW_FIELD = 'indicator.params.dataViewId';
const INDEX_FIELD = 'indicator.params.index';
const TIMESTAMP_FIELD = 'indicator.params.timestampField';

export function IndexSelection() {
const { control, getFieldState, setValue, watch } = useFormContext<CreateSLOForm>();
const { dataViews: dataViewsService } = useKibana().services;

const { isLoading: isDataViewsLoading, data: dataViews = [] } = useFetchDataViews();

const { dataViewEditor } = useKibana<ObservabilityPublicPluginsStart>().services;

const [adHocDataViews, setAdHocDataViews] = useState<DataView[]>([]);

const currentIndexPattern = watch('indicator.params.index');
const currentIndexPattern = watch(INDEX_FIELD);
const currentDataViewId = watch(DATA_VIEW_FIELD);

useEffect(() => {
if (!isDataViewsLoading) {
Expand Down Expand Up @@ -60,51 +63,63 @@ export function IndexSelection() {
);
};

const getDataViewIdByIndexPattern = (indexPattern: string) => {
return (
dataViews.find((dataView) => dataView.title === indexPattern) ||
adHocDataViews.find((dataView) => dataView.getIndexPattern() === indexPattern)
);
};
const getDataViewIdByIndexPattern = useCallback(
(indexPattern: string) => {
return (
dataViews.find((dataView) => dataView.title === indexPattern) ||
adHocDataViews.find((dataView) => dataView.getIndexPattern() === indexPattern)
);
},
[adHocDataViews, dataViews]
);

useEffect(() => {
if (!currentDataViewId && currentIndexPattern) {
setValue(DATA_VIEW_FIELD, getDataViewIdByIndexPattern(currentIndexPattern)?.id);
}
}, [currentDataViewId, currentIndexPattern, getDataViewIdByIndexPattern, setValue]);

return (
<EuiFormRow label={INDEX_LABEL} isInvalid={getFieldState('indicator.params.index').invalid}>
<EuiFormRow label={INDEX_LABEL} isInvalid={getFieldState(INDEX_FIELD).invalid}>
<Controller
defaultValue=""
name="indicator.params.index"
name={DATA_VIEW_FIELD}
control={control}
rules={{ required: true }}
rules={{ required: !Boolean(currentIndexPattern) }}
render={({ field, fieldState }) => (
<DataViewPicker
adHocDataViews={adHocDataViews}
trigger={{
label: field.value || SELECT_DATA_VIEW,
label: currentIndexPattern || SELECT_DATA_VIEW,
fullWidth: true,
color: fieldState.invalid ? 'danger' : 'text',
isLoading: isDataViewsLoading,
'data-test-subj': 'indexSelection',
}}
onChangeDataView={(newId: string) => {
field.onChange(getDataViewPatternById(newId));
setValue(INDEX_FIELD, getDataViewPatternById(newId)!);
field.onChange(newId);
dataViewsService.get(newId).then((dataView) => {
if (dataView.timeFieldName) {
setValue('indicator.params.timestampField', dataView.timeFieldName);
setValue(TIMESTAMP_FIELD, dataView.timeFieldName);
}
});
}}
currentDataViewId={getDataViewIdByIndexPattern(field.value)?.id}
currentDataViewId={field.value ?? getDataViewIdByIndexPattern(currentIndexPattern)?.id}
onDataViewCreated={() => {
dataViewEditor.openEditor({
allowAdHocDataView: true,
onSave: (dataView: DataView) => {
if (!dataView.isPersisted()) {
setAdHocDataViews([...adHocDataViews, dataView]);
field.onChange(dataView.getIndexPattern());
field.onChange(dataView.id);
setValue(INDEX_FIELD, dataView.getIndexPattern());
} else {
field.onChange(getDataViewPatternById(dataView.id));
field.onChange(dataView.id);
setValue(INDEX_FIELD, getDataViewPatternById(dataView.id)!);
}
if (dataView.timeFieldName) {
setValue('indicator.params.timestampField', dataView.timeFieldName);
setValue(TIMESTAMP_FIELD, dataView.timeFieldName);
}
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ import { CreateSLOForm } from '../../types';
import { DataPreviewChart } from '../common/data_preview_chart';
import { IndexFieldSelector } from '../common/index_field_selector';
import { QueryBuilder } from '../common/query_builder';
import { IndexSelection } from '../custom_common/index_selection';
import { DATA_VIEW_FIELD, IndexSelection } from '../custom_common/index_selection';

export function CustomKqlIndicatorTypeForm() {
const { watch } = useFormContext<CreateSLOForm>();
const index = watch('indicator.params.index');
const dataViewId = watch(DATA_VIEW_FIELD);

const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({
indexPatternString: index,
dataViewId,
});
const timestampFields = dataView?.fields?.filter((field) => field.type === 'date') ?? [];

Expand Down Expand Up @@ -52,7 +54,7 @@ export function CustomKqlIndicatorTypeForm() {
<EuiFlexItem>
<QueryBuilder
dataTestSubj="customKqlIndicatorFormQueryFilterInput"
indexPatternString={watch('indicator.params.index')}
dataView={dataView}
label={i18n.translate('xpack.observability.slo.sloEdit.sliType.customKql.queryFilter', {
defaultMessage: 'Query filter',
})}
Expand All @@ -79,7 +81,7 @@ export function CustomKqlIndicatorTypeForm() {
<EuiFlexItem>
<QueryBuilder
dataTestSubj="customKqlIndicatorFormGoodQueryInput"
indexPatternString={watch('indicator.params.index')}
dataView={dataView}
label={i18n.translate('xpack.observability.slo.sloEdit.sliType.customKql.goodQuery', {
defaultMessage: 'Good query',
})}
Expand Down Expand Up @@ -109,7 +111,7 @@ export function CustomKqlIndicatorTypeForm() {
<EuiFlexItem>
<QueryBuilder
dataTestSubj="customKqlIndicatorFormTotalQueryInput"
indexPatternString={watch('indicator.params.index')}
dataView={dataView}
label={i18n.translate('xpack.observability.slo.sloEdit.sliType.customKql.totalQuery', {
defaultMessage: 'Total query',
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function CustomMetricIndicatorTypeForm() {
<EuiFlexItem>
<QueryBuilder
dataTestSubj="customMetricIndicatorFormQueryFilterInput"
indexPatternString={watch('indicator.params.index')}
dataView={dataView}
label={i18n.translate(
'xpack.observability.slo.sloEdit.sliType.customMetric.queryFilter',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { first, range, xor } from 'lodash';
import React, { useEffect, useState } from 'react';
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
import { useCreateDataView } from '../../../../hooks/use_create_data_view';
import {
aggValueToLabel,
CUSTOM_METRIC_AGGREGATION_OPTIONS,
Expand Down Expand Up @@ -107,6 +108,10 @@ export function MetricIndicator({ type, metricFields, isLoadingIndex }: MetricIn
const equation = watch(`indicator.params.${type}.equation`);
const indexPattern = watch('indicator.params.index');

const { dataView } = useCreateDataView({
indexPatternString: indexPattern,
});

const disableAdd = fields?.length === MAX_VARIABLES || !indexPattern;
const disableDelete = fields?.length === 1 || !indexPattern;

Expand Down Expand Up @@ -279,7 +284,7 @@ export function MetricIndicator({ type, metricFields, isLoadingIndex }: MetricIn
<EuiFlexItem>
<QueryBuilder
dataTestSubj="customKqlIndicatorFormGoodQueryInput"
indexPatternString={watch('indicator.params.index')}
dataView={dataView}
label={`${filterLabel} ${metric.name}`}
name={`indicator.params.${type}.metrics.${index}.filter`}
placeholder={i18n.translate(
Expand Down
Loading

0 comments on commit c54d750

Please sign in to comment.