Skip to content

Commit

Permalink
refactored to use event bus for notifying click on annotation
Browse files Browse the repository at this point in the history
Signed-off-by: Amardeepsingh Siglani <amardeep7194@gmail.com>
  • Loading branch information
amsiglan committed May 11, 2023
1 parent 13608ed commit 1093a3f
Show file tree
Hide file tree
Showing 15 changed files with 73 additions and 113 deletions.
2 changes: 2 additions & 0 deletions src/plugins/ui_actions/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ export {
visualizeFieldTrigger,
VISUALIZE_GEO_FIELD_TRIGGER,
visualizeGeoFieldTrigger,
EXTERNAL_ACTION_TRIGGER,
externalActionTrigger,
} from './triggers';
export {
TriggerContextMapping,
Expand Down
44 changes: 44 additions & 0 deletions src/plugins/ui_actions/public/triggers/external_action_trigger.ts
Original file line number Diff line number Diff line change
@@ -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.',
}),
};
1 change: 1 addition & 0 deletions src/plugins/ui_actions/public/triggers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
2 changes: 2 additions & 0 deletions src/plugins/ui_actions/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 = '';
Expand Down
26 changes: 3 additions & 23 deletions src/plugins/vis_augmenter/public/test_constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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' },
],
};

Expand Down Expand Up @@ -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,
},
],
},
},
};
9 changes: 2 additions & 7 deletions src/plugins/vis_augmenter/public/vega/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
}
10 changes: 0 additions & 10 deletions src/plugins/vis_augmenter/public/vega/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
addMissingRowsToTableBounds,
addPointInTimeEventsLayersToTable,
addPointInTimeEventsLayersToSpec,
addPointInTimeInteractionsConfig,
} from './helpers';
import { VIS_LAYER_COLUMN_TYPE, VisLayerTypes, PointInTimeEventsVisLayer, VisLayer } from '../';
import {
Expand Down Expand Up @@ -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);
});
});
});
55 changes: 2 additions & 53 deletions src/plugins/vis_augmenter/public/vega/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.
Expand Down Expand Up @@ -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;
};
6 changes: 0 additions & 6 deletions src/plugins/vis_type_vega/public/data_model/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,13 @@ type ContextVarsObjectProps =

type ToolTipPositions = 'top' | 'right' | 'bottom' | 'left';

export interface VisInteractionDescriptor {
event: string;
handlerName: string;
}

export interface OpenSearchDashboards {
controlsLocation: ControlsLocation;
controlsDirection: ControlsDirection;
hideWarnings: boolean;
type: string;
renderer: Renderer;
visibleVisLayers?: Map<VisLayerTypes, boolean>;
visInteractions?: VisInteractionDescriptor[];
}

export interface VegaSpec {
Expand Down
5 changes: 0 additions & 5 deletions src/plugins/vis_type_vega/public/data_model/vega_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ import {
ControlsLocation,
ControlsDirection,
OpenSearchDashboards,
VisInteractionDescriptor,
} from './types';

// Set default single color to match other OpenSearch Dashboards visualizations
Expand Down Expand Up @@ -95,7 +94,6 @@ export class VegaParser {
filters: Bool;
timeCache: TimeCache;
visibleVisLayers: Map<VisLayerTypes, boolean>;
visInteractions?: VisInteractionDescriptor[];

constructor(
spec: VegaSpec | string,
Expand Down Expand Up @@ -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<VisLayerTypes, boolean>(result.visibleVisLayers);
}
if (result.visInteractions) {
this.visInteractions = result.visInteractions;
}
}
}
return result || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
addPointInTimeEventsLayersToTable,
addPointInTimeEventsLayersToSpec,
enableVisLayersInSpecConfig,
addPointInTimeInteractionsConfig,
} from '../../../vis_augmenter/public';
import { formatDatatable, createSpecFromDatatable } from './helpers';
import { VegaVisualizationDependencies } from '../plugin';
Expand Down Expand Up @@ -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);
},
Expand Down
15 changes: 8 additions & 7 deletions src/plugins/vis_type_vega/public/vega_view/vega_base_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
}
Expand Down
1 change: 1 addition & 0 deletions src/plugins/vis_type_vega/public/vega_visualization.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export const createVegaVisualization = ({ getServiceSettings }) =>
serviceSettings,
filterManager,
timefilter,
externalAction: this._vis.API.events.externalAction,
};

if (vegaParser.useMap) {
Expand Down
3 changes: 3 additions & 0 deletions src/plugins/visualizations/public/embeddable/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
5 changes: 5 additions & 0 deletions src/plugins/visualizations/public/expressions/vis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 });
},
},
};
}
Expand Down

0 comments on commit 1093a3f

Please sign in to comment.