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

[7.x] [ML] Persisted URL state for the "Anomaly detection jobs" page (#83149) #83285

Merged
merged 1 commit into from
Nov 12, 2020
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 @@ -19,6 +19,6 @@ test('MLLink produces the correct URL', async () => {
);

expect(href).toMatchInlineSnapshot(
`"/app/ml/jobs?mlManagement=(groupIds:!(apm),jobId:!(something))&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-5h,to:now-2h))"`
`"/app/ml/jobs?_a=(queryText:'id:(something)%20groups:(apm)')&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-5h,to:now-2h))"`
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

import { EuiCard, EuiIcon, EuiButtonEmpty, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import React, { useEffect, useState } from 'react';
import { SetupStatus } from '../../../../../common/log_analysis';
import { CreateJobButton, RecreateJobButton } from '../../log_analysis_setup/create_job_button';
import { useLinkProps } from '../../../../hooks/use_link_props';
import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
import { mountReactNode } from '../../../../../../../../src/core/public/utils';

export const LogAnalysisModuleListCard: React.FC<{
jobId: string;
Expand All @@ -26,19 +27,46 @@ export const LogAnalysisModuleListCard: React.FC<{
moduleStatus,
onViewSetup,
}) => {
const {
services: {
ml,
application: { navigateToUrl },
notifications: { toasts },
},
} = useKibanaContextForPlugin();

const [viewInMlLink, setViewInMlLink] = useState<string>('');

const getMlUrl = async () => {
if (!ml.urlGenerator) {
toasts.addWarning({
title: mountReactNode(
<FormattedMessage
id="xpack.infra.logs.analysis.mlNotAvailable"
defaultMessage="ML plugin is not available"
/>
),
});
return;
}
setViewInMlLink(await ml.urlGenerator.createUrl({ page: 'jobs', pageState: { jobId } }));
};

useEffect(() => {
getMlUrl();
});

const navigateToMlApp = async () => {
await navigateToUrl(viewInMlLink);
};

const moduleIcon =
moduleStatus.type === 'required' ? (
<EuiIcon size="xxl" type="machineLearningApp" />
) : (
<EuiIcon color="secondary" size="xxl" type="check" />
);

const viewInMlLinkProps = useLinkProps({
app: 'ml',
pathname: '/jobs',
search: { mlManagement: `(jobId:${jobId})` },
});

const moduleSetupButton =
moduleStatus.type === 'required' ? (
<CreateJobButton hasSetupCapabilities={hasSetupCapabilities} onClick={onViewSetup}>
Expand All @@ -50,13 +78,17 @@ export const LogAnalysisModuleListCard: React.FC<{
) : (
<>
<RecreateJobButton hasSetupCapabilities={hasSetupCapabilities} onClick={onViewSetup} />
<EuiSpacer size="xs" />
<EuiButtonEmpty {...viewInMlLinkProps}>
<FormattedMessage
id="xpack.infra.logs.analysis.viewInMlButtonLabel"
defaultMessage="View in Machine Learning"
/>
</EuiButtonEmpty>
{viewInMlLink ? (
<>
<EuiSpacer size="xs" />
<EuiButtonEmpty onClick={navigateToMlApp}>
<FormattedMessage
id="xpack.infra.logs.analysis.viewInMlButtonLabel"
defaultMessage="View in Machine Learning"
/>
</EuiButtonEmpty>
</>
) : null}
</>
);

Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/infra/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
ObservabilityPluginStart,
} from '../../observability/public';
import type { SpacesPluginStart } from '../../spaces/public';
import { MlPluginStart } from '../../ml/public';

// Our own setup and start contract values
export type InfraClientSetupExports = void;
Expand All @@ -38,6 +39,7 @@ export interface InfraClientStartDeps {
spaces: SpacesPluginStart;
triggersActionsUi: TriggersAndActionsUIPublicPluginSetup;
usageCollection: UsageCollectionStart;
ml: MlPluginStart;
}

export type InfraClientCoreSetup = CoreSetup<InfraClientStartDeps, InfraClientStartExports>;
Expand Down
22 changes: 21 additions & 1 deletion x-pack/plugins/ml/common/util/string_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { renderTemplate, getMedianStringLength, stringHash } from './string_utils';
import {
renderTemplate,
getMedianStringLength,
stringHash,
getGroupQueryText,
} from './string_utils';

const strings: string[] = [
'foo',
Expand Down Expand Up @@ -54,4 +59,19 @@ describe('ML - string utils', () => {
expect(hash1).not.toBe(hash2);
});
});

describe('getGroupQueryText', () => {
const groupIdOne = 'test_group_id_1';
const groupIdTwo = 'test_group_id_2';

it('should get query string for selected group ids', () => {
const actual = getGroupQueryText([groupIdOne, groupIdTwo]);
expect(actual).toBe(`groups:(${groupIdOne} or ${groupIdTwo})`);
});

it('should get query string for selected group id', () => {
const actual = getGroupQueryText([groupIdOne]);
expect(actual).toBe(`groups:(${groupIdOne})`);
});
});
});
8 changes: 8 additions & 0 deletions x-pack/plugins/ml/common/util/string_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,11 @@ export function stringHash(str: string): number {
}
return hash < 0 ? hash * -2 : hash;
}

export function getGroupQueryText(groupIds: string[]): string {
return `groups:(${groupIds.join(' or ')})`;
}

export function getJobQueryText(jobIds: string | string[]): string {
return Array.isArray(jobIds) ? `id:(${jobIds.join(' OR ')})` : jobIds;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,13 @@ import { getTaskStateBadge, getJobTypeBadge, useColumns } from './use_columns';
import { ExpandedRow } from './expanded_row';
import { AnalyticStatsBarStats, StatsBar } from '../../../../../components/stats_bar';
import { CreateAnalyticsButton } from '../create_analytics_button';
import {
getSelectedIdFromUrl,
getGroupQueryText,
} from '../../../../../jobs/jobs_list/components/utils';
import { getSelectedIdFromUrl } from '../../../../../jobs/jobs_list/components/utils';
import { SourceSelection } from '../source_selection';
import { filterAnalytics } from '../../../../common/search_bar_filters';
import { AnalyticsEmptyPrompt } from './empty_prompt';
import { useTableSettings } from './use_table_settings';
import { RefreshAnalyticsListButton } from '../refresh_analytics_list_button';
import { getGroupQueryText } from '../../../../../../../common/util/string_utils';

const filters: EuiSearchBarProps['filters'] = [
{
Expand Down

This file was deleted.

Loading