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

[Discover Next] Dataset Dropdown #7289

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions changelogs/fragments/7289.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Add DataSet dropdown with index patterns and indices ([#7289](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7289))
1 change: 1 addition & 0 deletions src/plugins/data/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ export {
QueryEditorTopRow,
// for BWC, keeping the old name
IUiStart as DataPublicPluginStartUi,
DataSetNavigator,
} from './ui';

/**
Expand Down
253 changes: 253 additions & 0 deletions src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useEffect, useState } from 'react';

import { EuiButtonEmpty, EuiContextMenu, EuiPopover } from '@elastic/eui';
import { SavedObjectsClientContract, SimpleSavedObject } from 'opensearch-dashboards/public';
import { map, scan } from 'rxjs/operators';
import { ISearchStart } from '../../search/types';
import { IIndexPattern } from '../..';
import { getUiService, getIndexPatterns, getSearchService } from '../../services';

const getClusters = async (savedObjectsClient: SavedObjectsClientContract) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be getDataSources?

return await savedObjectsClient.find({

Check warning on line 16 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L16

Added line #L16 was not covered by tests
type: 'data-source',
perPage: 10000,
});
};

export const searchResponseToArray = (showAllIndices: boolean) => (response) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit. "all" indices might be ambiguous, would it be better with includeHiddenIndices?

and there's the IOpenSearchDashboardsSearchResponse type although raw response is still any by default

Suggested change
export const searchResponseToArray = (showAllIndices: boolean) => (response) => {
export const searchResponseToArray = (showAllIndices: boolean) => (response: IOpenSearchDashboardsSearchResponse) => {

const { rawResponse } = response;

Check warning on line 23 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L23

Added line #L23 was not covered by tests
if (!rawResponse.aggregations) {
return [];

Check warning on line 25 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L25

Added line #L25 was not covered by tests
} else {
return rawResponse.aggregations.indices.buckets

Check warning on line 27 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L27

Added line #L27 was not covered by tests
.map((bucket: { key: string }) => {
return bucket.key;

Check warning on line 29 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L29

Added line #L29 was not covered by tests
})
.filter((indexName: string) => {
if (showAllIndices) {
return true;

Check warning on line 33 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L33

Added line #L33 was not covered by tests
} else {
return !indexName.startsWith('.');

Check warning on line 35 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L35

Added line #L35 was not covered by tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably doesn't matter but can this filtering be done in the request rather than post processing?

}
})
.map((indexName: string) => {
return {

Check warning on line 39 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L39

Added line #L39 was not covered by tests
name: indexName,
// item: {},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this comment useful?

};
});
}
};

const buildSearchRequest = (showAllIndices: boolean, pattern: string, dataSourceId?: string) => {
const request = {

Check warning on line 48 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L48

Added line #L48 was not covered by tests
params: {
ignoreUnavailable: true,
expand_wildcards: showAllIndices ? 'all' : 'open',
index: pattern,
body: {
size: 0, // no hits
aggs: {
indices: {
terms: {
field: '_index',
size: 100,
},
},
},
Comment on lines +55 to +62
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just cat indices?

},
},
dataSourceId,
};

return request;

Check warning on line 68 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L68

Added line #L68 was not covered by tests
};

const getIndices = async (search: ISearchStart, dataSourceId: string) => {
const request = buildSearchRequest(true, '*', dataSourceId);
return search

Check warning on line 73 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L72-L73

Added lines #L72 - L73 were not covered by tests
.getDefaultSearchInterceptor()
.search(request)
.pipe(map(searchResponseToArray(true)))
.pipe(scan((accumulator = [], value) => accumulator.join(value)))
.toPromise()
.catch(() => []);

Check warning on line 79 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L79

Added line #L79 was not covered by tests
};

interface DataSetOption {
id: string;
name: string;
dataSourceRef?: string;
}

interface DataSetNavigatorProps {
savedObjectsClient: SavedObjectsClientContract;
indexPatterns: Array<IIndexPattern | string>;
}

export const DataSetNavigator = ({ savedObjectsClient, indexPatterns }: DataSetNavigatorProps) => {
const [isDataSetNavigatorOpen, setIsDataSetNavigatorOpen] = useState(false);
const [clusterList, setClusterList] = useState<SimpleSavedObject[]>([]);
const [indexList, setIndexList] = useState<DataSetOption[]>([]);
const [selectedCluster, setSelectedCluster] = useState<any>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what exactly is a cluster? is this a dataSource?

const [selectedDataSet, setSelectedDataSet] = useState<DataSetOption>({

Check warning on line 98 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L94-L98

Added lines #L94 - L98 were not covered by tests
id: indexPatterns[0]?.id,
name: indexPatterns[0]?.title,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indexPatterns[number] can be a string based on its type, accessing .id and .title of a string will crash?

});
const [indexPatternList, setIndexPatternList] = useState<DataSetOption[]>([]);
const search = getSearchService();
const uiService = getUiService();
const indexPatternsService = getIndexPatterns();

Check warning on line 105 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L102-L105

Added lines #L102 - L105 were not covered by tests

const onButtonClick = () => setIsDataSetNavigatorOpen((isOpen) => !isOpen);
const closePopover = () => setIsDataSetNavigatorOpen(false);

Check warning on line 108 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L107-L108

Added lines #L107 - L108 were not covered by tests

const onDataSetClick = async (ds: DataSetOption) => {
const existingIndexPattern = indexPatternsService.getByTitle(ds.id, true);
const dataSet = await indexPatternsService.create(

Check warning on line 112 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L110-L112

Added lines #L110 - L112 were not covered by tests
{ id: ds.id, title: ds.name },
!existingIndexPattern?.id
);
// save to cache by title because the id is not unique for temporary index pattern created
indexPatternsService.saveToCache(dataSet.title, dataSet);
uiService.Settings.setSelectedDataSet({

Check warning on line 118 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L117-L118

Added lines #L117 - L118 were not covered by tests
id: dataSet.id,
name: dataSet.title,
dataSourceRef: selectedCluster?.id ?? undefined,
});
setSelectedDataSet(ds);
closePopover();

Check warning on line 124 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L123-L124

Added lines #L123 - L124 were not covered by tests
};

useEffect(() => {
const subscription = uiService.Settings.getSelectedDataSet$().subscribe((dataSet) => {

Check warning on line 128 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L127-L128

Added lines #L127 - L128 were not covered by tests
if (dataSet) {
setSelectedDataSet(dataSet);

Check warning on line 130 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L130

Added line #L130 was not covered by tests
}
});
return () => subscription.unsubscribe();

Check warning on line 133 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L133

Added line #L133 was not covered by tests
}, [uiService]);

// get all index patterns
useEffect(() => {
indexPatternsService.getIdsWithTitle().then((res) =>
setIndexPatternList(
res.map((indexPattern: { id: string; title: string }) => ({

Check warning on line 140 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L137-L140

Added lines #L137 - L140 were not covered by tests
id: indexPattern.id,
name: indexPattern.title,
}))
)
);
}, [indexPatternsService]);

useEffect(() => {
Promise.all([getClusters(savedObjectsClient)]).then((res) => {

Check warning on line 149 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L148-L149

Added lines #L148 - L149 were not covered by tests
setClusterList(res.length > 0 ? res?.[0].savedObjects : []);
});
}, [savedObjectsClient]);

useEffect(() => {

Check warning on line 154 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L154

Added line #L154 was not covered by tests
if (selectedCluster) {
// Get all indexes
getIndices(search, selectedCluster.id).then((res) => {
setIndexList(
res.map((index: { name: string }) => ({

Check warning on line 159 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L157-L159

Added lines #L157 - L159 were not covered by tests
name: index.name,
id: index.name,
dataSourceRef: selectedCluster.id,
}))
);
});
}
}, [search, selectedCluster, setIndexList]);

const dataSetButton = (
<EuiButtonEmpty

Check warning on line 170 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L170

Added line #L170 was not covered by tests
className="dataExplorerDSSelect"
color="text"
iconType="arrowDown"
iconSide="right"
onClick={onButtonClick}
>
{selectedDataSet ? selectedDataSet.name : 'Datasets'}
</EuiButtonEmpty>
);

return (

Check warning on line 181 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L181

Added line #L181 was not covered by tests
<EuiPopover
button={dataSetButton}
isOpen={isDataSetNavigatorOpen}
closePopover={closePopover}
anchorPosition="downLeft"
>
<EuiContextMenu
initialPanelId={0}
className="datasetNavigator"
panels={[
{
id: 0,
title: 'DATA',
items: [
{
name: 'Index Patterns',
panel: 1,
},
...(clusterList
? clusterList.map((cluster) => ({

Check warning on line 201 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L201

Added line #L201 was not covered by tests
name: cluster.attributes.title,
panel: 2,
onClick: () => {
setSelectedCluster(cluster);

Check warning on line 205 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L205

Added line #L205 was not covered by tests
},
}))
: []),
],
},
{
id: 1,
title: 'Index Patterns',
items: [
...(indexPatternList
? indexPatternList.map((indexPattern) => ({

Check warning on line 216 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L216

Added line #L216 was not covered by tests
name: indexPattern.name,
onClick: () => onDataSetClick(indexPattern),

Check warning on line 218 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L218

Added line #L218 was not covered by tests
}))
: []),
],
},
{
id: 2,
title: selectedCluster ? selectedCluster.attributes.title : 'Cluster',
items: [
{
name: 'Indexes',
panel: 3,
},
],
},
{
id: 3,
title: selectedCluster ? selectedCluster.attributes.title : 'Cluster',
items: [
...(indexList
? indexList.map((index) => ({

Check warning on line 238 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L238

Added line #L238 was not covered by tests
name: index.name,
onClick: () => onDataSetClick(index),

Check warning on line 240 in src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx#L240

Added line #L240 was not covered by tests
}))
: []),
],
},
{
id: 4,
title: 'clicked',
},
]}
/>
</EuiPopover>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
* SPDX-License-Identifier: Apache-2.0
*/

export * from './create_extension';
export { DataSetNavigator } from './dataset_navigator';
1 change: 1 addition & 0 deletions src/plugins/data/public/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ export {
} from './query_editor';
export { SearchBar, SearchBarProps, StatefulSearchBarProps } from './search_bar';
export { SuggestionsComponent } from './typeahead';
export { DataSetNavigator } from './dataset_navigator';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
.datasetNavigator {
min-width: 350px;
border-bottom: $euiBorderThin !important;
}
1 change: 1 addition & 0 deletions src/plugins/data/public/ui/query_editor/_index.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
@import "./language_selector";
@import "./dataset_navigator";
@import "./query_editor";
6 changes: 6 additions & 0 deletions src/plugins/data/public/ui/query_editor/_query_editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
}
}

