diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index 551bd678..5aa5d906 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -8,7 +8,7 @@ "optionalPlugins": [ "dataSource", "dataSourceManagement", - "dataExplorer" + "assistantDashboards" ], "requiredPlugins": [ "opensearchDashboardsUtils", diff --git a/public/components/DiscoverAction/SuggestAnomalyDetector.test.tsx b/public/components/DiscoverAction/SuggestAnomalyDetector.test.tsx index cca54108..4a320382 100644 --- a/public/components/DiscoverAction/SuggestAnomalyDetector.test.tsx +++ b/public/components/DiscoverAction/SuggestAnomalyDetector.test.tsx @@ -16,50 +16,13 @@ import { import { Provider } from 'react-redux'; import configureStore from '../../redux/configureStore'; -import GenerateAnomalyDetector from './SuggestAnomalyDetector'; -import { DiscoverActionContext } from '../../../../../src/plugins/data_explorer/public'; +import SuggestAnomalyDetector from './SuggestAnomalyDetector'; import { fieldFormatsMock } from '../../../../../src/plugins/data/common/field_formats/mocks'; import { IndexPattern } from '../../../../../src/plugins/data/common'; import userEvent from '@testing-library/user-event'; import { HttpFetchOptionsWithPath } from '../../../../../src/core/public'; import { BASE_NODE_API_PATH } from '../../../utils/constants'; - -const notifications = { - toasts: { - addDanger: jest.fn().mockName('addDanger'), - addSuccess: jest.fn().mockName('addSuccess'), - } -}; - -const getNotifications = () => { - return notifications; -} - -jest.mock('../../services', () => ({ - ...jest.requireActual('../../services'), - getNotifications: getNotifications, -})); - -const renderWithRouter = (context: DiscoverActionContext) => ({ - ...render( - - - - ( - - - - )} - /> - - - - ), -}); +import { getQueryService } from '../../services'; export function shouldReadFieldFromDocValues(aggregatable: boolean, opensearchType: string) { return ( @@ -69,7 +32,6 @@ export function shouldReadFieldFromDocValues(aggregatable: boolean, opensearchTy ); } - function stubbedSampleFields() { return [ ['bytes', 'long', true, true, { count: 10 }], @@ -141,89 +103,92 @@ function createIndexPattern(id: string): IndexPattern { }; } -const expectedAnomalyDetector = { - name: "test-pattern_anomaly_detector", - description: "Created based on the OpenSearch Assistant", - indices: ["test-pattern"], - filterQuery: { - match_all: {} - }, - uiMetadata: { - features: { - feature_responseLatency: { - featureType: "simple_aggs", - aggregationBy: "avg", - aggregationOf: "responseLatency" - }, - feature_response: { - featureType: "simple_aggs", - aggregationBy: "sum", - aggregationOf: "response" - } - }, - filters: [] - }, - featureAttributes: [ - { - featureName: "feature_responseLatency", - featureEnabled: true, - importance: 1, - aggregationQuery: { - feature_response_latency: { - avg: { - field: "responseLatency" - } - } - } - }, - { - featureName: "feature_response", - featureEnabled: true, - importance: 1, - aggregationQuery: { - feature_response: { - sum: { - field: "response" - } - } - } - } - ], - timeField: "timestamp", - detectionInterval: { - period: { - interval: 10, - unit: "Minutes" - } - }, - windowDelay: { - period: { - interval: 1, - unit: "Minutes" - } - }, - shingleSize: 8, - categoryField: ["ip"] +const mockedIndexPattern = createIndexPattern('test-pattern'); + +const notifications = { + toasts: { + addDanger: jest.fn().mockName('addDanger'), + addSuccess: jest.fn().mockName('addSuccess'), + } }; +const getNotifications = () => { + return notifications; +} + +jest.mock('../../services', () => ({ + ...jest.requireActual('../../services'), + getNotifications: getNotifications, + getQueryService: jest.fn().mockReturnValue({ + queryString: { + getQuery: jest.fn(), + }, + }), + getIndexPatternService: () => ({ + get: () => (mockedIndexPattern) + }) +})); + +const renderWithRouter = () => ({ + ...render( + + + + ( + + + + )} + /> + + + + ), +}); + describe('GenerateAnomalyDetector spec', () => { - describe('Renders loading component', () => { + describe('Renders failed', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders with invalid dataset type', async () => { + const queryService = getQueryService(); + queryService.queryString.getQuery.mockReturnValue({ + dataset: { + id: undefined, + title: undefined, + type: 'INDEX' + }, + }); + + + const { queryByText } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).toBeNull(); + + await waitFor(() => { + expect(getNotifications().toasts.addDanger).toHaveBeenCalledTimes(1); + expect(getNotifications().toasts.addDanger).toHaveBeenCalledWith( + 'Unsupported dataset type' + ); + }); + }); + it('renders empty component', async () => { - httpClientMock.post = jest.fn().mockResolvedValue({ - ok: true, - generatedParameters: { - categoryField: '', - aggregationField: '', - aggregationMethod: '', - dateFields: '', + const queryService = getQueryService(); + queryService.queryString.getQuery.mockReturnValue({ + dataset: { + id: undefined, + title: undefined, + type: 'INDEX_PATTERN' }, }); - const context = { - indexPattern: createIndexPattern(''), - }; - const { queryByText } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).toBeNull(); + const { queryByText } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).toBeNull(); await waitFor(() => { expect(getNotifications().toasts.addDanger).toHaveBeenCalledTimes(1); @@ -232,17 +197,29 @@ describe('GenerateAnomalyDetector spec', () => { ); }); }); + }); + + describe('Renders loading component', () => { + beforeEach(() => { + jest.clearAllMocks(); + const queryService = getQueryService(); + queryService.queryString.getQuery.mockReturnValue({ + dataset: { + id: 'test-pattern', + title: 'test-pattern', + type: 'INDEX_PATTERN', + timeFieldName: '@timestamp', + }, + }); + }); it('renders with empty generated parameters', async () => { httpClientMock.post = jest.fn().mockResolvedValue({ ok: true, }); - const context = { - indexPattern: createIndexPattern('test-pattern'), - } - const { queryByText } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).not.toBeNull(); + const { queryByText } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).not.toBeNull(); await waitFor(() => { expect(getNotifications().toasts.addDanger).toHaveBeenCalledTimes(1); @@ -263,11 +240,8 @@ describe('GenerateAnomalyDetector spec', () => { }, }); - const context = { - indexPattern: createIndexPattern('test-pattern'), - } - const { queryByText } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).not.toBeNull(); + const { queryByText } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).not.toBeNull(); await waitFor(() => { expect(getNotifications().toasts.addDanger).toHaveBeenCalledTimes(1); @@ -288,11 +262,8 @@ describe('GenerateAnomalyDetector spec', () => { }, }); - const context = { - indexPattern: createIndexPattern('test-pattern'), - } - const { queryByText } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).not.toBeNull(); + const { queryByText } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).not.toBeNull(); await waitFor(() => { expect(getNotifications().toasts.addDanger).toHaveBeenCalledTimes(1); @@ -313,11 +284,8 @@ describe('GenerateAnomalyDetector spec', () => { }, }); - const context = { - indexPattern: createIndexPattern('test-pattern'), - } - const { queryByText } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).not.toBeNull(); + const { queryByText } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).not.toBeNull(); await waitFor(() => { expect(getNotifications().toasts.addDanger).toHaveBeenCalledTimes(1); @@ -338,11 +306,8 @@ describe('GenerateAnomalyDetector spec', () => { }, }); - const context = { - indexPattern: createIndexPattern('test-pattern'), - } - const { queryByText } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).not.toBeNull(); + const { queryByText } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).not.toBeNull(); await waitFor(() => { expect(queryByText('Create detector')).not.toBeNull(); @@ -354,8 +319,20 @@ describe('GenerateAnomalyDetector spec', () => { }); - describe('Test API calls', () => { + beforeEach(() => { + jest.clearAllMocks(); + const queryService = getQueryService(); + queryService.queryString.getQuery.mockReturnValue({ + dataset: { + id: 'test-pattern', + title: 'test-pattern', + type: 'INDEX_PATTERN', + timeFieldName: '@timestamp', + }, + }); + }); + it('All API calls execute successfully', async () => { httpClientMock.post = jest.fn((pathOrOptions: string | HttpFetchOptionsWithPath) => { const url = typeof pathOrOptions === 'string' ? pathOrOptions : pathOrOptions.path; @@ -384,11 +361,8 @@ describe('GenerateAnomalyDetector spec', () => { } }); - const context = { - indexPattern: createIndexPattern('test-pattern'), - } - const { queryByText, getByTestId } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).not.toBeNull(); + const { queryByText, getByTestId } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).not.toBeNull(); await waitFor(() => { expect(queryByText('Generating parameters...')).toBeNull(); expect(queryByText('Create detector')).not.toBeNull(); @@ -407,15 +381,6 @@ describe('GenerateAnomalyDetector spec', () => { body: JSON.stringify({ index: 'test-pattern' }), } ); - expect(httpClientMock.post).toHaveBeenCalledWith( - `${BASE_NODE_API_PATH}/detectors`, - { - body: JSON.stringify(expectedAnomalyDetector), - } - ); - expect(httpClientMock.post).toHaveBeenCalledWith( - `${BASE_NODE_API_PATH}/detectors/test/start` - ); expect(getNotifications().toasts.addSuccess).toHaveBeenCalledTimes(1); }); }); @@ -426,11 +391,8 @@ describe('GenerateAnomalyDetector spec', () => { error: 'Generate parameters failed' }); - const context = { - indexPattern: createIndexPattern('test-pattern'), - } - const { queryByText } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).not.toBeNull(); + const { queryByText } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).not.toBeNull(); await waitFor(() => { expect(getNotifications().toasts.addDanger).toHaveBeenCalledTimes(1); expect(getNotifications().toasts.addDanger).toHaveBeenCalledWith( @@ -472,12 +434,8 @@ describe('GenerateAnomalyDetector spec', () => { }, }); - - const context = { - indexPattern: createIndexPattern('test-pattern'), - } - const { queryByText, getByTestId } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).not.toBeNull(); + const { queryByText, getByTestId } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).not.toBeNull(); await waitFor(() => { expect(queryByText('Generating parameters...')).toBeNull(); @@ -539,11 +497,8 @@ describe('GenerateAnomalyDetector spec', () => { }); - const context = { - indexPattern: createIndexPattern('test-pattern'), - } - const { queryByText, getByTestId } = renderWithRouter(context); - expect(queryByText('Suggest anomaly detector')).not.toBeNull(); + const { queryByText, getByTestId } = renderWithRouter(); + expect(queryByText('Suggested anomaly detector')).not.toBeNull(); await waitFor(() => { expect(queryByText('Generating parameters...')).toBeNull(); diff --git a/public/components/DiscoverAction/SuggestAnomalyDetector.tsx b/public/components/DiscoverAction/SuggestAnomalyDetector.tsx index a5ec1a59..58fa7033 100644 --- a/public/components/DiscoverAction/SuggestAnomalyDetector.tsx +++ b/public/components/DiscoverAction/SuggestAnomalyDetector.tsx @@ -61,7 +61,7 @@ import { formikToDetector } from '../../pages/ReviewAndCreate/utils/helpers'; import { FormattedFormRow } from '../FormattedFormRow/FormattedFormRow'; import { FeatureAccordion } from '../../pages/ConfigureModel/components/FeatureAccordion'; import { AD_DOCS_LINK, DEFAULT_SHINGLE_SIZE, MAX_FEATURE_NUM, PLUGIN_NAME } from '../../utils/constants'; -import { getNotifications } from '../../services'; +import { getIndexPatternService, getNotifications, getQueryService } from '../../services'; import { prettifyErrorMessage } from '../../../server/utils/helpers'; import EnhancedAccordion from '../FeatureAnywhereContextMenu/EnhancedAccordion'; import MinimalAccordion from '../FeatureAnywhereContextMenu/MinimalAccordion'; @@ -69,10 +69,10 @@ import { DataFilterList } from '../../pages/DefineDetector/components/DataFilter import { generateParameters } from '../../redux/reducers/assistant'; import { FEATURE_TYPE } from '../../models/interfaces'; import { FeaturesFormikValues } from '../../pages/ConfigureModel/models/interfaces'; -import { DiscoverActionContext } from '../../../../../src/plugins/data_explorer/public/types'; import { getMappings } from '../../redux/reducers/opensearch'; import { mountReactNode } from '../../../../../src/core/public/utils'; import { formikToDetectorName } from '../FeatureAnywhereContextMenu/CreateAnomalyDetector/helpers'; +import { DEFAULT_DATA } from '../../../../../src/plugins/data/common'; export interface GeneratedParameters { categoryField: string; @@ -80,41 +80,35 @@ export interface GeneratedParameters { dateFields: string[]; } -function GenerateAnomalyDetector({ +function SuggestAnomalyDetector({ closeFlyout, - context, }: { closeFlyout: any; - context: DiscoverActionContext; }) { const dispatch = useDispatch(); const notifications = getNotifications(); - const indexPatternId = context.indexPattern?.id; - const indexPatternName = context.indexPattern?.title; - if (!indexPatternId || !indexPatternName) { + const queryString = getQueryService().queryString; + const dataset = queryString.getQuery().dataset || queryString.getDefaultQuery().dataset; + if (dataset.type != DEFAULT_DATA.SET_TYPES.INDEX_PATTERN) { notifications.toasts.addDanger( - 'Cannot extract index pattern from the context' + 'Unsupported dataset type' ); return <>; } - const dataSourceId = context.indexPattern?.dataSourceRef?.id; - const timeFieldFromIndexPattern = context.indexPattern?.timeFieldName; - const fieldsFromContext = context.indexPattern?.fields || []; - const [categoricalFields, dateFields] = fieldsFromContext.reduce( - ([cFields, dFields], indexPatternField) => { - const esType = indexPatternField.spec.esTypes?.[0]; - const name = indexPatternField.spec.name; - if (esType === 'keyword' || esType === 'ip') { - cFields.push(name); - } else if (esType === 'date') { - dFields.push(name); - } - return [cFields, dFields]; - }, - [[], []] as [string[], string[]] - ) || [[], []]; + const indexPatternId = dataset.id; + const indexPatternName = dataset.title; + const timeFieldFromIndexPattern = dataset.timeFieldName; + if (!indexPatternId || !indexPatternName || !timeFieldFromIndexPattern) { + notifications.toasts.addDanger( + 'Cannot extract index pattern from the context' + ); + return <>; + } + const [dataSourceId, setDataSourceId] = useState(undefined); + const [categoricalFields, setCategoricalFields] = useState([]); + const [dateFields, setDateFields] = useState([]); const [isLoading, setIsLoading] = useState(true); const [buttonName, setButtonName] = useState( 'Generating parameters...' @@ -130,6 +124,37 @@ function GenerateAnomalyDetector({ formikToDetectorName(indexPatternName.substring(0, 40)) ); + async function getIndexPatternDetails() { + try { + const indexPatternService = getIndexPatternService(); + const indexPatternDetail = await indexPatternService.get(indexPatternId); + + setDataSourceId(indexPatternDetail?.dataSourceId); + + const fieldsFromContext = indexPatternDetail?.fields || []; + const [categoricalFieldsFromContext, dateFieldsFromContext] = fieldsFromContext.reduce( + ([cFields, dFields], indexPatternField) => { + const esType = indexPatternField.spec.esTypes?.[0]; + const name = indexPatternField.spec.name; + if (esType === 'keyword' || esType === 'ip') { + cFields.push(name); + } else if (esType === 'date') { + dFields.push(name); + } + return [cFields, dFields]; + }, + [[], []] as [string[], string[]] + ) || [[], []]; + + setCategoricalFields(categoricalFieldsFromContext); + setDateFields(dateFieldsFromContext); + } catch (error) { + notifications.toasts.addDanger( + 'Get index pattern details failed, reason: ' + error + ); + } + } + // let LLM to generate parameters for creating anomaly detector async function getParameters() { try { @@ -207,6 +232,7 @@ function GenerateAnomalyDetector({ useEffect(() => { async function fetchData() { + await getIndexPatternDetails(); await getParameters(); const getMappingDispatchCall = dispatch( getMappings(indexPatternName, dataSourceId) @@ -382,7 +408,7 @@ function GenerateAnomalyDetector({

- Suggest anomaly detector + Suggested anomaly detector

@@ -857,4 +883,4 @@ function GenerateAnomalyDetector({ ); } -export default GenerateAnomalyDetector; +export default SuggestAnomalyDetector; diff --git a/public/plugin.ts b/public/plugin.ts index 68eedfcf..b53ebc59 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -27,7 +27,7 @@ import { } from '../../../src/plugins/embeddable/public'; import { ACTION_AD } from './action/ad_dashboard_action'; import { APP_PATH, DASHBOARD_PAGE_NAV_ID, DETECTORS_PAGE_NAV_ID, OVERVIEW_PAGE_NAV_ID, PLUGIN_NAME } from './utils/constants'; -import { getActions } from './utils/contextMenu/getActions'; +import { ACTION_SUGGEST_AD, getActions, getSuggestAnomalyDetectorAction } from './utils/contextMenu/getActions'; import { overlayAnomaliesFunction } from './expressions/overlay_anomalies'; import { setClient, @@ -42,7 +42,8 @@ import { setDataSourceManagementPlugin, setDataSourceEnabled, setNavigationUI, - setApplication + setApplication, + setIndexPatternService } from './services'; import { AnomalyDetectionOpenSearchDashboardsPluginStart } from 'public'; import { @@ -50,16 +51,16 @@ import { VisAugmenterStart, } from '../../../src/plugins/vis_augmenter/public'; import { UiActionsStart } from '../../../src/plugins/ui_actions/public'; -import { DataPublicPluginStart } from '../../../src/plugins/data/public'; +import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../src/plugins/data/public'; import { DataSourceManagementPluginSetup } from '../../../src/plugins/data_source_management/public'; import { DataSourcePluginSetup } from '../../../src/plugins/data_source/public'; import { NavigationPublicPluginStart } from '../../../src/plugins/navigation/public'; -import { getDiscoverAction } from './utils/discoverAction'; -import { DataExplorerPluginSetup } from '../../../src/plugins/data_explorer/public'; +import { AssistantSetup } from '../../../plugins/dashboards-assistant/public'; declare module '../../../src/plugins/ui_actions/public' { export interface ActionContextMapping { [ACTION_AD]: {}; + [ACTION_SUGGEST_AD]: {} } } @@ -70,7 +71,7 @@ export interface AnomalyDetectionSetupDeps { visAugmenter: VisAugmenterSetup; dataSourceManagement: DataSourceManagementPluginSetup; dataSource: DataSourcePluginSetup; - dataExplorer: DataExplorerPluginSetup; + data: DataPublicPluginSetup; } export interface AnomalyDetectionStartDeps { @@ -192,9 +193,9 @@ export class AnomalyDetectionOpenSearchDashboardsPlugin plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, action); }); - // Add action to Discover - const discoverAction = getDiscoverAction(); - plugins.dataExplorer.registerDiscoverAction(discoverAction); + // Add suggest anomaly detector action to the uiActions in Discover + const suggestAnomalyDetectorAction = getSuggestAnomalyDetectorAction(); + plugins.uiActions.addTriggerAction(plugins.assistantDashboards.assistantTriggers.AI_ASSISTANT_TRIGGER, suggestAnomalyDetectorAction); // registers the expression function used to render anomalies on an Augmented Visualization plugins.expressions.registerFunction(overlayAnomaliesFunction); @@ -212,6 +213,7 @@ export class AnomalyDetectionOpenSearchDashboardsPlugin setNotifications(core.notifications); setUiActions(uiActions); setQueryService(data.query); + setIndexPatternService(data.indexPatterns); setSavedObjectsClient(core.savedObjects.client); setNavigationUI(navigation.ui); setApplication(core.application); diff --git a/public/services.ts b/public/services.ts index 0c3d45dd..f7f4d935 100644 --- a/public/services.ts +++ b/public/services.ts @@ -45,6 +45,9 @@ export const [getUISettings, setUISettings] = export const [getQueryService, setQueryService] = createGetterSetter('Query'); +export const [getIndexPatternService, setIndexPatternService] = + createGetterSetter('IndexPatterns'); + export const [getSavedObjectsClient, setSavedObjectsClient] = createGetterSetter('SavedObjectsClient'); @@ -54,10 +57,10 @@ export const [getDataSourceManagementPlugin, setDataSourceManagementPlugin] = export const [getDataSourceEnabled, setDataSourceEnabled] = createGetterSetter('DataSourceEnabled'); -export const [getNavigationUI, setNavigationUI] = +export const [getNavigationUI, setNavigationUI] = createGetterSetter('navigation'); -export const [getApplication, setApplication] = +export const [getApplication, setApplication] = createGetterSetter('application'); // This is primarily used for mocking this module and each of its fns in tests. diff --git a/public/utils/contextMenu/getActions.tsx b/public/utils/contextMenu/getActions.tsx index f58a7a9e..30ae041e 100644 --- a/public/utils/contextMenu/getActions.tsx +++ b/public/utils/contextMenu/getActions.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { i18n } from '@osd/i18n'; import { EuiIconType } from '@elastic/eui'; import { toMountPoint } from '../../../../../src/plugins/opensearch_dashboards_react/public'; -import { Action } from '../../../../../src/plugins/ui_actions/public'; +import { Action, createAction } from '../../../../../src/plugins/ui_actions/public'; import { createADAction } from '../../action/ad_dashboard_action'; import AnywhereParentFlyout from '../../components/FeatureAnywhereContextMenu/AnywhereParentFlyout'; import { Provider } from 'react-redux'; @@ -16,6 +16,9 @@ import DocumentationTitle from '../../components/FeatureAnywhereContextMenu/Docu import { AD_FEATURE_ANYWHERE_LINK, ANOMALY_DETECTION_ICON } from '../constants'; import { getClient, getOverlays } from '../../../public/services'; import { FLYOUT_MODES } from '../../../public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/constants'; +import SuggestAnomalyDetector from '../../../public/components/DiscoverAction/SuggestAnomalyDetector'; + +export const ACTION_SUGGEST_AD = 'suggestAnomalyDetector'; // This is used to create all actions in the same context menu const grouping: Action['grouping'] = [ @@ -31,23 +34,23 @@ const grouping: Action['grouping'] = [ export const getActions = () => { const getOnClick = (startingFlyout) => - async ({ embeddable }) => { - const overlayService = getOverlays(); - const openFlyout = overlayService.openFlyout; - const store = configureStore(getClient()); - const overlay = openFlyout( - toMountPoint( - - overlay.close()} - /> - - ), - { size: 'm', className: 'context-menu__flyout' } - ); - }; + async ({ embeddable }) => { + const overlayService = getOverlays(); + const openFlyout = overlayService.openFlyout; + const store = configureStore(getClient()); + const overlay = openFlyout( + toMountPoint( + + overlay.close()} + /> + + ), + { size: 'm', className: 'context-menu__flyout' } + ); + }; return [ { @@ -87,3 +90,31 @@ export const getActions = () => { }, ].map((options) => createADAction({ ...options, grouping })); }; + +export const getSuggestAnomalyDetectorAction = () => { + const onClick = async function () { + const overlayService = getOverlays(); + const openFlyout = overlayService.openFlyout; + const store = configureStore(getClient()); + const overlay = openFlyout( + toMountPoint( + + overlay.close()} + /> + + ) + ); + } + + return createAction({ + id: 'suggestAnomalyDetector', + order: 100, + type: ACTION_SUGGEST_AD, + getDisplayName: () => 'Suggest anomaly detector', + getIconType: () => ANOMALY_DETECTION_ICON, + execute: async () => { + onClick(); + }, + }); +} diff --git a/public/utils/discoverAction.tsx b/public/utils/discoverAction.tsx deleted file mode 100644 index 9b345ee8..00000000 --- a/public/utils/discoverAction.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react' -import { ANOMALY_DETECTION_ICON } from "./constants"; -import GenerateAnomalyDetector from "../components/DiscoverAction/SuggestAnomalyDetector"; -import { getClient, getOverlays } from '../../public/services'; -import { toMountPoint } from "../../../../src/plugins/opensearch_dashboards_react/public"; -import { Provider } from "react-redux"; -import configureStore from '../redux/configureStore'; -import { DiscoverAction, DiscoverActionContext } from "../../../../src/plugins/data_explorer/public/types"; - -export const getDiscoverAction = (): DiscoverAction => { - const onClick = function (context: DiscoverActionContext) { - const overlayService = getOverlays(); - const openFlyout = overlayService.openFlyout; - const store = configureStore(getClient()); - const overlay = openFlyout( - toMountPoint( - - overlay.close()} - context={context} - /> - - ) - ); - } - - return { - order: 0, - name: 'Suggest anomaly detector', - iconType: ANOMALY_DETECTION_ICON, - onClick: onClick, - } -}; diff --git a/server/routes/assistant.ts b/server/routes/assistant.ts index 6669b9c3..5c1a0cd0 100644 --- a/server/routes/assistant.ts +++ b/server/routes/assistant.ts @@ -56,16 +56,14 @@ export default class AssistantService { }); if ( - !getAgentResponse || - !getAgentResponse['configuration'] || - !getAgentResponse['configuration']['agent_id'] + !getAgentResponse || !(getAgentResponse.ml_configuration?.agent_id || getAgentResponse.configuration?.agent_id) ) { throw new Error( 'Cannot get flow agent id for generating anomaly detector' ); } - const agentId = getAgentResponse['configuration']['agent_id']; + const agentId = getAgentResponse.ml_configuration?.agent_id || getAgentResponse.configuration?.agent_id; const executeAgentResponse = await callWithRequest('ml.executeAgent', { agentId: agentId, diff --git a/server/utils/constants.ts b/server/utils/constants.ts index 8c071556..1a756187 100644 --- a/server/utils/constants.ts +++ b/server/utils/constants.ts @@ -133,4 +133,4 @@ export const HISTORICAL_TASK_TYPES = [ export const CUSTOM_AD_RESULT_INDEX_PREFIX = 'opensearch-ad-plugin-result-'; -export const SUGGEST_ANOMALY_DETECTOR_CONFIG_ID = 'suggest_anomaly_detector'; +export const SUGGEST_ANOMALY_DETECTOR_CONFIG_ID = 'os_suggest_ad';