lens config builder example app (#178475)

This commit is contained in:
Peter Pisljar 2024-03-13 12:56:37 +01:00 committed by GitHub
parent 2550d40166
commit 6c44ba196a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 327 additions and 0 deletions

1
.github/CODEOWNERS vendored
View file

@ -488,6 +488,7 @@ src/plugins/kibana_usage_collection @elastic/kibana-core
src/plugins/kibana_utils @elastic/appex-sharedux
x-pack/plugins/kubernetes_security @elastic/kibana-cloud-security-posture
packages/kbn-language-documentation-popover @elastic/kibana-visualizations
x-pack/examples/lens_config_builder_example @elastic/kibana-visualizations
packages/kbn-lens-embeddable-utils @elastic/obs-ux-infra_services-team @elastic/kibana-visualizations
packages/kbn-lens-formula-docs @elastic/kibana-visualizations
x-pack/examples/lens_embeddable_inline_editing_example @elastic/kibana-visualizations

View file

@ -514,6 +514,7 @@
"@kbn/kibana-utils-plugin": "link:src/plugins/kibana_utils",
"@kbn/kubernetes-security-plugin": "link:x-pack/plugins/kubernetes_security",
"@kbn/language-documentation-popover": "link:packages/kbn-language-documentation-popover",
"@kbn/lens-config-builder-example-plugin": "link:x-pack/examples/lens_config_builder_example",
"@kbn/lens-embeddable-utils": "link:packages/kbn-lens-embeddable-utils",
"@kbn/lens-formula-docs": "link:packages/kbn-lens-formula-docs",
"@kbn/lens-inline-editing-example-plugin": "link:x-pack/examples/lens_embeddable_inline_editing_example",

View file

@ -970,6 +970,8 @@
"@kbn/kubernetes-security-plugin/*": ["x-pack/plugins/kubernetes_security/*"],
"@kbn/language-documentation-popover": ["packages/kbn-language-documentation-popover"],
"@kbn/language-documentation-popover/*": ["packages/kbn-language-documentation-popover/*"],
"@kbn/lens-config-builder-example-plugin": ["x-pack/examples/lens_config_builder_example"],
"@kbn/lens-config-builder-example-plugin/*": ["x-pack/examples/lens_config_builder_example/*"],
"@kbn/lens-embeddable-utils": ["packages/kbn-lens-embeddable-utils"],
"@kbn/lens-embeddable-utils/*": ["packages/kbn-lens-embeddable-utils/*"],
"@kbn/lens-formula-docs": ["packages/kbn-lens-formula-docs"],

View file

@ -0,0 +1,5 @@
{
"rules": {
"@typescript-eslint/consistent-type-definitions": 0
}
}

View file

@ -0,0 +1,7 @@
# Lens Config Builder 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.

View file

@ -0,0 +1,19 @@
{
"type": "plugin",
"id": "@kbn/lens-config-builder-example-plugin",
"owner": "@elastic/kibana-visualizations",
"plugin": {
"id": "lensConfigBuilderExample",
"server": false,
"browser": true,
"configPath": [
"lens_config_builder_example"
],
"requiredPlugins": [
"lens",
"data",
"embeddable",
"developerExamples"
]
}
}

View file

@ -0,0 +1,163 @@
/*
* 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 React, { useState } from 'react';
import useAsync from 'react-use/lib/useAsync';
import {
EuiPage,
EuiPageBody,
EuiPageSection,
EuiPageHeader,
EuiSpacer,
EuiTextArea,
EuiFlexItem,
EuiButton,
EuiFlexGroup,
} from '@elastic/eui';
import type { CoreStart } from '@kbn/core/public';
import type { LensEmbeddableInput, FormulaPublicApi } from '@kbn/lens-plugin/public';
import { ViewMode } from '@kbn/embeddable-plugin/public';
import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public';
import { LensConfig, LensConfigBuilder } from '@kbn/lens-embeddable-utils/config_builder';
import { DataViewsContract } from '@kbn/data-views-plugin/public';
import { TypedLensByValueInput } from '@kbn/lens-plugin/public';
import type { StartDependencies } from './plugin';
export const App = (props: {
core: CoreStart;
plugins: StartDependencies;
dataViews: DataViewsContract;
formula: FormulaPublicApi;
}) => {
const [error, setError] = useState<string | null>(null);
const [isSaveModalVisible, setIsSaveModalVisible] = useState(false);
const [time, setTime] = useState({
from: 'now-5d',
to: 'now',
});
const [searchSession, setSearchSession] = useState(() =>
props.plugins.data.search.session.start()
);
const [lensConfig, setLensConfig] = useState<LensConfig>({
chartType: 'metric',
title: 'Total Sales',
dataset: {
esql: 'from kibana_sample_data_logs | stats totalBytes = sum(bytes)',
},
value: 'totalBytes',
label: 'Total Bytes Value',
});
const [lensConfigString, setLensConfigString] = useState(JSON.stringify(lensConfig));
const LensComponent = props.plugins.lens.EmbeddableComponent;
const LensSaveModalComponent = props.plugins.lens.SaveModalComponent;
const attributes = useAsync(async () => {
const configBuilder = new LensConfigBuilder(props.formula, props.dataViews);
return (await configBuilder.build(lensConfig, {
embeddable: false,
})) as TypedLensByValueInput['attributes'];
}, [lensConfig]);
if (!attributes.value && !attributes.error && !error) return null;
return (
<EuiPage>
<EuiPageBody style={{ maxWidth: 800, margin: '0 auto' }}>
<EuiPageHeader paddingSize="s" bottomBorder={true} pageTitle="Embedded Lens vis" />
<EuiPageSection paddingSize="s">
<p>
This app embeds a Lens visualization by specifying the configuration. Data fetching and
rendering is completely managed by Lens itself.
</p>
<EuiSpacer />
<EuiTextArea
fullWidth
compressed={true}
value={lensConfigString}
onChange={(e) => {
setLensConfigString(e.target.value);
}}
/>
<EuiFlexGroup wrap gutterSize="s">
<EuiFlexItem grow={false}>
<EuiButton
aria-label="Refresh"
data-test-subj="lns-example-refresh"
onClick={() => {
try {
const newConfig = JSON.parse(lensConfigString);
setLensConfig(newConfig);
setSearchSession(props.plugins.data.search.session.start());
setError(null);
} catch (e) {
setError(e.message);
}
}}
>
Refresh
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
{error && <div>{error}</div>}
{attributes.value && (
<LensComponent
id=""
withDefaultActions
style={{ height: 500 }}
timeRange={time}
attributes={attributes.value}
searchSessionId={searchSession}
onBrushEnd={({ range }) => {
setTime({
from: new Date(range[0]).toISOString(),
to: new Date(range[1]).toISOString(),
});
}}
onFilter={(_data) => {
// call back event for on filter event
}}
onTableRowClick={(_data) => {
// call back event for on table row click event
}}
viewMode={ViewMode.VIEW}
extraActions={[
{
id: 'testAction',
type: 'link',
getIconType: () => 'save',
async isCompatible(context: ActionExecutionContext<object>): Promise<boolean> {
return true;
},
execute: async (context: ActionExecutionContext<object>) => {
alert('I am an extra action');
return;
},
getDisplayName: () => 'Extra action',
},
]}
/>
)}
{attributes.error && <div>{JSON.stringify(attributes.error)}</div>}
{isSaveModalVisible && (
<LensSaveModalComponent
initialInput={attributes as unknown as LensEmbeddableInput}
onSave={() => {}}
onClose={() => setIsSaveModalVisible(false)}
/>
)}
</EuiPageSection>
</EuiPageBody>
</EuiPage>
);
};

View file

@ -0,0 +1,10 @@
/*
* 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 { LensConfigBuilderExamplePlugin } from './plugin';
export const plugin = () => new LensConfigBuilderExamplePlugin();

View file

@ -0,0 +1,36 @@
/*
* 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 * as React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import type { CoreSetup, AppMountParameters } from '@kbn/core/public';
import type { StartDependencies } from './plugin';
export const mount =
(coreSetup: CoreSetup<StartDependencies>) =>
async ({ element }: AppMountParameters) => {
const [core, plugins] = await coreSetup.getStartServices();
const { App } = await import('./app');
const dataViews = plugins.data.indexPatterns;
const { formula } = await plugins.lens.stateHelperApi();
const i18nCore = core.i18n;
const reactElement = (
<i18nCore.Context>
<App core={core} plugins={plugins} dataViews={dataViews} formula={formula} />~
</i18nCore.Context>
);
render(reactElement, element);
return () => {
unmountComponentAtNode(element);
plugins.data.search.session.clear();
};
};

View 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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Plugin, CoreSetup } from '@kbn/core/public';
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
import { LensPublicStart } from '@kbn/lens-plugin/public';
import { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public';
import { mount } from './mount';
export interface SetupDependencies {
developerExamples: DeveloperExamplesSetup;
}
export interface StartDependencies {
data: DataPublicPluginStart;
lens: LensPublicStart;
}
export class LensConfigBuilderExamplePlugin
implements Plugin<void, void, SetupDependencies, StartDependencies>
{
public setup(core: CoreSetup<StartDependencies>, { developerExamples }: SetupDependencies) {
core.application.register({
id: 'lens_config_builder_example',
title: 'Lens Config Builder example',
visibleIn: [],
mount: mount(core),
});
developerExamples.register({
appId: 'lens_config_builder_example',
title: 'Lens Config Builder',
description: 'Embed Lens visualizations into other applications using Lens Config Builder.',
links: [
{
label: 'README',
href: 'https://github.com/elastic/kibana/tree/main/x-pack/examples/lens_config_builder_example',
iconType: 'logoGithub',
size: 's',
target: '_blank',
},
],
});
}
public start() {}
public stop() {}
}

View file

@ -0,0 +1,26 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types"
},
"include": [
"index.ts",
"public/**/*.ts",
"public/**/*.tsx",
"server/**/*.ts",
"../../../typings/**/*"
],
"exclude": [
"target/**/*",
],
"kbn_references": [
"@kbn/core",
"@kbn/data-plugin",
"@kbn/embeddable-plugin",
"@kbn/lens-plugin",
"@kbn/developer-examples-plugin",
"@kbn/data-views-plugin",
"@kbn/ui-actions-plugin",
"@kbn/lens-embeddable-utils",
]
}

View file

@ -5008,6 +5008,10 @@
version "0.0.0"
uid ""
"@kbn/lens-config-builder-example-plugin@link:x-pack/examples/lens_config_builder_example":
version "0.0.0"
uid ""
"@kbn/lens-embeddable-utils@link:packages/kbn-lens-embeddable-utils":
version "0.0.0"
uid ""