.osdQueryEditor__dataSetNavigatorWrapper {
:first-child {
border-bottom: $euiBorderThin !important;
}
}

@include euiBreakpoint("xs", "s") {
.osdQueryEditor--withDatePicker {
> :first-child {
Expand Down
20 changes: 8 additions & 12 deletions src/plugins/data/public/ui/query_editor/query_editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import { EuiFlexGroup, EuiFlexItem, htmlIdGenerator, PopoverAnchorPosition } from '@elastic/eui';
import classNames from 'classnames';
import { isEqual } from 'lodash';
import React, { Component, createRef, RefObject } from 'react';
import { Settings } from '..';
import React, { Component, createRef, RefObject, useCallback } from 'react';
import { DataSetNavigator, Settings } from '..';
import { DataSource, IDataPluginServices, IIndexPattern, Query, TimeRange } from '../..';
import {
CodeEditor,
Expand Down Expand Up @@ -294,11 +294,12 @@ export default class QueryEditorUI extends Component<Props, State> {
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center" className={`${className}__wrapper`}>
<EuiFlexItem grow={false}>{this.props.prepend}</EuiFlexItem>
{this.state.isDataSourcesVisible && (
<EuiFlexItem grow={false} className={`${className}__dataSourceWrapper`}>
<div ref={this.props.dataSourceContainerRef} />
</EuiFlexItem>
)}
<EuiFlexItem grow={false} className={`${className}__dataSetNavigatorWrapper`}>
<DataSetNavigator
savedObjectsClient={this.services.savedObjects.client}
indexPatterns={this.props.indexPatterns}
/>
</EuiFlexItem>
<EuiFlexItem grow={false} className={`${className}__languageWrapper`}>
<QueryLanguageSelector
language={this.props.query.language}
Expand All @@ -307,11 +308,6 @@ export default class QueryEditorUI extends Component<Props, State> {
appName={this.services.appName}
/>
</EuiFlexItem>
{this.state.isDataSetsVisible && (
<EuiFlexItem grow={false} className={`${className}__dataSetWrapper`}>
<div ref={this.props.containerRef} />
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem onClick={this.onClickInput} grow={true}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) {
}

function isValidQuery(query: Query | undefined) {
if (query && query.query) return true;
return query && query.query;
}

function getQueryStringInitialValue(language: string) {
Expand Down
21 changes: 21 additions & 0 deletions src/plugins/data/public/ui/settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
private isEnabled = false;
private enabledQueryEnhancementsUpdated$ = new BehaviorSubject<boolean>(this.isEnabled);
private enhancedAppNames: string[] = [];
private selectedDataSet$ = new BehaviorSubject<any>(null);

constructor(
private readonly config: ConfigSchema['enhancements'],
Expand All @@ -38,8 +39,28 @@
this.isEnabled = true;
this.setUserQueryEnhancementsEnabled(this.isEnabled);
this.enhancedAppNames = this.isEnabled ? this.config.supportedAppNames : [];
this.setSelectedDataSet(this.getSelectedDataSet());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this do?

}

/**
* @experimental - Sets the dataset BehaviorSubject
*/
setSelectedDataSet = (dataSet: any) => {
this.storage.set('opensearchDashboards.userQueryDataSet', dataSet);
this.selectedDataSet$.next(dataSet);
};

/**
* @experimental - Gets the dataset Observable
*/
getSelectedDataSet$ = () => {
return this.selectedDataSet$.asObservable();

Check warning on line 57 in src/plugins/data/public/ui/settings/settings.ts

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/settings/settings.ts#L57

Added line #L57 was not covered by tests
};

getSelectedDataSet = () => {
return this.storage.get('opensearchDashboards.userQueryDataSet');
};

supportsEnhancementsEnabled(appName: string) {
return this.enhancedAppNames.includes(appName);
}
Expand Down
3 changes: 3 additions & 0 deletions src/plugins/data/public/ui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ export interface IUiStart {
IndexPatternSelect: React.ComponentType<IndexPatternSelectProps>;
SearchBar: React.ComponentType<StatefulSearchBarProps>;
SuggestionsComponent: React.ComponentType<SuggestionsComponentProps>;
/**
* @experimental - Subject to change
*/
Settings: Settings;
dataSourceContainer$: Observable<HTMLDivElement | null>;
container$: Observable<HTMLDivElement | null>;
Expand Down
Loading
Loading