From 1093a3f750e5cd4f74cddb2bce0473f035d40381 Mon Sep 17 00:00:00 2001 From: Amardeepsingh Siglani Date: Thu, 11 May 2023 01:03:18 -0700 Subject: [PATCH] refactored to use event bus for notifying click on annotation Signed-off-by: Amardeepsingh Siglani --- src/plugins/ui_actions/public/index.ts | 2 + .../triggers/external_action_trigger.ts | 44 +++++++++++++++ .../ui_actions/public/triggers/index.ts | 1 + src/plugins/ui_actions/public/types.ts | 2 + .../vis_augmenter/public/test_constants.ts | 26 +-------- .../vis_augmenter/public/vega/constants.ts | 9 +-- .../vis_augmenter/public/vega/helpers.test.ts | 10 ---- .../vis_augmenter/public/vega/helpers.ts | 55 +------------------ .../vis_type_vega/public/data_model/types.ts | 6 -- .../public/data_model/vega_parser.ts | 5 -- .../public/expressions/line_vega_spec_fn.ts | 2 - .../public/vega_view/vega_base_view.js | 15 ++--- .../public/vega_visualization.js | 1 + .../public/embeddable/events.ts | 3 + .../visualizations/public/expressions/vis.ts | 5 ++ 15 files changed, 73 insertions(+), 113 deletions(-) create mode 100644 src/plugins/ui_actions/public/triggers/external_action_trigger.ts diff --git a/src/plugins/ui_actions/public/index.ts b/src/plugins/ui_actions/public/index.ts index 3560f473d33b..489cb5eee363 100644 --- a/src/plugins/ui_actions/public/index.ts +++ b/src/plugins/ui_actions/public/index.ts @@ -61,6 +61,8 @@ export { visualizeFieldTrigger, VISUALIZE_GEO_FIELD_TRIGGER, visualizeGeoFieldTrigger, + EXTERNAL_ACTION_TRIGGER, + externalActionTrigger, } from './triggers'; export { TriggerContextMapping, diff --git a/src/plugins/ui_actions/public/triggers/external_action_trigger.ts b/src/plugins/ui_actions/public/triggers/external_action_trigger.ts new file mode 100644 index 000000000000..87941fd47b88 --- /dev/null +++ b/src/plugins/ui_actions/public/triggers/external_action_trigger.ts @@ -0,0 +1,44 @@ +/* + * 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. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@osd/i18n'; +import { Trigger } from '.'; + +export const EXTERNAL_ACTION_TRIGGER = 'EXTERNAL_ACTION_TRIGGER'; +export const externalActionTrigger: Trigger<'EXTERNAL_ACTION_TRIGGER'> = { + id: EXTERNAL_ACTION_TRIGGER, + title: i18n.translate('uiActions.triggers.externalActionTitle', { + defaultMessage: 'Single click', + }), + description: i18n.translate('uiActions.triggers.externalActionDescription', { + defaultMessage: + 'A data point click on the visualization used to trigger external action like show flyout, etc.', + }), +}; diff --git a/src/plugins/ui_actions/public/triggers/index.ts b/src/plugins/ui_actions/public/triggers/index.ts index 2d012df76e08..0fcbbc4ee3fa 100644 --- a/src/plugins/ui_actions/public/triggers/index.ts +++ b/src/plugins/ui_actions/public/triggers/index.ts @@ -36,4 +36,5 @@ export * from './value_click_trigger'; export * from './apply_filter_trigger'; export * from './visualize_field_trigger'; export * from './visualize_geo_field_trigger'; +export * from './external_action_trigger'; export * from './default_trigger'; diff --git a/src/plugins/ui_actions/public/types.ts b/src/plugins/ui_actions/public/types.ts index 0c32a96755fe..8920e878d0df 100644 --- a/src/plugins/ui_actions/public/types.ts +++ b/src/plugins/ui_actions/public/types.ts @@ -36,6 +36,7 @@ import { APPLY_FILTER_TRIGGER, VISUALIZE_FIELD_TRIGGER, VISUALIZE_GEO_FIELD_TRIGGER, + EXTERNAL_ACTION_TRIGGER, DEFAULT_TRIGGER, } from './triggers'; import type { RangeSelectContext, ValueClickContext } from '../../embeddable/public'; @@ -63,6 +64,7 @@ export interface TriggerContextMapping { [APPLY_FILTER_TRIGGER]: ApplyGlobalFilterActionContext; [VISUALIZE_FIELD_TRIGGER]: VisualizeFieldContext; [VISUALIZE_GEO_FIELD_TRIGGER]: VisualizeFieldContext; + [EXTERNAL_ACTION_TRIGGER]: ValueClickContext; } const DEFAULT_ACTION = ''; diff --git a/src/plugins/vis_augmenter/public/test_constants.ts b/src/plugins/vis_augmenter/public/test_constants.ts index 4a8a4047ed5d..8bea01517137 100644 --- a/src/plugins/vis_augmenter/public/test_constants.ts +++ b/src/plugins/vis_augmenter/public/test_constants.ts @@ -5,7 +5,7 @@ import { OpenSearchDashboardsDatatable } from '../../expressions/public'; import { VIS_LAYER_COLUMN_TYPE, VisLayerTypes, HOVER_PARAM } from './'; -import { VisInteraction, VisInteractionEventHandlerName } from './vega/constants'; +import { VisAnnotationType } from './vega/constants'; const TEST_X_AXIS_ID = 'test-x-axis-id'; const TEST_VALUE_AXIS_ID = 'test-value-axis-id'; @@ -460,7 +460,7 @@ const TEST_EVENTS_LAYER_SINGLE_VIS_LAYER = { }, transform: [ { filter: `datum['${TEST_PLUGIN_RESOURCE_ID}'] > 0` }, - { calculate: `'${VisInteraction.POINT_IN_TIME_ANNOTATION}'`, as: 'annotationType' }, + { calculate: `'${VisAnnotationType.POINT_IN_TIME_ANNOTATION}'`, as: 'annotationType' }, ], params: [{ name: HOVER_PARAM, select: { type: 'point', on: 'mouseover' } }], encoding: { @@ -507,7 +507,7 @@ const TEST_EVENTS_LAYER_MULTIPLE_VIS_LAYERS = { { filter: `datum['${TEST_PLUGIN_RESOURCE_ID}'] > 0 || datum['${TEST_PLUGIN_RESOURCE_ID_2}'] > 0`, }, - { calculate: `'${VisInteraction.POINT_IN_TIME_ANNOTATION}'`, as: 'annotationType' }, + { calculate: `'${VisAnnotationType.POINT_IN_TIME_ANNOTATION}'`, as: 'annotationType' }, ], }; @@ -577,23 +577,3 @@ export const TEST_RESULT_SPEC_MULTIPLE_VIS_LAYERS = { TEST_EVENTS_LAYER_MULTIPLE_VIS_LAYERS, ], }; - -export const TEST_RESULT_SPEC_WITH_VIS_INTERACTION_CONFIG = { - ...TEST_SPEC_NO_VIS_LAYERS, - config: { - ...TEST_SPEC_NO_VIS_LAYERS.config, - kibana: { - ...(TEST_SPEC_NO_VIS_LAYERS.config.kibana || {}), - visInteractions: [ - { - event: 'click', - handlerName: VisInteractionEventHandlerName.POINT_IN_TIME_CLICK_EVENT_HANDLER, - }, - { - event: 'mouseover', - handlerName: VisInteractionEventHandlerName.POINT_IN_TIME_HOVER_IN_EVENT_HANDLER, - }, - ], - }, - }, -}; diff --git a/src/plugins/vis_augmenter/public/vega/constants.ts b/src/plugins/vis_augmenter/public/vega/constants.ts index e9c6fa5712a9..a5729725422e 100644 --- a/src/plugins/vis_augmenter/public/vega/constants.ts +++ b/src/plugins/vis_augmenter/public/vega/constants.ts @@ -3,11 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -export enum VisInteraction { - POINT_IN_TIME_ANNOTATION = 'POINT_IN_TIME_DATA_POINT', -} - -export enum VisInteractionEventHandlerName { - POINT_IN_TIME_CLICK_EVENT_HANDLER = 'visAugmenter.pointInTimeClickEventHandler', - POINT_IN_TIME_HOVER_IN_EVENT_HANDLER = 'visAugmenter.pointInTimeHoverInEventHandler', +export enum VisAnnotationType { + POINT_IN_TIME_ANNOTATION = 'POINT_IN_TIME_ANNOTATION', } diff --git a/src/plugins/vis_augmenter/public/vega/helpers.test.ts b/src/plugins/vis_augmenter/public/vega/helpers.test.ts index fb4c779ab733..924179ce9182 100644 --- a/src/plugins/vis_augmenter/public/vega/helpers.test.ts +++ b/src/plugins/vis_augmenter/public/vega/helpers.test.ts @@ -15,7 +15,6 @@ import { addMissingRowsToTableBounds, addPointInTimeEventsLayersToTable, addPointInTimeEventsLayersToSpec, - addPointInTimeInteractionsConfig, } from './helpers'; import { VIS_LAYER_COLUMN_TYPE, VisLayerTypes, PointInTimeEventsVisLayer, VisLayer } from '../'; import { @@ -457,13 +456,4 @@ describe('helpers', function () { expect(returnSpec).toEqual(expectedSpec); }); }); - - describe('addPointInTimeInteractionsConfig()', function () { - it('appends interactions config to the provided config from visualization spec', function () { - const expectedSpec = TEST_RESULT_SPEC_WITH_VIS_INTERACTION_CONFIG; - const testSpec = { ...TEST_SPEC_NO_VIS_LAYERS }; - testSpec.config = addPointInTimeInteractionsConfig(TEST_SPEC_NO_VIS_LAYERS.config) as any; - expect(testSpec).toEqual(expectedSpec); - }); - }); }); diff --git a/src/plugins/vis_augmenter/public/vega/helpers.ts b/src/plugins/vis_augmenter/public/vega/helpers.ts index 297c0f01e999..b80d2e3c8a31 100644 --- a/src/plugins/vis_augmenter/public/vega/helpers.ts +++ b/src/plugins/vis_augmenter/public/vega/helpers.ts @@ -5,7 +5,7 @@ import moment from 'moment'; import { cloneDeep, isEmpty, get } from 'lodash'; -import { Item, ScenegraphEvent } from 'vega'; +import { Item } from 'vega'; import { OpenSearchDashboardsDatatable, OpenSearchDashboardsDatatableColumn, @@ -25,7 +25,7 @@ import { VisLayers, VisLayerTypes, } from '../'; -import { VisInteractionEventHandlerName, VisInteraction as VisAnnotationType } from './constants'; +import { VisAnnotationType } from './constants'; // Given any visLayers, create a map to indicate which VisLayer types are present. // Convert to an array since ES6 Maps cannot be stringified. @@ -346,57 +346,6 @@ export const addPointInTimeEventsLayersToSpec = ( return newSpec; }; -/** - * Interaction handling functions mapped by their action names. - */ -export const interactionHandlersByAction = { - [VisInteractionEventHandlerName.POINT_IN_TIME_CLICK_EVENT_HANDLER]: ( - _event: ScenegraphEvent, - item?: Item | null - ) => { - if (isPointInTimeAnnotation(item)) { - // TODO: Show the events flyout - } - }, - [VisInteractionEventHandlerName.POINT_IN_TIME_HOVER_IN_EVENT_HANDLER]: ( - _event: ScenegraphEvent, - item?: Item | null - ) => { - if (isPointInTimeAnnotation(item)) { - // TODO: Show the custom tooltip - } - }, -}; - -/** - * Updating the vega-lite spec to add interaction config that is used to add event handlers on the visualization view. - * Note: Since, we cannot have handler functions added directly to the spec object as it is stringified, - * we pass the handler names as part of the config and use the @see interactionHandlersByAction to get the corresponding - * handler when required. - */ -export const addPointInTimeInteractionsConfig = (config: object) => { - const kibana = get(config, 'kibana', {}); - const withInteractionsConfig = { - ...kibana, - visInteractions: [ - ...(kibana.visInteractions || []), - { - event: 'click', - handlerName: VisInteractionEventHandlerName.POINT_IN_TIME_CLICK_EVENT_HANDLER, - }, - { - event: 'mouseover', - handlerName: VisInteractionEventHandlerName.POINT_IN_TIME_HOVER_IN_EVENT_HANDLER, - }, - ], - }; - - return { - ...config, - kibana: withInteractionsConfig, - }; -}; - export const isPointInTimeAnnotation = (item?: Item | null) => { return item?.datum?.annotationType === VisAnnotationType.POINT_IN_TIME_ANNOTATION; }; diff --git a/src/plugins/vis_type_vega/public/data_model/types.ts b/src/plugins/vis_type_vega/public/data_model/types.ts index a842e0b0244e..b5db91558c03 100644 --- a/src/plugins/vis_type_vega/public/data_model/types.ts +++ b/src/plugins/vis_type_vega/public/data_model/types.ts @@ -108,11 +108,6 @@ type ContextVarsObjectProps = type ToolTipPositions = 'top' | 'right' | 'bottom' | 'left'; -export interface VisInteractionDescriptor { - event: string; - handlerName: string; -} - export interface OpenSearchDashboards { controlsLocation: ControlsLocation; controlsDirection: ControlsDirection; @@ -120,7 +115,6 @@ export interface OpenSearchDashboards { type: string; renderer: Renderer; visibleVisLayers?: Map; - visInteractions?: VisInteractionDescriptor[]; } export interface VegaSpec { diff --git a/src/plugins/vis_type_vega/public/data_model/vega_parser.ts b/src/plugins/vis_type_vega/public/data_model/vega_parser.ts index 4eb699ba45ab..187c4690aad5 100644 --- a/src/plugins/vis_type_vega/public/data_model/vega_parser.ts +++ b/src/plugins/vis_type_vega/public/data_model/vega_parser.ts @@ -57,7 +57,6 @@ import { ControlsLocation, ControlsDirection, OpenSearchDashboards, - VisInteractionDescriptor, } from './types'; // Set default single color to match other OpenSearch Dashboards visualizations @@ -95,7 +94,6 @@ export class VegaParser { filters: Bool; timeCache: TimeCache; visibleVisLayers: Map; - visInteractions?: VisInteractionDescriptor[]; constructor( spec: VegaSpec | string, @@ -411,9 +409,6 @@ The URL is an identifier only. OpenSearch Dashboards and your browser will never if (result.visibleVisLayers !== undefined && Array.isArray(result.visibleVisLayers)) { result.visibleVisLayers = new Map(result.visibleVisLayers); } - if (result.visInteractions) { - this.visInteractions = result.visInteractions; - } } } return result || {}; diff --git a/src/plugins/vis_type_vega/public/expressions/line_vega_spec_fn.ts b/src/plugins/vis_type_vega/public/expressions/line_vega_spec_fn.ts index 6205aa789f60..499310c106d2 100644 --- a/src/plugins/vis_type_vega/public/expressions/line_vega_spec_fn.ts +++ b/src/plugins/vis_type_vega/public/expressions/line_vega_spec_fn.ts @@ -18,7 +18,6 @@ import { addPointInTimeEventsLayersToTable, addPointInTimeEventsLayersToSpec, enableVisLayersInSpecConfig, - addPointInTimeInteractionsConfig, } from '../../../vis_augmenter/public'; import { formatDatatable, createSpecFromDatatable } from './helpers'; import { VegaVisualizationDependencies } from '../plugin'; @@ -86,7 +85,6 @@ export const createLineVegaSpecFn = ( if (!isEmpty(pointInTimeEventsVisLayers) && dimensions.x !== null) { spec = addPointInTimeEventsLayersToSpec(table, dimensions, spec); spec.config = enableVisLayersInSpecConfig(spec, pointInTimeEventsVisLayers); - spec.config = addPointInTimeInteractionsConfig(spec.config); } return JSON.stringify(spec); }, diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js b/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js index d3945c831517..2fefa8fae686 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js +++ b/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js @@ -40,7 +40,6 @@ import { opensearchFilters } from '../../../data/public'; import { getEnableExternalUrls, getData } from '../services'; import { extractIndexPatternsFromSpec } from '../lib/extract_index_pattern'; -import { interactionHandlersByAction } from '../../../vis_augmenter/public'; vega.scheme('euiPaletteColorBlind', euiPaletteColorBlind()); @@ -77,6 +76,7 @@ export class VegaBaseView { this._serviceSettings = opts.serviceSettings; this._filterManager = opts.filterManager; this._applyFilter = opts.applyFilter; + this._triggerExternalAction = opts.externalAction; this._timefilter = opts.timefilter; this._view = null; this._vegaViewConfig = null; @@ -298,13 +298,14 @@ export class VegaBaseView { this._addDestroyHandler(() => tthandler.hideTooltip()); } - if (this._parser.visInteractions) { - this._parser.visInteractions.forEach(({ handlerName, event }) => { - if (interactionHandlersByAction[handlerName]) { - view.addEventListener(event, interactionHandlersByAction[handlerName]); - } + ['click', 'mouseover', 'mouseout'].forEach((eventName) => { + view.addEventListener(eventName, (event, item) => { + this._triggerExternalAction({ + event, + data: { item }, + }); }); - } + }); return view.runAsync(); // Allows callers to await rendering } diff --git a/src/plugins/vis_type_vega/public/vega_visualization.js b/src/plugins/vis_type_vega/public/vega_visualization.js index af5c58f8a149..379670bda413 100644 --- a/src/plugins/vis_type_vega/public/vega_visualization.js +++ b/src/plugins/vis_type_vega/public/vega_visualization.js @@ -90,6 +90,7 @@ export const createVegaVisualization = ({ getServiceSettings }) => serviceSettings, filterManager, timefilter, + externalAction: this._vis.API.events.externalAction, }; if (vegaParser.useMap) { diff --git a/src/plugins/visualizations/public/embeddable/events.ts b/src/plugins/visualizations/public/embeddable/events.ts index 2a17ef9d5ef3..3d34cfe49959 100644 --- a/src/plugins/visualizations/public/embeddable/events.ts +++ b/src/plugins/visualizations/public/embeddable/events.ts @@ -32,16 +32,19 @@ import { APPLY_FILTER_TRIGGER, SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER, + EXTERNAL_ACTION_TRIGGER, } from '../../../ui_actions/public'; export interface VisEventToTrigger { ['applyFilter']: typeof APPLY_FILTER_TRIGGER; ['brush']: typeof SELECT_RANGE_TRIGGER; ['filter']: typeof VALUE_CLICK_TRIGGER; + ['externalAction']: typeof EXTERNAL_ACTION_TRIGGER; } export const VIS_EVENT_TO_TRIGGER: VisEventToTrigger = { applyFilter: APPLY_FILTER_TRIGGER, brush: SELECT_RANGE_TRIGGER, filter: VALUE_CLICK_TRIGGER, + externalAction: EXTERNAL_ACTION_TRIGGER, }; diff --git a/src/plugins/visualizations/public/expressions/vis.ts b/src/plugins/visualizations/public/expressions/vis.ts index acf747973dee..02f13ab2ad8d 100644 --- a/src/plugins/visualizations/public/expressions/vis.ts +++ b/src/plugins/visualizations/public/expressions/vis.ts @@ -55,6 +55,7 @@ export interface ExprVisAPIEvents { filter: (data: any) => void; brush: (data: any) => void; applyFilter: (data: any) => void; + externalAction: (data: any) => void; } export interface ExprVisAPI { @@ -99,6 +100,10 @@ export class ExprVis extends EventEmitter { if (!this.eventsSubject) return; this.eventsSubject.next({ name: 'applyFilter', data }); }, + externalAction: (data: any) => { + if (!this.eventsSubject) return; + this.eventsSubject.next({ name: 'externalAction', data }); + }, }, }; }