Skip to content

Commit

Permalink
[ML] Data view loading refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
jgowdyelastic committed Oct 27, 2021
1 parent 6fbda83 commit ed496ad
Show file tree
Hide file tree
Showing 46 changed files with 275 additions and 188 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 @@ -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 indexPatternId = (await getIndexPatternIdFromName(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
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface MlContextValue {
combinedQuery: any;
currentIndexPattern: DataView; // TODO this should be IndexPattern or null
currentSavedSearch: SavedSearchSavedObject | null;
indexPatterns: DataViewsContract;
dataViewsContract: DataViewsContract;
kibanaConfig: any; // IUiSettingsClient;
kibanaVersion: string;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const useMlContext = () => {
context.combinedQuery === undefined ||
context.currentIndexPattern === 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 @@ -98,27 +98,28 @@ export const useResultsViewConfig = (jobId: string) => {
const destIndex = Array.isArray(jobConfigUpdate.dest.index)
? jobConfigUpdate.dest.index[0]
: jobConfigUpdate.dest.index;
const destIndexPatternId = getIndexPatternIdFromName(destIndex) || destIndex;
const destIndexPatternId = (await getIndexPatternIdFromName(destIndex)) ?? destIndex;
let indexP: DataView | undefined;

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

// 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(indexP);
} catch (e) {
indexP = undefined;
}

if (indexP === undefined) {
setNeedsDestIndexPattern(true);
const sourceIndex = jobConfigUpdate.source.index[0];
const sourceIndexPatternId = getIndexPatternIdFromName(sourceIndex) || sourceIndex;
const sourceIndexPatternId =
(await getIndexPatternIdFromName(sourceIndex)) ?? sourceIndex;
try {
indexP = await mlContext.indexPatterns.get(sourceIndexPatternId);
indexP = await mlContext.dataViewsContract.get(sourceIndexPatternId);
} catch (e) {
indexP = undefined;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => {
const dataViewName = destinationIndex;

try {
await mlContext.indexPatterns.createAndSave(
await mlContext.dataViewsContract.createAndSave(
{
title: dataViewName,
},
Expand Down Expand Up @@ -179,7 +179,7 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => {
try {
// Set the existing data view names.
const indexPatternsMap: SourceIndexMap = {};
const savedObjects = (await mlContext.indexPatterns.getCache()) || [];
const savedObjects = (await mlContext.dataViewsContract.getCache()) || [];
savedObjects.forEach((obj) => {
const title = obj?.attributes?.title;
if (title !== undefined) {
Expand All @@ -201,7 +201,7 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => {
};

const initiateWizard = async () => {
await mlContext.indexPatterns.clearCache();
await mlContext.dataViewsContract.clearCache();
await prepareFormValidation();
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ export const Controls: FC<Props> = React.memo(
const nodeType = selectedNode?.data('type');

const onCreateJobClick = useCallback(async () => {
const indexId = getIndexPatternIdFromName(nodeLabel);
const indexId = await getIndexPatternIdFromName(nodeLabel);

if (indexId) {
if (indexId !== null) {
const path = await mlLocator.getUrl({
page: ML_PAGES.DATA_FRAME_ANALYTICS_CREATE_JOB,
pageState: { index: indexId },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import { createJobs } from '../explorer_utils';
export function jobSelectionActionCreator(selectedJobIds: string[]) {
return from(mlFieldFormatService.populateFormats(selectedJobIds)).pipe(
map((resp) => {
if (resp.err) {
console.log('Error populating field formats:', resp.err); // eslint-disable-line no-console
if (resp.error) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { isValidLabel } from '../../../util/custom_url_utils';

import { TIME_RANGE_TYPE, URL_TYPE } from './constants';
import { UrlConfig } from '../../../../../common/types/custom_urls';
import { DataView } from '../../../../../../../../src/plugins/data_views/common';
import { DataViewListItem } from '../../../../../../../../src/plugins/data_views/common';

function getLinkToOptions() {
return [
Expand Down Expand Up @@ -59,7 +59,7 @@ interface CustomUrlEditorProps {
setEditCustomUrl: (url: any) => void;
savedCustomUrls: UrlConfig[];
dashboards: any[];
indexPatterns: DataView[];
dataViewListItems: DataViewListItem[];
queryEntityFieldNames: string[];
}

Expand All @@ -71,7 +71,7 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
setEditCustomUrl,
savedCustomUrls,
dashboards,
indexPatterns,
dataViewListItems,
queryEntityFieldNames,
}) => {
if (customUrl === undefined) {
Expand Down Expand Up @@ -164,8 +164,8 @@ export const CustomUrlEditor: FC<CustomUrlEditorProps> = ({
return { value: dashboard.id, text: dashboard.title };
});

const indexPatternOptions = indexPatterns.map((indexPattern) => {
return { value: indexPattern.id, text: indexPattern.title };
const indexPatternOptions = dataViewListItems.map(({ id, title }) => {
return { value: id, text: title };
});

const entityOptions = queryEntityFieldNames.map((fieldName) => ({ label: fieldName }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { DataView } from '../../../../../../../../src/plugins/data_views/common';
import { DataViewListItem } from '../../../../../../../../src/plugins/data_views/common';
import { UrlConfig } from '../../../../../common/types/custom_urls';
import { Job } from '../../../../../common/types/anomaly_detection_jobs';
import { TimeRangeType } from './constants';
Expand Down Expand Up @@ -34,7 +34,7 @@ export function isValidCustomUrlSettingsTimeRange(timeRangeSettings: any): boole
export function getNewCustomUrlDefaults(
job: Job,
dashboards: any[],
indexPatterns: DataView[]
dataViews: DataViewListItem[]
): CustomUrlSettings;
export function getQueryEntityFieldNames(job: Job): string[];
export function isValidCustomUrlSettings(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../../src/plugins
import { getPartitioningFieldNames } from '../../../../../common/util/job_utils';
import { parseInterval } from '../../../../../common/util/parse_interval';
import { replaceTokensInUrlValue, isValidLabel } from '../../../util/custom_url_utils';
import { getIndexPatternIdFromName } from '../../../util/index_utils';
// import { getIndexPatternIdFromName } from '../../../util/index_utils';
import { ml } from '../../../services/ml_api_service';
import { escapeForElasticsearchQuery } from '../../../util/string_utils';
import { getSavedObjectsClient, getGetUrlGenerator } from '../../../util/dependency_cache';

export function getNewCustomUrlDefaults(job, dashboards, indexPatterns) {
export function getNewCustomUrlDefaults(job, dashboards, dataViews) {
// Returns the settings object in the format used by the custom URL editor
// for a new custom URL.
const kibanaSettings = {
Expand All @@ -32,22 +32,24 @@ export function getNewCustomUrlDefaults(job, dashboards, indexPatterns) {
if (dashboards !== undefined && dashboards.length > 0) {
urlType = URL_TYPE.KIBANA_DASHBOARD;
kibanaSettings.dashboardId = dashboards[0].id;
} else if (indexPatterns !== undefined && indexPatterns.length > 0) {
} else if (dataViews !== undefined && dataViews.length > 0) {
urlType = URL_TYPE.KIBANA_DISCOVER;
}

// For the Discover option, set the default data view to that
// which matches the indices configured in the job datafeed.
const datafeedConfig = job.datafeed_config;
if (
indexPatterns !== undefined &&
indexPatterns.length > 0 &&
dataViews !== undefined &&
dataViews.length > 0 &&
datafeedConfig !== undefined &&
datafeedConfig.indices !== undefined &&
datafeedConfig.indices.length > 0
) {
const defaultIndexPatternId =
getIndexPatternIdFromName(datafeedConfig.indices.join()) ?? indexPatterns[0].id;
// const defaultIndexPatternId =
// (await getIndexPatternIdFromName(datafeedConfig.indices.join())) ?? dataViews[0].id;
const indicesName = datafeedConfig.indices.join();
const defaultIndexPatternId = dataViews.find((dv) => dv.title === indicesName)?.id;
kibanaSettings.discoverIndexPatternId = defaultIndexPatternId;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/

import type { DataView } from 'src/plugins/data_views/common';
import type { DataView, DataViewListItem } from 'src/plugins/data_views/common';

export function loadSavedDashboards(maxNumber: number): Promise<any[]>;
export function loadIndexPatterns(maxNumber: number): Promise<DataView[]>;
export function loadDataViewListItems(): Promise<DataViewListItem[]>;
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,12 @@ export function loadSavedDashboards(maxNumber) {
});
}

export function loadIndexPatterns(maxNumber) {
export async function loadDataViewListItems() {
const dataViewsContract = getDataViews();
return (await dataViewsContract.getIdsWithTitle()).sort((a, b) => a.title.localeCompare(b.title));
}

export function loadIndexPatterns2(maxNumber) {
// Loads the list of Kibana data views, as used in editing custom URLs.
return new Promise((resolve, reject) => {
const dataViewsContract = getDataViews();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,14 @@ import {
CustomUrlSettings,
} from '../../../../components/custom_url_editor/utils';
import { withKibana } from '../../../../../../../../../../src/plugins/kibana_react/public';
import { loadSavedDashboards, loadIndexPatterns } from '../edit_utils';
import { loadSavedDashboards, loadDataViewListItems } from '../edit_utils';
import { openCustomUrlWindow } from '../../../../../util/custom_url_utils';
import { Job } from '../../../../../../../common/types/anomaly_detection_jobs';
import { UrlConfig } from '../../../../../../../common/types/custom_urls';
import { DataView } from '../../../../../../../../../../src/plugins/data_views/common';
import { DataViewListItem } from '../../../../../../../../../../src/plugins/data_views/common';
import { MlKibanaReactContextValue } from '../../../../../contexts/kibana';

const MAX_NUMBER_DASHBOARDS = 1000;
const MAX_NUMBER_INDEX_PATTERNS = 1000;

interface CustomUrlsProps {
job: Job;
Expand All @@ -54,7 +53,7 @@ interface CustomUrlsProps {
interface CustomUrlsState {
customUrls: UrlConfig[];
dashboards: any[];
indexPatterns: DataView[];
dataViewListItems: DataViewListItem[];
queryEntityFieldNames: string[];
editorOpen: boolean;
editorSettings?: CustomUrlSettings;
Expand All @@ -67,7 +66,7 @@ class CustomUrlsUI extends Component<CustomUrlsProps, CustomUrlsState> {
this.state = {
customUrls: [],
dashboards: [],
indexPatterns: [],
dataViewListItems: [],
queryEntityFieldNames: [],
editorOpen: false,
};
Expand Down Expand Up @@ -100,9 +99,9 @@ class CustomUrlsUI extends Component<CustomUrlsProps, CustomUrlsState> {
);
});

loadIndexPatterns(MAX_NUMBER_INDEX_PATTERNS)
.then((indexPatterns) => {
this.setState({ indexPatterns });
loadDataViewListItems()
.then((dataViewListItems) => {
this.setState({ dataViewListItems });
})
.catch((resp) => {
// eslint-disable-next-line no-console
Expand All @@ -121,11 +120,11 @@ class CustomUrlsUI extends Component<CustomUrlsProps, CustomUrlsState> {
editNewCustomUrl = () => {
// Opens the editor for configuring a new custom URL.
this.setState((prevState) => {
const { dashboards, indexPatterns } = prevState;
const { dashboards, dataViewListItems } = prevState;

return {
editorOpen: true,
editorSettings: getNewCustomUrlDefaults(this.props.job, dashboards, indexPatterns),
editorSettings: getNewCustomUrlDefaults(this.props.job, dashboards, dataViewListItems),
};
});
};
Expand Down Expand Up @@ -209,7 +208,7 @@ class CustomUrlsUI extends Component<CustomUrlsProps, CustomUrlsState> {
editorOpen,
editorSettings,
dashboards,
indexPatterns,
dataViewListItems,
queryEntityFieldNames,
} = this.state;

Expand All @@ -220,7 +219,7 @@ class CustomUrlsUI extends Component<CustomUrlsProps, CustomUrlsState> {
setEditCustomUrl={this.setEditCustomUrl}
savedCustomUrls={customUrls}
dashboards={dashboards}
indexPatterns={indexPatterns}
dataViewListItems={dataViewListItems}
queryEntityFieldNames={queryEntityFieldNames}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import { checkPermission } from '../../../../capabilities/check_capabilities';
import { mlNodesAvailable } from '../../../../ml_nodes_check/check_ml_nodes';
import { getIndexPatternNames } from '../../../../util/index_utils';
import { JOB_ACTION } from '../../../../../../common/constants/job_actions';

import {
Expand All @@ -19,7 +18,6 @@ import {
isClosable,
isResettable,
} from '../utils';
import { getToastNotifications } from '../../../../util/dependency_cache';
import { i18n } from '@kbn/i18n';

export function actionsMenuContent(
Expand Down Expand Up @@ -136,21 +134,7 @@ export function actionsMenuContent(
return isJobBlocked(item) === false && canCreateJob;
},
onClick: (item) => {
const indexPatternNames = getIndexPatternNames();
const indexPatternTitle = item.datafeedIndices.join(',');
const jobIndicesAvailable = indexPatternNames.includes(indexPatternTitle);

if (!jobIndicesAvailable) {
getToastNotifications().addDanger(
i18n.translate('xpack.ml.jobsList.managementActions.noSourceDataViewForClone', {
defaultMessage:
'Unable to clone the anomaly detection job {jobId}. No data view exists for index {indexPatternTitle}.',
values: { jobId: item.id, indexPatternTitle },
})
);
} else {
cloneJob(item.id);
}
cloneJob(item.id);
closeMenu(true);
},
'data-test-subj': 'mlActionButtonCloneJob',
Expand Down
Loading

0 comments on commit ed496ad

Please sign in to comment.