Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable plugins to augment visualizations with additional data and context #4361

Merged
merged 43 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ba6f9eb
Add a new `vis_augmenter` plugin (#3107)
ohltyler Dec 22, 2022
e78ccbf
Add interfaces for layering data on Visualizations (#3108)
ohltyler Dec 30, 2022
2b82edd
Rebase feature/feature-anywhere with main (#3364)
ohltyler Feb 1, 2023
a990ab9
Update VisLayer data models (#3374)
ohltyler Feb 4, 2023
eeed599
Add a new `augment-vis` saved object type (#3109)
ohltyler Feb 8, 2023
d63ef1f
Create switch to render line charts using vega-lite (#3106)
lezzago Feb 21, 2023
236f49f
Add logic to collect `VisLayer`s in line chart render flow (#3131)
ohltyler Mar 9, 2023
797f73d
Merge branch 'main' into feature/feature-anywhere
joshuarrrr Mar 9, 2023
6f9f2c7
Add error types to VisLayers (#3646)
ohltyler Mar 22, 2023
79b9f50
Setting savedAugmentVisLoader in Visualizations plugin (#3616)
amitgalitz Mar 22, 2023
c8af939
Merge branch 'main' into feature/feature-anywhere
joshuarrrr Mar 30, 2023
8a2cc69
Dynamically update vega spec to show `VisLayer`s (#3145)
ohltyler Mar 30, 2023
de61732
[Feature Anywhere] Fix visibleVisLayers ser/deser (#3758)
ohltyler Mar 31, 2023
3a719c5
Merge branch 'main' into feature/feature-anywhere
joshuarrrr Apr 22, 2023
03b393f
Add VisLayer error toasts when rendering vis (#3649)
ohltyler Apr 26, 2023
609bcc1
Finalize eligibility check for augmenting visualizations by vis augme…
lezzago May 10, 2023
2cc88f3
Add a `VisAugmenter` stats API (#4006)
ohltyler May 17, 2023
e7e4b2a
[Feature anywhere] Add annotation click handler (#3777)
amsiglan May 22, 2023
2f94a6d
showing default tooltip on mark (#4120)
amsiglan May 24, 2023
570a1c4
Support formatted tooltip for events (#4123)
ohltyler May 24, 2023
ec4c1df
Add new advanced settings for vis augmenter (#3961)
lezzago May 24, 2023
66070aa
Expose external services to helper fns (#4139)
ohltyler May 30, 2023
319b5a2
[Feature Anywhere] Add view events flyout (#3415)
ohltyler May 31, 2023
538d91e
Clean up stale `augment-vis` saved objs (#4059)
ohltyler May 31, 2023
6eda3ef
Rebase Feature-Anywhere branch with main (#4192)
lezzago Jun 1, 2023
b05c633
[Feature Anywhere] Various bug fixes (#4245)
ohltyler Jun 5, 2023
6189e87
[Feature Anywhere] More bug fixes (#4251)
ohltyler Jun 8, 2023
bcc8f94
Allow plugins get vis embeddable to show in flyouts (#4250)
lezzago Jun 9, 2023
1009efe
[Feature Anywhere] More bug fixes (#4269)
ohltyler Jun 15, 2023
83e2ff9
[Feature Anywhere] Fix bug of tooltip showing 'undefined' in certain …
ohltyler Jun 15, 2023
2362c35
Merge main changes to Feature-Anywhere branch (#4295)
lezzago Jun 19, 2023
12b6d44
Group ViewEvents option and bug fix (#4309)
lezzago Jun 19, 2023
4536bb8
Allow queryStart to be passed into fetchVisEmbeddable (#4336)
lezzago Jun 21, 2023
7f1bf92
Merge branch 'main' into feature/feature-anywhere
ohltyler Jun 22, 2023
45ecc1f
[Feature Anywhere] Fix legacy tests / bug fixes (#4327)
ohltyler Jun 22, 2023
f028e8d
Fix unrelated changes to be synced with main (#4414)
ohltyler Jun 29, 2023
70a9ee0
Fix event charts to render with vega (#4443)
ohltyler Jun 29, 2023
799737d
Merge branch 'main' into feature/feature-anywhere
ohltyler Jun 30, 2023
0496f6b
Update default setting; fix single snapshot (#4455)
ohltyler Jun 30, 2023
4cbd72a
Add comment about decoupling from embeddables plugin (#4484)
ohltyler Jul 5, 2023
c3a64d7
Merge branch 'main' into feature/feature-anywhere
ohltyler Jul 5, 2023
1cdc0f6
[Vis Augmenter] Minor follow up improvements (#4503)
ohltyler Jul 5, 2023
04ae9cb
Add TODOs (#4513)
ohltyler Jul 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Bump OUI to `1.1.2` to make `anomalyDetection` icon available ([#4408](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4408))
- Add `color-scheme` to the root styling ([#4477](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4477))
- [Multiple DataSource] Frontend support for adding sample data ([#4412](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4412))
- Enable plugins to augment visualizations with additional data and context ([#4361](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4361))

### 🐛 Bug Fixes

Expand Down
4 changes: 4 additions & 0 deletions config/opensearch_dashboards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,7 @@

# Set the value of this setting to false to hide the help menu link to the OpenSearch Dashboards user survey
# opensearchDashboards.survey.url: "https://survey.opensearch.org"

# Set the value of this setting to true to enable plugin augmentation on Dashboard
ohltyler marked this conversation as resolved.
Show resolved Hide resolved
# vis_augmenter.pluginAugmentationEnabled: true

Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ interface Props {
SavedObjectFinder: React.ComponentType<any>;
stateTransfer?: EmbeddableStateTransfer;
hideHeader?: boolean;
// TODO: the below hasBorder and hasShadow fields may be removed as part of
// https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4483
hasBorder?: boolean;
hasShadow?: boolean;
ohltyler marked this conversation as resolved.
Show resolved Hide resolved
}

interface State {
Expand Down Expand Up @@ -234,6 +238,8 @@ export class EmbeddablePanel extends React.Component<Props, State> {
paddingSize="none"
role="figure"
aria-labelledby={headerId}
hasBorder={this.props.hasBorder}
hasShadow={this.props.hasShadow}
>
{!this.props.hideHeader && (
<PanelHeader
Expand Down
13 changes: 12 additions & 1 deletion src/plugins/embeddable/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,12 @@ export interface EmbeddableStart extends PersistableState<EmbeddableInput> {
getStateTransfer: (history?: ScopedHistory) => EmbeddableStateTransfer;
}

export type EmbeddablePanelHOC = React.FC<{ embeddable: IEmbeddable; hideHeader?: boolean }>;
export type EmbeddablePanelHOC = React.FC<{
embeddable: IEmbeddable;
hideHeader?: boolean;
hasBorder?: boolean;
hasShadow?: boolean;
}>;

export class EmbeddablePublicPlugin implements Plugin<EmbeddableSetup, EmbeddableStart> {
private readonly embeddableFactoryDefinitions: Map<
Expand Down Expand Up @@ -168,12 +173,18 @@ export class EmbeddablePublicPlugin implements Plugin<EmbeddableSetup, Embeddabl
const getEmbeddablePanelHoc = (stateTransfer?: EmbeddableStateTransfer) => ({
embeddable,
hideHeader,
hasBorder,
hasShadow,
}: {
embeddable: IEmbeddable;
hideHeader?: boolean;
hasBorder?: boolean;
hasShadow?: boolean;
}) => (
<EmbeddablePanel
hideHeader={hideHeader}
hasBorder={hasBorder}
hasShadow={hasShadow}
embeddable={embeddable}
stateTransfer={stateTransfer ? stateTransfer : this.outgoingOnlyStateTransfer}
getActions={uiActions.getTriggerCompatibleActions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export const stackManagementSchema: MakeSchemaFrom<UsageStats> = {
'visualization:regionmap:showWarnings': { type: 'boolean' },
'visualization:dimmingOpacity': { type: 'float' },
'visualization:tileMap:maxPrecision': { type: 'long' },
'visualization:enablePluginAugmentation': { type: 'boolean' },
'visualization:enablePluginAugmentation.maxPluginObjects': { type: 'number' },
'securitySolution:ipReputationLinks': { type: 'text' },
'csv:separator': { type: 'keyword' },
'visualization:tileMap:WMSdefaults': { type: 'text' },
Expand Down
160 changes: 109 additions & 51 deletions src/plugins/saved_objects/README.md
ohltyler marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,78 @@

The saved object plugin provides all the core services and functionalities of saved objects. It is utilized by many core plugins such as [`visualization`](../visualizations/), [`dashboard`](../dashboard/) and [`visBuilder`](../vis_builder/), as well as external plugins. Saved object is the primary way to store app and plugin data in a standardized form in OpenSearch Dashboards. They allow plugin developers to manage creating, saving, editing and retrieving data for the application. They can also make reference to other saved objects and have useful features out of the box, such as migrations and strict typings. The saved objects can be managed by the Saved Object Management UI.

## Save relationships to index pattern
### Relationships
ohltyler marked this conversation as resolved.
Show resolved Hide resolved

Saved objects that have relationships to index patterns are saved using the [`kibanaSavedObjectMeta`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts#L59) attribute and the [`references`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts#L60) array structure. Functions from the data plugin are used by the saved object plugin to manage this index pattern relationship.
Saved objects can persist parent/child relationships to other saved objects via `references`. These relationships can be viewed on the UI in the [saved objects management plugin](src/core/server/saved_objects_management/README.md). Relationships can be useful to combine existing saved objects to produce new ones, such as using an index pattern as the source for a visualization, or a dashboard consisting of many visualizations.

A standard saved object and its index pattern relationship:
Some saved object fields have pre-defined logic. For example, if a saved object type has a `searchSource` field indicating an index pattern relationship, a reference will automatically be created using the [`kibanaSavedObjectMeta`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts#L59) attribute and the [`references`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts#L60) array structure. Functions from the data plugin are used by the saved object plugin to manage this index pattern relationship.

An example of a visualization saved object and its index pattern relationship:

```ts

"kibanaSavedObjectMeta" : {
"searchSourceJSON" : """{"filter":[],"query":{"query":"","language":"kuery"},"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}"""
}
},
"type" : "visualization",
"references" : [
{
"name" : "kibanaSavedObjectMeta.searchSourceJSON.index",
"type" : "index-pattern",
"id" : "90943e30-9a47-11e8-b64d-95841ca0b247"
}
],
}
"type" : "visualization",
"references" : [
{
"name" : "kibanaSavedObjectMeta.searchSourceJSON.index",
"type" : "index-pattern",
"id" : "90943e30-9a47-11e8-b64d-95841ca0b247"
}
],

```

### Saving a saved object

When saving a saved object and its relationship to the index pattern:
When saving a saved object and its relationship to the index pattern:

1. A saved object will be built using [`buildSavedObject`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts#L46) function. Services such as hydrating index pattern, initializing and serializing the saved object are set, and configs such as saved object id, migration version are defined.
2. The saved object will then be serialized by three steps:

a. By using [`extractReferences`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/data/common/search/search_source/extract_references.ts#L35) function from the data plugin, the index pattern information will be extracted using the index pattern id within the `kibanaSavedObjectMeta`, and the id will be replaced by a reference name, such as `indexRefName`. A corresponding index pattern object will then be created to include more detailed information of the index pattern: name (`kibanaSavedObjectMeta.searchSourceJSON.index`), type, and id.

```ts
let searchSourceFields = { ...state };
const references = [];

if (searchSourceFields.index) {
const indexId = searchSourceFields.index.id || searchSourceFields.index;
const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
references.push({
name: refName,
type: 'index-pattern',
id: indexId
});
searchSourceFields = { ...searchSourceFields,
indexRefName: refName,
index: undefined
};
}
```
2. The saved object will then be serialized by three steps:

b. The `indexRefName` along with other information will be stringified and saved into `kibanaSavedObjectMeta.searchSourceJSON`.

c. Saved object client will create the reference array attribute, and the index pattern object will be pushed into the reference array.
a. By using [`extractReferences`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/data/common/search/search_source/extract_references.ts#L35) function from the data plugin, the index pattern information will be extracted using the index pattern id within the `kibanaSavedObjectMeta`, and the id will be replaced by a reference name, such as `indexRefName`. A corresponding index pattern object will then be created to include more detailed information of the index pattern: name (`kibanaSavedObjectMeta.searchSourceJSON.index`), type, and id.

```ts
let searchSourceFields = { ...state };
const references = [];

if (searchSourceFields.index) {
const indexId = searchSourceFields.index.id || searchSourceFields.index;
const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
references.push({
name: refName,
type: 'index-pattern',
id: indexId,
});
searchSourceFields = { ...searchSourceFields, indexRefName: refName, index: undefined };
}
```

b. The `indexRefName` along with other information will be stringified and saved into `kibanaSavedObjectMeta.searchSourceJSON`.

c. Saved object client will create the reference array attribute, and the index pattern object will be pushed into the reference array.

### Loading an existing or creating a new saved object

1. When loading an existing object or creating a new saved object, [`initializeSavedObject`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/initialize_saved_object.ts#L38) function will be called.
1. When loading an existing object or creating a new saved object, [`initializeSavedObject`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/initialize_saved_object.ts#L38) function will be called.
2. The saved object will be deserialized in the [`applyOpenSearchResp`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/apply_opensearch_resp.ts#L50) function.

a. Using [`injectReferences`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/data/common/search/search_source/inject_references.ts#L34) function from the data plugin, the index pattern reference name within the `kibanaSavedObject` will be substituted by the index pattern id and the corresponding index pattern reference object will be deleted if filters are applied.
a. Using [`injectReferences`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/data/common/search/search_source/inject_references.ts#L34) function from the data plugin, the index pattern reference name within the `kibanaSavedObject` will be substituted by the index pattern id and the corresponding index pattern reference object will be deleted if filters are applied.

```ts
searchSourceReturnFields.index = reference.id;
delete searchSourceReturnFields.indexRefName;
```

```ts
searchSourceReturnFields.index = reference.id;
delete searchSourceReturnFields.indexRefName;
```
### Creating a new saved object type

### Others

If a saved object type wishes to have additional custom functionalities when extracting/injecting references, or after OpenSearch's response, it can define functions in the class constructor when extending the `SavedObjectClass`. For example, visualization plugin's [`SavedVis`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#L91) class has additional `extractReferences`, `injectReferences` and `afterOpenSearchResp` functions defined in [`_saved_vis.ts`](../visualizations/public/saved_visualizations/_saved_vis.ts).
Steps need to be done on both the public/client-side & the server-side for creating a new saved object type.

Client-side:

1. Define a class that extends `SavedObjectClass`. This is where custom functionalities, such as extracting/injecting references, or overriding `afterOpenSearchResp` can be set in the constructor. For example, visualization plugin's [`SavedVis`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#L91) class has additional `extractReferences`, `injectReferences` and `afterOpenSearchResp` functions defined in [`_saved_vis.ts`](../visualizations/public/saved_visualizations/_saved_vis.ts), and set in the `SavedVis` constructor.

```ts
class SavedVis extends SavedObjectClass {
Expand All @@ -85,14 +86,71 @@ class SavedVis extends SavedObjectClass {
afterOpenSearchResp: async (savedObject: SavedObject) => {
const savedVis = (savedObject as any) as ISavedVis;
... ...

return (savedVis as any) as SavedObject;
},
```

2. Optionally create a loader class that extends `SavedObjectLoader`. This can be useful for performing default CRUD operations on this particular saved object type, as well as overriding default utility functions like `find`. For example, the `visualization` saved object overrides `mapHitSource` (used in `find` & `findAll`) to do additional checking on the returned source object, such as if the returned type is valid:

```ts
class SavedObjectLoaderVisualize extends SavedObjectLoader {
mapHitSource = (source: Record<string, any>, id: string) => {
const visTypes = visualizationTypes;
... ...
let typeName = source.typeName;
if (source.visState) {
try {
typeName = JSON.parse(String(source.visState)).type;
} catch (e) {
/* missing typename handled below */
}
}

if (!typeName || !visTypes.get(typeName)) {
source.error = 'Unknown visualization type';
return source;
}
... ...
return source;
};
```

The loader can then be instantiated once and referenced when needed. For example, the `visualizations` plugin creates and sets it in its `services` in the plugin's start lifecycle:

```ts
public start(
core: CoreStart,
{ data, expressions, uiActions, embeddable, dashboard }: VisualizationsStartDeps
): VisualizationsStart {
... ...
const savedVisualizationsLoader = createSavedVisLoader({
savedObjectsClient: core.savedObjects.client,
indexPatterns: data.indexPatterns,
search: data.search,
chrome: core.chrome,
overlays: core.overlays,
visualizationTypes: types,
});
setSavedVisualizationsLoader(savedVisualizationsLoader);
... ...
}
```

Server-side:

1. Define the new type that is of type `SavedObjectsType`, which is where various settings can be configured, including the index mappings when the object is stored in the system index. To see an example type definition, you can refer to the [visualization saved object type](src/plugins/visualizations/server/saved_objects/visualization.ts).
2. Register the new type in the respective plugin's setup lifecycle function. For example, the `visualizations` plugin registers the `visualization` saved object type like below:

```ts
core.savedObjects.registerType(visualizationSavedObjectType);
```

To make the new type manageable in the `saved_objects_management` plugin, refer to the [plugin README](src/plugins/saved_objects_management/README.md)

## Migration

When a saved object is created using a previous version, the migration will trigger if there is a new way of saving the saved object and the migration functions alter the structure of the old saved object to follow the new structure. Migrations can be defined in the specific saved object type in the plugin's server folder. For example,
When a saved object is created using a previous version, the migration will trigger if there is a new way of saving the saved object and the migration functions alter the structure of the old saved object to follow the new structure. Migrations can be defined in the specific saved object type in the plugin's server folder. For example,

```ts
export const visualizationSavedObjectType: SavedObjectsType = {
Expand All @@ -116,4 +174,4 @@ The migraton version will be saved as a `migrationVersion` attribute in the save
},
```

For a more detailed explanation on the migration, refer to [`saved objects management`](src/core/server/saved_objects/migrations/README.md).
For a more detailed explanation on the migration, refer to [`saved objects management`](src/core/server/saved_objects/migrations/README.md).
3 changes: 3 additions & 0 deletions src/plugins/saved_objects/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@
*/

export const PER_PAGE_SETTING = 'savedObjects:perPage';
export const PER_PAGE_VALUE = 20;

export const LISTING_LIMIT_SETTING = 'savedObjects:listingLimit';
export const LISTING_LIMIT_VALUE = 1000;
11 changes: 8 additions & 3 deletions src/plugins/saved_objects/server/ui_settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@ import { i18n } from '@osd/i18n';
import { schema } from '@osd/config-schema';

import { UiSettingsParams } from 'opensearch-dashboards/server';
import { PER_PAGE_SETTING, LISTING_LIMIT_SETTING } from '../common';
import {
PER_PAGE_SETTING,
PER_PAGE_VALUE,
LISTING_LIMIT_SETTING,
LISTING_LIMIT_VALUE,
} from '../common';

export const uiSettings: Record<string, UiSettingsParams> = {
[PER_PAGE_SETTING]: {
name: i18n.translate('savedObjects.advancedSettings.perPageTitle', {
defaultMessage: 'Objects per page',
}),
value: 20,
value: PER_PAGE_VALUE,
type: 'number',
description: i18n.translate('savedObjects.advancedSettings.perPageText', {
defaultMessage: 'Number of objects to show per page in the load dialog',
Expand All @@ -51,7 +56,7 @@ export const uiSettings: Record<string, UiSettingsParams> = {
defaultMessage: 'Objects listing limit',
}),
type: 'number',
value: 1000,
value: LISTING_LIMIT_VALUE,
description: i18n.translate('savedObjects.advancedSettings.listingLimitText', {
defaultMessage: 'Number of objects to fetch for the listing pages',
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@
"version": "opensearchDashboards",
"server": true,
"ui": true,
"requiredPlugins": ["management", "data"],
"optionalPlugins": ["dashboard", "visualizations", "discover", "home", "visBuilder"],
"requiredPlugins": ["management", "data", "uiActions"],
ohltyler marked this conversation as resolved.
Show resolved Hide resolved
"optionalPlugins": [
"dashboard",
"visualizations",
"discover",
"home",
"visBuilder",
"visAugmenter"
],
"extraPublicDirs": ["public/lib"],
"requiredBundles": ["opensearchDashboardsReact", "home"]
}
Loading