adds a check to allow only data views with time fields

This commit is contained in:
Walter Rafelsberger 2024-10-10 15:11:10 +02:00
parent 2b58567771
commit a01975dba7
4 changed files with 105 additions and 46 deletions

View file

@ -0,0 +1,38 @@
/*
* 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 { EuiSpacer, EuiCallOut } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
export const TimeFieldWarning = () => {
return (
<>
<EuiCallOut
size="s"
title={i18n.translate(
'xpack.aiops.logCategorization.embeddableMenu.timeFieldWarning.title',
{
defaultMessage: 'The selected data view does not contain a time field.',
}
)}
color="warning"
iconType="warning"
>
<p>
{i18n.translate(
'xpack.aiops.logCategorization.embeddableMenu.timeFieldWarning.title.description',
{
defaultMessage: 'Pattern analysis can only be run on data views with a time field.',
}
)}
</p>
</EuiCallOut>
<EuiSpacer />
</>
);
};

View file

@ -8,6 +8,7 @@
import type { FC } from 'react';
import React, { useEffect, useMemo, useState, useCallback } from 'react';
import { pick } from 'lodash';
import useMountedState from 'react-use/lib/useMountedState';
import {
EuiFlyoutHeader,
@ -20,6 +21,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiFlyoutFooter,
EuiSpacer,
} from '@elastic/eui';
import type { IndexPatternSelectProps } from '@kbn/unified-search-plugin/public';
@ -29,6 +31,8 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { isPopulatedObject } from '@kbn/ml-is-populated-object';
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import { TimeFieldWarning } from '../../components/time_field_warning';
import type { LogRateAnalysisEmbeddableRuntimeState } from './types';
export interface LogRateAnalysisEmbeddableInitializerProps {
@ -52,13 +56,22 @@ export const LogRateAnalysisEmbeddableInitializer: FC<
onPreview,
isNewPanel,
}) => {
const isMounted = useMountedState();
const [formInput, setFormInput] = useState<LogRateAnalysisEmbeddableRuntimeState>(
pick(initialInput ?? {}, ['dataViewId']) as LogRateAnalysisEmbeddableRuntimeState
);
// State to track if the selected data view is time based, undefined is used
// to track that the check is in progress.
const [isDataViewTimeBased, setIsDataViewTimeBased] = useState<boolean | undefined>();
const isFormValid = useMemo(
() => isPopulatedObject(formInput, ['dataViewId']) && formInput.dataViewId !== '',
[formInput]
() =>
isPopulatedObject(formInput, ['dataViewId']) &&
formInput.dataViewId !== '' &&
isDataViewTimeBased === true,
[formInput, isDataViewTimeBased]
);
const updatedProps = useMemo(() => {
@ -78,7 +91,7 @@ export const LogRateAnalysisEmbeddableInitializer: FC<
onPreview(updatedProps);
}
},
[isFormValid, onPreview, updatedProps]
[isFormValid, onPreview, updatedProps, isDataViewTimeBased]
);
const setDataViewId = useCallback(
@ -87,10 +100,36 @@ export const LogRateAnalysisEmbeddableInitializer: FC<
...formInput,
dataViewId: dataViewId ?? '',
});
setIsDataViewTimeBased(undefined);
},
[formInput]
);
useEffect(
function checkIsDataViewTimeBased() {
setIsDataViewTimeBased(undefined);
const { dataViewId } = formInput;
if (!dataViewId) {
return;
}
dataViews
.get(dataViewId)
.then((dataView) => {
if (!isMounted()) {
return;
}
setIsDataViewTimeBased(dataView.isTimeBased());
})
.catch(() => {
setIsDataViewTimeBased(undefined);
});
},
[dataViews, formInput, isMounted]
);
return (
<>
<EuiFlyoutHeader
@ -121,21 +160,29 @@ export const LogRateAnalysisEmbeddableInitializer: FC<
defaultMessage: 'Data view',
})}
>
<IndexPatternSelect
autoFocus={!formInput.dataViewId}
fullWidth
compressed
indexPatternId={formInput.dataViewId}
placeholder={i18n.translate(
'xpack.aiops.embeddableLogRateAnalysis.config.dataViewSelectorPlaceholder',
{
defaultMessage: 'Select data view',
}
<>
<IndexPatternSelect
autoFocus={!formInput.dataViewId}
fullWidth
compressed
indexPatternId={formInput.dataViewId}
placeholder={i18n.translate(
'xpack.aiops.embeddableLogRateAnalysis.config.dataViewSelectorPlaceholder',
{
defaultMessage: 'Select data view',
}
)}
onChange={(newId) => {
setDataViewId(newId ?? '');
}}
/>
{isDataViewTimeBased === false && (
<>
<EuiSpacer size="m" />
<TimeFieldWarning />
</>
)}
onChange={(newId) => {
setDataViewId(newId ?? '');
}}
/>
</>
</EuiFormRow>
</EuiForm>
</EuiFlyoutBody>

View file

@ -33,6 +33,7 @@ import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
import { DataSourceContextProvider } from '../../hooks/use_data_source';
import type { PatternAnalysisEmbeddableRuntimeState } from './types';
import { PatternAnalysisSettings } from '../../components/log_categorization/log_categorization_for_embeddable/embeddable_menu';
import { TimeFieldWarning } from '../../components/time_field_warning';
import { RandomSampler } from '../../components/log_categorization/sampling_menu';
import {
DEFAULT_PROBABILITY,
@ -394,31 +395,3 @@ const TextFieldWarning = () => {
</>
);
};
const TimeFieldWarning = () => {
return (
<>
<EuiCallOut
size="s"
title={i18n.translate(
'xpack.aiops.logCategorization.embeddableMenu.timeFieldWarning.title',
{
defaultMessage: 'The selected data view does not contain a time field.',
}
)}
color="warning"
iconType="warning"
>
<p>
{i18n.translate(
'xpack.aiops.logCategorization.embeddableMenu.timeFieldWarning.title.description',
{
defaultMessage: 'Pattern analysis can only be run on data views with a time field.',
}
)}
</p>
</EuiCallOut>
<EuiSpacer />
</>
);
};

View file

@ -146,6 +146,7 @@ const LogRateAnalysisEmbeddableWrapperWithDeps: FC<LogRateAnalysisPropsWithDeps>
setRerenderFlag((prev) => !prev);
}
}, [dataViewId, prevDataViewId]);
const showComponent = prevDataViewId === undefined || prevDataViewId === dataViewId;
// TODO: Remove data-shared-item as part of https://github.com/elastic/kibana/issues/179376>
return (
@ -159,7 +160,7 @@ const LogRateAnalysisEmbeddableWrapperWithDeps: FC<LogRateAnalysisPropsWithDeps>
padding: '10px',
}}
>
{prevDataViewId === dataViewId && (
{showComponent && (
<Router history={history}>
<ReloadContextProvider reload$={resultObservable$}>
<AiopsAppContext.Provider value={aiopsAppContextValue}>