Skip to content

Commit

Permalink
Changeset file for PR opensearch-project#7289 created/updated
Browse files Browse the repository at this point in the history
running linter

Signed-off-by: Sean Li <[email protected]>

removing connections bar component

Signed-off-by: Sean Li <[email protected]>

remove unused property

Signed-off-by: Sean Li <[email protected]>

use default search interceptor for get indices

Signed-off-by: Sean Li <[email protected]>

removing unused file

Signed-off-by: Sean Li <[email protected]>

adding onselect for dataset navigator

Signed-off-by: Sean Li <[email protected]>

trying to make a commponetto call

Signed-off-by: Kawika Avilla <[email protected]>

no clue if it works

Signed-off-by: Kawika Avilla <[email protected]>

trying out changes

Signed-off-by: Sean Li <[email protected]>
  • Loading branch information
opensearch-changeset-bot[bot] authored and kavilla committed Jul 20, 2024
1 parent c0d03d2 commit ca02056
Show file tree
Hide file tree
Showing 31 changed files with 383 additions and 446 deletions.
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))
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export interface DataSourceOption {
value: string;
type: string;
ds: DataSource;
checked?: boolean;
}

export interface DataSourceSelectableProps extends Pick<EuiComboBoxProps<unknown>, 'fullWidth'> {
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ export {
// for BWC, keeping the old name
IUiStart as DataPublicPluginStartUi,
DataSetNavigator,
DataSetOption,
} from './ui';

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { SavedObjectsClientContract } from 'src/core/public';
import { IndexPatternsContract } from 'src/plugins/data/public';
import { DataSetNavigator, DataSetNavigatorProps } from './';
import { Settings } from '../settings';

// Updated function signature to include additional dependencies
export function createDataSetNavigator(
settings: Settings,
savedObjectsClient: SavedObjectsClientContract,
indexPatternsService: IndexPatternsContract,
search: any,
onDataSetSelected: any,
) {
// Return a function that takes props, omitting the dependencies from the props type
return (
props: Omit<DataSetNavigatorProps, 'savedObjectsClient' | 'indexPatternsService' | 'search'>
) => (
<DataSetNavigator
{...props}
settings={settings}
savedObjectsClient={savedObjectsClient}
indexPatternsService={indexPatternsService}
search={search}
onDataSetSelected={onDataSetSelected}
/>
);
}
295 changes: 101 additions & 194 deletions src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,166 +4,84 @@
*/

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 { SavedObjectsClientContract } from 'opensearch-dashboards/public';
import _ from 'lodash';
import { IIndexPattern } from '../..';
import { getUiService, getIndexPatterns, getSearchService } from '../../services';

const getClusters = async (savedObjectsClient: SavedObjectsClientContract) => {
return await savedObjectsClient.find({
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,
};

return request;
};
import { fetchClusters } from './fetch_clusters';
import { fetchIndices } from './fetch_indices';
import { Settings } from '../settings';

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 DataSetOption {
export interface DataSetOption {
id: string;
name: string;
dataSourceRef?: string;
}

interface DataSetNavigatorProps {
export interface DataSetNavigatorProps {
settings: Settings;
savedObjectsClient: SavedObjectsClientContract;
indexPatterns: Array<IIndexPattern | string>;
indexPattern?: Array<IIndexPattern | string>;
dataSetId?: string;
onDataSetSelected: (dataSet: DataSetOption) => void;
indexPatternsService: any;
search: any;
}

interface DataSetNavigatorState {
isLoading: boolean;
isOpen: boolean;
clusters: DataSetOption[];
indices: DataSetOption[];
indexPatterns: DataSetOption[];
selectedDataSet: DataSetOption | undefined;
selectedCluster: DataSetOption | undefined;
searchValue: string | undefined;
dataSourceIdToTitle: Map<string, string>;
}

export const DataSetNavigator = ({ savedObjectsClient, indexPatterns }: DataSetNavigatorProps) => {
export const DataSetNavigator = (props: DataSetNavigatorProps) => {
const { settings, indexPatternsService, savedObjectsClient, search, onDataSetSelected } = props;
const [indexPatternList, setIndexPatternList] = useState([]);
const [clusterList, setClusterList] = useState([]);
const [indexList, setIndexList] = useState([]);
const [selectedCluster, setSelectedCluster] = useState(null);
const [selectedDataSet, setSelectedDataSet] = useState(null);
const [isDataSetNavigatorOpen, setIsDataSetNavigatorOpen] = useState(false);
const [clusterList, setClusterList] = useState<SimpleSavedObject[]>([]);
const [indexList, setIndexList] = useState<DataSetOption[]>([]);
const [selectedCluster, setSelectedCluster] = useState<any>();
const [selectedDataSet, setSelectedDataSet] = useState<DataSetOption>({
id: indexPatterns[0]?.id,
name: indexPatterns[0]?.title,
});
const [indexPatternList, setIndexPatternList] = useState<DataSetOption[]>([]);
const search = getSearchService();
const uiService = getUiService();
const indexPatternsService = getIndexPatterns();

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

const onDataSetClick = async (ds: DataSetOption) => {
const existingIndexPattern = indexPatternsService.getByTitle(ds.id, true);
const dataSet = await indexPatternsService.create(
{ 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({
id: dataSet.id,
name: dataSet.title,
dataSourceRef: selectedCluster?.id ?? undefined,
});
setSelectedDataSet(ds);
const onDataSetClick = async (dataSet) => {
setSelectedDataSet(dataSet);
onDataSetSelected(dataSet);
settings.setSelectedDataSet(dataSet);
closePopover();
};

useEffect(() => {
const subscription = uiService.Settings.getSelectedDataSet$().subscribe((dataSet) => {
if (dataSet) {
setSelectedDataSet(dataSet);
}
// Fetch index patterns
indexPatternsService.getIdsWithTitle().then((res) => {
setIndexPatternList(res.map(({ id, title }) => ({ id, name: title })));
});
return () => subscription.unsubscribe();
}, [uiService]);

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

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

useEffect(() => {
// Fetch indices if a cluster is selected
if (selectedCluster) {
// Get all indexes
getIndices(search, selectedCluster.id).then((res) => {
fetchIndices(search, selectedCluster.id).then((res) => {
setIndexList(
res.map((index: { name: string }) => ({
name: index.name,
id: index.name,
res.map(({ name }) => ({
name,
id: name,
dataSourceRef: selectedCluster.id,
}))
);
});
}
}, [search, selectedCluster, setIndexList]);
}, [indexPatternsService, savedObjectsClient, search, selectedCluster]);

const dataSetButton = (
<EuiButtonEmpty
Expand All @@ -177,76 +95,65 @@ export const DataSetNavigator = ({ savedObjectsClient, indexPatterns }: DataSetN
</EuiButtonEmpty>
);

const contextMenuPanels = [
{
id: 0,
title: 'DATA',
items: [
{
name: 'Index Patterns',
panel: 1,
},
...clusterList.map((cluster) => ({
name: cluster.attributes.title,
panel: 2,
onClick: () => setSelectedCluster(cluster),
})),
],
},
{
id: 1,
title: 'Index Patterns',
items: indexPatternList.map((indexPattern) => ({
name: indexPattern.name,
onClick: () => onDataSetClick(indexPattern),
})),
},
{
id: 2,
title: selectedCluster ? selectedCluster.attributes.title : 'Cluster',
items: [
{
name: 'Indexes',
panel: 3,
},
],
},
{
id: 3,
title: selectedCluster ? selectedCluster.attributes.title : 'Cluster',
items: indexList.map((index) => ({
name: index.name,
onClick: () => onDataSetClick(index),
})),
},
{
id: 4,
title: 'clicked',
},
];

return (
<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) => ({
name: cluster.attributes.title,
panel: 2,
onClick: () => {
setSelectedCluster(cluster);
},
}))
: []),
],
},
{
id: 1,
title: 'Index Patterns',
items: [
...(indexPatternList
? indexPatternList.map((indexPattern) => ({
name: indexPattern.name,
onClick: () => onDataSetClick(indexPattern),
}))
: []),
],
},
{
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) => ({
name: index.name,
onClick: () => onDataSetClick(index),
}))
: []),
],
},
{
id: 4,
title: 'clicked',
},
]}
/>
<EuiContextMenu initialPanelId={0} className="datasetNavigator" panels={contextMenuPanels} />
</EuiPopover>
);
};

// eslint-disable-next-line import/no-default-export
export default DataSetNavigator;
Loading

0 comments on commit ca02056

Please sign in to comment.