Skip to content

Commit

Permalink
[Canvas] Extract and inject references for by-value embeddables (#115124
Browse files Browse the repository at this point in the history
)

* Extract/inject references for by-value embeddables in embeddable function

Fixed server interpreter setup

Register external functions in canvas_plugin_src plugin def

* Fixed ref name in embeddable.inject

* Fixed ts errors

* Fix missing type error
  • Loading branch information
cqliu1 authored Oct 26, 2021
1 parent d3e9f7d commit e5e3dad
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,11 @@
*/

import { functions as commonFunctions } from '../common';
import { functions as externalFunctions } from '../external';
import { location } from './location';
import { markdown } from './markdown';
import { urlparam } from './urlparam';
import { escount } from './escount';
import { esdocs } from './esdocs';
import { essql } from './essql';

export const functions = [
location,
markdown,
urlparam,
escount,
esdocs,
essql,
...commonFunctions,
...externalFunctions,
];
export const functions = [location, markdown, urlparam, escount, esdocs, essql, ...commonFunctions];
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
* 2.0.
*/

import { embeddable } from './embeddable';
import { embeddableFunctionFactory } from './embeddable';
import { getQueryFilters } from '../../../common/lib/build_embeddable_filters';
import { ExpressionValueFilter } from '../../../types';
import { encode } from '../../../common/lib/embeddable_dataurl';
import { InitializeArguments } from '.';

