Skip to content

Commit

Permalink
Add vis layer parsing in visualize_embeddable
Browse files Browse the repository at this point in the history
Signed-off-by: Tyler Ohlsen <[email protected]>
  • Loading branch information
ohltyler committed Feb 9, 2023
1 parent eeed599 commit 3cc0f35
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { IContainer, ErrorEmbeddable } from '../../../embeddable/public';
import { DisabledLabEmbeddable } from './disabled_lab_embeddable';
import {
getSavedVisualizationsLoader,
getSavedAugmentVisLoader,
getUISettings,
getHttp,
getTimeFilter,
Expand Down Expand Up @@ -88,6 +89,8 @@ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDe

const editable = getCapabilities().visualize.save as boolean;

const savedAugmentVisLoader = getSavedAugmentVisLoader();

return new VisualizeEmbeddable(
getTimeFilter(),
{
Expand All @@ -101,6 +104,7 @@ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDe
input,
attributeService,
savedVisualizationsLoader,
savedAugmentVisLoader,
parent
);
} catch (e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -54,8 +54,15 @@ import {
IExpressionLoaderParams,
ExpressionsStart,
ExpressionRenderError,
// TODO: this should resolve after rebasing
ExprVisLayers,
} from '../../../expressions/public';
import { buildPipeline } from '../legacy/build_pipeline';
import {
buildPipeline,
getAugmentVisSavedObjs,
buildPipelineFromAugmentVisSavedObjs,
isEligibleForVisLayers,
} from '../legacy/build_pipeline';
import { Vis, SerializedVis } from '../vis';
import { getExpressions, getUiActions } from '../services';
import { VIS_EVENT_TO_TRIGGER } from './events';
Expand All @@ -64,7 +71,11 @@ import { TriggerId } from '../../../ui_actions/public';
import { SavedObjectAttributes } from '../../../../core/types';
import { AttributeService } from '../../../dashboard/public';
import { SavedVisualizationsLoader } from '../saved_visualizations';
// TODO: this should resolve after rebasing
import { SavedAugmentVisLoader } from '../../../vis_augmenter/public';
import { VisSavedObject } from '../types';
// TODO: this should resolve after rebasing
import { VisLayers } from '../../../vis_augmenter/common';

const getKeys = <T extends {}>(o: T): Array<keyof T> => Object.keys(o) as Array<keyof T>;

Expand Down Expand Up @@ -127,6 +138,7 @@ export class VisualizeEmbeddable
VisualizeByReferenceInput
>;
private savedVisualizationsLoader?: SavedVisualizationsLoader;
private savedAugmentVisLoader?: SavedAugmentVisLoader;

constructor(
timefilter: TimefilterContract,
Expand All @@ -138,6 +150,7 @@ export class VisualizeEmbeddable
VisualizeByReferenceInput
>,
savedVisualizationsLoader?: SavedVisualizationsLoader,
savedAugmentVisLoader?: SavedAugmentVisLoader,
parent?: IContainer
) {
super(
Expand All @@ -160,7 +173,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));
Expand Down Expand Up @@ -393,10 +406,38 @@ export class VisualizeEmbeddable
}
this.abortController = new AbortController();
const abortController = this.abortController;

// Collect any vis layers from plugin expr fns (e.g., anomalies/alerts)
// by fetching all augment vis saved objs that match the vis ID
let exprVisLayers = {} as ExprVisLayers;
if (isEligibleForVisLayers(this.vis)) {
const augmentVisSavedObjs = await getAugmentVisSavedObjs(
this.vis.id,
this.savedAugmentVisLoader
);
if (!isEmpty(augmentVisSavedObjs) && !abortController.signal.aborted) {
const visLayersPipeline = buildPipelineFromAugmentVisSavedObjs(augmentVisSavedObjs);
const visLayersPipelineInput = {
type: 'vis_layers',
layers: [] as VisLayers,
};
// TODO: could run via handler but it may not make sense in this context.
// it would also require adding a new static fn to run the standalone run() cmd
// we only need to have the expressions service exposed to run this standalone
// pipeline to collect the VisLayers
exprVisLayers = (await getExpressions().run(
visLayersPipeline,
visLayersPipelineInput,
expressionParams as Record<string, unknown>
)) as ExprVisLayers;
}
}

this.expression = await buildPipeline(this.vis, {
timefilter: this.timefilter,
timeRange: this.timeRange,
abortSignal: this.abortController!.signal,
visLayers: !isEmpty(exprVisLayers) ? exprVisLayers.layers : ([] as VisLayers),
});

if (this.handler && !abortController.signal.aborted) {
Expand Down
69 changes: 69 additions & 0 deletions src/plugins/visualizations/public/legacy/build_pipeline.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
buildPipeline,
SchemaConfig,
Schemas,
buildPipelineFromAugmentVisSavedObjs,
isEligibleForVisLayers,
} from './build_pipeline';
import { Vis } from '..';
import { dataPluginMock } from '../../../data/public/mocks';
Expand Down Expand Up @@ -346,4 +348,71 @@ describe('visualize loader pipeline helpers: build pipeline', () => {
});
});
});

