mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[8.x] [ML][Fleet] Adds link to anomaly detection configurations from Integration > Assets tab (#193105) (#193485)
# Backport This will backport the following commits from `main` to `8.x`: - [[ML][Fleet] Adds link to anomaly detection configurations from Integration > Assets tab (#193105)](https://github.com/elastic/kibana/pull/193105) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Melissa Alvarez","email":"melissa.alvarez@elastic.co"},"sourceCommit":{"committedDate":"2024-09-19T20:40:44Z","message":"[ML][Fleet] Adds link to anomaly detection configurations from Integration > Assets tab (#193105)\n\n## Summary\r\n\r\nRelated issue: https://github.com/elastic/kibana/issues/182199?reload=1\r\n\r\nThis PR adds a link to `ML > Anomaly Detection > Supplied\r\nConfigurations` from `Integration > Assets tab` for 'ML Modules' assets.\r\n\r\nThe naming of the asset is also updated in Fleet to be consistent with\r\nthe ML UI.\r\n\r\n<img width=\"429\" alt=\"Screenshot 2024-09-19 at 13 46 47\"\r\nsrc=\"https://github.com/user-attachments/assets/9fcc3606-cc08-483f-88b4-00c07de3fc57\">\r\n\r\n<img width=\"717\" alt=\"Screenshot 2024-09-19 at 13 47 52\"\r\nsrc=\"https://github.com/user-attachments/assets/847f3d6e-95a1-491c-aa3e-7d54da7df98a\">\r\n\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [ ] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [ ] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [ ] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n- [ ] If a plugin configuration key changed, check if it needs to be\r\nallowlisted in the cloud and added to the [docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n- [ ] This renders correctly on smaller devices using a responsive\r\nlayout. (You can test this [in your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n- [ ] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"052187ce180f0cbcb062486f36a562495f840bef","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:enhancement",":ml","Team:Fleet","v9.0.0","backport:prev-minor","v8.16.0"],"title":"[ML][Fleet] Adds link to anomaly detection configurations from Integration > Assets tab","number":193105,"url":"https://github.com/elastic/kibana/pull/193105","mergeCommit":{"message":"[ML][Fleet] Adds link to anomaly detection configurations from Integration > Assets tab (#193105)\n\n## Summary\r\n\r\nRelated issue: https://github.com/elastic/kibana/issues/182199?reload=1\r\n\r\nThis PR adds a link to `ML > Anomaly Detection > Supplied\r\nConfigurations` from `Integration > Assets tab` for 'ML Modules' assets.\r\n\r\nThe naming of the asset is also updated in Fleet to be consistent with\r\nthe ML UI.\r\n\r\n<img width=\"429\" alt=\"Screenshot 2024-09-19 at 13 46 47\"\r\nsrc=\"https://github.com/user-attachments/assets/9fcc3606-cc08-483f-88b4-00c07de3fc57\">\r\n\r\n<img width=\"717\" alt=\"Screenshot 2024-09-19 at 13 47 52\"\r\nsrc=\"https://github.com/user-attachments/assets/847f3d6e-95a1-491c-aa3e-7d54da7df98a\">\r\n\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [ ] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [ ] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [ ] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n- [ ] If a plugin configuration key changed, check if it needs to be\r\nallowlisted in the cloud and added to the [docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n- [ ] This renders correctly on smaller devices using a responsive\r\nlayout. (You can test this [in your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n- [ ] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"052187ce180f0cbcb062486f36a562495f840bef"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193105","number":193105,"mergeCommit":{"message":"[ML][Fleet] Adds link to anomaly detection configurations from Integration > Assets tab (#193105)\n\n## Summary\r\n\r\nRelated issue: https://github.com/elastic/kibana/issues/182199?reload=1\r\n\r\nThis PR adds a link to `ML > Anomaly Detection > Supplied\r\nConfigurations` from `Integration > Assets tab` for 'ML Modules' assets.\r\n\r\nThe naming of the asset is also updated in Fleet to be consistent with\r\nthe ML UI.\r\n\r\n<img width=\"429\" alt=\"Screenshot 2024-09-19 at 13 46 47\"\r\nsrc=\"https://github.com/user-attachments/assets/9fcc3606-cc08-483f-88b4-00c07de3fc57\">\r\n\r\n<img width=\"717\" alt=\"Screenshot 2024-09-19 at 13 47 52\"\r\nsrc=\"https://github.com/user-attachments/assets/847f3d6e-95a1-491c-aa3e-7d54da7df98a\">\r\n\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [ ] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [ ] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [ ] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n- [ ] If a plugin configuration key changed, check if it needs to be\r\nallowlisted in the cloud and added to the [docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n- [ ] This renders correctly on smaller devices using a responsive\r\nlayout. (You can test this [in your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n- [ ] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"052187ce180f0cbcb062486f36a562495f840bef"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Melissa Alvarez <melissa.alvarez@elastic.co>
This commit is contained in:
parent
c37ef77fb5
commit
d253c0eb67
8 changed files with 120 additions and 27 deletions
|
@ -66,10 +66,10 @@ export const AssetTitleMap: Record<
|
|||
}
|
||||
),
|
||||
'ml-module': i18n.translate('xpack.fleet.epm.assetTitles.mlModules', {
|
||||
defaultMessage: 'ML modules',
|
||||
defaultMessage: 'Anomaly detection configurations',
|
||||
}),
|
||||
ml_module: i18n.translate('xpack.fleet.epm.assetTitles.mlModules', {
|
||||
defaultMessage: 'ML modules',
|
||||
defaultMessage: 'Anomaly detection configurations',
|
||||
}),
|
||||
tag: i18n.translate('xpack.fleet.epm.assetTitles.tag', {
|
||||
defaultMessage: 'Tags',
|
||||
|
|
|
@ -71,7 +71,6 @@ export async function getBulkAssets(
|
|||
}
|
||||
|
||||
// TODO: Ask for Kibana SOs to have `getInAppUrl()` registered so that the above works safely:
|
||||
// ml-module
|
||||
// security-rule
|
||||
// csp-rule-template
|
||||
// osquery-pack-asset
|
||||
|
|
|
@ -6,22 +6,45 @@
|
|||
*/
|
||||
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import type { SearchFilterConfig, FieldValueOptionType } from '@elastic/eui';
|
||||
import { EuiCard, EuiIcon, EuiFlexGrid, EuiFlexItem, EuiSearchBar, EuiSpacer } from '@elastic/eui';
|
||||
import type { SearchFilterConfig, FieldValueOptionType, EuiSearchBarProps } from '@elastic/eui';
|
||||
import {
|
||||
EuiCard,
|
||||
EuiIcon,
|
||||
EuiFlexGrid,
|
||||
EuiFlexItem,
|
||||
EuiFormRow,
|
||||
EuiSearchBar,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { usePageUrlState, type PageUrlState } from '@kbn/ml-url-state';
|
||||
import useMountedState from 'react-use/lib/useMountedState';
|
||||
import useMount from 'react-use/lib/useMount';
|
||||
import { isPopulatedObject } from '@kbn/ml-is-populated-object';
|
||||
import { useMlKibana } from '../contexts/kibana';
|
||||
import type { Module } from '../../../common/types/modules';
|
||||
import { ML_PAGES } from '../../../common/constants/locator';
|
||||
import { LoadingIndicator } from '../components/loading_indicator';
|
||||
import { filterModules } from './utils';
|
||||
import { SuppliedConfigurationsFlyout } from './supplied_configurations_flyout';
|
||||
|
||||
interface SuppliedConfigurationsPageUrlState {
|
||||
queryText: string;
|
||||
}
|
||||
|
||||
export function isLogoObject(arg: unknown): arg is { icon: string } {
|
||||
return isPopulatedObject(arg) && Object.hasOwn(arg, 'icon');
|
||||
}
|
||||
|
||||
const SCHEMA = {
|
||||
strict: true,
|
||||
fields: {
|
||||
tags: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const SuppliedConfigurations = () => {
|
||||
const {
|
||||
services: {
|
||||
|
@ -31,9 +54,14 @@ export const SuppliedConfigurations = () => {
|
|||
},
|
||||
} = useMlKibana();
|
||||
|
||||
const [suppliedConfigurationsPageState, setSuppliedConfigurationsPageState] =
|
||||
usePageUrlState<PageUrlState>(ML_PAGES.SUPPLIED_CONFIGURATIONS, {
|
||||
queryText: '',
|
||||
});
|
||||
|
||||
const [modules, setModules] = useState<Module[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [query, setQuery] = useState(EuiSearchBar.Query.MATCH_ALL);
|
||||
const [searchError, setSearchError] = useState<string | undefined>();
|
||||
const [isFlyoutVisible, setIsFlyoutVisible] = useState<boolean>(false);
|
||||
const [selectedModuleId, setSelectedModuleId] = useState<string | undefined>();
|
||||
|
||||
|
@ -82,13 +110,27 @@ export const SuppliedConfigurations = () => {
|
|||
];
|
||||
}, [modules]);
|
||||
|
||||
const schema = {
|
||||
strict: true,
|
||||
fields: {
|
||||
tags: {
|
||||
type: 'string',
|
||||
},
|
||||
const setSearchQueryText = useCallback(
|
||||
(value: string) => {
|
||||
setSuppliedConfigurationsPageState({ queryText: value });
|
||||
},
|
||||
[setSuppliedConfigurationsPageState]
|
||||
);
|
||||
|
||||
const query = useMemo(() => {
|
||||
const searchQueryText = (suppliedConfigurationsPageState as SuppliedConfigurationsPageUrlState)
|
||||
.queryText;
|
||||
return searchQueryText !== '' ? EuiSearchBar.Query.parse(searchQueryText) : undefined;
|
||||
}, [suppliedConfigurationsPageState]);
|
||||
|
||||
const onChange: EuiSearchBarProps['onChange'] = (search) => {
|
||||
if (search.error !== null) {
|
||||
setSearchError(search.error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
setSearchError(undefined);
|
||||
setSearchQueryText(search.queryText);
|
||||
};
|
||||
|
||||
const filteredModules = useMemo(() => {
|
||||
|
@ -96,8 +138,6 @@ export const SuppliedConfigurations = () => {
|
|||
return clauses.length > 0 ? filterModules(modules, clauses) : modules;
|
||||
}, [query, modules]);
|
||||
|
||||
const onChange = useCallback(({ query: onChangeQuery }) => setQuery(onChangeQuery), [setQuery]);
|
||||
|
||||
if (isLoading === true) return <LoadingIndicator />;
|
||||
|
||||
return (
|
||||
|
@ -112,11 +152,18 @@ export const SuppliedConfigurations = () => {
|
|||
}
|
||||
),
|
||||
incremental: true,
|
||||
schema,
|
||||
schema: SCHEMA,
|
||||
}}
|
||||
filters={filters}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<EuiFormRow
|
||||
data-test-subj="mlAnomalyJobSelectionControls"
|
||||
isInvalid={searchError !== undefined}
|
||||
error={searchError}
|
||||
>
|
||||
<></>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="l" />
|
||||
<EuiFlexGrid gutterSize="l" columns={4}>
|
||||
{filteredModules.map(({ description, id, logo, title }) => {
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
mlEscape,
|
||||
escapeForElasticsearchQuery,
|
||||
escapeKueryForEmbeddableFieldValuePair,
|
||||
stringMatch,
|
||||
} from './string_utils';
|
||||
|
||||
describe('ML - string utils', () => {
|
||||
|
@ -170,4 +171,19 @@ describe('ML - string utils', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stringMatch', () => {
|
||||
test('should return true for partial match', () => {
|
||||
expect(stringMatch('foobar', 'Foo')).toBe(true);
|
||||
});
|
||||
test('should return true for exact match', () => {
|
||||
expect(stringMatch('foobar', 'foobar')).toBe(true);
|
||||
});
|
||||
test('should return false for no match', () => {
|
||||
expect(stringMatch('foobar', 'nomatch')).toBe(false);
|
||||
});
|
||||
test('should catch error for invalid regex substring and return false', () => {
|
||||
expect(stringMatch('foobar', '?')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -187,9 +187,13 @@ export function calculateTextWidth(txt: string | number, isNumber: boolean) {
|
|||
}
|
||||
|
||||
export function stringMatch(str: string | undefined, substr: any) {
|
||||
return (
|
||||
typeof str === 'string' &&
|
||||
typeof substr === 'string' &&
|
||||
(str.toLowerCase().match(substr.toLowerCase()) === null) === false
|
||||
);
|
||||
try {
|
||||
return (
|
||||
typeof str === 'string' &&
|
||||
typeof substr === 'string' &&
|
||||
(str.toLowerCase().match(substr.toLowerCase()) === null) === false
|
||||
);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { SavedObjectsServiceSetup } from '@kbn/core/server';
|
||||
import rison from '@kbn/rison';
|
||||
import { mlJob, mlTrainedModel, mlModule } from './mappings';
|
||||
|
||||
import { migrations } from './migrations';
|
||||
|
@ -15,6 +16,17 @@ import {
|
|||
ML_TRAINED_MODEL_SAVED_OBJECT_TYPE,
|
||||
} from '../../common/types/saved_objects';
|
||||
|
||||
interface MlModuleAttributes {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
type: string;
|
||||
logo?: object;
|
||||
query?: string;
|
||||
jobs: object[];
|
||||
datafeeds: object[];
|
||||
}
|
||||
|
||||
export function setupSavedObjects(savedObjects: SavedObjectsServiceSetup) {
|
||||
savedObjects.registerType({
|
||||
name: ML_JOB_SAVED_OBJECT_TYPE,
|
||||
|
@ -30,12 +42,23 @@ export function setupSavedObjects(savedObjects: SavedObjectsServiceSetup) {
|
|||
migrations,
|
||||
mappings: mlTrainedModel,
|
||||
});
|
||||
savedObjects.registerType({
|
||||
savedObjects.registerType<MlModuleAttributes>({
|
||||
name: ML_MODULE_SAVED_OBJECT_TYPE,
|
||||
hidden: false,
|
||||
management: {
|
||||
importableAndExportable: true,
|
||||
visibleInManagement: false,
|
||||
getTitle(obj) {
|
||||
return obj.attributes.title;
|
||||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/ml/supplied_configurations/?_a=${encodeURIComponent(
|
||||
rison.encode({ supplied_configurations: { queryText: obj.attributes.title } })
|
||||
)}`,
|
||||
uiCapabilitiesPath: 'ml.canGetJobs',
|
||||
};
|
||||
},
|
||||
},
|
||||
namespaceType: 'agnostic',
|
||||
migrations,
|
||||
|
|
|
@ -62,11 +62,15 @@ export const transformFilters: SearchFilterConfig[] = [
|
|||
];
|
||||
|
||||
function stringMatch(str: string | undefined, substr: any) {
|
||||
return (
|
||||
typeof str === 'string' &&
|
||||
typeof substr === 'string' &&
|
||||
(str.toLowerCase().match(substr.toLowerCase()) === null) === false
|
||||
);
|
||||
try {
|
||||
return (
|
||||
typeof str === 'string' &&
|
||||
typeof substr === 'string' &&
|
||||
(str.toLowerCase().match(substr.toLowerCase()) === null) === false
|
||||
);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const filterTransforms = (transforms: TransformListRow[], clauses: Clause[]) => {
|
||||
|
|
|
@ -140,7 +140,7 @@ Array [
|
|||
"type": "index-pattern",
|
||||
},
|
||||
Object {
|
||||
"appLink": "",
|
||||
"appLink": "/app/ml/supplied_configurations/?_a=(supplied_configurations%3A(queryText%3A'Nginx%20access%20logs'))",
|
||||
"attributes": Object {
|
||||
"description": "Find unusual activity in HTTP access logs from filebeat (ECS).",
|
||||
"title": "Nginx access logs",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue