parent
91436b387e
commit
5ce8a5d4f4
19 changed files with 506 additions and 15 deletions
5
x-pack/examples/embedded_lens_example/.eslintrc.json
Normal file
5
x-pack/examples/embedded_lens_example/.eslintrc.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"rules": {
|
||||
"@typescript-eslint/consistent-type-definitions": 0
|
||||
}
|
||||
}
|
13
x-pack/examples/embedded_lens_example/README.md
Normal file
13
x-pack/examples/embedded_lens_example/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Embedded Lens examples
|
||||
|
||||
To run this example plugin, use the command `yarn start --run-examples`.
|
||||
|
||||
This example shows how to embed Lens into other applications. Using the `EmbeddableComponent` of the `lens` start plugin,
|
||||
you can pass in a valid Lens configuration which will get rendered the same way Lens dashboard panels work. Updating the
|
||||
configuration will reload the embedded visualization.
|
||||
|
||||
## Link to editor
|
||||
|
||||
It is possible to use the same configuration and the `navigateToPrefilledEditor` method to navigate the current user to a
|
||||
prefilled Lens editor so they can manipulate the configuration on their own and even save the results to a dashboard.
|
||||
Make sure to always check permissions using `canUseEditor` whether the current user has permissions to access Lens.
|
15
x-pack/examples/embedded_lens_example/kibana.json
Normal file
15
x-pack/examples/embedded_lens_example/kibana.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"id": "embeddedLensExample",
|
||||
"version": "0.0.1",
|
||||
"kibanaVersion": "kibana",
|
||||
"configPath": ["embedded_lens_example"],
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": [
|
||||
"lens",
|
||||
"data",
|
||||
"developerExamples"
|
||||
],
|
||||
"optionalPlugins": [],
|
||||
"requiredBundles": []
|
||||
}
|
14
x-pack/examples/embedded_lens_example/package.json
Normal file
14
x-pack/examples/embedded_lens_example/package.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "embedded_lens_example",
|
||||
"version": "1.0.0",
|
||||
"main": "target/examples/embedded_lens_example",
|
||||
"kibana": {
|
||||
"version": "kibana",
|
||||
"templateVersion": "1.0.0"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"kbn": "node ../../../scripts/kbn.js",
|
||||
"build": "rm -rf './target' && ../../../node_modules/.bin/tsc"
|
||||
}
|
||||
}
|
180
x-pack/examples/embedded_lens_example/public/app.tsx
Normal file
180
x-pack/examples/embedded_lens_example/public/app.tsx
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiPage,
|
||||
EuiPageBody,
|
||||
EuiPageContent,
|
||||
EuiPageContentBody,
|
||||
EuiPageHeader,
|
||||
EuiPageHeaderSection,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { IndexPattern } from 'src/plugins/data/public';
|
||||
import { CoreStart } from 'kibana/public';
|
||||
import { TypedLensByValueInput } from '../../../plugins/lens/public';
|
||||
import { StartDependencies } from './plugin';
|
||||
|
||||
// Generate a Lens state based on some app-specific input parameters.
|
||||
// `TypedLensByValueInput` can be used for type-safety - it uses the same interfaces as Lens-internal code.
|
||||
function getLensAttributes(
|
||||
defaultIndexPattern: IndexPattern,
|
||||
color: string
|
||||
): TypedLensByValueInput['attributes'] {
|
||||
return {
|
||||
visualizationType: 'lnsXY',
|
||||
title: 'Prefilled from example app',
|
||||
references: [
|
||||
{
|
||||
id: defaultIndexPattern.id!,
|
||||
name: 'indexpattern-datasource-current-indexpattern',
|
||||
type: 'index-pattern',
|
||||
},
|
||||
{
|
||||
id: defaultIndexPattern.id!,
|
||||
name: 'indexpattern-datasource-layer-layer1',
|
||||
type: 'index-pattern',
|
||||
},
|
||||
],
|
||||
state: {
|
||||
datasourceStates: {
|
||||
indexpattern: {
|
||||
layers: {
|
||||
layer1: {
|
||||
columnOrder: ['col1', 'col2'],
|
||||
columns: {
|
||||
col2: {
|
||||
dataType: 'number',
|
||||
isBucketed: false,
|
||||
label: 'Count of records',
|
||||
operationType: 'count',
|
||||
scale: 'ratio',
|
||||
sourceField: 'Records',
|
||||
},
|
||||
col1: {
|
||||
dataType: 'date',
|
||||
isBucketed: true,
|
||||
label: '@timestamp',
|
||||
operationType: 'date_histogram',
|
||||
params: { interval: 'auto' },
|
||||
scale: 'interval',
|
||||
sourceField: defaultIndexPattern.timeFieldName!,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
filters: [],
|
||||
query: { language: 'kuery', query: '' },
|
||||
visualization: {
|
||||
axisTitlesVisibilitySettings: { x: true, yLeft: true, yRight: true },
|
||||
fittingFunction: 'None',
|
||||
gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true },
|
||||
layers: [
|
||||
{
|
||||
accessors: ['col2'],
|
||||
layerId: 'layer1',
|
||||
seriesType: 'bar_stacked',
|
||||
xAccessor: 'col1',
|
||||
yConfig: [{ forAccessor: 'col2', color }],
|
||||
},
|
||||
],
|
||||
legend: { isVisible: true, position: 'right' },
|
||||
preferredSeriesType: 'bar_stacked',
|
||||
tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true },
|
||||
valueLabels: 'hide',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const App = (props: {
|
||||
core: CoreStart;
|
||||
plugins: StartDependencies;
|
||||
defaultIndexPattern: IndexPattern | null;
|
||||
}) => {
|
||||
const [color, setColor] = useState('green');
|
||||
const LensComponent = props.plugins.lens.EmbeddableComponent;
|
||||
return (
|
||||
<EuiPage>
|
||||
<EuiPageBody style={{ maxWidth: 1200, margin: '0 auto' }}>
|
||||
<EuiPageHeader>
|
||||
<EuiPageHeaderSection>
|
||||
<EuiTitle size="l">
|
||||
<h1>Embedded Lens vis</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageHeaderSection>
|
||||
</EuiPageHeader>
|
||||
<EuiPageContent>
|
||||
<EuiPageContentBody style={{ maxWidth: 800, margin: '0 auto' }}>
|
||||
<p>
|
||||
This app embeds a Lens visualization by specifying the configuration. Data fetching
|
||||
and rendering is completely managed by Lens itself.
|
||||
</p>
|
||||
<p>
|
||||
The Change color button will update the configuration by picking a new random color of
|
||||
the series which causes Lens to re-render. The Edit button will take the current
|
||||
configuration and navigate to a prefilled editor.
|
||||
</p>
|
||||
{props.defaultIndexPattern && props.defaultIndexPattern.isTimeBased() ? (
|
||||
<>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
onClick={() => {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const newColor = '#' + ((Math.random() * 0xffffff) << 0).toString(16);
|
||||
setColor(newColor);
|
||||
}}
|
||||
>
|
||||
Change color
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
isDisabled={!props.plugins.lens.canUseEditor()}
|
||||
onClick={() => {
|
||||
props.plugins.lens.navigateToPrefilledEditor({
|
||||
id: '',
|
||||
timeRange: {
|
||||
from: 'now-5d',
|
||||
to: 'now',
|
||||
},
|
||||
attributes: getLensAttributes(props.defaultIndexPattern!, color),
|
||||
});
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const newColor = '#' + ((Math.random() * 0xffffff) << 0).toString(16);
|
||||
setColor(newColor);
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<LensComponent
|
||||
id=""
|
||||
style={{ height: 500 }}
|
||||
timeRange={{
|
||||
from: 'now-5d',
|
||||
to: 'now',
|
||||
}}
|
||||
attributes={getLensAttributes(props.defaultIndexPattern, color)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<p>This demo only works if your default index pattern is set and time based</p>
|
||||
)}
|
||||
</EuiPageContentBody>
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
);
|
||||
};
|
9
x-pack/examples/embedded_lens_example/public/index.ts
Normal file
9
x-pack/examples/embedded_lens_example/public/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EmbeddedLensExamplePlugin } from './plugin';
|
||||
|
||||
export const plugin = () => new EmbeddedLensExamplePlugin();
|
28
x-pack/examples/embedded_lens_example/public/mount.tsx
Normal file
28
x-pack/examples/embedded_lens_example/public/mount.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { CoreSetup, AppMountParameters } from 'kibana/public';
|
||||
import { StartDependencies } from './plugin';
|
||||
|
||||
export const mount = (coreSetup: CoreSetup<StartDependencies>) => async ({
|
||||
element,
|
||||
}: AppMountParameters) => {
|
||||
const [core, plugins] = await coreSetup.getStartServices();
|
||||
const { App } = await import('./app');
|
||||
|
||||
const deps = {
|
||||
core,
|
||||
plugins,
|
||||
};
|
||||
|
||||
const defaultIndexPattern = await plugins.data.indexPatterns.getDefault();
|
||||
|
||||
const reactElement = <App {...deps} defaultIndexPattern={defaultIndexPattern} />;
|
||||
render(reactElement, element);
|
||||
return () => unmountComponentAtNode(element);
|
||||
};
|
53
x-pack/examples/embedded_lens_example/public/plugin.ts
Normal file
53
x-pack/examples/embedded_lens_example/public/plugin.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup, AppNavLinkStatus } from '../../../../src/core/public';
|
||||
import { DataPublicPluginStart } from '../../../../src/plugins/data/public';
|
||||
import { LensPublicStart } from '../../../plugins/lens/public';
|
||||
import { DeveloperExamplesSetup } from '../../../../examples/developer_examples/public';
|
||||
import { mount } from './mount';
|
||||
|
||||
export interface SetupDependencies {
|
||||
developerExamples: DeveloperExamplesSetup;
|
||||
}
|
||||
|
||||
export interface StartDependencies {
|
||||
data: DataPublicPluginStart;
|
||||
lens: LensPublicStart;
|
||||
}
|
||||
|
||||
export class EmbeddedLensExamplePlugin
|
||||
implements Plugin<void, void, SetupDependencies, StartDependencies> {
|
||||
public setup(core: CoreSetup<StartDependencies>, { developerExamples }: SetupDependencies) {
|
||||
core.application.register({
|
||||
id: 'embedded_lens_example',
|
||||
title: 'Embedded Lens example',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
mount: mount(core),
|
||||
});
|
||||
|
||||
developerExamples.register({
|
||||
appId: 'embedded_lens_example',
|
||||
title: 'Embedded Lens',
|
||||
description:
|
||||
'Embed Lens visualizations into other applications and link to a pre-configured Lens editor to allow users to use visualizations in your app as starting points for further explorations.',
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href:
|
||||
'https://github.com/elastic/kibana/tree/master/x-pack/examples/embedded_lens_example',
|
||||
iconType: 'logoGithub',
|
||||
size: 's',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
||||
public stop() {}
|
||||
}
|
22
x-pack/examples/embedded_lens_example/tsconfig.json
Normal file
22
x-pack/examples/embedded_lens_example/tsconfig.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"index.ts",
|
||||
"public/**/*.ts",
|
||||
"public/**/*.tsx",
|
||||
"server/**/*.ts",
|
||||
"../../typings/**/*"
|
||||
],
|
||||
"exclude": [],
|
||||
"references": [
|
||||
{ "path": "../../../src/core/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/kibana_utils/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/kibana_react/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/share/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/data/tsconfig.json" }
|
||||
]
|
||||
}
|
|
@ -38,7 +38,7 @@ import {
|
|||
EmbeddableStateTransfer,
|
||||
} from '../../../../../src/plugins/embeddable/public';
|
||||
import { TableInspectorAdapter } from '../editor_frame_service/types';
|
||||
import { EditorFrameInstance } from '..';
|
||||
import { EditorFrameInstance } from '../types';
|
||||
|
||||
export interface LensAppState {
|
||||
isLoading: boolean;
|
||||
|
|
|
@ -214,8 +214,6 @@ describe('embeddable', () => {
|
|||
searchSessionId: 'searchSessionId',
|
||||
});
|
||||
|
||||
expect(expressionRenderer).toHaveBeenCalledTimes(1);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
expect(expressionRenderer).toHaveBeenCalledTimes(2);
|
||||
|
|
|
@ -57,6 +57,10 @@ interface LensBaseEmbeddableInput extends EmbeddableInput {
|
|||
filters?: Filter[];
|
||||
query?: Query;
|
||||
timeRange?: TimeRange;
|
||||
palette?: PaletteOutput;
|
||||
renderMode?: RenderMode;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export type LensByValueInput = {
|
||||
|
@ -64,10 +68,7 @@ export type LensByValueInput = {
|
|||
} & LensBaseEmbeddableInput;
|
||||
|
||||
export type LensByReferenceInput = SavedObjectEmbeddableInput & LensBaseEmbeddableInput;
|
||||
export type LensEmbeddableInput = (LensByValueInput | LensByReferenceInput) & {
|
||||
palette?: PaletteOutput;
|
||||
renderMode?: RenderMode;
|
||||
};
|
||||
export type LensEmbeddableInput = LensByValueInput | LensByReferenceInput;
|
||||
|
||||
export interface LensEmbeddableOutput extends EmbeddableOutput {
|
||||
indexPatterns?: IIndexPattern[];
|
||||
|
@ -159,6 +160,37 @@ export class Embeddable
|
|||
.subscribe((input) => {
|
||||
this.reload();
|
||||
});
|
||||
|
||||
// Re-initialize the visualization if either the attributes or the saved object id changes
|
||||
input$
|
||||
.pipe(
|
||||
distinctUntilChanged((a, b) =>
|
||||
isEqual(
|
||||
['attributes' in a && a.attributes, 'savedObjectId' in a && a.savedObjectId],
|
||||
['attributes' in b && b.attributes, 'savedObjectId' in b && b.savedObjectId]
|
||||
)
|
||||
),
|
||||
skip(1)
|
||||
)
|
||||
.subscribe(async (input) => {
|
||||
await this.initializeSavedVis(input);
|
||||
this.reload();
|
||||
});
|
||||
|
||||
// Update search context and reload on changes related to search
|
||||
input$
|
||||
.pipe(
|
||||
distinctUntilChanged((a, b) =>
|
||||
isEqual(
|
||||
[a.filters, a.query, a.timeRange, a.searchSessionId],
|
||||
[b.filters, b.query, b.timeRange, b.searchSessionId]
|
||||
)
|
||||
),
|
||||
skip(1)
|
||||
)
|
||||
.subscribe(async (input) => {
|
||||
this.onContainerStateChanged(input);
|
||||
});
|
||||
}
|
||||
|
||||
public supportedTriggers() {
|
||||
|
@ -262,6 +294,8 @@ export class Embeddable
|
|||
renderMode={input.renderMode}
|
||||
syncColors={input.syncColors}
|
||||
hasCompatibleActions={this.hasCompatibleActions}
|
||||
className={input.className}
|
||||
style={input.style}
|
||||
/>,
|
||||
domNode
|
||||
);
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import {
|
||||
EmbeddableRenderer,
|
||||
EmbeddableStart,
|
||||
} from '../../../../../../src/plugins/embeddable/public';
|
||||
import type { LensByReferenceInput, LensByValueInput } from './embeddable';
|
||||
import type { Document } from '../../persistence';
|
||||
import type { IndexPatternPersistedState } from '../../indexpattern_datasource/types';
|
||||
import type { XYState } from '../../xy_visualization/types';
|
||||
import type { PieVisualizationState } from '../../pie_visualization/types';
|
||||
import type { DatatableVisualizationState } from '../../datatable_visualization/visualization';
|
||||
import type { State as MetricState } from '../../metric_visualization/types';
|
||||
|
||||
type LensAttributes<TVisType, TVisState> = Omit<
|
||||
Document,
|
||||
'savedObjectId' | 'type' | 'state' | 'visualizationType'
|
||||
> & {
|
||||
visualizationType: TVisType;
|
||||
state: Omit<Document['state'], 'datasourceStates' | 'visualization'> & {
|
||||
datasourceStates: {
|
||||
indexpattern: IndexPatternPersistedState;
|
||||
};
|
||||
visualization: TVisState;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Type-safe variant of by value embeddable input for Lens.
|
||||
* This can be used to hardcode certain Lens chart configurations within another app.
|
||||
*/
|
||||
export type TypedLensByValueInput = Omit<LensByValueInput, 'attributes'> & {
|
||||
attributes:
|
||||
| LensAttributes<'lnsXY', XYState>
|
||||
| LensAttributes<'lnsPie', PieVisualizationState>
|
||||
| LensAttributes<'lnsDatatable', DatatableVisualizationState>
|
||||
| LensAttributes<'lnsMetric', MetricState>;
|
||||
};
|
||||
|
||||
export type EmbeddableComponentProps = TypedLensByValueInput | LensByReferenceInput;
|
||||
|
||||
export function getEmbeddableComponent(embeddableStart: EmbeddableStart) {
|
||||
return (props: EmbeddableComponentProps) => {
|
||||
const factory = embeddableStart.getEmbeddableFactory('lens')!;
|
||||
return <EmbeddableRenderer factory={factory} input={props} />;
|
||||
};
|
||||
}
|
|
@ -15,6 +15,7 @@ import {
|
|||
} from 'src/plugins/expressions/public';
|
||||
import { ExecutionContextSearch } from 'src/plugins/data/public';
|
||||
import { DefaultInspectorAdapters, RenderMode } from 'src/plugins/expressions';
|
||||
import classNames from 'classnames';
|
||||
import { getOriginalRequestErrorMessage } from '../error_helper';
|
||||
|
||||
export interface ExpressionWrapperProps {
|
||||
|
@ -31,6 +32,8 @@ export interface ExpressionWrapperProps {
|
|||
renderMode?: RenderMode;
|
||||
syncColors?: boolean;
|
||||
hasCompatibleActions?: ReactExpressionRendererProps['hasCompatibleActions'];
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function ExpressionWrapper({
|
||||
|
@ -44,6 +47,8 @@ export function ExpressionWrapper({
|
|||
renderMode,
|
||||
syncColors,
|
||||
hasCompatibleActions,
|
||||
style,
|
||||
className,
|
||||
}: ExpressionWrapperProps) {
|
||||
return (
|
||||
<I18nProvider>
|
||||
|
@ -62,7 +67,7 @@ export function ExpressionWrapper({
|
|||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
) : (
|
||||
<div className="lnsExpressionRenderer">
|
||||
<div className={classNames('lnsExpressionRenderer', className)} style={style}>
|
||||
<ExpressionRendererComponent
|
||||
className="lnsExpressionRenderer__component"
|
||||
padding="s"
|
||||
|
|
|
@ -6,6 +6,15 @@
|
|||
|
||||
import { LensPlugin } from './plugin';
|
||||
|
||||
export * from './types';
|
||||
export {
|
||||
EmbeddableComponentProps,
|
||||
TypedLensByValueInput,
|
||||
} from './editor_frame_service/embeddable/embeddable_component';
|
||||
export type { XYState } from './xy_visualization/types';
|
||||
export type { PieVisualizationState } from './pie_visualization/types';
|
||||
export type { DatatableVisualizationState } from './datatable_visualization/visualization';
|
||||
export type { State as MetricState } from './metric_visualization/types';
|
||||
export type { IndexPatternPersistedState } from './indexpattern_datasource/types';
|
||||
export { LensPublicStart } from './plugin';
|
||||
|
||||
export const plugin = () => new LensPlugin();
|
||||
|
|
|
@ -47,7 +47,7 @@ import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/p
|
|||
import { DataPublicPluginStart } from '../../../../../src/plugins/data/public';
|
||||
import { VisualizeFieldContext } from '../../../../../src/plugins/ui_actions/public';
|
||||
import { mergeLayer } from './state_helpers';
|
||||
import { Datasource, StateSetter } from '../index';
|
||||
import { Datasource, StateSetter } from '../types';
|
||||
import { ChartsPluginSetup } from '../../../../../src/plugins/charts/public';
|
||||
import { deleteColumn, isReferenced } from './operations';
|
||||
import { Dragging } from '../drag_drop/providers';
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { getSuggestions } from './metric_suggestions';
|
||||
import { TableSuggestionColumn, TableSuggestion } from '../index';
|
||||
import { TableSuggestionColumn, TableSuggestion } from '../types';
|
||||
|
||||
describe('metric_suggestions', () => {
|
||||
function numCol(columnId: string): TableSuggestionColumn {
|
||||
|
|
|
@ -17,6 +17,7 @@ import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/
|
|||
import { UrlForwardingSetup } from '../../../../src/plugins/url_forwarding/public';
|
||||
import { GlobalSearchPluginSetup } from '../../global_search/public';
|
||||
import { ChartsPluginSetup, ChartsPluginStart } from '../../../../src/plugins/charts/public';
|
||||
import { EmbeddableStateTransfer } from '../../../../src/plugins/embeddable/public';
|
||||
import { EditorFrameService } from './editor_frame_service';
|
||||
import {
|
||||
IndexPatternDatasource,
|
||||
|
@ -37,7 +38,7 @@ import {
|
|||
ACTION_VISUALIZE_FIELD,
|
||||
VISUALIZE_FIELD_TRIGGER,
|
||||
} from '../../../../src/plugins/ui_actions/public';
|
||||
import { NOT_INTERNATIONALIZED_PRODUCT_NAME } from '../common';
|
||||
import { getEditPath, NOT_INTERNATIONALIZED_PRODUCT_NAME } from '../common';
|
||||
import { PLUGIN_ID_OSS } from '../../../../src/plugins/lens_oss/common/constants';
|
||||
import { EditorFrameStart } from './types';
|
||||
import { getLensAliasConfig } from './vis_type_alias';
|
||||
|
@ -45,6 +46,11 @@ import { visualizeFieldAction } from './trigger_actions/visualize_field_actions'
|
|||
import { getSearchProvider } from './search_provider';
|
||||
|
||||
import { LensAttributeService } from './lens_attribute_service';
|
||||
import { LensEmbeddableInput } from './editor_frame_service/embeddable';
|
||||
import {
|
||||
EmbeddableComponentProps,
|
||||
getEmbeddableComponent,
|
||||
} from './editor_frame_service/embeddable/embeddable_component';
|
||||
|
||||
export interface LensPluginSetupDependencies {
|
||||
urlForwarding: UrlForwardingSetup;
|
||||
|
@ -68,6 +74,31 @@ export interface LensPluginStartDependencies {
|
|||
savedObjectsTagging?: SavedObjectTaggingPluginStart;
|
||||
}
|
||||
|
||||
export interface LensPublicStart {
|
||||
/**
|
||||
* React component which can be used to embed a Lens visualization into another application.
|
||||
* See `x-pack/examples/embedded_lens_example` for exemplary usage.
|
||||
*
|
||||
* This API might undergo breaking changes even in minor versions.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
EmbeddableComponent: React.ComponentType<EmbeddableComponentProps>;
|
||||
/**
|
||||
* Method which navigates to the Lens editor, loading the state specified by the `input` parameter.
|
||||
* See `x-pack/examples/embedded_lens_example` for exemplary usage.
|
||||
*
|
||||
* This API might undergo breaking changes even in minor versions.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
navigateToPrefilledEditor: (input: LensEmbeddableInput) => void;
|
||||
/**
|
||||
* Method which returns true if the user has permission to use Lens as defined by application capabilities.
|
||||
*/
|
||||
canUseEditor: () => boolean;
|
||||
}
|
||||
|
||||
export class LensPlugin {
|
||||
private datatableVisualization: DatatableVisualization;
|
||||
private editorFrameService: EditorFrameService;
|
||||
|
@ -174,8 +205,9 @@ export class LensPlugin {
|
|||
urlForwarding.forwardApp('lens', 'lens');
|
||||
}
|
||||
|
||||
start(core: CoreStart, startDependencies: LensPluginStartDependencies) {
|
||||
this.createEditorFrame = this.editorFrameService.start(core, startDependencies).createInstance;
|
||||
start(core: CoreStart, startDependencies: LensPluginStartDependencies): LensPublicStart {
|
||||
const frameStart = this.editorFrameService.start(core, startDependencies);
|
||||
this.createEditorFrame = frameStart.createInstance;
|
||||
// unregisters the OSS alias
|
||||
startDependencies.visualizations.unRegisterAlias(PLUGIN_ID_OSS);
|
||||
// unregisters the Visualize action and registers the lens one
|
||||
|
@ -186,6 +218,29 @@ export class LensPlugin {
|
|||
VISUALIZE_FIELD_TRIGGER,
|
||||
visualizeFieldAction(core.application)
|
||||
);
|
||||
|
||||
return {
|
||||
EmbeddableComponent: getEmbeddableComponent(startDependencies.embeddable),
|
||||
navigateToPrefilledEditor: (input: LensEmbeddableInput) => {
|
||||
if (input.timeRange) {
|
||||
startDependencies.data.query.timefilter.timefilter.setTime(input.timeRange);
|
||||
}
|
||||
const transfer = new EmbeddableStateTransfer(
|
||||
core.application.navigateToApp,
|
||||
core.application.currentAppId$
|
||||
);
|
||||
transfer.navigateToEditor('lens', {
|
||||
path: getEditPath(undefined),
|
||||
state: {
|
||||
originatingApp: '',
|
||||
valueInput: input,
|
||||
},
|
||||
});
|
||||
},
|
||||
canUseEditor: () => {
|
||||
return Boolean(core.application.capabilities.visualize?.show);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
|
|
@ -19,7 +19,7 @@ import { LensIconChartBarHorizontalStacked } from '../assets/chart_bar_horizonta
|
|||
import { LensIconChartBarHorizontalPercentage } from '../assets/chart_bar_horizontal_percentage';
|
||||
import { LensIconChartLine } from '../assets/chart_line';
|
||||
|
||||
import { VisualizationType } from '../index';
|
||||
import { VisualizationType } from '../types';
|
||||
import { FittingFunction } from './fitting_functions';
|
||||
|
||||
export interface LegendConfig {
|
||||
|
|
Loading…
Reference in a new issue