describe('getAugmentVisSavedObjs', () => {
// TODO: add tests after saved obj PR tests are added; can use
// them for instantiating mock saved obj loader
});

describe('buildPipelineFromAugmentVisSavedObjs', () => {
const obj1 = {
visLayerExpressionFn: {
// TODO: uncomment when VisLayerTypes resolves
// type: VisLayerTypes.PointInTimeEventsLayer,
name: 'fn-1',
args: {
arg1: 'value-1',
},
},
};
const obj2 = {
visLayerExpressionFn: {
// TODO: uncomment when VisLayerTypes resolves
// type: VisLayerTypes.PointInTimeEventsLayer,
name: 'fn-2',
args: {
arg2: 'value-2',
},
},
};
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"`);
});
});

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);
});
// TODO: add more when there is more logic added to determine eligibility
});
});
56 changes: 55 additions & 1 deletion src/plugins/visualizations/public/legacy/build_pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,21 @@

import { get } from 'lodash';
import moment from 'moment';
import { formatExpression, SerializedFieldFormat } from '../../../../plugins/expressions/public';
import {
formatExpression,
SerializedFieldFormat,
buildExpressionFunction,
buildExpression,
ExpressionAstFunctionBuilder,
} from '../../../../plugins/expressions/public';
import { IAggConfig, search, TimefilterContract } from '../../../../plugins/data/public';
import { Vis, VisParams } from '../types';

// TODO: below 3 imports should resolve after rebasing
import { VisLayerFunctionDefinition } from '../../../vis_augmenter/common';
import { ISavedAugmentVis, SavedAugmentVisLoader } from '../../../vis_augmenter/public';
import { VisLayers } from '../../../vis_augmenter/common';

const { isDateHistogramBucketAggConfig } = search.aggs;

interface SchemaConfigParams {
Expand Down Expand Up @@ -85,6 +97,7 @@ export interface BuildPipelineParams {
timefilter: TimefilterContract;
timeRange?: any;
abortSignal?: AbortSignal;
visLayers?: VisLayers;
}

const vislibCharts: string[] = [
Expand Down Expand Up @@ -435,3 +448,44 @@ export const buildPipeline = async (vis: Vis, params: BuildPipelineParams) => {

return pipeline;
};

export const getAugmentVisSavedObjs = async (
visId: string | undefined,
loader: SavedAugmentVisLoader | undefined
): Promise<ISavedAugmentVis[]> => {
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) {
// console.error('Unable to search for augment-vis saved objects: ', e);
return [] as ISavedAugmentVis[];
}
};

export const buildPipelineFromAugmentVisSavedObjs = (objs: ISavedAugmentVis[]): string => {
const visLayerExpressionFns = [] as Array<
ExpressionAstFunctionBuilder<VisLayerFunctionDefinition>
>;

try {
objs.forEach((obj: ISavedAugmentVis) => {
visLayerExpressionFns.push(
buildExpressionFunction<VisLayerFunctionDefinition>(
obj.visLayerExpressionFn.name,
obj.visLayerExpressionFn.args
)
);
});
const ast = buildExpression(visLayerExpressionFns).toAst();
return formatExpression(ast);
} catch (e) {
throw new Error('Expression function from augment-vis saved objects could not be generated');
}
};

// TODO: deeper logic will need to be added here to determine eligibility.
// Probably will need to check the vis config for proper axes configurations, etc.
export const isEligibleForVisLayers = (vis: Vis): boolean => {
return vis.params.type === 'line';
};
6 changes: 6 additions & 0 deletions src/plugins/visualizations/public/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { VisAugmenterStart } from '../../vis_augmenter/public';

export const [getUISettings, setUISettings] = createGetterSetter<IUiSettingsClient>('UISettings');

Expand Down Expand Up @@ -106,3 +107,8 @@ export const [getChrome, setChrome] = createGetterSetter<ChromeStart>('Chrome');
export const [getSavedSearchLoader, setSavedSearchLoader] = createGetterSetter<SavedObjectLoader>(
'savedSearchLoader'
);

// TODO: this should resolve after rebasing
export const [getSavedAugmentVisLoader, setSavedAugmentVisLoader] = createGetterSetter<
VisAugmenterStart
>('savedAugmentVisLoader');

0 comments on commit 3cc0f35

Please sign in to comment.