Skip to content

Commit

Permalink
[ML] Add linking to dataframe from job management tab (#65778)
Browse files Browse the repository at this point in the history
* [ML] Add linking to dataframe from job management tab

* [ML] Add linking to df analytics job list from management tab

* [ML] Add ability to query text/job id from url for DFA page

* [ML] Add linking to dataframe from job management tab

* [ML] Add linking to df analytics job list from management tab

* [ML] Add ability to query text/job id from url for DFA page

* [ML] Refactor get_job_id_url util function & clean up

* [ML] Add declaration file for job_list's utils

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
qn895 and elasticmachine authored May 15, 2020
1 parent b2df052 commit ae663eb
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -15,6 +15,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiSearchBar,
} from '@elastic/eui';

import {
Expand Down Expand Up @@ -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[],
Expand Down Expand Up @@ -91,6 +93,8 @@ export const DataFrameAnalyticsList: FC<Props> = ({
const [isLoading, setIsLoading] = useState(false);
const [filterActive, setFilterActive] = useState(false);

const [queryText, setQueryText] = useState('');

const [analytics, setAnalytics] = useState<DataFrameAnalyticsListRow[]>([]);
const [analyticsStats, setAnalyticsStats] = useState<AnalyticStatsBarStats | undefined>(
undefined
Expand All @@ -107,6 +111,7 @@ export const DataFrameAnalyticsList: FC<Props> = ({
const [sortField, setSortField] = useState<string>(DataFrameAnalyticsListColumn.id);
const [sortDirection, setSortDirection] = useState<SortDirection>(SORT_DIRECTION.ASC);

const [jobIdSelected, setJobIdSelected] = useState<boolean>(false);
const disabled =
!checkPermission('canCreateDataFrameAnalytics') ||
!checkPermission('canStartStopDataFrameAnalytics');
Expand All @@ -119,6 +124,20 @@ export const DataFrameAnalyticsList: FC<Props> = ({
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,
Expand All @@ -134,6 +153,7 @@ export const DataFrameAnalyticsList: FC<Props> = ({
clauses = query.ast.clauses;
}
if (clauses.length > 0) {
setQueryText(query.text);
setFilterActive(true);
filterAnalytics(clauses as Array<TermClause | FieldClause>);
} else {
Expand Down Expand Up @@ -297,6 +317,7 @@ export const DataFrameAnalyticsList: FC<Props> = ({
};

const search = {
query: queryText,
onChange: onQueryChange,
box: {
incremental: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -135,6 +137,10 @@ export const progressColumn = {
'data-test-subj': 'mlAnalyticsTableColumnProgress',
};

export const getDFAnalyticsJobIdLink = (item: DataFrameAnalyticsListRow) => (
<EuiLink href={getJobIdUrl('data_frame_analytics', item.id)}>{item.id}</EuiLink>
);

export const getColumns = (
expandedRowItemIds: DataFrameAnalyticsId[],
setExpandedRowItemIds: React.Dispatch<React.SetStateAction<DataFrameAnalyticsId[]>>,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -71,7 +71,7 @@ export class JobsList extends Component {
return id;
}

return <EuiLink href={getJobIdUrl(id)}>{id}</EuiLink>;
return <EuiLink href={getJobIdUrl('jobs', id)}>{id}</EuiLink>;
}

getPageOfJobs(index, size, sortField, sortDirection) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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) {
Expand Down
20 changes: 20 additions & 0 deletions x-pack/plugins/ml/public/application/util/get_job_id_url.ts
Original file line number Diff line number Diff line change
@@ -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}`;
}

0 comments on commit ae663eb

Please sign in to comment.