Skip to content

Commit

Permalink
[ML] Data view loading refactor (#116455)
Browse files Browse the repository at this point in the history
* [ML] Data view loading refactor

* more renaming

* more renaming

* fixing tests

* fixing jest test

* small changes based on review

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
jgowdyelastic and kibanamachine authored Nov 3, 2021
1 parent 6328a9f commit ee63830
Show file tree
Hide file tree
Showing 78 changed files with 454 additions and 402 deletions.
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

0 comments on commit ee63830

Please sign in to comment.