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] Data Frame Analytics: Fixes link to results page from Management app jobs list #69550

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ export function getCloneAction(createAnalyticsForm: CreateAnalyticsFormProps) {
}

interface CloneActionProps {
item: DeepReadonly<DataFrameAnalyticsListRow>;
item: DataFrameAnalyticsListRow;
createAnalyticsForm: CreateAnalyticsFormProps;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import React, { FC } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButtonEmpty, EuiToolTip } from '@elastic/eui';
import { DeepReadonly } from '../../../../../../../common/types/common';

import {
checkPermission,
Expand All @@ -21,6 +20,7 @@ import {
isClassificationAnalysis,
} from '../../../../common/analytics';
import { CreateAnalyticsFormProps } from '../../hooks/use_create_analytics_form';
import { useMlKibana } from '../../../../../contexts/kibana';
import { CloneAction } from './action_clone';

import { getResultsUrl, isDataFrameAnalyticsRunning, DataFrameAnalyticsListRow } from './common';
Expand All @@ -29,87 +29,123 @@ import { stopAnalytics } from '../../services/analytics_service';
import { StartAction } from './action_start';
import { DeleteAction } from './action_delete';

export const AnalyticsViewAction = {
isPrimary: true,
render: (item: DataFrameAnalyticsListRow) => {
const analysisType = getAnalysisType(item.config.analysis);
const isDisabled =
!isRegressionAnalysis(item.config.analysis) &&
!isOutlierAnalysis(item.config.analysis) &&
!isClassificationAnalysis(item.config.analysis);

const url = getResultsUrl(item.id, analysisType);
return (
<EuiButtonEmpty
isDisabled={isDisabled}
onClick={() => (window.location.href = url)}
size="xs"
color="text"
iconType="visTable"
aria-label={i18n.translate('xpack.ml.dataframe.analyticsList.viewAriaLabel', {
defaultMessage: 'View',
})}
data-test-subj="mlAnalyticsJobViewButton"
>
{i18n.translate('xpack.ml.dataframe.analyticsList.viewActionName', {
defaultMessage: 'View',
})}
</EuiButtonEmpty>
);
},
interface Props {
item: DataFrameAnalyticsListRow;
isManagementTable: boolean;
}

const AnalyticsViewButton: FC<Props> = ({ item, isManagementTable }) => {
const {
services: {
application: { navigateToUrl, navigateToApp },
},
} = useMlKibana();

const analysisType = getAnalysisType(item.config.analysis);
const isDisabled =
!isRegressionAnalysis(item.config.analysis) &&
!isOutlierAnalysis(item.config.analysis) &&
!isClassificationAnalysis(item.config.analysis);

const url = getResultsUrl(item.id, analysisType);
const navigator = isManagementTable
? () => navigateToApp('ml', { path: url })
: () => navigateToUrl(url);

return (
<EuiButtonEmpty
isDisabled={isDisabled}
onClick={navigator}
size="xs"
color="text"
iconType="visTable"
aria-label={i18n.translate('xpack.ml.dataframe.analyticsList.viewAriaLabel', {
defaultMessage: 'View',
})}
data-test-subj="mlAnalyticsJobViewButton"
>
{i18n.translate('xpack.ml.dataframe.analyticsList.viewActionName', {
defaultMessage: 'View',
})}
</EuiButtonEmpty>
Comment on lines +56 to +70
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: could it be just a link?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case it needs to work from the management page and the list so it feels clearer to keep it as is so we can cover both cases with straight-forward logic.

);
};

export const getActions = (createAnalyticsForm: CreateAnalyticsFormProps) => {
interface Action {
isPrimary?: boolean;
render: (item: DataFrameAnalyticsListRow) => any;
}

export const getAnalyticsViewAction = (isManagementTable: boolean = false): Action => ({
isPrimary: true,
render: (item: DataFrameAnalyticsListRow) => (
<AnalyticsViewButton item={item} isManagementTable={isManagementTable} />
),
});

export const getActions = (
createAnalyticsForm: CreateAnalyticsFormProps,
isManagementTable: boolean
) => {
const canStartStopDataFrameAnalytics: boolean = checkPermission('canStartStopDataFrameAnalytics');
const actions: Action[] = [getAnalyticsViewAction(isManagementTable)];

return [
AnalyticsViewAction,
{
render: (item: DataFrameAnalyticsListRow) => {
if (!isDataFrameAnalyticsRunning(item.stats.state)) {
return <StartAction item={item} />;
}

const buttonStopText = i18n.translate('xpack.ml.dataframe.analyticsList.stopActionName', {
defaultMessage: 'Stop',
});

const stopButton = (
<EuiButtonEmpty
size="xs"
color="text"
disabled={!canStartStopDataFrameAnalytics}
iconType="stop"
onClick={() => stopAnalytics(item)}
aria-label={buttonStopText}
data-test-subj="mlAnalyticsJobStopButton"
>
{buttonStopText}
</EuiButtonEmpty>
);
if (!canStartStopDataFrameAnalytics) {
return (
<EuiToolTip
position="top"
content={createPermissionFailureMessage('canStartStopDataFrameAnalytics')}
>
{stopButton}
</EuiToolTip>
);
}

return stopButton;
},
},
{
render: (item: DataFrameAnalyticsListRow) => {
return <DeleteAction item={item} />;
},
},
{
render: (item: DeepReadonly<DataFrameAnalyticsListRow>) => {
return <CloneAction item={item} createAnalyticsForm={createAnalyticsForm} />;
},
},
];
if (isManagementTable === false) {
actions.push(
...[
{
render: (item: DataFrameAnalyticsListRow) => {
if (!isDataFrameAnalyticsRunning(item.stats.state)) {
return <StartAction item={item} />;
}

const buttonStopText = i18n.translate(
'xpack.ml.dataframe.analyticsList.stopActionName',
{
defaultMessage: 'Stop',
}
);

const stopButton = (
<EuiButtonEmpty
size="xs"
color="text"
disabled={!canStartStopDataFrameAnalytics}
iconType="stop"
onClick={() => stopAnalytics(item)}
aria-label={buttonStopText}
data-test-subj="mlAnalyticsJobStopButton"
>
{buttonStopText}
</EuiButtonEmpty>
);
if (!canStartStopDataFrameAnalytics) {
return (
<EuiToolTip
position="top"
content={createPermissionFailureMessage('canStartStopDataFrameAnalytics')}
>
{stopButton}
</EuiToolTip>
);
}

return stopButton;
},
},
{
render: (item: DataFrameAnalyticsListRow) => {
return <DeleteAction item={item} />;
},
},
{
render: (item: DataFrameAnalyticsListRow) => {
return <CloneAction item={item} createAnalyticsForm={createAnalyticsForm} />;
},
},
]
);
}

return actions;
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
DataFrameAnalyticsListRow,
DataFrameAnalyticsStats,
} from './common';
import { getActions, AnalyticsViewAction } from './actions';
import { getActions } from './actions';

enum TASK_STATE_COLOR {
analyzing = 'primary',
Expand Down Expand Up @@ -148,8 +148,7 @@ export const getColumns = (
isMlEnabledInSpace: boolean = true,
createAnalyticsForm?: CreateAnalyticsFormProps
) => {
const actions =
isManagementTable === true ? [AnalyticsViewAction] : getActions(createAnalyticsForm!);
const actions = getActions(createAnalyticsForm!, isManagementTable);

function toggleDetails(item: DataFrameAnalyticsListRow) {
const index = expandedRowItemIds.indexOf(item.config.id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,5 @@ export function isCompletedAnalyticsJob(stats: DataFrameAnalyticsStats) {
}

export function getResultsUrl(jobId: string, analysisType: string) {
return `ml#/data_frame_analytics/exploration?_g=(ml:(jobId:${jobId},analysisType:${analysisType}))`;
return `#/data_frame_analytics/exploration?_g=(ml:(jobId:${jobId},analysisType:${analysisType}))`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from '@elastic/eui';

import { checkGetManagementMlJobsResolver } from '../../../../capabilities/check_capabilities';
import { KibanaContextProvider } from '../../../../../../../../../src/plugins/kibana_react/public';

import { getDocLinks } from '../../../../util/dependency_cache';
// @ts-ignore undeclared module
Expand Down Expand Up @@ -65,13 +66,12 @@ function getTabs(isMlEnabledInSpace: boolean): Tab[] {
];
}

export const JobsListPage: FC<{ I18nContext: CoreStart['i18n']['Context'] }> = ({
I18nContext,
}) => {
export const JobsListPage: FC<{ coreStart: CoreStart }> = ({ coreStart }) => {
const [initialized, setInitialized] = useState(false);
const [isMlEnabledInSpace, setIsMlEnabledInSpace] = useState(false);
const tabs = getTabs(isMlEnabledInSpace);
const [currentTabId, setCurrentTabId] = useState(tabs[0].id);
const I18nContext = coreStart.i18n.Context;

const check = async () => {
try {
Expand Down Expand Up @@ -122,46 +122,48 @@ export const JobsListPage: FC<{ I18nContext: CoreStart['i18n']['Context'] }> = (

return (
<I18nContext>
<EuiPageContent id="kibanaManagementMLSection">
<EuiTitle size="l">
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<h1>
{i18n.translate('xpack.ml.management.jobsList.jobsListTitle', {
defaultMessage: 'Machine Learning Jobs',
})}
</h1>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
target="_blank"
iconType="help"
iconSide="left"
color="primary"
href={
currentTabId === 'anomaly_detection_jobs'
? anomalyDetectionJobsUrl
: anomalyJobsUrl
}
>
{currentTabId === 'anomaly_detection_jobs'
? anomalyDetectionDocsLabel
: analyticsDocsLabel}
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiTitle>
<EuiSpacer size="s" />
<EuiTitle size="s">
<EuiText color="subdued">
{i18n.translate('xpack.ml.management.jobsList.jobsListTagline', {
defaultMessage: 'View machine learning analytics and anomaly detection jobs.',
})}
</EuiText>
</EuiTitle>
<EuiSpacer size="l" />
<EuiPageContentBody>{renderTabs()}</EuiPageContentBody>
</EuiPageContent>
<KibanaContextProvider services={{ ...coreStart }}>
<EuiPageContent id="kibanaManagementMLSection">
<EuiTitle size="l">
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<h1>
{i18n.translate('xpack.ml.management.jobsList.jobsListTitle', {
defaultMessage: 'Machine Learning Jobs',
})}
</h1>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
target="_blank"
iconType="help"
iconSide="left"
color="primary"
href={
currentTabId === 'anomaly_detection_jobs'
? anomalyDetectionJobsUrl
: anomalyJobsUrl
}
>
{currentTabId === 'anomaly_detection_jobs'
? anomalyDetectionDocsLabel
: analyticsDocsLabel}
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiTitle>
<EuiSpacer size="s" />
<EuiTitle size="s">
<EuiText color="subdued">
{i18n.translate('xpack.ml.management.jobsList.jobsListTagline', {
defaultMessage: 'View machine learning analytics and anomaly detection jobs.',
})}
</EuiText>
</EuiTitle>
<EuiSpacer size="l" />
<EuiPageContentBody>{renderTabs()}</EuiPageContentBody>
</EuiPageContent>
</KibanaContextProvider>
</I18nContext>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import { getJobsListBreadcrumbs } from '../breadcrumbs';
import { setDependencyCache, clearCache } from '../../util/dependency_cache';

const renderApp = (element: HTMLElement, coreStart: CoreStart) => {
const I18nContext = coreStart.i18n.Context;
ReactDOM.render(React.createElement(JobsListPage, { I18nContext }), element);
ReactDOM.render(React.createElement(JobsListPage, { coreStart }), element);
return () => {
unmountComponentAtNode(element);
clearCache();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
getTaskStateBadge,
progressColumn,
} from '../../../data_frame_analytics/pages/analytics_management/components/analytics_list/columns';
import { AnalyticsViewAction } from '../../../data_frame_analytics/pages/analytics_management/components/analytics_list/actions';
import { getAnalyticsViewAction } from '../../../data_frame_analytics/pages/analytics_management/components/analytics_list/actions';
import { formatHumanReadableDateTimeSeconds } from '../../../util/date_utils';

const MlInMemoryTable = mlInMemoryTableFactory<DataFrameAnalyticsListRow>();
Expand Down Expand Up @@ -82,7 +82,7 @@ export const AnalyticsTable: FC<Props> = ({ items }) => {
name: i18n.translate('xpack.ml.overview.analyticsList.tableActionLabel', {
defaultMessage: 'Actions',
}),
actions: [AnalyticsViewAction],
actions: [getAnalyticsViewAction()],
width: '100px',
},
];
Expand Down