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] Add linking to dataframe from job management tab #65778

Merged
merged 11 commits into from
May 15, 2020
Merged
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
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}`;
}