diff --git a/src/plugins/vis_augmenter/common/types.ts b/src/plugins/vis_augmenter/common/types.ts deleted file mode 100644 index ceb8b1973ba7..000000000000 --- a/src/plugins/vis_augmenter/common/types.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { ExpressionFunctionDefinition } from '../../expressions'; - -export enum VisLayerTypes { - PointInTimeEvents = 'PointInTimeEvents', -} - -export type PluginResourceType = string; - -export interface PluginResource { - type: PluginResourceType; - id: string; - name: string; - urlPath: string; -} - -export interface VisLayer { - type: keyof typeof VisLayerTypes; - originPlugin: string; - pluginResource: PluginResource; -} - -export type VisLayers = VisLayer[]; - -export interface EventMetadata { - pluginResourceId: string; - tooltip?: string; -} - -export interface PointInTimeEvent { - timestamp: number; - metadata: EventMetadata; -} - -export interface PointInTimeEventsVisLayer extends VisLayer { - events: PointInTimeEvent[]; -} - -export const isPointInTimeEventsVisLayer = (obj: any) => { - return obj?.type === VisLayerTypes.PointInTimeEvents; -}; - -export const isValidVisLayer = (obj: any) => { - return obj?.type in VisLayerTypes; -}; - -export interface VisLayerResponseValue { - visLayers: object; -} - -export type VisLayerFunctionDefinition = ExpressionFunctionDefinition< - string, - VisLayerResponseValue, - any, - Promise ->; diff --git a/src/plugins/vis_augmenter/public/expressions/index.ts b/src/plugins/vis_augmenter/public/expressions/index.ts index f7bcfbd083fe..9f269633f307 100644 --- a/src/plugins/vis_augmenter/public/expressions/index.ts +++ b/src/plugins/vis_augmenter/public/expressions/index.ts @@ -3,4 +3,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -export * from './vis_layers'; +export * from './types'; diff --git a/src/plugins/vis_augmenter/public/expressions/vis_layers.ts b/src/plugins/vis_augmenter/public/expressions/types.ts similarity index 56% rename from src/plugins/vis_augmenter/public/expressions/vis_layers.ts rename to src/plugins/vis_augmenter/public/expressions/types.ts index f99ead0407eb..b907e570e108 100644 --- a/src/plugins/vis_augmenter/public/expressions/vis_layers.ts +++ b/src/plugins/vis_augmenter/public/expressions/types.ts @@ -3,8 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { ExpressionTypeDefinition } from '../../../expressions'; -import { VisLayers } from '../../common'; +import { ExpressionTypeDefinition, ExpressionFunctionDefinition } from '../../../expressions'; +import { VisLayers, VisLayerTypes } from '../'; const name = 'vis_layers'; @@ -31,3 +31,17 @@ export const visLayers: ExpressionTypeDefinition = { }, }, }; + +export type VisLayerFunctionDefinition = ExpressionFunctionDefinition< + string, + ExprVisLayers, + any, + Promise +>; + +export interface VisLayerExpressionFn { + type: keyof typeof VisLayerTypes; + name: string; + // plugin expression fns can freely set custom arguments + args: { [key: string]: any }; +} diff --git a/src/plugins/vis_augmenter/public/index.ts b/src/plugins/vis_augmenter/public/index.ts index cf736bf6d3e6..e374cbe8d2cf 100644 --- a/src/plugins/vis_augmenter/public/index.ts +++ b/src/plugins/vis_augmenter/public/index.ts @@ -18,4 +18,8 @@ export { SavedObjectOpenSearchDashboardsServicesWithAugmentVis, } from './saved_augment_vis'; -export { ISavedAugmentVis, VisLayerExpressionFn, AugmentVisSavedObject } from './types'; +export { VisLayer, VisLayers, VisLayerTypes } from './types'; + +export * from './expressions'; +export * from './utils'; +export * from './saved_augment_vis'; diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/index.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/index.ts index 5ac3a159132e..ce1680204953 100644 --- a/src/plugins/vis_augmenter/public/saved_augment_vis/index.ts +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/index.ts @@ -5,3 +5,4 @@ export * from './saved_augment_vis'; export * from './utils'; +export * from './types'; diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.test.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.test.ts index bc44a0ed6dc2..51360f72c331 100644 --- a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.test.ts +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.test.ts @@ -3,8 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { VisLayerExpressionFn } from '../types'; -import { VisLayerTypes } from '../../common'; +import { VisLayerExpressionFn, VisLayerTypes } from '../types'; import { createSavedAugmentVisLoader, SavedObjectOpenSearchDashboardsServicesWithAugmentVis, @@ -19,15 +18,23 @@ describe('SavedObjectLoaderAugmentVis', () => { testArg: 'test-value', }, } as VisLayerExpressionFn; - const validObj1 = generateAugmentVisSavedObject('valid-obj-id-1', fn); - const validObj2 = generateAugmentVisSavedObject('valid-obj-id-2', fn); - const invalidFnTypeObj = generateAugmentVisSavedObject('invalid-fn-obj-id-1', { - ...fn, - // @ts-ignore - type: 'invalid-type', - }); - // @ts-ignore - const missingFnObj = generateAugmentVisSavedObject('missing-fn-obj-id-1', {}); + const validObj1 = generateAugmentVisSavedObject('valid-obj-id-1', fn, 'test-vis-id'); + const validObj2 = generateAugmentVisSavedObject('valid-obj-id-2', fn, 'test-vis-id'); + const invalidFnTypeObj = generateAugmentVisSavedObject( + 'invalid-fn-obj-id-1', + { + ...fn, + // @ts-ignore + type: 'invalid-type', + }, + 'test-vis-id' + ); + + const missingFnObj = generateAugmentVisSavedObject( + 'missing-fn-obj-id-1', + {} as VisLayerExpressionFn, + 'test-vis-id' + ); it('find returns single saved obj', async () => { const loader = createSavedAugmentVisLoader({ diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.ts index 82e6e24a7e3e..910ef0b9ea75 100644 --- a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.ts +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.ts @@ -9,7 +9,7 @@ import { SavedObjectOpenSearchDashboardsServices, } from '../../../saved_objects/public'; import { createSavedAugmentVisClass } from './_saved_augment_vis'; -import { VisLayerTypes } from '../../common'; +import { VisLayerTypes } from '../types'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface SavedObjectOpenSearchDashboardsServicesWithAugmentVis diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.test.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.test.ts index 4a19b84dc40e..1b5a0ad6cd98 100644 --- a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.test.ts +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.test.ts @@ -3,9 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { extractReferences, injectReferences } from './saved_augment_vis_references'; +import { + extractReferences, + injectReferences, + VIS_REFERENCE_NAME, +} from './saved_augment_vis_references'; import { AugmentVisSavedObject } from '../types'; -import { VIS_REFERENCE_NAME } from './saved_augment_vis_references'; describe('extractReferences()', () => { test('extracts nothing if visId is null', () => { diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/types.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/types.ts new file mode 100644 index 000000000000..dee349cb9001 --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/types.ts @@ -0,0 +1,20 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObject } from '../../../saved_objects/public'; +import { VisLayerExpressionFn } from '../expressions'; + +export interface ISavedAugmentVis { + id?: string; + title: string; + description?: string; + pluginResourceId: string; + visName?: string; + visId?: string; + visLayerExpressionFn: VisLayerExpressionFn; + version?: number; +} + +export interface AugmentVisSavedObject extends SavedObject, ISavedAugmentVis {} diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/utils/test_helpers.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/utils/test_helpers.ts index c237fa7551c3..9bbfb8940b27 100644 --- a/src/plugins/vis_augmenter/public/saved_augment_vis/utils/test_helpers.ts +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/utils/test_helpers.ts @@ -8,16 +8,21 @@ import { VisLayerExpressionFn, ISavedAugmentVis } from '../../types'; import { VIS_REFERENCE_NAME } from '../saved_augment_vis_references'; const pluginResourceId = 'test-plugin-resource-id'; -const visId = 'test-vis-id'; +const title = 'test-title'; const version = 1; -export const generateAugmentVisSavedObject = (idArg: string, exprFnArg: VisLayerExpressionFn) => { +export const generateAugmentVisSavedObject = ( + idArg: string, + exprFnArg: VisLayerExpressionFn, + visIdArg: string +) => { return { id: idArg, + title, pluginResourceId, visLayerExpressionFn: exprFnArg, VIS_REFERENCE_NAME, - visId, + visId: visIdArg, version, } as ISavedAugmentVis; }; diff --git a/src/plugins/vis_augmenter/common/types.test.ts b/src/plugins/vis_augmenter/public/types.test.ts similarity index 100% rename from src/plugins/vis_augmenter/common/types.test.ts rename to src/plugins/vis_augmenter/public/types.test.ts diff --git a/src/plugins/vis_augmenter/public/types.ts b/src/plugins/vis_augmenter/public/types.ts index 5ddd191cace5..920a8db02843 100644 --- a/src/plugins/vis_augmenter/public/types.ts +++ b/src/plugins/vis_augmenter/public/types.ts @@ -3,24 +3,45 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { SavedObject } from '../../saved_objects/public'; -import { VisLayerTypes } from '../common'; +export enum VisLayerTypes { + PointInTimeEvents = 'PointInTimeEvents', +} -export interface ISavedAugmentVis { - id?: string; - description?: string; - pluginResourceId: string; - visName?: string; - visId?: string; - visLayerExpressionFn: VisLayerExpressionFn; - version?: number; +export type PluginResourceType = string; + +export interface PluginResource { + type: PluginResourceType; + id: string; + name: string; + urlPath: string; } -export interface VisLayerExpressionFn { +export interface VisLayer { type: keyof typeof VisLayerTypes; - name: string; - // plugin expression fns can freely set custom arguments - args: { [key: string]: any }; + originPlugin: string; + pluginResource: PluginResource; +} + +export type VisLayers = VisLayer[]; + +export interface EventMetadata { + pluginResourceId: string; + tooltip?: string; +} + +export interface PointInTimeEvent { + timestamp: number; + metadata: EventMetadata; } -export interface AugmentVisSavedObject extends SavedObject, ISavedAugmentVis {} +export interface PointInTimeEventsVisLayer extends VisLayer { + events: PointInTimeEvent[]; +} + +export const isPointInTimeEventsVisLayer = (obj: any) => { + return obj?.type === VisLayerTypes.PointInTimeEvents; +}; + +export const isValidVisLayer = (obj: any) => { + return obj?.type in VisLayerTypes; +}; diff --git a/src/plugins/vis_augmenter/common/index.ts b/src/plugins/vis_augmenter/public/utils/index.ts similarity index 77% rename from src/plugins/vis_augmenter/common/index.ts rename to src/plugins/vis_augmenter/public/utils/index.ts index 9f269633f307..079132ce99d2 100644 --- a/src/plugins/vis_augmenter/common/index.ts +++ b/src/plugins/vis_augmenter/public/utils/index.ts @@ -3,4 +3,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -export * from './types'; +export * from './utils'; diff --git a/src/plugins/vis_augmenter/public/utils/utils.test.ts b/src/plugins/vis_augmenter/public/utils/utils.test.ts new file mode 100644 index 000000000000..3c770b1db8ba --- /dev/null +++ b/src/plugins/vis_augmenter/public/utils/utils.test.ts @@ -0,0 +1,132 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Vis } from '../../../visualizations/public'; +import { + buildPipelineFromAugmentVisSavedObjs, + getAugmentVisSavedObjs, + isEligibleForVisLayers, +} from './utils'; +import { VisLayerTypes, ISavedAugmentVis, VisLayerExpressionFn } from '../types'; +import { + createSavedAugmentVisLoader, + SavedObjectOpenSearchDashboardsServicesWithAugmentVis, + getMockAugmentVisSavedObjectClient, + generateAugmentVisSavedObject, +} from '../saved_augment_vis'; + +describe('utils', () => { + // TODO: redo / update this test suite when eligibility is finalized. + // Tracked in https://github.com/opensearch-project/OpenSearch-Dashboards/issues/3268 + describe('isEligibleForVisLayers', () => { + it('vis is ineligible with invalid type', async () => { + const vis = ({ + params: { + type: 'not-line', + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(vis)).toEqual(false); + }); + it('vis is eligible with valid type', async () => { + const vis = ({ + params: { + type: 'line', + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(vis)).toEqual(true); + }); + }); + + describe('getAugmentVisSavedObjs', () => { + const fn = { + type: VisLayerTypes.PointInTimeEvents, + name: 'test-fn', + args: { + testArg: 'test-value', + }, + } as VisLayerExpressionFn; + const visId1 = 'test-vis-id-1'; + const visId2 = 'test-vis-id-2'; + const visId3 = 'test-vis-id-3'; + const obj1 = generateAugmentVisSavedObject('valid-obj-id-1', fn, visId1); + const obj2 = generateAugmentVisSavedObject('valid-obj-id-2', fn, visId1); + const obj3 = generateAugmentVisSavedObject('valid-obj-id-3', fn, visId2); + + it('returns no matching saved objs with filtering', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1, obj2, obj3]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId3, loader)).length).toEqual(0); + }); + it('returns no matching saved objs when client returns empty list', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId1, loader)).length).toEqual(0); + }); + it('returns one matching saved obj', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId1, loader)).length).toEqual(1); + }); + it('returns multiple matching saved objs without filtering', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1, obj2]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId1, loader)).length).toEqual(2); + }); + it('returns multiple matching saved objs with filtering', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1, obj2, obj3]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId1, loader)).length).toEqual(2); + }); + }); + + describe('buildPipelineFromAugmentVisSavedObjs', () => { + const obj1 = { + title: 'obj1', + pluginResourceId: 'obj-1-resource-id', + visLayerExpressionFn: { + type: VisLayerTypes.PointInTimeEvents, + name: 'fn-1', + args: { + arg1: 'value-1', + }, + }, + } as ISavedAugmentVis; + const obj2 = { + title: 'obj2', + pluginResourceId: 'obj-2-resource-id', + visLayerExpressionFn: { + type: VisLayerTypes.PointInTimeEvents, + name: 'fn-2', + args: { + arg2: 'value-2', + }, + }, + } as ISavedAugmentVis; + it('catches error with empty array', async () => { + try { + buildPipelineFromAugmentVisSavedObjs([]); + } catch (e: any) { + expect( + e.message.includes( + 'Expression function from augment-vis saved objects could not be generated' + ) + ); + } + }); + it('builds with one saved obj', async () => { + const str = buildPipelineFromAugmentVisSavedObjs([obj1]); + expect(str).toEqual('fn-1 arg1="value-1"'); + }); + it('builds with multiple saved objs', async () => { + const str = buildPipelineFromAugmentVisSavedObjs([obj1, obj2]); + expect(str).toEqual(`fn-1 arg1="value-1"\n| fn-2 arg2="value-2"`); + }); + }); +}); diff --git a/src/plugins/vis_augmenter/public/utils/utils.ts b/src/plugins/vis_augmenter/public/utils/utils.ts new file mode 100644 index 000000000000..c0d357d517e9 --- /dev/null +++ b/src/plugins/vis_augmenter/public/utils/utils.ts @@ -0,0 +1,60 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { get } from 'lodash'; +import { Vis } from '../../../../plugins/visualizations/public'; +import { + formatExpression, + buildExpressionFunction, + buildExpression, + ExpressionAstFunctionBuilder, +} from '../../../../plugins/expressions/public'; +import { ISavedAugmentVis, SavedAugmentVisLoader, VisLayerFunctionDefinition } from '../'; + +// TODO: provide a deeper eligibility check. +// Tracked in https://github.com/opensearch-project/OpenSearch-Dashboards/issues/3268 +export const isEligibleForVisLayers = (vis: Vis): boolean => { + return vis.params.type === 'line'; +}; + +/** + * Using a SavedAugmentVisLoader, fetch all saved objects that are of 'augment-vis' type + * and filter out to return the ones associated to the particular vis via + * matching vis ID. + */ +export const getAugmentVisSavedObjs = async ( + visId: string | undefined, + loader: SavedAugmentVisLoader | undefined +): Promise => { + try { + const resp = await loader?.findAll(); + const allSavedObjects = (get(resp, 'hits', []) as any[]) as ISavedAugmentVis[]; + return allSavedObjects.filter((hit: ISavedAugmentVis) => hit.visId === visId); + } catch (e) { + return [] as ISavedAugmentVis[]; + } +}; + +/** + * Given an array of augment-vis saved objects that contain expression function details, + * construct a pipeline that will execute each of these expression functions. + * Note that the order does not matter; each expression function should be taking + * in the current output and appending its results to it, such that the end result + * contains the results from each expression function that was ran. + */ +export const buildPipelineFromAugmentVisSavedObjs = (objs: ISavedAugmentVis[]): string => { + try { + const visLayerExpressionFns = objs.map((obj: ISavedAugmentVis) => + buildExpressionFunction( + obj.visLayerExpressionFn.name, + obj.visLayerExpressionFn.args + ) + ) as Array>; + const ast = buildExpression(visLayerExpressionFns).toAst(); + return formatExpression(ast); + } catch (e) { + throw new Error('Expression function from augment-vis saved objects could not be generated'); + } +}; diff --git a/src/plugins/visualizations/opensearch_dashboards.json b/src/plugins/visualizations/opensearch_dashboards.json index 6223ffce3808..b7c5e4ab9b4e 100644 --- a/src/plugins/visualizations/opensearch_dashboards.json +++ b/src/plugins/visualizations/opensearch_dashboards.json @@ -5,5 +5,5 @@ "ui": true, "requiredPlugins": ["data", "expressions", "uiActions", "embeddable", "inspector", "dashboard"], "optionalPlugins": ["usageCollection"], - "requiredBundles": ["opensearchDashboardsUtils", "discover", "savedObjects"] + "requiredBundles": ["opensearchDashboardsUtils", "discover", "savedObjects", "visAugmenter"] } diff --git a/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts b/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts index 03666a199dca..e09f789f9a68 100644 --- a/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts +++ b/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts @@ -40,6 +40,7 @@ import { IContainer, ErrorEmbeddable } from '../../../embeddable/public'; import { DisabledLabEmbeddable } from './disabled_lab_embeddable'; import { getSavedVisualizationsLoader, + getSavedAugmentVisLoader, getUISettings, getHttp, getTimeFilter, @@ -88,6 +89,8 @@ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDe const editable = getCapabilities().visualize.save as boolean; + const savedAugmentVisLoader = getSavedAugmentVisLoader(); + return new VisualizeEmbeddable( getTimeFilter(), { @@ -101,6 +104,7 @@ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDe input, attributeService, savedVisualizationsLoader, + savedAugmentVisLoader, parent ); } catch (e) { diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index f3808951d519..c0d43cd521da 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -28,7 +28,7 @@ * under the License. */ -import _, { get } from 'lodash'; +import _, { get, isEmpty } from 'lodash'; import { Subscription } from 'rxjs'; import * as Rx from 'rxjs'; import { i18n } from '@osd/i18n'; @@ -64,6 +64,14 @@ import { TriggerId } from '../../../ui_actions/public'; import { SavedObjectAttributes } from '../../../../core/types'; import { AttributeService } from '../../../dashboard/public'; import { SavedVisualizationsLoader } from '../saved_visualizations'; +import { + SavedAugmentVisLoader, + ExprVisLayers, + VisLayers, + isEligibleForVisLayers, + getAugmentVisSavedObjs, + buildPipelineFromAugmentVisSavedObjs, +} from '../../../vis_augmenter/public'; import { VisSavedObject } from '../types'; const getKeys = (o: T): Array => Object.keys(o) as Array; @@ -127,6 +135,7 @@ export class VisualizeEmbeddable VisualizeByReferenceInput >; private savedVisualizationsLoader?: SavedVisualizationsLoader; + private savedAugmentVisLoader?: SavedAugmentVisLoader; constructor( timefilter: TimefilterContract, @@ -138,6 +147,7 @@ export class VisualizeEmbeddable VisualizeByReferenceInput >, savedVisualizationsLoader?: SavedVisualizationsLoader, + savedAugmentVisLoader?: SavedAugmentVisLoader, parent?: IContainer ) { super( @@ -160,7 +170,7 @@ export class VisualizeEmbeddable this.vis.uiState.on('reload', this.reload); this.attributeService = attributeService; this.savedVisualizationsLoader = savedVisualizationsLoader; - + this.savedAugmentVisLoader = savedAugmentVisLoader; this.autoRefreshFetchSubscription = timefilter .getAutoRefreshFetch$() .subscribe(this.updateHandler.bind(this)); @@ -393,10 +403,14 @@ export class VisualizeEmbeddable } this.abortController = new AbortController(); const abortController = this.abortController; + + const visLayers = await this.fetchVisLayers(expressionParams, abortController); + this.expression = await buildPipeline(this.vis, { timefilter: this.timefilter, timeRange: this.timeRange, abortSignal: this.abortController!.signal, + visLayers, }); if (this.handler && !abortController.signal.aborted) { @@ -465,4 +479,46 @@ export class VisualizeEmbeddable { showSaveModal: true, saveModalTitle } ); }; + + /** + * Collects any VisLayers from plugin expressions functions + * by fetching all AugmentVisSavedObjects that match the vis + * saved object ID. + * + * TODO: final eligibility will be defined as part of a separate effort. + * Right now we have a placeholder function isEligibleForVisLayers() which + * is used below. For more details, see + * https://github.com/opensearch-project/OpenSearch-Dashboards/issues/3268 + */ + fetchVisLayers = async ( + expressionParams: IExpressionLoaderParams, + abortController: AbortController + ): Promise => { + const augmentVisSavedObjs = await getAugmentVisSavedObjs( + this.vis.id, + this.savedAugmentVisLoader + ); + if ( + !isEmpty(augmentVisSavedObjs) && + !abortController.signal.aborted && + isEligibleForVisLayers(this.vis) + ) { + const visLayersPipeline = buildPipelineFromAugmentVisSavedObjs(augmentVisSavedObjs); + // The initial input for the pipeline will just be an empty arr of VisLayers. As plugin + // expression functions are ran, they will incrementally append their generated VisLayers to it. + const visLayersPipelineInput = { + type: 'vis_layers', + layers: [] as VisLayers, + }; + // We cannot use this.handler in this case, since it does not support the run() cmd + // we need here. So, we consume the expressions service to run this instead. + const exprVisLayers = (await getExpressions().run( + visLayersPipeline, + visLayersPipelineInput, + expressionParams as Record + )) as ExprVisLayers; + return exprVisLayers.layers; + } + return [] as VisLayers; + }; } diff --git a/src/plugins/visualizations/public/legacy/build_pipeline.ts b/src/plugins/visualizations/public/legacy/build_pipeline.ts index a2b95afe6756..d751e088c99d 100644 --- a/src/plugins/visualizations/public/legacy/build_pipeline.ts +++ b/src/plugins/visualizations/public/legacy/build_pipeline.ts @@ -33,6 +33,8 @@ import moment from 'moment'; import { formatExpression, SerializedFieldFormat } from '../../../../plugins/expressions/public'; import { IAggConfig, search, TimefilterContract } from '../../../../plugins/data/public'; import { Vis, VisParams } from '../types'; +import { VisLayers } from '../../../../plugins/vis_augmenter/public'; + const { isDateHistogramBucketAggConfig } = search.aggs; interface SchemaConfigParams { @@ -85,6 +87,7 @@ export interface BuildPipelineParams { timefilter: TimefilterContract; timeRange?: any; abortSignal?: AbortSignal; + visLayers?: VisLayers; } const vislibCharts: string[] = [ diff --git a/src/plugins/visualizations/public/services.ts b/src/plugins/visualizations/public/services.ts index e3f3ba56f6b1..1ad0b37d76a4 100644 --- a/src/plugins/visualizations/public/services.ts +++ b/src/plugins/visualizations/public/services.ts @@ -52,6 +52,7 @@ import { UiActionsStart } from '../../ui_actions/public'; import { SavedVisualizationsLoader } from './saved_visualizations'; import { SavedObjectLoader } from '../../saved_objects/public'; import { EmbeddableStart } from '../../embeddable/public'; +import { SavedAugmentVisLoader } from '../../vis_augmenter/public'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); @@ -106,3 +107,7 @@ export const [getChrome, setChrome] = createGetterSetter('Chrome'); export const [getSavedSearchLoader, setSavedSearchLoader] = createGetterSetter( 'savedSearchLoader' ); + +export const [getSavedAugmentVisLoader, setSavedAugmentVisLoader] = createGetterSetter< + SavedAugmentVisLoader +>('SavedAugmentVisLoader');