Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ML] Data view loading refactor #116455

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion x-pack/plugins/ml/public/application/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const App: FC<AppProps> = ({ coreStart, deps, appMountParams }) => {

const pageDeps = {
history: appMountParams.history,
indexPatterns: deps.data.indexPatterns,
dataViewsContract: deps.data.dataViews,
config: coreStart.uiSettings!,
setBreadcrumbs: coreStart.chrome!.setBreadcrumbs,
redirectToMlAccessDeniedPage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { ml } from '../../services/ml_api_service';
import { mlJobService } from '../../services/job_service';
import { getUrlForRecord, openCustomUrlWindow } from '../../util/custom_url_utils';
import { formatHumanReadableDateTimeSeconds } from '../../../../common/util/date_utils';
import { getIndexPatternIdFromName } from '../../util/index_utils';
import { getDataViewIdFromName } from '../../util/index_utils';
import { replaceStringTokens } from '../../util/string_utils';
import { ML_APP_LOCATOR, ML_PAGES } from '../../../../common/constants/locator';
/*
Expand Down Expand Up @@ -258,18 +258,18 @@ class LinksMenuUI extends Component {
};

const createAndOpenUrl = (index, categorizationFieldType) => {
// Find the ID of the data view with a title attribute which matches the
// index configured in the datafeed. If a Kibana data view has not been created
// for this index, then the user will see a warning message on the Discover tab advising
// them that no matching data view has been configured.
const indexPatternId = getIndexPatternIdFromName(index) || index;

// Get the definition of the category and use the terms or regex to view the
// matching events in the Kibana Discover tab depending on whether the
// categorization field is of mapping type text (preferred) or keyword.
ml.results
.getCategoryDefinition(record.job_id, categoryId)
.then((resp) => {
.then(async (resp) => {
// Find the ID of the data view with a title attribute which matches the
// index configured in the datafeed. If a Kibana data view has not been created
// for this index, then the user will see a warning message on the Discover tab advising
// them that no matching data view has been configured.
const dataViewId = (await getDataViewIdFromName(index)) ?? index;

let query = null;
// Build query using categorization regex (if keyword type) or terms (if text type).
// Check for terms or regex in case categoryId represents an anomaly from the absence of the
Expand Down Expand Up @@ -313,7 +313,7 @@ class LinksMenuUI extends Component {
});

const appStateProps = {
index: indexPatternId,
index: dataViewId,
filters: [],
};
if (query !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jest.mock('./full_time_range_selector_service', () => ({
}));

describe('FullTimeRangeSelector', () => {
const indexPattern = {
const dataView = {
id: '0844fc70-5ab5-11e9-935e-836737467b0f',
fields: [],
title: 'test-data-view',
Expand All @@ -34,7 +34,7 @@ describe('FullTimeRangeSelector', () => {
};

const requiredProps = {
indexPattern,
dataView,
query,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ import type { DataView } from '../../../../../../../src/plugins/data_views/publi
import { setFullTimeRange } from './full_time_range_selector_service';

interface Props {
indexPattern: DataView;
dataView: DataView;
query: Query;
disabled: boolean;
callback?: (a: any) => void;
}

// Component for rendering a button which automatically sets the range of the time filter
// to the time range of data in the index(es) mapped to the supplied Kibana index pattern or query.
export const FullTimeRangeSelector: FC<Props> = ({ indexPattern, query, disabled, callback }) => {
export const FullTimeRangeSelector: FC<Props> = ({ dataView, query, disabled, callback }) => {
// wrapper around setFullTimeRange to allow for the calling of the optional callBack prop
async function setRange(i: DataView, q: Query) {
const fullTimeRange = await setFullTimeRange(i, q);
Expand All @@ -33,14 +33,14 @@ export const FullTimeRangeSelector: FC<Props> = ({ indexPattern, query, disabled
return (
<EuiButton
isDisabled={disabled}
onClick={() => setRange(indexPattern, query)}
onClick={() => setRange(dataView, query)}
data-test-subj="mlButtonUseFullData"
>
<FormattedMessage
id="xpack.ml.fullTimeRangeSelector.useFullDataButtonLabel"
defaultMessage="Use full {dataViewTitle} data"
values={{
dataViewTitle: indexPattern.title,
dataViewTitle: dataView.title,
}}
/>
</EuiButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import type { DataView } from '../../../../../../../../src/plugins/data_views/public';

export const indexPatternMock = {
export const dataViewMock = {
id: 'the-index-pattern-id',
title: 'the-index-pattern-title',
fields: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import type { DataViewsContract } from '../../../../../../../../src/plugins/data_views/public';

export const indexPatternsMock = new (class {
export const dataViewsContractMock = new (class {
fieldFormats = [];
config = {};
savedObjectsClient = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* 2.0.
*/

import { indexPatternMock } from './index_pattern';
import { indexPatternsMock } from './index_patterns';
import { dataViewMock } from './data_view';
import { dataViewsContractMock } from './data_view_contract';
import { kibanaConfigMock } from './kibana_config';
import { savedSearchMock } from './saved_search';

Expand All @@ -15,8 +15,8 @@ export const kibanaContextValueMock = {
query: 'the-query-string',
language: 'the-query-language',
},
currentIndexPattern: indexPatternMock,
currentDataView: dataViewMock,
currentSavedSearch: savedSearchMock,
indexPatterns: indexPatternsMock,
dataViewsContract: dataViewsContractMock,
kibanaConfig: kibanaConfigMock,
};
16 changes: 4 additions & 12 deletions x-pack/plugins/ml/public/application/contexts/ml/ml_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,17 @@ import { MlServicesContext } from '../../app';

export interface MlContextValue {
combinedQuery: any;
currentIndexPattern: DataView; // TODO this should be IndexPattern or null
currentDataView: DataView; // TODO this should be DataView or null
currentSavedSearch: SavedSearchSavedObject | null;
indexPatterns: DataViewsContract;
dataViewsContract: DataViewsContract;
kibanaConfig: any; // IUiSettingsClient;
kibanaVersion: string;
}

export type SavedSearchQuery = object;

// This context provides dependencies which can be injected
// via angularjs only (like services, currentIndexPattern etc.).
// Because we cannot just import these dependencies, the default value
// for the context is just {} and of type `Partial<KibanaContextValue>`
// for the angularjs based dependencies. Therefore, the
// actual dependencies are set like we did previously with KibanaContext
// in the wrapping angularjs directive. In the custom hook we check if
// the dependencies are present with error reporting if they weren't
// added properly. That's why in tests, these custom hooks must not
// be mocked, instead <UiChrome.Provider value="mocked-value">` needs
// In tests, these custom hooks must not be mocked,
// instead <UiChrome.Provider value="mocked-value">` needs
// to be used. This guarantees that we have both properly set up
// TypeScript support and runtime checks for these dependencies.
// Multiple custom hooks can be created to access subsets of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import { MlContext } from './ml_context';
export const useCurrentIndexPattern = () => {
const context = useContext(MlContext);

if (context.currentIndexPattern === undefined) {
throw new Error('currentIndexPattern is undefined');
if (context.currentDataView === undefined) {
throw new Error('currentDataView is undefined');
}

return context.currentIndexPattern;
return context.currentDataView;
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ export const useMlContext = () => {

if (
context.combinedQuery === undefined ||
context.currentIndexPattern === undefined ||
context.currentDataView === undefined ||
context.currentSavedSearch === undefined ||
context.indexPatterns === undefined ||
context.dataViewsContract === undefined ||
context.kibanaConfig === undefined
) {
throw new Error('required attribute is undefined');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { DataView } from '../../../../../../../src/plugins/data_views/publi

import { extractErrorMessage } from '../../../../common/util/errors';

import { getIndexPatternIdFromName } from '../../util/index_utils';
import { getDataViewIdFromName } from '../../util/index_utils';
import { ml } from '../../services/ml_api_service';
import { newJobCapsServiceAnalytics } from '../../services/new_job_capabilities/new_job_capabilities_service_analytics';
import { useMlContext } from '../../contexts/ml';
Expand Down Expand Up @@ -98,36 +98,36 @@ export const useResultsViewConfig = (jobId: string) => {
const destIndex = Array.isArray(jobConfigUpdate.dest.index)
? jobConfigUpdate.dest.index[0]
: jobConfigUpdate.dest.index;
const destIndexPatternId = getIndexPatternIdFromName(destIndex) || destIndex;
let indexP: DataView | undefined;
const destDataViewId = (await getDataViewIdFromName(destIndex)) ?? destIndex;
let dataView: DataView | undefined;

try {
indexP = await mlContext.indexPatterns.get(destIndexPatternId);
dataView = await mlContext.dataViewsContract.get(destDataViewId);

// Force refreshing the fields list here because a user directly coming
// from the job creation wizard might land on the page without the
// data view being fully initialized because it was created
// before the analytics job populated the destination index.
await mlContext.indexPatterns.refreshFields(indexP);
await mlContext.dataViewsContract.refreshFields(dataView);
} catch (e) {
indexP = undefined;
dataView = undefined;
}

if (indexP === undefined) {
if (dataView === undefined) {
setNeedsDestIndexPattern(true);
const sourceIndex = jobConfigUpdate.source.index[0];
const sourceIndexPatternId = getIndexPatternIdFromName(sourceIndex) || sourceIndex;
const sourceDataViewId = (await getDataViewIdFromName(sourceIndex)) ?? sourceIndex;
try {
indexP = await mlContext.indexPatterns.get(sourceIndexPatternId);
dataView = await mlContext.dataViewsContract.get(sourceDataViewId);
} catch (e) {
indexP = undefined;
dataView = undefined;
}
}

if (indexP !== undefined) {
await newJobCapsServiceAnalytics.initializeFromIndexPattern(indexP);
if (dataView !== undefined) {
await newJobCapsServiceAnalytics.initializeFromDataVIew(dataView);
setJobConfig(analyticsConfigs.data_frame_analytics[0]);
setIndexPattern(indexP);
setIndexPattern(dataView);
setIsInitialized(true);
setIsLoadingJobConfig(false);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ interface Props {

export const ConfigurationStepDetails: FC<Props> = ({ setCurrentStep, state }) => {
const mlContext = useMlContext();
const { currentIndexPattern } = mlContext;
const { currentDataView } = mlContext;
const { form, isJobCreated } = state;
const { dependentVariable, includes, jobConfigQueryString, jobType, trainingPercent } = form;

Expand All @@ -43,7 +43,7 @@ export const ConfigurationStepDetails: FC<Props> = ({ setCurrentStep, state }) =
title: i18n.translate('xpack.ml.dataframe.analytics.create.configDetails.sourceIndex', {
defaultMessage: 'Source index',
}),
description: currentIndexPattern.title || UNSET_CONFIG_ITEM,
description: currentDataView.title || UNSET_CONFIG_ITEM,
},
{
title: i18n.translate('xpack.ml.dataframe.analytics.create.configDetails.Query', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const ConfigurationStepForm: FC<ConfigurationStepProps> = ({
setCurrentStep,
}) => {
const mlContext = useMlContext();
const { currentSavedSearch, currentIndexPattern } = mlContext;
const { currentSavedSearch, currentDataView } = mlContext;
const { savedSearchQuery, savedSearchQueryStr } = useSavedSearch();

const [fieldOptionsFetchFail, setFieldOptionsFetchFail] = useState<boolean>(false);
Expand Down Expand Up @@ -167,7 +167,7 @@ export const ConfigurationStepForm: FC<ConfigurationStepProps> = ({
};

const indexData = useIndexData(
currentIndexPattern,
currentDataView,
getIndexDataQuery(savedSearchQuery, jobConfigQuery),
toastNotifications,
runtimeMappings
Expand Down Expand Up @@ -196,7 +196,7 @@ export const ConfigurationStepForm: FC<ConfigurationStepProps> = ({
setMaxDistinctValuesError(undefined);

try {
if (currentIndexPattern !== undefined) {
if (currentDataView !== undefined) {
const depVarOptions = [];
let depVarUpdate = formState.dependentVariable;
// Get fields and filter for supported types for job type
Expand Down Expand Up @@ -334,7 +334,7 @@ export const ConfigurationStepForm: FC<ConfigurationStepProps> = ({
}, 300);

useEffect(() => {
setFormState({ sourceIndex: currentIndexPattern.title });
setFormState({ sourceIndex: currentDataView.title });
}, []);

const indexPatternFieldsTableItems = useMemo(() => {
Expand All @@ -356,7 +356,7 @@ export const ConfigurationStepForm: FC<ConfigurationStepProps> = ({

useEffect(() => {
if (isJobTypeWithDepVar) {
const indexPatternRuntimeFields = getCombinedRuntimeMappings(currentIndexPattern);
const indexPatternRuntimeFields = getCombinedRuntimeMappings(currentDataView);
let runtimeOptions;

if (indexPatternRuntimeFields) {
Expand Down Expand Up @@ -498,14 +498,14 @@ export const ConfigurationStepForm: FC<ConfigurationStepProps> = ({
fields: includesTableItems
.filter((d) => d.feature_type === 'numerical' && d.is_included)
.map((d) => d.name),
index: currentIndexPattern.title,
index: currentDataView.title,
legendType: getScatterplotMatrixLegendType(jobType),
searchQuery: jobConfigQuery,
runtimeMappings,
indexPattern: currentIndexPattern,
indexPattern: currentDataView,
}),
[
currentIndexPattern.title,
currentDataView.title,
dependentVariable,
includesTableItems,
isJobTypeWithDepVar,
Expand Down Expand Up @@ -548,7 +548,7 @@ export const ConfigurationStepForm: FC<ConfigurationStepProps> = ({
fullWidth
>
<ExplorationQueryBar
indexPattern={currentIndexPattern}
indexPattern={currentDataView}
setSearchQuery={setJobConfigQuery}
query={query}
/>
Expand All @@ -568,7 +568,7 @@ export const ConfigurationStepForm: FC<ConfigurationStepProps> = ({
<EuiBadge color="hollow">
{savedSearchQuery !== null
? currentSavedSearch?.attributes.title
: currentIndexPattern.title}
: currentDataView.title}
</EuiBadge>
</Fragment>
}
Expand All @@ -586,7 +586,7 @@ export const ConfigurationStepForm: FC<ConfigurationStepProps> = ({
helpText={
dependentVariableOptions.length === 0 &&
dependentVariableFetchFail === false &&
currentIndexPattern &&
currentDataView &&
i18n.translate(
'xpack.ml.dataframe.analytics.create.dependentVariableOptionsNoNumericalFields',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function useSavedSearch() {
const [savedSearchQueryStr, setSavedSearchQueryStr] = useState<SavedSearchQueryStr>(undefined);

const mlContext = useMlContext();
const { currentSavedSearch, currentIndexPattern, kibanaConfig } = mlContext;
const { currentSavedSearch, currentDataView, kibanaConfig } = mlContext;

const getQueryData = () => {
let qry: estypes.QueryDslQueryContainer = {};
Expand All @@ -46,7 +46,7 @@ export function useSavedSearch() {

if (queryLanguage === SEARCH_QUERY_LANGUAGE.KUERY) {
const ast = fromKueryExpression(qryString);
qry = toElasticsearchQuery(ast, currentIndexPattern);
qry = toElasticsearchQuery(ast, currentDataView);
} else {
qry = luceneStringToDsl(qryString);
decorateQuery(qry, kibanaConfig.get('query:queryString:options'));
Expand Down
Loading