const filterContext: ExpressionValueFilter = {
type: 'filter',
Expand All @@ -32,7 +33,7 @@ const filterContext: ExpressionValueFilter = {
};

describe('embeddable', () => {
const fn = embeddable().fn;
const fn = embeddableFunctionFactory({} as InitializeArguments)().fn;
const config = {
id: 'some-id',
timerange: { from: '15m', to: 'now' },
Expand Down
166 changes: 102 additions & 64 deletions x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import { getFunctionHelp } from '../../../i18n';
import { SavedObjectReference } from '../../../../../../src/core/types';
import { getQueryFilters } from '../../../common/lib/build_embeddable_filters';
import { decode, encode } from '../../../common/lib/embeddable_dataurl';
import { InitializeArguments } from '.';

interface Arguments {
export interface Arguments {
config: string;
type: string;
}
Expand All @@ -31,77 +32,114 @@ const baseEmbeddableInput = {

type Return = EmbeddableExpression<EmbeddableInput>;

export function embeddable(): ExpressionFunctionDefinition<
type EmbeddableFunction = ExpressionFunctionDefinition<
'embeddable',
ExpressionValueFilter | null,
Arguments,
Return
> {
const { help, args: argHelp } = getFunctionHelp().embeddable;

return {
name: 'embeddable',
help,
args: {
config: {
aliases: ['_'],
types: ['string'],
required: true,
help: argHelp.config,
},
type: {
types: ['string'],
required: true,
help: argHelp.type,
},
},
context: {
types: ['filter'],
},
type: EmbeddableExpressionType,
fn: (input, args) => {
const filters = input ? input.and : [];

const embeddableInput = decode(args.config) as EmbeddableInput;

return {
type: EmbeddableExpressionType,
input: {
...baseEmbeddableInput,
...embeddableInput,
filters: getQueryFilters(filters),
>;

export function embeddableFunctionFactory({
embeddablePersistableStateService,
}: InitializeArguments): () => EmbeddableFunction {
return function embeddable(): EmbeddableFunction {
const { help, args: argHelp } = getFunctionHelp().embeddable;

return {
name: 'embeddable',
help,
args: {
config: {
aliases: ['_'],
types: ['string'],
required: true,
help: argHelp.config,
},
generatedAt: Date.now(),
embeddableType: args.type,
};
},

extract(state) {
const input = decode(state.config[0] as string);
const refName = 'embeddable.id';

const references: SavedObjectReference[] = [
{
name: refName,
type: state.type[0] as string,
id: input.savedObjectId as string,
type: {
types: ['string'],
required: true,
help: argHelp.type,
},
];
},
context: {
types: ['filter'],
},
type: EmbeddableExpressionType,
fn: (input, args) => {
const filters = input ? input.and : [];

const embeddableInput = decode(args.config) as EmbeddableInput;

return {
state,
references,
};
},
return {
type: EmbeddableExpressionType,
input: {
...baseEmbeddableInput,
...embeddableInput,
filters: getQueryFilters(filters),
},
generatedAt: Date.now(),
embeddableType: args.type,
};
},

inject(state, references) {
const reference = references.find((ref) => ref.name === 'embeddable.id');
if (reference) {
extract(state) {
const input = decode(state.config[0] as string);
input.savedObjectId = reference.id;
state.config[0] = encode(input);
}
return state;
},

// extracts references for by-reference embeddables
if (input.savedObjectId) {
const refName = 'embeddable.savedObjectId';

const references: SavedObjectReference[] = [
{
name: refName,
type: state.type[0] as string,
id: input.savedObjectId as string,
},
];

return {
state,
references,
};
}

// extracts references for by-value embeddables
const { state: extractedState, references: extractedReferences } =
embeddablePersistableStateService.extract({
...input,
type: state.type[0],
});

const { type, ...extractedInput } = extractedState;

return {
state: { ...state, config: [encode(extractedInput)], type: [type] },
references: extractedReferences,
};
},

inject(state, references) {
const input = decode(state.config[0] as string);
const savedObjectReference = references.find(
(ref) => ref.name === 'embeddable.savedObjectId'
);

// injects saved object id for by-references embeddable
if (savedObjectReference) {
input.savedObjectId = savedObjectReference.id;
state.config[0] = encode(input);
state.type[0] = savedObjectReference.type;
} else {
// injects references for by-value embeddables
const { type, ...injectedInput } = embeddablePersistableStateService.inject(
{ ...input, type: state.type[0] },
references
);
state.config[0] = encode(injectedInput);
state.type[0] = type;
}
return state;
},
};
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,26 @@
* 2.0.
*/

import { EmbeddableStart } from 'src/plugins/embeddable/public';
import { embeddableFunctionFactory } from './embeddable';
import { savedLens } from './saved_lens';
import { savedMap } from './saved_map';
import { savedSearch } from './saved_search';
import { savedVisualization } from './saved_visualization';
import { embeddable } from './embeddable';

export const functions = [embeddable, savedLens, savedMap, savedSearch, savedVisualization];
export interface InitializeArguments {
embeddablePersistableStateService: {
extract: EmbeddableStart['extract'];
inject: EmbeddableStart['inject'];
};
}

export function initFunctions(initialize: InitializeArguments) {
return [
embeddableFunctionFactory(initialize),
savedLens,
savedMap,
savedSearch,
savedVisualization,
];
}
8 changes: 8 additions & 0 deletions x-pack/plugins/canvas/canvas_plugin_src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { UiActionsStart } from '../../../../src/plugins/ui_actions/public';
import { Start as InspectorStart } from '../../../../src/plugins/inspector/public';

import { functions } from './functions/browser';
import { initFunctions } from './functions/external';
import { typeFunctions } from './expression_types';
import { renderFunctions, renderFunctionFactories } from './renderers';

Expand Down Expand Up @@ -41,6 +42,13 @@ export class CanvasSrcPlugin implements Plugin<void, void, SetupDeps, StartDeps>
plugins.canvas.addRenderers(renderFunctions);

core.getStartServices().then(([coreStart, depsStart]) => {
const externalFunctions = initFunctions({
embeddablePersistableStateService: {
extract: depsStart.embeddable.extract,
inject: depsStart.embeddable.inject,
},
});
plugins.canvas.addFunctions(externalFunctions);
plugins.canvas.addRenderers(
renderFunctionFactories.map((factory: any) => factory(coreStart, depsStart))
);
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/canvas/i18n/functions/dict/embeddable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
*/

import { i18n } from '@kbn/i18n';
import { embeddable } from '../../../canvas_plugin_src/functions/external/embeddable';
import { embeddableFunctionFactory } from '../../../canvas_plugin_src/functions/external/embeddable';
import { FunctionHelp } from '../function_help';
import { FunctionFactory } from '../../../types';

export const help: FunctionHelp<FunctionFactory<typeof embeddable>> = {
export const help: FunctionHelp<FunctionFactory<ReturnType<typeof embeddableFunctionFactory>>> = {
help: i18n.translate('xpack.canvas.functions.embeddableHelpText', {
defaultMessage: `Returns an embeddable with the provided configuration`,
}),
Expand Down
9 changes: 8 additions & 1 deletion x-pack/plugins/canvas/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ExpressionsServerSetup } from 'src/plugins/expressions/server';
import { BfetchServerSetup } from 'src/plugins/bfetch/server';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
import { HomeServerPluginSetup } from 'src/plugins/home/server';
import { EmbeddableSetup } from 'src/plugins/embeddable/server';
import { ESSQL_SEARCH_STRATEGY } from '../common/lib/constants';
import { ReportingSetup } from '../../reporting/server';
import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server';
Expand All @@ -30,6 +31,7 @@ import { CanvasRouteHandlerContext, createWorkpadRouteContext } from './workpad_

interface PluginsSetup {
expressions: ExpressionsServerSetup;
embeddable: EmbeddableSetup;
features: FeaturesPluginSetup;
home: HomeServerPluginSetup;
bfetch: BfetchServerSetup;
Expand Down Expand Up @@ -82,7 +84,12 @@ export class CanvasPlugin implements Plugin {
const globalConfig = this.initializerContext.config.legacy.get();
registerCanvasUsageCollector(plugins.usageCollection, globalConfig.kibana.index);

setupInterpreter(expressionsFork);
setupInterpreter(expressionsFork, {
embeddablePersistableStateService: {
extract: plugins.embeddable.extract,
inject: plugins.embeddable.inject,
},
});

coreSetup.getStartServices().then(([_, depsStart]) => {
const strategy = essqlSearchStrategyProvider();
Expand Down
12 changes: 9 additions & 3 deletions x-pack/plugins/canvas/server/setup_interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@

import { ExpressionsServerSetup } from 'src/plugins/expressions/server';
import { functions } from '../canvas_plugin_src/functions/server';
import { functions as externalFunctions } from '../canvas_plugin_src/functions/external';
import {
initFunctions as initExternalFunctions,
InitializeArguments,
} from '../canvas_plugin_src/functions/external';

export function setupInterpreter(expressions: ExpressionsServerSetup) {
export function setupInterpreter(
expressions: ExpressionsServerSetup,
dependencies: InitializeArguments
) {
functions.forEach((f) => expressions.registerFunction(f));
externalFunctions.forEach((f) => expressions.registerFunction(f));
initExternalFunctions(dependencies).forEach((f) => expressions.registerFunction(f));
}
10 changes: 6 additions & 4 deletions x-pack/plugins/canvas/types/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { UnwrapPromiseOrReturn } from '@kbn/utility-types';
import { functions as commonFunctions } from '../canvas_plugin_src/functions/common';
import { functions as browserFunctions } from '../canvas_plugin_src/functions/browser';
import { functions as serverFunctions } from '../canvas_plugin_src/functions/server';
import { functions as externalFunctions } from '../canvas_plugin_src/functions/external';
import { initFunctions } from '../public/functions';
import { initFunctions as initExternalFunctions } from '../canvas_plugin_src/functions/external';
import { initFunctions as initClientFunctions } from '../public/functions';

/**
* A `ExpressionFunctionFactory` is a powerful type used for any function that produces
Expand Down Expand Up @@ -90,9 +90,11 @@ export type FunctionFactory<FnFactory> =
type CommonFunction = FunctionFactory<typeof commonFunctions[number]>;
type BrowserFunction = FunctionFactory<typeof browserFunctions[number]>;
type ServerFunction = FunctionFactory<typeof serverFunctions[number]>;
type ExternalFunction = FunctionFactory<typeof externalFunctions[number]>;
type ExternalFunction = FunctionFactory<
ReturnType<typeof initExternalFunctions> extends Array<infer U> ? U : never
>;
type ClientFunctions = FunctionFactory<
ReturnType<typeof initFunctions> extends Array<infer U> ? U : never
ReturnType<typeof initClientFunctions> extends Array<infer U> ? U : never
>;

/**
Expand Down

0 comments on commit e5e3dad

Please sign in to comment.