From 53a33246609624d98e80ba2d18b3a9999a3e8e50 Mon Sep 17 00:00:00 2001 From: Jackie Han Date: Fri, 12 May 2023 14:35:18 -0700 Subject: [PATCH 1/7] Register AD as dashboard context menu option Signed-off-by: Jackie Han --- opensearch_dashboards.json | 9 +- public/action/ad_dashboard_action.tsx | 74 +++++++++++++++ .../AnywhereParentFlyout.tsx | 32 +++++++ .../AnywhereParentFlyout/index.tsx | 8 ++ .../AnywhereParentFlyout/styles.scss | 7 ++ public/plugin.tsx | 72 +++++++++++++++ public/utils/constants.ts | 2 + public/utils/contextMenu/getActions.tsx | 92 +++++++++++++++++++ 8 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 public/action/ad_dashboard_action.tsx create mode 100644 public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx create mode 100644 public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/index.tsx create mode 100644 public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/styles.scss create mode 100644 public/plugin.tsx create mode 100644 public/utils/contextMenu/getActions.tsx diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index 8fdba21c..21cd2fbb 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -7,7 +7,14 @@ "opensearchDashboardsUtils", "expressions", "data", - "visAugmenter" + "visAugmenter", + "uiActions", + "dashboard", + "embeddable", + "opensearchDashboardsReact", + "savedObjects", + "visAugmenter", + "opensearchDashboardsUtils" ], "server": true, "ui": true diff --git a/public/action/ad_dashboard_action.tsx b/public/action/ad_dashboard_action.tsx new file mode 100644 index 00000000..0d8c4389 --- /dev/null +++ b/public/action/ad_dashboard_action.tsx @@ -0,0 +1,74 @@ +import { IEmbeddable } from '../../../../src/plugins/dashboard/public/embeddable_plugin'; +import { + DASHBOARD_CONTAINER_TYPE, + DashboardContainer, +} from '../../../../src/plugins/dashboard/public'; +import { + IncompatibleActionError, + createAction, + Action, +} from '../../../../src/plugins/ui_actions/public'; +import { isReferenceOrValueEmbeddable } from '../../../../src/plugins/embeddable/public'; +import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; + +export const ACTION_AD = 'ad'; + +function isDashboard( + embeddable: IEmbeddable +): embeddable is DashboardContainer { + return embeddable.type === DASHBOARD_CONTAINER_TYPE; +} + +export interface ActionContext { + embeddable: IEmbeddable; +} + +export interface CreateOptions { + grouping: Action['grouping']; + title: string; + icon: EuiIconType; + id: string; + order: number; + onClick: Function; +} + +export const createADAction = ({ + grouping, + title, + icon, + id, + order, + onClick, +}: CreateOptions) => + createAction({ + id, + order, + getDisplayName: ({ embeddable }: ActionContext) => { + if (!embeddable.parent || !isDashboard(embeddable.parent)) { + throw new IncompatibleActionError(); + } + return title; + }, + getIconType: () => icon, + type: ACTION_AD, + grouping, + isCompatible: async ({ embeddable }: ActionContext) => { + const paramsType = embeddable.vis?.params?.type; + const seriesParams = embeddable.vis?.params?.seriesParams || []; + const series = embeddable.vis?.params?.series || []; + const isLineGraph = + seriesParams.find((item) => item.type === 'line') || + series.find((item) => item.chart_type === 'line'); + const isValidVis = isLineGraph && paramsType !== 'table'; + return Boolean( + embeddable.parent && isDashboard(embeddable.parent) && isValidVis + ); + }, + execute: async ({ embeddable }: ActionContext) => { + if (!isReferenceOrValueEmbeddable(embeddable)) { + throw new IncompatibleActionError(); + } + + onClick({ embeddable }); + }, + }); \ No newline at end of file diff --git a/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx new file mode 100644 index 00000000..414c9d15 --- /dev/null +++ b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx @@ -0,0 +1,32 @@ +import React, { useState } from 'react'; +import './styles.scss'; +import { get } from 'lodash'; +import AddAnomalyDetector from '../CreateAnomalyDetector'; + +const AnywhereParentFlyout = ({ startingFlyout, ...props }) => { + const { embeddable } = props; + const indices: { label: string }[] = [ + { label: get(embeddable, 'vis.data.indexPattern.title', '') }, + ]; + const [mode, setMode] = useState(startingFlyout); + const [selectedDetectorId, setSelectedDetectorId] = useState(); + + const Flyout = { + create: AddAnomalyDetector, + }[mode]; + + return ( + + ); +}; + +export default AnywhereParentFlyout; \ No newline at end of file diff --git a/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/index.tsx b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/index.tsx new file mode 100644 index 00000000..cca0078b --- /dev/null +++ b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/index.tsx @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import AnywhereParentFlyout from './AnywhereParentFlyout'; + +export default AnywhereParentFlyout; \ No newline at end of file diff --git a/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/styles.scss b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/styles.scss new file mode 100644 index 00000000..11cf4c6c --- /dev/null +++ b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/styles.scss @@ -0,0 +1,7 @@ +.context-menu { + &__flyout { + &.euiFlyout--medium { + width: 740px; + } + } +} \ No newline at end of file diff --git a/public/plugin.tsx b/public/plugin.tsx new file mode 100644 index 00000000..70550051 --- /dev/null +++ b/public/plugin.tsx @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { + AppMountParameters, + CoreSetup, + Plugin, + PluginInitializerContext, +} from '../../../src/core/public'; +import { CONTEXT_MENU_TRIGGER } from '../../../src/plugins/embeddable/public'; +import { ACTION_AD } from './action/ad_dashboard_action'; +import { PLUGIN_NAME } from './utils/constants'; +import { getActions } from './utils/contextMenu/getActions'; +import { setSavedFeatureAnywhereLoader } from './services'; +import { overlayAnomaliesFunction } from './expressions/overlay_anomalies'; +import { setClient } from './services'; + +declare module '../../../src/plugins/ui_actions/public' { + export interface ActionContextMapping { + [ACTION_AD]: {}; + } +} + +export class AnomalyDetectionOpenSearchDashboardsPlugin implements Plugin { + public setup(core: CoreSetup, plugins) { + core.application.register({ + id: PLUGIN_NAME, + title: 'Anomaly Detection', + category: { + id: 'opensearch', + label: 'OpenSearch Plugins', + order: 2000, + }, + order: 5000, + mount: async (params: AppMountParameters) => { + const { renderApp } = await import('./anomaly_detection_app'); + const [coreStart] = await core.getStartServices(); + return renderApp(coreStart, params); + }, + }); + + // Create context menu actions. Pass core, to access service for flyouts. + const actions = getActions({ core }); + + // Add actions to uiActions + actions.forEach((action) => { + plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, action); + }); + + // Set the HTTP client so it can be pulled into expression fns to make + // direct server-side calls + setClient(core.http); + + // registers the expression function used to render anomalies on an Augmented Visualization + plugins.expressions.registerFunction(overlayAnomaliesFunction); + return {}; + } + + public start(core: CoreStart, plugins) { + setSavedFeatureAnywhereLoader(plugins.visAugmenter.savedAugmentVisLoader); + return {}; + } + public stop() {} +} \ No newline at end of file diff --git a/public/utils/constants.ts b/public/utils/constants.ts index 23354742..492433c6 100644 --- a/public/utils/constants.ts +++ b/public/utils/constants.ts @@ -53,6 +53,8 @@ export const ANOMALY_RESULT_INDEX = '.opendistro-anomaly-results'; export const BASE_DOCS_LINK = 'https://opensearch.org/docs/monitoring-plugins'; +export const AD_DOCS_LINK = 'https://opensearch.org/docs/latest/monitoring-plugins/anomaly-detection/index/'; + export const MAX_DETECTORS = 1000; export const MAX_ANOMALIES = 10000; diff --git a/public/utils/contextMenu/getActions.tsx b/public/utils/contextMenu/getActions.tsx new file mode 100644 index 00000000..96a0fde6 --- /dev/null +++ b/public/utils/contextMenu/getActions.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import { i18n } from '@osd/i18n'; +import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; +import { toMountPoint } from '../../../../../src/plugins/opensearch_dashboards_react/public'; +import { Action } from '../../../../../src/plugins/ui_actions/public'; +import { createADAction } from '../../action/ad_dashboard_action'; +import AnywhereParentFlyout from '../../components/FeatureAnywhereContextMenu/AnywhereParentFlyout'; +import { Provider } from 'react-redux'; +import { CoreServicesContext } from '../../../public/components/CoreServices/CoreServices'; +import configureStore from '../../redux/configureStore'; +import DocumentationTitle from '../../../public/components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle'; +import { AD_DOCS_LINK } from '../constants'; + +// This is used to create all actions in the same context menu +const grouping: Action['grouping'] = [ + { + id: 'ad-dashboard-context-menu', + getDisplayName: () => 'Anomaly Detector', + getIconType: () => 'apmTrace', + }, +]; + +export const getActions = ({ core, plugins }) => { + const getOnClick = + (startingFlyout) => + async ({ embeddable }) => { + const services = await core.getStartServices(); + const openFlyout = services[0].overlays.openFlyout; + const http = services[0].http; + const store = configureStore(http); + const overlay = openFlyout( + toMountPoint( + + + overlay.close(), + core, + services, + }} + /> + + + ), + { size: 'm', className: 'context-menu__flyout' } + ); + }; + + return [ + { + grouping, + id: 'createAnomalyDetector', + title: i18n.translate( + 'dashboard.actions.adMenuItem.createAnomalyDetector.displayName', + { + defaultMessage: 'Create anomaly detector', + } + ), + icon: 'plusInCircle' as EuiIconType, + order: 100, + onClick: getOnClick('create'), + }, + { + grouping, + id: 'associatedAnomalyDetector', + title: i18n.translate( + 'dashboard.actions.adMenuItem.associatedAnomalyDetector.displayName', + { + defaultMessage: 'Associated anomaly detector', + } + ), + icon: 'gear' as EuiIconType, + order: 99, + onClick: getOnClick('associated'), + }, + { + id: 'documentationAnomalyDetector', + title: , + icon: 'documentation' as EuiIconType, + order: 98, + onExecute: () => { + window.open( + AD_DOCS_LINK, + '_blank' + ); + }, + }, + ].map((options) => createADAction({ ...options, grouping })); +}; \ No newline at end of file From 5711948daece210227d0929dfd4bfec6f93d8553 Mon Sep 17 00:00:00 2001 From: Jackie Han Date: Wed, 17 May 2023 11:05:57 -0700 Subject: [PATCH 2/7] addressing comments Signed-off-by: Jackie Han --- public/action/ad_dashboard_action.tsx | 4 ++ .../AnywhereParentFlyout.tsx | 11 +++-- .../AnywhereParentFlyout/styles.scss | 7 --- .../containers/DocumentationTitle.tsx | 28 ++++++++++++ .../DocumentationTitle/index.tsx | 8 ++++ public/plugin.ts | 43 ++++++++++--------- public/utils/constants.ts | 4 +- public/utils/contextMenu/getActions.tsx | 8 ++-- 8 files changed, 76 insertions(+), 37 deletions(-) delete mode 100644 public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/styles.scss create mode 100644 public/components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle.tsx create mode 100644 public/components/FeatureAnywhereContextMenu/DocumentationTitle/index.tsx diff --git a/public/action/ad_dashboard_action.tsx b/public/action/ad_dashboard_action.tsx index 0d8c4389..0be356ed 100644 --- a/public/action/ad_dashboard_action.tsx +++ b/public/action/ad_dashboard_action.tsx @@ -1,3 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ import { IEmbeddable } from '../../../../src/plugins/dashboard/public/embeddable_plugin'; import { DASHBOARD_CONTAINER_TYPE, diff --git a/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx index 414c9d15..cb35e7a8 100644 --- a/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx +++ b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx @@ -1,5 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ import React, { useState } from 'react'; -import './styles.scss'; import { get } from 'lodash'; import AddAnomalyDetector from '../CreateAnomalyDetector'; @@ -11,12 +14,12 @@ const AnywhereParentFlyout = ({ startingFlyout, ...props }) => { const [mode, setMode] = useState(startingFlyout); const [selectedDetectorId, setSelectedDetectorId] = useState(); - const Flyout = { + const AnywhereFlyout = { create: AddAnomalyDetector, }[mode]; return ( - { selectedDetectorId, setSelectedDetectorId, }} - /> + /> ); }; diff --git a/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/styles.scss b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/styles.scss deleted file mode 100644 index 11cf4c6c..00000000 --- a/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/styles.scss +++ /dev/null @@ -1,7 +0,0 @@ -.context-menu { - &__flyout { - &.euiFlyout--medium { - width: 740px; - } - } -} \ No newline at end of file diff --git a/public/components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle.tsx b/public/components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle.tsx new file mode 100644 index 00000000..22d2ac3c --- /dev/null +++ b/public/components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle.tsx @@ -0,0 +1,28 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiIcon, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; + +const DocumentationTitle = () => ( + + + + {i18n.translate( + 'dashboard.actions.adMenuItem.documentation.displayName', + { + defaultMessage: 'Documentation', + } + )} + + + + + + +); + +export default DocumentationTitle; \ No newline at end of file diff --git a/public/components/FeatureAnywhereContextMenu/DocumentationTitle/index.tsx b/public/components/FeatureAnywhereContextMenu/DocumentationTitle/index.tsx new file mode 100644 index 00000000..03b2fb80 --- /dev/null +++ b/public/components/FeatureAnywhereContextMenu/DocumentationTitle/index.tsx @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import DocumentationTitle from './containers/DocumentationTitle'; + +export default DocumentationTitle; \ No newline at end of file diff --git a/public/plugin.ts b/public/plugin.ts index 2f55a028..a7d60d75 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -14,32 +14,25 @@ import { CoreSetup, CoreStart, Plugin, - PluginInitializerContext, } from '../../../src/core/public'; -import { - AnomalyDetectionOpenSearchDashboardsPluginSetup, - AnomalyDetectionOpenSearchDashboardsPluginStart, -} from '.'; +import { CONTEXT_MENU_TRIGGER } from '../../../src/plugins/embeddable/public'; +import { ACTION_AD } from './action/ad_dashboard_action'; +import { PLUGIN_NAME } from './utils/constants'; +import { getActions } from './utils/contextMenu/getActions'; import { overlayAnomaliesFunction } from './expressions/overlay_anomalies'; import { setClient } from './services'; +import { AnomalyDetectionOpenSearchDashboardsPluginStart } from 'public'; -export class AnomalyDetectionOpenSearchDashboardsPlugin - implements - Plugin< - AnomalyDetectionOpenSearchDashboardsPluginSetup, - AnomalyDetectionOpenSearchDashboardsPluginStart - > -{ - constructor(private readonly initializerContext: PluginInitializerContext) { - // can retrieve config from initializerContext +declare module '../../../src/plugins/ui_actions/public' { + export interface ActionContextMapping { + [ACTION_AD]: {}; } +} - public setup( - core: CoreSetup, - plugins - ): AnomalyDetectionOpenSearchDashboardsPluginSetup { +export class AnomalyDetectionOpenSearchDashboardsPlugin implements Plugin { + public setup(core: CoreSetup, plugins) { core.application.register({ - id: 'anomaly-detection-dashboards', + id: PLUGIN_NAME, title: 'Anomaly Detection', category: { id: 'opensearch', @@ -49,11 +42,19 @@ export class AnomalyDetectionOpenSearchDashboardsPlugin order: 5000, mount: async (params: AppMountParameters) => { const { renderApp } = await import('./anomaly_detection_app'); - const [coreStart, depsStart] = await core.getStartServices(); + const [coreStart] = await core.getStartServices(); return renderApp(coreStart, params); }, }); + // Create context menu actions. Pass core, to access service for flyouts. + const actions = getActions({ core }); + + // Add actions to uiActions + actions.forEach((action) => { + plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, action); + }); + // Set the HTTP client so it can be pulled into expression fns to make // direct server-side calls setClient(core.http); @@ -68,4 +69,4 @@ export class AnomalyDetectionOpenSearchDashboardsPlugin ): AnomalyDetectionOpenSearchDashboardsPluginStart { return {}; } -} +} \ No newline at end of file diff --git a/public/utils/constants.ts b/public/utils/constants.ts index 492433c6..099e6a7e 100644 --- a/public/utils/constants.ts +++ b/public/utils/constants.ts @@ -53,7 +53,7 @@ export const ANOMALY_RESULT_INDEX = '.opendistro-anomaly-results'; export const BASE_DOCS_LINK = 'https://opensearch.org/docs/monitoring-plugins'; -export const AD_DOCS_LINK = 'https://opensearch.org/docs/latest/monitoring-plugins/anomaly-detection/index/'; +export const AD_DOCS_LINK = 'https://opensearch.org/docs/latest/observing-your-data/ad/index/'; export const MAX_DETECTORS = 1000; @@ -89,3 +89,5 @@ export enum MISSING_FEATURE_DATA_SEVERITY { } export const SPACE_STR = ' '; + +export const APM_TRACE = 'apmTrace'; diff --git a/public/utils/contextMenu/getActions.tsx b/public/utils/contextMenu/getActions.tsx index 96a0fde6..8a38838e 100644 --- a/public/utils/contextMenu/getActions.tsx +++ b/public/utils/contextMenu/getActions.tsx @@ -8,15 +8,15 @@ import AnywhereParentFlyout from '../../components/FeatureAnywhereContextMenu/An import { Provider } from 'react-redux'; import { CoreServicesContext } from '../../../public/components/CoreServices/CoreServices'; import configureStore from '../../redux/configureStore'; -import DocumentationTitle from '../../../public/components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle'; -import { AD_DOCS_LINK } from '../constants'; +import DocumentationTitle from '../../components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle'; +import { AD_DOCS_LINK, APM_TRACE } from '../constants'; // This is used to create all actions in the same context menu const grouping: Action['grouping'] = [ { id: 'ad-dashboard-context-menu', getDisplayName: () => 'Anomaly Detector', - getIconType: () => 'apmTrace', + getIconType: () => APM_TRACE, }, ]; @@ -81,7 +81,7 @@ export const getActions = ({ core, plugins }) => { title: , icon: 'documentation' as EuiIconType, order: 98, - onExecute: () => { + onClick: () => { window.open( AD_DOCS_LINK, '_blank' From cde1797c4ed5dbbb34c660471f4b3719605a33c5 Mon Sep 17 00:00:00 2001 From: Jackie Han Date: Wed, 17 May 2023 15:27:33 -0700 Subject: [PATCH 3/7] add getActions props Signed-off-by: Jackie Han --- public/plugin.ts | 2 +- public/plugin.tsx | 72 ------------------------- public/utils/contextMenu/getActions.tsx | 10 +++- 3 files changed, 9 insertions(+), 75 deletions(-) delete mode 100644 public/plugin.tsx diff --git a/public/plugin.ts b/public/plugin.ts index a7d60d75..d08f6c2d 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -30,7 +30,7 @@ declare module '../../../src/plugins/ui_actions/public' { } export class AnomalyDetectionOpenSearchDashboardsPlugin implements Plugin { - public setup(core: CoreSetup, plugins) { + public setup(core: CoreSetup, plugins: any) { core.application.register({ id: PLUGIN_NAME, title: 'Anomaly Detection', diff --git a/public/plugin.tsx b/public/plugin.tsx deleted file mode 100644 index 70550051..00000000 --- a/public/plugin.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -import { - AppMountParameters, - CoreSetup, - Plugin, - PluginInitializerContext, -} from '../../../src/core/public'; -import { CONTEXT_MENU_TRIGGER } from '../../../src/plugins/embeddable/public'; -import { ACTION_AD } from './action/ad_dashboard_action'; -import { PLUGIN_NAME } from './utils/constants'; -import { getActions } from './utils/contextMenu/getActions'; -import { setSavedFeatureAnywhereLoader } from './services'; -import { overlayAnomaliesFunction } from './expressions/overlay_anomalies'; -import { setClient } from './services'; - -declare module '../../../src/plugins/ui_actions/public' { - export interface ActionContextMapping { - [ACTION_AD]: {}; - } -} - -export class AnomalyDetectionOpenSearchDashboardsPlugin implements Plugin { - public setup(core: CoreSetup, plugins) { - core.application.register({ - id: PLUGIN_NAME, - title: 'Anomaly Detection', - category: { - id: 'opensearch', - label: 'OpenSearch Plugins', - order: 2000, - }, - order: 5000, - mount: async (params: AppMountParameters) => { - const { renderApp } = await import('./anomaly_detection_app'); - const [coreStart] = await core.getStartServices(); - return renderApp(coreStart, params); - }, - }); - - // Create context menu actions. Pass core, to access service for flyouts. - const actions = getActions({ core }); - - // Add actions to uiActions - actions.forEach((action) => { - plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, action); - }); - - // Set the HTTP client so it can be pulled into expression fns to make - // direct server-side calls - setClient(core.http); - - // registers the expression function used to render anomalies on an Augmented Visualization - plugins.expressions.registerFunction(overlayAnomaliesFunction); - return {}; - } - - public start(core: CoreStart, plugins) { - setSavedFeatureAnywhereLoader(plugins.visAugmenter.savedAugmentVisLoader); - return {}; - } - public stop() {} -} \ No newline at end of file diff --git a/public/utils/contextMenu/getActions.tsx b/public/utils/contextMenu/getActions.tsx index 8a38838e..5b661e62 100644 --- a/public/utils/contextMenu/getActions.tsx +++ b/public/utils/contextMenu/getActions.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { i18n } from '@osd/i18n'; -import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; +import { EuiIconType } from '@elastic/eui'; import { toMountPoint } from '../../../../../src/plugins/opensearch_dashboards_react/public'; import { Action } from '../../../../../src/plugins/ui_actions/public'; import { createADAction } from '../../action/ad_dashboard_action'; @@ -10,6 +10,7 @@ import { CoreServicesContext } from '../../../public/components/CoreServices/Cor import configureStore from '../../redux/configureStore'; import DocumentationTitle from '../../components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle'; import { AD_DOCS_LINK, APM_TRACE } from '../constants'; +import { CoreSetup } from '../../../../../src/core/public'; // This is used to create all actions in the same context menu const grouping: Action['grouping'] = [ @@ -20,7 +21,12 @@ const grouping: Action['grouping'] = [ }, ]; -export const getActions = ({ core, plugins }) => { +interface GetActionsProps { + core: CoreSetup; + plugins: any; +} + +export const getActions = ({ core, plugins }: GetActionsProps) => { const getOnClick = (startingFlyout) => async ({ embeddable }) => { From 8b12e8c64494b305c6ab2b100bf7771e0aff7866 Mon Sep 17 00:00:00 2001 From: Jackie Han Date: Thu, 18 May 2023 14:42:32 -0700 Subject: [PATCH 4/7] add EmbeddableStart Signed-off-by: Jackie Han --- .../AnywhereParentFlyout.tsx | 4 +- public/plugin.ts | 85 +++++++++++-------- public/services.ts | 4 + public/utils/contextMenu/getActions.tsx | 4 +- 4 files changed, 56 insertions(+), 41 deletions(-) diff --git a/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx index cb35e7a8..2a54a169 100644 --- a/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx +++ b/public/components/FeatureAnywhereContextMenu/AnywhereParentFlyout/AnywhereParentFlyout.tsx @@ -5,12 +5,14 @@ import React, { useState } from 'react'; import { get } from 'lodash'; import AddAnomalyDetector from '../CreateAnomalyDetector'; +import { getEmbeddable } from '../../../../public/services'; const AnywhereParentFlyout = ({ startingFlyout, ...props }) => { - const { embeddable } = props; + const embeddable = getEmbeddable().getEmbeddableFactory; const indices: { label: string }[] = [ { label: get(embeddable, 'vis.data.indexPattern.title', '') }, ]; + const [mode, setMode] = useState(startingFlyout); const [selectedDetectorId, setSelectedDetectorId] = useState(); diff --git a/public/plugin.ts b/public/plugin.ts index d08f6c2d..c724668a 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -15,12 +15,12 @@ import { CoreStart, Plugin, } from '../../../src/core/public'; -import { CONTEXT_MENU_TRIGGER } from '../../../src/plugins/embeddable/public'; +import { CONTEXT_MENU_TRIGGER, EmbeddableSetup, EmbeddableStart } from '../../../src/plugins/embeddable/public'; import { ACTION_AD } from './action/ad_dashboard_action'; import { PLUGIN_NAME } from './utils/constants'; import { getActions } from './utils/contextMenu/getActions'; import { overlayAnomaliesFunction } from './expressions/overlay_anomalies'; -import { setClient } from './services'; +import { setClient, setEmbeddable } from './services'; import { AnomalyDetectionOpenSearchDashboardsPluginStart } from 'public'; declare module '../../../src/plugins/ui_actions/public' { @@ -29,44 +29,55 @@ declare module '../../../src/plugins/ui_actions/public' { } } -export class AnomalyDetectionOpenSearchDashboardsPlugin implements Plugin { - public setup(core: CoreSetup, plugins: any) { - core.application.register({ - id: PLUGIN_NAME, - title: 'Anomaly Detection', - category: { - id: 'opensearch', - label: 'OpenSearch Plugins', - order: 2000, - }, - order: 5000, - mount: async (params: AppMountParameters) => { - const { renderApp } = await import('./anomaly_detection_app'); - const [coreStart] = await core.getStartServices(); - return renderApp(coreStart, params); - }, - }); +export interface AnomalyDetectionSetupDeps { + embeddable: EmbeddableSetup; +} - // Create context menu actions. Pass core, to access service for flyouts. - const actions = getActions({ core }); +export interface AnomalyDetectionStartDeps { + embeddable: EmbeddableStart; +} - // Add actions to uiActions - actions.forEach((action) => { - plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, action); - }); +export class AnomalyDetectionOpenSearchDashboardsPlugin implements + Plugin { + public setup(core: CoreSetup, plugins: any) { + core.application.register({ + id: PLUGIN_NAME, + title: 'Anomaly Detection', + category: { + id: 'opensearch', + label: 'OpenSearch Plugins', + order: 2000, + }, + order: 5000, + mount: async (params: AppMountParameters) => { + const { renderApp } = await import('./anomaly_detection_app'); + const [coreStart] = await core.getStartServices(); + return renderApp(coreStart, params); + }, + }); - // Set the HTTP client so it can be pulled into expression fns to make - // direct server-side calls - setClient(core.http); + // Set the HTTP client so it can be pulled into expression fns to make + // direct server-side calls + setClient(core.http); - // registers the expression function used to render anomalies on an Augmented Visualization - plugins.expressions.registerFunction(overlayAnomaliesFunction); - return {}; - } + // Create context menu actions. Pass core, to access service for flyouts. + const actions = getActions({ core }); - public start( - core: CoreStart - ): AnomalyDetectionOpenSearchDashboardsPluginStart { - return {}; - } + // Add actions to uiActions + actions.forEach((action) => { + plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, action); + }); + + // registers the expression function used to render anomalies on an Augmented Visualization + plugins.expressions.registerFunction(overlayAnomaliesFunction); + return {}; + } + + public start( + core: CoreStart, + {embeddable }: AnomalyDetectionStartDeps + ): AnomalyDetectionOpenSearchDashboardsPluginStart { + setEmbeddable(embeddable); + return {}; + } } \ No newline at end of file diff --git a/public/services.ts b/public/services.ts index d9161693..99915e03 100644 --- a/public/services.ts +++ b/public/services.ts @@ -4,6 +4,7 @@ */ import { CoreStart } from '../../../src/core/public'; +import { EmbeddableStart } from '../../../src/plugins/embeddable/public'; import { createGetterSetter } from '../../../src/plugins/opensearch_dashboards_utils/public'; import { SavedObjectLoader } from '../../../src/plugins/saved_objects/public'; @@ -12,3 +13,6 @@ export const [getSavedFeatureAnywhereLoader, setSavedFeatureAnywhereLoader] = export const [getClient, setClient] = createGetterSetter('http'); + +export const [getEmbeddable, setEmbeddable] = + createGetterSetter('Embeddable'); diff --git a/public/utils/contextMenu/getActions.tsx b/public/utils/contextMenu/getActions.tsx index 5b661e62..debba806 100644 --- a/public/utils/contextMenu/getActions.tsx +++ b/public/utils/contextMenu/getActions.tsx @@ -23,10 +23,9 @@ const grouping: Action['grouping'] = [ interface GetActionsProps { core: CoreSetup; - plugins: any; } -export const getActions = ({ core, plugins }: GetActionsProps) => { +export const getActions = ({ core }: GetActionsProps) => { const getOnClick = (startingFlyout) => async ({ embeddable }) => { @@ -42,7 +41,6 @@ export const getActions = ({ core, plugins }: GetActionsProps) => { {...{ startingFlyout, embeddable, - plugins, closeFlyout: () => overlay.close(), core, services, From e145bd308396926bac27ebe38a1b7da3dffca797 Mon Sep 17 00:00:00 2001 From: Jackie Han Date: Fri, 19 May 2023 13:36:44 -0700 Subject: [PATCH 5/7] remove spread operator Signed-off-by: Jackie Han --- public/utils/contextMenu/getActions.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/public/utils/contextMenu/getActions.tsx b/public/utils/contextMenu/getActions.tsx index debba806..ee7678c0 100644 --- a/public/utils/contextMenu/getActions.tsx +++ b/public/utils/contextMenu/getActions.tsx @@ -10,7 +10,6 @@ import { CoreServicesContext } from '../../../public/components/CoreServices/Cor import configureStore from '../../redux/configureStore'; import DocumentationTitle from '../../components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle'; import { AD_DOCS_LINK, APM_TRACE } from '../constants'; -import { CoreSetup } from '../../../../../src/core/public'; // This is used to create all actions in the same context menu const grouping: Action['grouping'] = [ @@ -21,6 +20,7 @@ const grouping: Action['grouping'] = [ }, ]; + interface GetActionsProps { core: CoreSetup; } @@ -29,6 +29,7 @@ export const getActions = ({ core }: GetActionsProps) => { const getOnClick = (startingFlyout) => async ({ embeddable }) => { + //const services = core; const services = await core.getStartServices(); const openFlyout = services[0].overlays.openFlyout; const http = services[0].http; @@ -38,13 +39,10 @@ export const getActions = ({ core }: GetActionsProps) => { overlay.close(), - core, - services, - }} + startingFlyout={startingFlyout} + embeddable={embeddable} + closeFlyout={() => overlay.close()} + services={services} /> From 8a37e4c5fb6c0266a60405f781f5fe572d0e68e7 Mon Sep 17 00:00:00 2001 From: Jackie Han Date: Fri, 19 May 2023 13:51:39 -0700 Subject: [PATCH 6/7] clenaup Signed-off-by: Jackie Han --- public/utils/contextMenu/getActions.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/public/utils/contextMenu/getActions.tsx b/public/utils/contextMenu/getActions.tsx index ee7678c0..08bd395a 100644 --- a/public/utils/contextMenu/getActions.tsx +++ b/public/utils/contextMenu/getActions.tsx @@ -29,7 +29,6 @@ export const getActions = ({ core }: GetActionsProps) => { const getOnClick = (startingFlyout) => async ({ embeddable }) => { - //const services = core; const services = await core.getStartServices(); const openFlyout = services[0].overlays.openFlyout; const http = services[0].http; From 152ba99ce7e3537911d2eb6cf26cbb80393bfa18 Mon Sep 17 00:00:00 2001 From: Jackie Han Date: Fri, 19 May 2023 14:08:58 -0700 Subject: [PATCH 7/7] add overlay getter and setter Signed-off-by: Jackie Han --- public/plugin.ts | 7 +++++-- public/services.ts | 5 ++++- public/utils/contextMenu/getActions.tsx | 21 ++++++--------------- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/public/plugin.ts b/public/plugin.ts index c724668a..36e15cc3 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -20,8 +20,9 @@ import { ACTION_AD } from './action/ad_dashboard_action'; import { PLUGIN_NAME } from './utils/constants'; import { getActions } from './utils/contextMenu/getActions'; import { overlayAnomaliesFunction } from './expressions/overlay_anomalies'; -import { setClient, setEmbeddable } from './services'; +import { setClient, setEmbeddable, setOverlays } from './services'; import { AnomalyDetectionOpenSearchDashboardsPluginStart } from 'public'; +import { createStartServicesGetter } from '../../../src/plugins/opensearch_dashboards_utils/public'; declare module '../../../src/plugins/ui_actions/public' { export interface ActionContextMapping { @@ -39,6 +40,7 @@ export interface AnomalyDetectionStartDeps { export class AnomalyDetectionOpenSearchDashboardsPlugin implements Plugin { + public setup(core: CoreSetup, plugins: any) { core.application.register({ id: PLUGIN_NAME, @@ -61,7 +63,7 @@ export class AnomalyDetectionOpenSearchDashboardsPlugin implements setClient(core.http); // Create context menu actions. Pass core, to access service for flyouts. - const actions = getActions({ core }); + const actions = getActions(); // Add actions to uiActions actions.forEach((action) => { @@ -78,6 +80,7 @@ export class AnomalyDetectionOpenSearchDashboardsPlugin implements {embeddable }: AnomalyDetectionStartDeps ): AnomalyDetectionOpenSearchDashboardsPluginStart { setEmbeddable(embeddable); + setOverlays(core.overlays); return {}; } } \ No newline at end of file diff --git a/public/services.ts b/public/services.ts index 99915e03..3857a95f 100644 --- a/public/services.ts +++ b/public/services.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { CoreStart } from '../../../src/core/public'; +import { CoreStart, OverlayStart } from '../../../src/core/public'; import { EmbeddableStart } from '../../../src/plugins/embeddable/public'; import { createGetterSetter } from '../../../src/plugins/opensearch_dashboards_utils/public'; import { SavedObjectLoader } from '../../../src/plugins/saved_objects/public'; @@ -16,3 +16,6 @@ export const [getClient, setClient] = export const [getEmbeddable, setEmbeddable] = createGetterSetter('Embeddable'); + +export const [getOverlays, setOverlays] = + createGetterSetter('Overlays'); diff --git a/public/utils/contextMenu/getActions.tsx b/public/utils/contextMenu/getActions.tsx index 08bd395a..4dcb05f6 100644 --- a/public/utils/contextMenu/getActions.tsx +++ b/public/utils/contextMenu/getActions.tsx @@ -6,10 +6,10 @@ import { Action } from '../../../../../src/plugins/ui_actions/public'; import { createADAction } from '../../action/ad_dashboard_action'; import AnywhereParentFlyout from '../../components/FeatureAnywhereContextMenu/AnywhereParentFlyout'; import { Provider } from 'react-redux'; -import { CoreServicesContext } from '../../../public/components/CoreServices/CoreServices'; import configureStore from '../../redux/configureStore'; import DocumentationTitle from '../../components/FeatureAnywhereContextMenu/DocumentationTitle/containers/DocumentationTitle'; import { AD_DOCS_LINK, APM_TRACE } from '../constants'; +import { getClient, getOverlays } from '../../../public/services'; // This is used to create all actions in the same context menu const grouping: Action['grouping'] = [ @@ -20,30 +20,21 @@ const grouping: Action['grouping'] = [ }, ]; - -interface GetActionsProps { - core: CoreSetup; -} - -export const getActions = ({ core }: GetActionsProps) => { +export const getActions = () => { const getOnClick = (startingFlyout) => async ({ embeddable }) => { - const services = await core.getStartServices(); - const openFlyout = services[0].overlays.openFlyout; - const http = services[0].http; - const store = configureStore(http); + const overlayService = getOverlays(); + const openFlyout = overlayService.openFlyout; + const store = configureStore(getClient()); const overlay = openFlyout( toMountPoint( - - overlay.close()} - services={services} /> - ), { size: 'm', className: 'context-menu__flyout' }