diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx index 01cce153ce494..68e728c019873 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, FC, useState } from 'react'; +import React, { Fragment, FC, useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; @@ -15,6 +15,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, + EuiSearchBar, } from '@elastic/eui'; import { @@ -51,6 +52,7 @@ import { RefreshAnalyticsListButton } from '../refresh_analytics_list_button'; import { CreateAnalyticsButton } from '../create_analytics_button'; import { CreateAnalyticsFormProps } from '../../hooks/use_create_analytics_form'; import { CreateAnalyticsFlyoutWrapper } from '../create_analytics_flyout_wrapper'; +import { getSelectedJobIdFromUrl } from '../../../../../jobs/jobs_list/components/utils'; function getItemIdToExpandedRowMap( itemIds: DataFrameAnalyticsId[], @@ -91,6 +93,8 @@ export const DataFrameAnalyticsList: FC = ({ const [isLoading, setIsLoading] = useState(false); const [filterActive, setFilterActive] = useState(false); + const [queryText, setQueryText] = useState(''); + const [analytics, setAnalytics] = useState([]); const [analyticsStats, setAnalyticsStats] = useState( undefined @@ -107,6 +111,7 @@ export const DataFrameAnalyticsList: FC = ({ const [sortField, setSortField] = useState(DataFrameAnalyticsListColumn.id); const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.ASC); + const [jobIdSelected, setJobIdSelected] = useState(false); const disabled = !checkPermission('canCreateDataFrameAnalytics') || !checkPermission('canStartStopDataFrameAnalytics'); @@ -119,6 +124,20 @@ export const DataFrameAnalyticsList: FC = ({ blockRefresh ); + // Query text/job_id based on url but only after getAnalytics is done first + // jobIdSelected makes sure the query is only run once since analytics is being refreshed constantly + const selectedId = getSelectedJobIdFromUrl(window.location.href); + useEffect(() => { + if (jobIdSelected === false && analytics.length > 0) { + if (selectedId !== undefined) { + setJobIdSelected(true); + setQueryText(selectedId); + const selectedIdQuery: Query = EuiSearchBar.Query.parse(selectedId); + onQueryChange({ query: selectedIdQuery, error: undefined }); + } + } + }, [jobIdSelected, analytics]); + // Subscribe to the refresh observable to trigger reloading the analytics list. useRefreshAnalyticsList({ isLoading: setIsLoading, @@ -134,6 +153,7 @@ export const DataFrameAnalyticsList: FC = ({ clauses = query.ast.clauses; } if (clauses.length > 0) { + setQueryText(query.text); setFilterActive(true); filterAnalytics(clauses as Array); } else { @@ -297,6 +317,7 @@ export const DataFrameAnalyticsList: FC = ({ }; const search = { + query: queryText, onChange: onQueryChange, box: { incremental: true, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/columns.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/columns.tsx index 19b51f7615345..236a8083a95e6 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/columns.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/columns.tsx @@ -16,8 +16,10 @@ import { EuiScreenReaderOnly, EuiText, EuiToolTip, + EuiLink, RIGHT_ALIGNMENT, } from '@elastic/eui'; +import { getJobIdUrl } from '../../../../../util/get_job_id_url'; import { getAnalysisType, DataFrameAnalyticsId } from '../../../../common'; import { CreateAnalyticsFormProps } from '../../hooks/use_create_analytics_form'; @@ -135,6 +137,10 @@ export const progressColumn = { 'data-test-subj': 'mlAnalyticsTableColumnProgress', }; +export const getDFAnalyticsJobIdLink = (item: DataFrameAnalyticsListRow) => ( + {item.id} +); + export const getColumns = ( expandedRowItemIds: DataFrameAnalyticsId[], setExpandedRowItemIds: React.Dispatch>, @@ -193,12 +199,13 @@ export const getColumns = ( 'data-test-subj': 'mlAnalyticsTableRowDetailsToggle', }, { - field: DataFrameAnalyticsListColumn.id, name: 'ID', - sortable: true, + sortable: (item: DataFrameAnalyticsListRow) => item.id, truncateText: true, 'data-test-subj': 'mlAnalyticsTableColumnId', scope: 'row', + render: (item: DataFrameAnalyticsListRow) => + isManagementTable ? getDFAnalyticsJobIdLink(item) : item.id, }, { field: DataFrameAnalyticsListColumn.description, diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js index 7036b4f64b3c5..9874ac56577d3 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js @@ -14,7 +14,7 @@ import { toLocaleString } from '../../../../util/string_utils'; import { ResultLinks, actionsMenuContent } from '../job_actions'; import { JobDescription } from './job_description'; import { JobIcon } from '../../../../components/job_message_icon'; -import { getJobIdUrl } from '../utils'; +import { getJobIdUrl } from '../../../../util/get_job_id_url'; import { EuiBadge, EuiBasicTable, EuiButtonIcon, EuiLink, EuiScreenReaderOnly } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -71,7 +71,7 @@ export class JobsList extends Component { return id; } - return {id}; + return {id}; } getPageOfJobs(index, size, sortField, sortDirection) { diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.d.ts b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.d.ts new file mode 100644 index 0000000000000..5f72d155cbd5a --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.d.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +export function getSelectedJobIdFromUrl(str: string): string; +export function clearSelectedJobIdFromUrl(str: string): void; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js index 1f2a57f999775..4f77004b91f99 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js @@ -10,7 +10,7 @@ import rison from 'rison-node'; import { mlJobService } from '../../../services/job_service'; import { ml } from '../../../services/ml_api_service'; -import { getToastNotifications, getBasePath } from '../../../util/dependency_cache'; +import { getToastNotifications } from '../../../util/dependency_cache'; import { JOB_STATE, DATAFEED_STATE } from '../../../../../common/constants/states'; import { parseInterval } from '../../../../../common/util/parse_interval'; import { i18n } from '@kbn/i18n'; @@ -367,18 +367,6 @@ function jobProperty(job, prop) { return job[propMap[prop]]; } -export function getJobIdUrl(jobId) { - // Create url for filtering by job id for kibana management table - const settings = { - jobId, - }; - const encoded = rison.encode(settings); - const url = `?mlManagement=${encoded}`; - const basePath = getBasePath(); - - return `${basePath.get()}/app/ml#/jobs${url}`; -} - function getUrlVars(url) { const vars = {}; url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(_, key, value) { diff --git a/x-pack/plugins/ml/public/application/util/get_job_id_url.ts b/x-pack/plugins/ml/public/application/util/get_job_id_url.ts new file mode 100644 index 0000000000000..a6ca575f21b50 --- /dev/null +++ b/x-pack/plugins/ml/public/application/util/get_job_id_url.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import rison from 'rison-node'; + +import { getBasePath } from './dependency_cache'; + +export function getJobIdUrl(tabId: string, jobId: string): string { + // Create url for filtering by job id for kibana management table + const settings = { + jobId, + }; + const encoded = rison.encode(settings); + const url = `?mlManagement=${encoded}`; + const basePath = getBasePath(); + + return `${basePath.get()}/app/ml#/${tabId}${url}`; +}