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 #7267

Closed
wants to merge 81 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
40d6ed1
init
kavilla Jun 11, 2024
b7063c5
fixing bugs and removing target
sejli Jun 11, 2024
a34f895
Updating plugin.ts and removing target directory
kavilla Jun 11, 2024
c767590
add target and build to .gitignore
sejli Jun 11, 2024
50ce9c6
Add target and build to .gitignore
kavilla Jun 11, 2024
0783ea3
Remove SQL Async and Query Assist
kavilla Jun 12, 2024
c0304d1
adding fix for PPL queries
sejli Jun 13, 2024
c617aa5
Merge pull request #3 from sejli/ppl-fix
kavilla Jun 13, 2024
67e6b30
Clean up files and add helper functions
kavilla Jun 14, 2024
e11a384
final touches
kavilla Jun 14, 2024
8867564
Clean up files and use helper functions
kavilla Jun 14, 2024
b6d54a5
[Discover-next] add query assist to query enhancements plugin (#6895)
joshuali925 Jun 4, 2024
b0053b9
[Discover-next] Address comments for search bar extensions and query …
joshuali925 Jun 6, 2024
eb0e6f3
[Discover-next] Support data sources for query assist (#6972)
joshuali925 Jun 7, 2024
56ab13b
add query assist banner
joshuali925 Jun 17, 2024
43d1d43
implement banner rendering logic
joshuali925 Jun 18, 2024
c97cd2d
pick opensearch-project/dashboards-observability/pull/1896
joshuali925 Jun 18, 2024
48f9c7a
Conditionally render the data source select config
kavilla Jun 19, 2024
ec37345
restore no space
kavilla Jun 19, 2024
780fbd5
add basic tests
joshuali925 Jun 20, 2024
9b811a5
add index selector
joshuali925 Jun 21, 2024
c636dee
Conditionally render the data source select config
kavilla Jun 22, 2024
8572c23
MDS working with PPL and SQL
kavilla Jun 24, 2024
fd651e7
rename logo to mark
joshuali925 Jun 25, 2024
8ad8600
extract supported languages to config
joshuali925 Jun 25, 2024
90ab0bf
Add query assist to query enhancements plugin
kavilla Jun 25, 2024
97b57ba
Merge branch 'main' into kavilla/mds_working
kavilla Jun 25, 2024
3d2e294
MDS working + more cleanups
kavilla Jun 26, 2024
2e3304e
Add missing license headers
kavilla Jun 26, 2024
6192877
Adds license headers
kavilla Jun 26, 2024
0b3cb2a
initial implementation for async queries
sejli Jun 23, 2024
5a7cb21
remove queryId and sessionId from facet
sejli Jun 24, 2024
36f6218
fix: Update call out tests with intl wrapper
Swiddis Jun 27, 2024
0c84b4c
maintenance: Add and apply lint command
Swiddis Jun 27, 2024
35102fc
changing to observables
sejli Jun 27, 2024
25526d2
search interceptor and cleanup
sejli Jun 28, 2024
49cfd34
moving polling class into plugin
sejli Jun 28, 2024
f16fb12
maintenance: Add and apply lint command
kavilla Jun 28, 2024
9daa636
SQL Async queries
kavilla Jun 28, 2024
045af8e
Some minor clean ups plus lint
kavilla Jun 28, 2024
d0541ff
Merge pull request #23 from kavilla/asynccleanup
kavilla Jun 28, 2024
2ac79c5
test: Add mock-heavy tests for sql search strategy
Swiddis Jun 28, 2024
51cb500
test: add GH workflows
Swiddis Jun 28, 2024
27bf623
More clean ups
kavilla Jun 29, 2024
5b401be
Add some props interfaces and consolidated some of the facets
kavilla Jun 29, 2024
ca89c60
test: add GH workflows
kavilla Jun 29, 2024
4f52c32
fix: Update call out tests with intl wrapper
kavilla Jun 29, 2024
9e4c83c
Merge remote-tracking branch 'kavilla/main' into test/sql_search_stra…
Swiddis Jul 1, 2024
f3320a5
chore: apply auto-lints to plugin
Swiddis Jul 1, 2024
bea27f8
Not done
kavilla Jul 1, 2024
cfc4741
working
kavilla Jul 2, 2024
6d0730f
working and styled
kavilla Jul 2, 2024
388ea43
add connection service
kavilla Jul 2, 2024
48d9c00
Update public/types.ts
kavilla Jul 2, 2024
e73982b
Update public/plugin.tsx
kavilla Jul 2, 2024
6ee5508
Update public/plugin.tsx
kavilla Jul 2, 2024
8bb83a1
fix linter
kavilla Jul 2, 2024
e5f626b
[MDS] datasource selector added
kavilla Jul 2, 2024
3543d51
add more tests for query assist (#31)
joshuali925 Jul 3, 2024
222b928
fix!: remove dataSource key in get connection response
joshuali925 Jul 3, 2024
9f43eba
change isEnabled to an observable based on selected connection
joshuali925 Jul 3, 2024
a43fcdc
protect duplicated calls
joshuali925 Jul 3, 2024
9306f14
test: Add mock-heavy tests for sql search strategy
kavilla Jul 8, 2024
468b74b
(Query assist) change isEnabled to an observable based on selected co…
kavilla Jul 8, 2024
9abc883
[build] import via start services
kavilla Jul 3, 2024
e2a1636
Add 'src/plugins/query_enhancements/' from commit '9abc883f56e1d032fd…
kavilla Jul 9, 2024
fdab7a2
Changeset file for PR #7212 created/updated
opensearch-changeset-bot[bot] Jul 9, 2024
dbf05b5
foobar
kavilla Jul 9, 2024
b398640
Merge branch 'query_enhancements' of github.com:kavilla/OpenSearch-Da…
kavilla Jul 10, 2024
f879c1b
updating imports still in progress
kavilla Jul 10, 2024
ece47d0
Update more imports
kavilla Jul 10, 2024
f58c4ba
fix setting of state
kavilla Jul 11, 2024
20411f1
fixes bugs
kavilla Jul 11, 2024
70ed2c7
initial implementation for dataset dropdown
sejli Jul 11, 2024
26385ef
initial metadata commit
sejli Jul 11, 2024
6099185
bug fixes
sejli Jul 11, 2024
c45be4a
hiding datasource cluster selctor and other bug fixes
sejli Jul 11, 2024
fc025aa
refactoring and fixing datasource selector button
sejli Jul 15, 2024
a5144f4
fix breaking loop
sejli Jul 15, 2024
0e026d4
last working commit
sejli Jul 16, 2024
9235350
WIP indices
sejli Jul 17, 2024
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/7212.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Add query enhancements plugin as a core plugin ([#7212](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7212))
1 change: 1 addition & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
- forms
- [Form_wizard](../src/plugins/opensearch_ui_shared/public/forms/form_wizard/README.md)
- [Multi_content](../src/plugins/opensearch_ui_shared/public/forms/multi_content/README.md)
- [Query_enhancements](../src/plugins/query_enhancements/README.md)
- [Saved_objects](../src/plugins/saved_objects/README.md)
- [Saved_objects_management](../src/plugins/saved_objects_management/README.md)
- [Share](../src/plugins/share/README.md)
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/data/common/index_patterns/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export interface IIndexPattern {
) => FieldFormat;
}

// export interface IDataSet {
// dataSetType: opensearch / s3 / index / indexpattern
// }

export interface IndexPatternAttributes {
type: string;
fields: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ export const DataSourceSelectable = ({
onRefresh,
...comboBoxProps
}: DataSourceSelectableProps) => {
console.log('dataSources:', dataSources);
console.log('dataSources filter:', dataSources.filter((ds) => ds.getMetadata().ui.selector.displayDatasetsAsSource));
// This effect gets data sets and prepares the datasource list for UI rendering.
useEffect(() => {
Promise.all(
Expand All @@ -149,6 +151,7 @@ export const DataSourceSelectable = ({
);

const memorizedDataSourceOptionList = useMemo(() => {
console.log('dataSourceOptionList:', dataSourceOptionList);
return dataSourceOptionList.map((dsGroup: DataSourceGroup) => {
return {
...dsGroup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface DataSourceOption {
value: string;
type: string;
ds: DataSource;
checked?: boolean;
}

export interface DataSourceSelectableProps extends Pick<EuiComboBoxProps<unknown>, 'fullWidth'> {
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/data/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,16 @@ export {
IndexPatternSelectProps,
QueryStringInput,
QueryStringInputProps,
QueryEditor,
QueryEditorExtensionConfig,
QueryEditorExtensions,
QueryEditorExtensionDependencies,
QueryEditorProps,
QueryEditorTopRow,
// for BWC, keeping the old name
IUiStart as DataPublicPluginStartUi,
DataSetNavigator,
IndexPatternSelectable
} from './ui';

/**
Expand Down
317 changes: 317 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,317 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

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

import {
EuiButtonEmpty,
EuiContextMenu,
EuiContextMenuItem,
EuiContextMenuPanelDescriptor,
EuiPopover,
} from '@elastic/eui';
import {
DataSetWithDataSource,
DataSource,
IndexPatternOption,
} from '../../data_sources/datasource';
import { DataSourceOption } from '../../data_sources/datasource_selector/types';
import { IndexPatternSelectable } from './index_pattern_selectable';
import {
HttpSetup,
SavedObjectsClientContract,
SimpleSavedObject,
} from 'opensearch-dashboards/public';
import { DataSourceAttributes } from '../../../../data_source_management/public/types';
import { ISearchStart } from '../../search/types';
import { map, scan } from 'rxjs/operators';
import { IndexPatternsContract } from '../..';

const getAndFormatIndexPatternsFromDataSource = async (
ds: DataSource
): Promise<DataSetWithDataSource<IndexPatternOption>> => {
const { dataSets } = await ds.getDataSet();
return { ds, list: dataSets } as DataSetWithDataSource<IndexPatternOption>;
};

const getAllIndexPatterns = (dataSources: DataSource[]) =>
dataSources.map((ds) => getAndFormatIndexPatternsFromDataSource(ds));

const consolidateIndexPatternList = (
dataSets: DataSetWithDataSource<IndexPatternOption>[],
selectedSources: DataSourceOption[]
): DataSourceOption[] => {
const result: DataSourceOption[] = [];

dataSets.forEach((dataSet) => {
dataSet.list.forEach((indexPatternOption) => {
const dataSourceOption: DataSourceOption = {
type: 'indexPattern',
name: dataSet.ds.getName(),
ds: dataSet.ds,
key: indexPatternOption.id as string,
label: indexPatternOption.title as string,
value: indexPatternOption.id as string,
};

if (selectedSources.length !== 0 && selectedSources[0].value === dataSourceOption.value) {
dataSourceOption.checked = true;
}

result.push(dataSourceOption);
});
});
console.log('results:', result);

return result;
};

const getClusters = async (savedObjectsClient: SavedObjectsClientContract) => {
return await savedObjectsClient.find<DataSourceAttributes>({
type: 'data-source',
perPage: 10000,
});
};

export const searchResponseToArray = (showAllIndices: boolean) => (response) => {
const { rawResponse } = response;
if (!rawResponse.aggregations) {
return [];
} else {
return rawResponse.aggregations.indices.buckets
.map((bucket: { key: string }) => {
return bucket.key;
})
.filter((indexName: string) => {
if (showAllIndices) {
return true;
} else {
return !indexName.startsWith('.');
}
})
.map((indexName: string) => {
return {
name: indexName,
// item: {},
};
});
}
};

const buildSearchRequest = (showAllIndices: boolean, pattern: string, dataSourceId?: string) => {
const request = {
params: {
ignoreUnavailable: true,
expand_wildcards: showAllIndices ? 'all' : 'open',
index: pattern,
body: {
size: 0, // no hits
aggs: {
indices: {
terms: {
field: '_index',
size: 100,
},
},
},
},
},
dataSourceId: dataSourceId,
};

return request;
};

const getIndices = async (search: ISearchStart, dataSourceId: string) => {
const request = buildSearchRequest(true, '*', dataSourceId);
return search
.search(request)
.pipe(map(searchResponseToArray(true)))
.pipe(scan((accumulator = [], value) => accumulator.join(value)))
.toPromise()
.catch(() => []);
};

interface DataSetNavigatorProps {
http: HttpSetup;
search: ISearchStart;
savedObjectsClient: SavedObjectsClientContract;
indexPatterns: IndexPatternsContract;
dataSources: DataSource[];
indexPatternOptionList: any;
selectedSources: DataSourceOption[];
selectedCluster: any;
setIndexPatternOptionList: any;
setSelectedCluster: any;
handleSourceSelection: any;
}

export const DataSetNavigator = ({
http,
search,
savedObjectsClient,
indexPatterns,
dataSources,
indexPatternOptionList,
selectedSources,
selectedCluster,
setIndexPatternOptionList,
setSelectedCluster,
handleSourceSelection,
}: DataSetNavigatorProps) => {
const [isDataSetNavigatorOpen, setIsDataSetNavigatorOpen] = useState(false);
const [clusterList, setClusterList] = useState<SimpleSavedObject<DataSourceAttributes>[]>([]);
const [indexList, setIndexList] = useState<any[]>([]);
const [selectedIndex, setSelectedIndex] = useState<string>('');
const [selectedField, setSelectedField] = useState<string>('');

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

useEffect(() => {
Promise.all(
getAllIndexPatterns(
dataSources.filter((ds) => ds.getMetadata().ui.selector.displayDatasetsAsSource)
)
).then((dataSetResults) => {
setIndexPatternOptionList(consolidateIndexPatternList(dataSetResults, selectedSources));
});
}, [dataSources, setIndexPatternOptionList]);

useEffect(() => {
Promise.all([getClusters(savedObjectsClient)]).then((res) => {
setClusterList(res.length > 0 ? res?.[0].savedObjects : []);
});
}, [savedObjectsClient]);

useEffect(() => {
if (selectedCluster) {
// Get all indexes
Promise.all([getIndices(search, selectedCluster.id)]).then((res) => {
if (res && res.length > 0) {
console.log('res', Object.values(res?.[0]));
setIndexList(
Object.values(res?.[0]).map((index: any) => ({
...index,
// panel: 4,
onClick: async () => {
setSelectedIndex(index.name);
const existingIndexPattern = indexPatterns.getByTitle(index.name, true);
const dataSet = await indexPatterns.create(
{ id: index.name, title: index.name },
!existingIndexPattern?.id
);
// save to cache by title because the id is not unique for temporary index pattern created
indexPatterns.saveToCache(dataSet.title, dataSet);
handleSourceSelection([
{
type: 'indexPattern',
name: 'OpenSearch Default',
ds: selectedCluster,
key: index.name,
label: index.name,
value: index.name,
},
]);
},
}))
);
}
});
// Update panels related to cluster
}
}, [selectedCluster, setIndexList, setSelectedIndex]);

useEffect(() => {
if (selectedIndex) {
Promise.all([
indexPatterns.getFieldsForWildcard({
pattern: selectedIndex,
dataSourceId: selectedCluster.id,
}),
]).then((res) => console.log(res));
}
}, [selectedIndex]);

const dataSetButton = (
<EuiButtonEmpty
className="dataExplorerDSSelect"
color="text"
iconType="arrowDown"
iconSide="right"
onClick={onButtonClick}
>
{selectedSources.length > 0 ? selectedSources[0].label : 'Datasets'}
</EuiButtonEmpty>
);

return (
<EuiPopover
button={dataSetButton}
isOpen={isDataSetNavigatorOpen}
closePopover={closePopover}
anchorPosition="downLeft"
>
<EuiContextMenu
initialPanelId={0}
panels={[
{
id: 0,
title: 'DATA SETS',
items: [
{
name: 'Index Patterns',
panel: 1,
},
// Use spread operator with conditional mapping
...(clusterList
? clusterList.map((cluster) => ({
name: cluster.attributes.title,
panel: 2,
onClick: () => {
setSelectedCluster(cluster);
},
}))
: []),
],
},
{
id: 1,
title: 'Index Patterns',
content: (
<IndexPatternSelectable
indexPatternOptionList={indexPatternOptionList}
setIndexPatternOptionList={setIndexPatternOptionList}
handleSourceSelection={handleSourceSelection}
/>
),
},
{
id: 2,
title: selectedCluster ? selectedCluster.attributes.title : 'Cluster',
items: [
{
name: 'Indexes',
panel: 3,
},
{
name: 'Connected Data Sources',
},
],
},
{
id: 3,
title: selectedCluster ? selectedCluster.attributes.title : 'Cluster',
items: indexList,
},
{
id: 4,
title: 'clicked',
},
]}
/>
</EuiPopover>
);
};
Loading