diff --git a/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts b/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts
index ac2e8e8babee1..f1ede936c6ace 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts
@@ -6,12 +6,11 @@
*/
import { ExpressionTypeDefinition } from '../../../../../src/plugins/expressions';
-import { EmbeddableInput } from '../../../../../src/plugins/embeddable/common/';
+import { EmbeddableInput } from '../../types';
import { EmbeddableTypes } from './embeddable_types';
export const EmbeddableExpressionType = 'embeddable';
export { EmbeddableTypes, EmbeddableInput };
-
export interface EmbeddableExpression {
/**
* The type of the expression result
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts
index 6642a6e64fdae..f846f23ff7f73 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts
@@ -6,14 +6,8 @@
*/
import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common';
-import { TimeRange } from 'src/plugins/data/public';
-import { Filter } from '@kbn/es-query';
-import { ExpressionValueFilter } from '../../../types';
-import {
- EmbeddableExpressionType,
- EmbeddableExpression,
- EmbeddableInput as Input,
-} from '../../expression_types';
+import { ExpressionValueFilter, EmbeddableInput } from '../../../types';
+import { EmbeddableExpressionType, EmbeddableExpression } from '../../expression_types';
import { getFunctionHelp } from '../../../i18n';
import { SavedObjectReference } from '../../../../../../src/core/types';
import { getQueryFilters } from '../../../common/lib/build_embeddable_filters';
@@ -29,12 +23,6 @@ const defaultTimeRange = {
to: 'now',
};
-export type EmbeddableInput = Input & {
- timeRange?: TimeRange;
- filters?: Filter[];
- savedObjectId: string;
-};
-
const baseEmbeddableInput = {
timeRange: defaultTimeRange,
disableTriggers: true,
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts
index 082a69a874cae..67947691f7757 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts
@@ -9,9 +9,8 @@ import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common';
import { PaletteOutput } from 'src/plugins/charts/common';
import { Filter as DataFilter } from '@kbn/es-query';
import { TimeRange } from 'src/plugins/data/common';
-import { EmbeddableInput } from 'src/plugins/embeddable/common';
import { getQueryFilters } from '../../../common/lib/build_embeddable_filters';
-import { ExpressionValueFilter, TimeRange as TimeRangeArg } from '../../../types';
+import { ExpressionValueFilter, EmbeddableInput, TimeRange as TimeRangeArg } from '../../../types';
import {
EmbeddableTypes,
EmbeddableExpressionType,
@@ -27,7 +26,7 @@ interface Arguments {
}
export type SavedLensInput = EmbeddableInput & {
- id: string;
+ savedObjectId: string;
timeRange?: TimeRange;
filters: DataFilter[];
palette?: PaletteOutput;
@@ -73,18 +72,19 @@ export function savedLens(): ExpressionFunctionDefinition<
},
},
type: EmbeddableExpressionType,
- fn: (input, args) => {
+ fn: (input, { id, timerange, title, palette }) => {
const filters = input ? input.and : [];
return {
type: EmbeddableExpressionType,
input: {
- id: args.id,
+ id,
+ savedObjectId: id,
filters: getQueryFilters(filters),
- timeRange: args.timerange || defaultTimeRange,
- title: args.title === null ? undefined : args.title,
+ timeRange: timerange || defaultTimeRange,
+ title: title === null ? undefined : title,
disableTriggers: true,
- palette: args.palette,
+ palette,
},
embeddableType: EmbeddableTypes.lens,
generatedAt: Date.now(),
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts
index 538ed3f919823..a7471c755155c 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts
@@ -30,7 +30,7 @@ const defaultTimeRange = {
to: 'now',
};
-type Output = EmbeddableExpression;
+type Output = EmbeddableExpression;
export function savedMap(): ExpressionFunctionDefinition<
'savedMap',
@@ -85,8 +85,9 @@ export function savedMap(): ExpressionFunctionDefinition<
return {
type: EmbeddableExpressionType,
input: {
- attributes: { title: '' },
id: args.id,
+ attributes: { title: '' },
+ savedObjectId: args.id,
filters: getQueryFilters(filters),
timeRange: args.timerange || defaultTimeRange,
refreshConfig: {
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts
index 5c0442b43250c..31e3fb2a8c564 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts
@@ -25,7 +25,7 @@ interface Arguments {
title: string | null;
}
-type Output = EmbeddableExpression;
+type Output = EmbeddableExpression;
const defaultTimeRange = {
from: 'now-15m',
@@ -94,6 +94,7 @@ export function savedVisualization(): ExpressionFunctionDefinition<
type: EmbeddableExpressionType,
input: {
id,
+ savedObjectId: id,
disableTriggers: true,
timeRange: timerange || defaultTimeRange,
filters: getQueryFilters(filters),
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx
index 2db4c78ca4b32..953746c280840 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx
+++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx
@@ -13,12 +13,12 @@ import {
IEmbeddable,
EmbeddableFactory,
EmbeddableFactoryNotFoundError,
+ isErrorEmbeddable,
} from '../../../../../../src/plugins/embeddable/public';
import { EmbeddableExpression } from '../../expression_types/embeddable';
import { RendererStrings } from '../../../i18n';
import { embeddableInputToExpression } from './embeddable_input_to_expression';
-import { EmbeddableInput } from '../../expression_types';
-import { RendererFactory } from '../../../types';
+import { RendererFactory, EmbeddableInput } from '../../../types';
import { CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib';
const { embeddable: strings } = RendererStrings;
@@ -71,16 +71,27 @@ export const embeddableRendererFactory = (
throw new EmbeddableFactoryNotFoundError(embeddableType);
}
- const embeddablePromise = factory
- .createFromSavedObject(input.id, input)
- .then((embeddable) => {
- // stores embeddable in registrey
- embeddablesRegistry[uniqueId] = embeddable;
- return embeddable;
- });
- embeddablesRegistry[uniqueId] = embeddablePromise;
-
- const embeddableObject = await (async () => embeddablePromise)();
+ const embeddableInput = { ...input, id: uniqueId };
+
+ const embeddablePromise = input.savedObjectId
+ ? factory
+ .createFromSavedObject(input.savedObjectId, embeddableInput)
+ .then((embeddable) => {
+ // stores embeddable in registrey
+ embeddablesRegistry[uniqueId] = embeddable;
+ return embeddable;
+ })
+ : factory.create(embeddableInput).then((embeddable) => {
+ if (!embeddable || isErrorEmbeddable(embeddable)) {
+ return;
+ }
+ // stores embeddable in registry
+ embeddablesRegistry[uniqueId] = embeddable as IEmbeddable;
+ return embeddable;
+ });
+ embeddablesRegistry[uniqueId] = embeddablePromise as Promise;
+
+ const embeddableObject = (await (async () => embeddablePromise)()) as IEmbeddable;
const palettes = await plugins.charts.palettes.getPalettes();
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.test.ts
new file mode 100644
index 0000000000000..4b78acec8750a
--- /dev/null
+++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.test.ts
@@ -0,0 +1,128 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { toExpression } from './embeddable';
+import { EmbeddableInput } from '../../../../types';
+import { decode } from '../../../../common/lib/embeddable_dataurl';
+import { fromExpression } from '@kbn/interpreter/common';
+
+describe('toExpression', () => {
+ describe('by-reference embeddable input', () => {
+ const baseEmbeddableInput = {
+ id: 'elementId',
+ savedObjectId: 'embeddableId',
+ filters: [],
+ };
+
+ it('converts to an embeddable expression', () => {
+ const input: EmbeddableInput = baseEmbeddableInput;
+
+ const expression = toExpression(input, 'visualization');
+ const ast = fromExpression(expression);
+
+ expect(ast.type).toBe('expression');
+ expect(ast.chain[0].function).toBe('embeddable');
+ expect(ast.chain[0].arguments.type[0]).toBe('visualization');
+
+ const config = decode(ast.chain[0].arguments.config[0] as string);
+
+ expect(config.savedObjectId).toStrictEqual(input.savedObjectId);
+ });
+
+ it('includes optional input values', () => {
+ const input: EmbeddableInput = {
+ ...baseEmbeddableInput,
+ title: 'title',
+ timeRange: {
+ from: 'now-1h',
+ to: 'now',
+ },
+ };
+
+ const expression = toExpression(input, 'visualization');
+ const ast = fromExpression(expression);
+
+ const config = decode(ast.chain[0].arguments.config[0] as string);
+
+ expect(config).toHaveProperty('title', input.title);
+ expect(config).toHaveProperty('timeRange');
+ expect(config.timeRange).toHaveProperty('from', input.timeRange?.from);
+ expect(config.timeRange).toHaveProperty('to', input.timeRange?.to);
+ });
+
+ it('includes empty panel title', () => {
+ const input: EmbeddableInput = {
+ ...baseEmbeddableInput,
+ title: '',
+ };
+
+ const expression = toExpression(input, 'visualization');
+ const ast = fromExpression(expression);
+
+ const config = decode(ast.chain[0].arguments.config[0] as string);
+
+ expect(config).toHaveProperty('title', input.title);
+ });
+ });
+
+ describe('by-value embeddable input', () => {
+ const baseEmbeddableInput = {
+ id: 'elementId',
+ disableTriggers: true,
+ filters: [],
+ };
+ it('converts to an embeddable expression', () => {
+ const input: EmbeddableInput = baseEmbeddableInput;
+
+ const expression = toExpression(input, 'visualization');
+ const ast = fromExpression(expression);
+
+ expect(ast.type).toBe('expression');
+ expect(ast.chain[0].function).toBe('embeddable');
+ expect(ast.chain[0].arguments.type[0]).toBe('visualization');
+
+ const config = decode(ast.chain[0].arguments.config[0] as string);
+ expect(config.filters).toStrictEqual(input.filters);
+ expect(config.disableTriggers).toStrictEqual(input.disableTriggers);
+ });
+
+ it('includes optional input values', () => {
+ const input: EmbeddableInput = {
+ ...baseEmbeddableInput,
+ title: 'title',
+ timeRange: {
+ from: 'now-1h',
+ to: 'now',
+ },
+ };
+
+ const expression = toExpression(input, 'visualization');
+ const ast = fromExpression(expression);
+
+ const config = decode(ast.chain[0].arguments.config[0] as string);
+
+ expect(config).toHaveProperty('title', input.title);
+ expect(config).toHaveProperty('timeRange');
+ expect(config.timeRange).toHaveProperty('from', input.timeRange?.from);
+ expect(config.timeRange).toHaveProperty('to', input.timeRange?.to);
+ });
+
+ it('includes empty panel title', () => {
+ const input: EmbeddableInput = {
+ ...baseEmbeddableInput,
+ title: '',
+ };
+
+ const expression = toExpression(input, 'visualization');
+ const ast = fromExpression(expression);
+
+ const config = decode(ast.chain[0].arguments.config[0] as string);
+
+ expect(config).toHaveProperty('title', input.title);
+ });
+ });
+});
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts
index 24da7238bcee9..224cdfba389d7 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts
@@ -11,7 +11,8 @@ import { fromExpression, Ast } from '@kbn/interpreter/common';
import { chartPluginMock } from 'src/plugins/charts/public/mocks';
const baseEmbeddableInput = {
- id: 'embeddableId',
+ id: 'elementId',
+ savedObjectId: 'embeddableId',
filters: [],
};
@@ -27,7 +28,7 @@ describe('toExpression', () => {
expect(ast.type).toBe('expression');
expect(ast.chain[0].function).toBe('savedLens');
- expect(ast.chain[0].arguments.id).toStrictEqual([input.id]);
+ expect(ast.chain[0].arguments.id).toStrictEqual([input.savedObjectId]);
expect(ast.chain[0].arguments).not.toHaveProperty('title');
expect(ast.chain[0].arguments).not.toHaveProperty('timerange');
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts
index 35e106f234fa4..5a13b73b3fe74 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts
@@ -14,7 +14,7 @@ export function toExpression(input: SavedLensInput, palettes: PaletteRegistry):
expressionParts.push('savedLens');
- expressionParts.push(`id="${input.id}"`);
+ expressionParts.push(`id="${input.savedObjectId}"`);
if (input.title !== undefined) {
expressionParts.push(`title="${input.title}"`);
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts
index 804d0d849cc7f..af7b40a9b283d 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts
@@ -6,12 +6,12 @@
*/
import { toExpression } from './map';
-import { MapEmbeddableInput } from '../../../../../../plugins/maps/public/embeddable';
import { fromExpression, Ast } from '@kbn/interpreter/common';
const baseSavedMapInput = {
+ id: 'elementId',
attributes: { title: '' },
- id: 'embeddableId',
+ savedObjectId: 'embeddableId',
filters: [],
isLayerTOCOpen: false,
refreshConfig: {
@@ -23,7 +23,7 @@ const baseSavedMapInput = {
describe('toExpression', () => {
it('converts to a savedMap expression', () => {
- const input: MapEmbeddableInput = {
+ const input = {
...baseSavedMapInput,
};
@@ -33,7 +33,7 @@ describe('toExpression', () => {
expect(ast.type).toBe('expression');
expect(ast.chain[0].function).toBe('savedMap');
- expect(ast.chain[0].arguments.id).toStrictEqual([input.id]);
+ expect(ast.chain[0].arguments.id).toStrictEqual([input.savedObjectId]);
expect(ast.chain[0].arguments).not.toHaveProperty('title');
expect(ast.chain[0].arguments).not.toHaveProperty('center');
@@ -41,7 +41,7 @@ describe('toExpression', () => {
});
it('includes optional input values', () => {
- const input: MapEmbeddableInput = {
+ const input = {
...baseSavedMapInput,
mapCenter: {
lat: 1,
@@ -73,7 +73,7 @@ describe('toExpression', () => {
});
it('includes empty panel title', () => {
- const input: MapEmbeddableInput = {
+ const input = {
...baseSavedMapInput,
title: '',
};
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts
index 3fd6a68a327c6..03746f38b4696 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts
@@ -5,13 +5,14 @@
* 2.0.
*/
-import { MapEmbeddableInput } from '../../../../../../plugins/maps/public/embeddable';
+import { MapEmbeddableInput } from '../../../../../../plugins/maps/public';
-export function toExpression(input: MapEmbeddableInput): string {
+export function toExpression(input: MapEmbeddableInput & { savedObjectId: string }): string {
const expressionParts = [] as string[];
expressionParts.push('savedMap');
- expressionParts.push(`id="${input.id}"`);
+
+ expressionParts.push(`id="${input.savedObjectId}"`);
if (input.title !== undefined) {
expressionParts.push(`title="${input.title}"`);
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts
index c5106b9a102b4..4c61a130f3c95 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts
@@ -9,7 +9,8 @@ import { toExpression } from './visualization';
import { fromExpression, Ast } from '@kbn/interpreter/common';
const baseInput = {
- id: 'embeddableId',
+ id: 'elementId',
+ savedObjectId: 'embeddableId',
};
describe('toExpression', () => {
@@ -24,7 +25,7 @@ describe('toExpression', () => {
expect(ast.type).toBe('expression');
expect(ast.chain[0].function).toBe('savedVisualization');
- expect(ast.chain[0].arguments.id).toStrictEqual([input.id]);
+ expect(ast.chain[0].arguments.id).toStrictEqual([input.savedObjectId]);
});
it('includes timerange if given', () => {
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts
index bcb73b2081fee..364d7cd0755db 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts
@@ -7,11 +7,11 @@
import { VisualizeInput } from 'src/plugins/visualizations/public';
-export function toExpression(input: VisualizeInput): string {
+export function toExpression(input: VisualizeInput & { savedObjectId: string }): string {
const expressionParts = [] as string[];
expressionParts.push('savedVisualization');
- expressionParts.push(`id="${input.id}"`);
+ expressionParts.push(`id="${input.savedObjectId}"`);
if (input.title !== undefined) {
expressionParts.push(`title="${input.title}"`);
diff --git a/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts b/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts
index d8246449f90ba..e76dedfe63b14 100644
--- a/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts
+++ b/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { EmbeddableInput } from '../../canvas_plugin_src/expression_types';
+import { EmbeddableInput } from '../../types';
export const encode = (input: Partial) =>
Buffer.from(JSON.stringify(input)).toString('base64');
diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx
index 5985c99747870..4dc8d963932d8 100644
--- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx
+++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx
@@ -85,9 +85,10 @@ export const AddEmbeddablePanel: React.FunctionComponent = ({
};
// If by-value is enabled, we'll handle both by-reference and by-value embeddables
- // with the new generic `embeddable` function
+ // with the new generic `embeddable` function.
+ // Otherwise we fallback to the embeddable type specific expressions.
if (isByValueEnabled) {
- const config = encode({ id });
+ const config = encode({ savedObjectId: id });
partialElement.expression = `embeddable config="${config}"
type="${type}"
| render`;
diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx b/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx
index 50d527036560a..ffd5b095b12e5 100644
--- a/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx
+++ b/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx
@@ -6,3 +6,5 @@
*/
export { useDownloadWorkpad, useDownloadRenderedWorkpad } from './use_download_workpad';
+
+export { useIncomingEmbeddable } from './use_incoming_embeddable';
diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts b/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts
new file mode 100644
index 0000000000000..27f68ca15a200
--- /dev/null
+++ b/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts
@@ -0,0 +1,63 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { useEffect } from 'react';
+import { useDispatch } from 'react-redux';
+import { CANVAS_APP } from '../../../../common/lib';
+import { encode } from '../../../../common/lib/embeddable_dataurl';
+import { useEmbeddablesService, useLabsService } from '../../../services';
+// @ts-expect-error unconverted file
+import { addElement } from '../../../state/actions/elements';
+// @ts-expect-error unconverted file
+import { selectToplevelNodes } from '../../../state/actions/transient';
+
+import {
+ updateEmbeddableExpression,
+ fetchEmbeddableRenderable,
+} from '../../../state/actions/embeddable';
+import { clearValue } from '../../../state/actions/resolved_args';
+
+export const useIncomingEmbeddable = (pageId: string) => {
+ const embeddablesService = useEmbeddablesService();
+ const labsService = useLabsService();
+ const dispatch = useDispatch();
+ const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable');
+ const stateTransferService = embeddablesService.getStateTransfer();
+
+ // fetch incoming embeddable from state transfer service.
+ const incomingEmbeddable = stateTransferService.getIncomingEmbeddablePackage(CANVAS_APP, true);
+
+ useEffect(() => {
+ if (isByValueEnabled && incomingEmbeddable) {
+ const { embeddableId, input, type } = incomingEmbeddable;
+
+ const config = encode(input);
+ const expression = `embeddable config="${config}"
+ type="${type}"
+| render`;
+
+ if (embeddableId) {
+ // clear out resolved arg for old embeddable
+ const argumentPath = [embeddableId, 'expressionRenderable'];
+ dispatch(clearValue({ path: argumentPath }));
+
+ // update existing embeddable expression
+ dispatch(
+ updateEmbeddableExpression({ elementId: embeddableId, embeddableExpression: expression })
+ );
+
+ // update resolved args
+ dispatch(fetchEmbeddableRenderable(embeddableId));
+
+ // select new embeddable element
+ dispatch(selectToplevelNodes([embeddableId]));
+ } else {
+ dispatch(addElement(pageId, { expression }));
+ }
+ }
+ }, [dispatch, pageId, incomingEmbeddable, isByValueEnabled]);
+};
diff --git a/x-pack/plugins/canvas/public/components/workpad/workpad.tsx b/x-pack/plugins/canvas/public/components/workpad/workpad.tsx
index 622c885b6ef28..bc867333b648f 100644
--- a/x-pack/plugins/canvas/public/components/workpad/workpad.tsx
+++ b/x-pack/plugins/canvas/public/components/workpad/workpad.tsx
@@ -27,6 +27,7 @@ import { WorkpadRoutingContext } from '../../routes/workpad';
import { usePlatformService } from '../../services';
import { Workpad as WorkpadComponent, Props } from './workpad.component';
import { State } from '../../../types';
+import { useIncomingEmbeddable } from '../hooks';
type ContainerProps = Pick;
@@ -58,6 +59,9 @@ export const Workpad: FC = (props) => {
};
});
+ const pageId = propsFromState.pages[propsFromState.selectedPageNumber - 1].id;
+ useIncomingEmbeddable(pageId);
+
const fetchAllRenderables = useCallback(() => {
dispatch(fetchAllRenderablesAction());
}, [dispatch]);
diff --git a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/__stories__/element_menu.stories.tsx b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/__stories__/element_menu.stories.tsx
index 9d37873bcae0a..a48a6e35a4a37 100644
--- a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/__stories__/element_menu.stories.tsx
+++ b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/__stories__/element_menu.stories.tsx
@@ -130,5 +130,9 @@ You can use standard Markdown in here, but you can also access your piped-in dat
};
storiesOf('components/WorkpadHeader/ElementMenu', module).add('default', () => (
-
+
));
diff --git a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx
index 8ac581b0866a4..024c71c7a8dfc 100644
--- a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx
+++ b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx
@@ -18,6 +18,7 @@ import { ElementSpec } from '../../../../types';
import { flattenPanelTree } from '../../../lib/flatten_panel_tree';
import { AssetManager } from '../../asset_manager';
import { SavedElementsModal } from '../../saved_elements_modal';
+import { useLabsService } from '../../../services';
interface CategorizedElementLists {
[key: string]: ElementSpec[];
@@ -112,7 +113,7 @@ const categorizeElementsByType = (elements: ElementSpec[]): { [key: string]: Ele
return categories;
};
-interface Props {
+export interface Props {
/**
* Dictionary of elements from elements registry
*/
@@ -120,10 +121,20 @@ interface Props {
/**
* Handler for adding a selected element to the workpad
*/
- addElement: (element: ElementSpec) => void;
+ addElement: (element: Partial) => void;
+ /**
+ * Crete new embeddable
+ */
+ createNewEmbeddable: () => void;
}
-export const ElementMenu: FunctionComponent = ({ elements, addElement }) => {
+export const ElementMenu: FunctionComponent = ({
+ elements,
+ addElement,
+ createNewEmbeddable,
+}) => {
+ const labsService = useLabsService();
+ const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable');
const [isAssetModalVisible, setAssetModalVisible] = useState(false);
const [isSavedElementsModalVisible, setSavedElementsModalVisible] = useState(false);
@@ -199,6 +210,18 @@ export const ElementMenu: FunctionComponent = ({ elements, addElement })
closePopover();
},
},
+ // TODO: Remove this menu option. This is a temporary menu options just for testing,
+ // will be removed once toolbar is implemented
+ isByValueEnabled
+ ? {
+ name: 'Lens',
+ icon: ,
+ onClick: () => {
+ createNewEmbeddable();
+ closePopover();
+ },
+ }
+ : {},
],
};
};
diff --git a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.tsx b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.tsx
index d43d13a65a5d7..b4f28df9e9a11 100644
--- a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.tsx
+++ b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.tsx
@@ -5,4 +5,34 @@
* 2.0.
*/
-export * from './element_menu.component';
+import React, { FC, useCallback } from 'react';
+import { useLocation } from 'react-router-dom';
+import { trackCanvasUiMetric, METRIC_TYPE } from '../../../../public/lib/ui_metric';
+import { CANVAS_APP } from '../../../../common/lib';
+import { ElementMenu as Component, Props } from './element_menu.component';
+import { useEmbeddablesService } from '../../../services';
+
+export const ElementMenu: FC> = (props) => {
+ const embeddablesService = useEmbeddablesService();
+ const stateTransferService = embeddablesService.getStateTransfer();
+ const { pathname, search } = useLocation();
+
+ const createNewEmbeddable = useCallback(() => {
+ const path = '#/';
+ const appId = 'lens';
+
+ if (trackCanvasUiMetric) {
+ trackCanvasUiMetric(METRIC_TYPE.CLICK, `${appId}:create`);
+ }
+
+ stateTransferService.navigateToEditor(appId, {
+ path,
+ state: {
+ originatingApp: CANVAS_APP,
+ originatingPath: `#/${pathname}${search}`,
+ },
+ });
+ }, [pathname, search, stateTransferService]);
+
+ return ;
+};
diff --git a/x-pack/plugins/canvas/public/plugin.tsx b/x-pack/plugins/canvas/public/plugin.tsx
index 723d1afea2860..afaa750c124bf 100644
--- a/x-pack/plugins/canvas/public/plugin.tsx
+++ b/x-pack/plugins/canvas/public/plugin.tsx
@@ -122,7 +122,12 @@ export class CanvasPlugin
const { pluginServices } = await import('./services');
pluginServices.setRegistry(
- pluginServiceRegistry.start({ coreStart, startPlugins, initContext: this.initContext })
+ pluginServiceRegistry.start({
+ coreStart,
+ startPlugins,
+ appUpdater: this.appUpdater,
+ initContext: this.initContext,
+ })
);
// Load application bundle
diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts
index 35e79b442a15d..bd9a4e7141c27 100644
--- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts
+++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts
@@ -53,14 +53,24 @@ export const useWorkpad = (
workpad.aliasId = aliasId;
}
- dispatch(setAssets(assets));
- dispatch(setWorkpad(workpad, { loadPages }));
- dispatch(setZoomScale(1));
+ if (storedWorkpad.id !== workpadId || storedWorkpad.aliasId !== aliasId) {
+ dispatch(setAssets(assets));
+ dispatch(setWorkpad(workpad, { loadPages }));
+ dispatch(setZoomScale(1));
+ }
} catch (e) {
setError(e as Error | string);
}
})();
- }, [workpadId, dispatch, setError, loadPages, workpadResolve]);
+ }, [
+ workpadId,
+ dispatch,
+ setError,
+ loadPages,
+ workpadResolve,
+ storedWorkpad.id,
+ storedWorkpad.aliasId,
+ ]);
useEffect(() => {
(() => {
diff --git a/x-pack/plugins/canvas/public/services/embeddables.ts b/x-pack/plugins/canvas/public/services/embeddables.ts
index 24d7a57e086f2..26b150b7a5349 100644
--- a/x-pack/plugins/canvas/public/services/embeddables.ts
+++ b/x-pack/plugins/canvas/public/services/embeddables.ts
@@ -5,8 +5,12 @@
* 2.0.
*/
-import { EmbeddableFactory } from '../../../../../src/plugins/embeddable/public';
+import {
+ EmbeddableFactory,
+ EmbeddableStateTransfer,
+} from '../../../../../src/plugins/embeddable/public';
export interface CanvasEmbeddablesService {
getEmbeddableFactories: () => IterableIterator;
+ getStateTransfer: () => EmbeddableStateTransfer;
}
diff --git a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts b/x-pack/plugins/canvas/public/services/kibana/embeddables.ts
index 054b9da7409fb..8d1a86edab3d8 100644
--- a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts
+++ b/x-pack/plugins/canvas/public/services/kibana/embeddables.ts
@@ -16,4 +16,5 @@ export type EmbeddablesServiceFactory = KibanaPluginServiceFactory<
export const embeddablesServiceFactory: EmbeddablesServiceFactory = ({ startPlugins }) => ({
getEmbeddableFactories: startPlugins.embeddable.getEmbeddableFactories,
+ getStateTransfer: startPlugins.embeddable.getStateTransfer,
});
diff --git a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts b/x-pack/plugins/canvas/public/services/stubs/embeddables.ts
index 173d27563e2b2..9c2cf4d0650ab 100644
--- a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts
+++ b/x-pack/plugins/canvas/public/services/stubs/embeddables.ts
@@ -14,4 +14,5 @@ const noop = (..._args: any[]): any => {};
export const embeddablesServiceFactory: EmbeddablesServiceFactory = () => ({
getEmbeddableFactories: noop,
+ getStateTransfer: noop,
});
diff --git a/x-pack/plugins/canvas/types/embeddables.ts b/x-pack/plugins/canvas/types/embeddables.ts
new file mode 100644
index 0000000000000..b78efece59d8f
--- /dev/null
+++ b/x-pack/plugins/canvas/types/embeddables.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { TimeRange } from 'src/plugins/data/public';
+import { Filter } from '@kbn/es-query';
+import { EmbeddableInput as Input } from '../../../../src/plugins/embeddable/common/';
+
+export type EmbeddableInput = Input & {
+ timeRange?: TimeRange;
+ filters?: Filter[];
+ savedObjectId?: string;
+};
diff --git a/x-pack/plugins/canvas/types/index.ts b/x-pack/plugins/canvas/types/index.ts
index 09ae1510be6da..930f337292088 100644
--- a/x-pack/plugins/canvas/types/index.ts
+++ b/x-pack/plugins/canvas/types/index.ts
@@ -9,6 +9,7 @@ export * from '../../../../src/plugins/expressions/common';
export * from './assets';
export * from './canvas';
export * from './elements';
+export * from './embeddables';
export * from './filters';
export * from './functions';
export * from './renderers';