Skip to content

Commit

Permalink
trying to make a commponetto call
Browse files Browse the repository at this point in the history
Signed-off-by: Kawika Avilla <[email protected]>
  • Loading branch information
kavilla committed Jul 19, 2024
1 parent 24de41a commit f34cc7a
Show file tree
Hide file tree
Showing 14 changed files with 276 additions and 162 deletions.
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,17 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import _ from 'lodash';
import React from 'react';

import { SavedObjectsClientContract } from 'src/core/public';
import { DataSetNavigator, DataSetNavigatorProps } from './';

// Takes in stateful runtime dependencies and pre-wires them to the component
export function createDataSetNavigator(savedObjectsClient: SavedObjectsClientContract) {
return (props: Omit<DataSetNavigatorProps, 'savedObjectsClient'>) => (
<DataSetNavigator {...props} savedObjectsClient={savedObjectsClient} />
);
}
215 changes: 126 additions & 89 deletions src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,95 +3,143 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useEffect, useState } from 'react';
import React, { Component, 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';
import { getUiService, getIndexPatterns, getSearchService, getQueryService } from '../../services';
import { fetchClusters } from './fetch_clusters';
import { fetchIndices } from './fetch_indices';
import _ from 'lodash';
import { fetchIndexPatterns } from './fetch_index_patterns';

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;
};

const getIndices = async (search: ISearchStart, dataSourceId: string) => {
const request = buildSearchRequest(true, '*', dataSourceId);
return search
.getDefaultSearchInterceptor()
.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 {
savedObjectsClient: SavedObjectsClientContract;
indexPatterns: Array<IIndexPattern | string>;
onSubmit: any;
dataSetId: string;
}

interface DataSetNavigatorState {
isLoading: boolean;
options: [];
selectedDataSet: DataSetOption | undefined;
searchValue: string | undefined;
dataSourceIdToTitle: Map<string, string>;
}

export const DataSetNavigator = ({ savedObjectsClient, indexPatterns, onSubmit }: DataSetNavigatorProps) => {
// eslint-disable-next-line import/no-default-export
export default class DataSetNavigator extends Component<DataSetNavigatorProps> {
private isMounted: boolean = false;
state: DataSetNavigatorState;


constructor(props: DataSetNavigatorProps) {
super(props);

this.state = {
isLoading: false,
options: [],
selectedDataSet: undefined,
searchValue: undefined,
dataSourceIdToTitle: new Map(),
};
}

debouncedFetch = _.debounce(async (searchValue: string) => {
const { savedObjectsClient } = this.props;

const savedObjectFields = ['title'];
let savedObjects = await fetchIndexPatterns(savedObjectsClient, searchValue, savedObjectFields);



if (!this.isMounted) {
return;
}

// We need this check to handle the case where search results come back in a different
// order than they were sent out. Only load results for the most recent search.
if (searchValue === this.state.searchValue) {
const dataSourcesToFetch: Array<{ type: string; id: string }> = [];
const dataSourceIdSet = new Set();
savedObjects.map((indexPatternSavedObject: SimpleSavedObject<any>) => {
const dataSourceReference = getDataSourceReference(indexPatternSavedObject.references);
if (
dataSourceReference &&
!this.state.dataSourceIdToTitle.has(dataSourceReference.id) &&
!dataSourceIdSet.has(dataSourceReference.id)
) {
dataSourceIdSet.add(dataSourceReference.id);
dataSourcesToFetch.push({ type: 'data-source', id: dataSourceReference.id });
}
});

const dataSourceIdToTitleToUpdate = new Map();

if (dataSourcesToFetch.length > 0) {
const resp = await savedObjectsClient.bulkGet(dataSourcesToFetch);
resp.savedObjects.map((dataSourceSavedObject: SimpleSavedObject<any>) => {
dataSourceIdToTitleToUpdate.set(
dataSourceSavedObject.id,
dataSourceSavedObject.attributes.title
);
});
}

const options = savedObjects.map((indexPatternSavedObject: SimpleSavedObject<any>) => {
const dataSourceReference = getDataSourceReference(indexPatternSavedObject.references);
if (dataSourceReference) {
const dataSourceTitle =
this.state.dataSourceIdToTitle.get(dataSourceReference.id) ||
dataSourceIdToTitleToUpdate.get(dataSourceReference.id) ||
dataSourceReference.id;
return {
label: `${concatDataSourceWithIndexPattern(
dataSourceTitle,
indexPatternSavedObject.attributes.title
)}`,
value: indexPatternSavedObject.id,
};
}
return {
label: indexPatternSavedObject.attributes.title,
value: indexPatternSavedObject.id,
};
});

if (dataSourceIdToTitleToUpdate.size > 0) {
const mergedDataSourceIdToTitle = new Map();
this.state.dataSourceIdToTitle.forEach((k, v) => {
mergedDataSourceIdToTitle.set(k, v);
});
dataSourceIdToTitleToUpdate.forEach((k, v) => {
mergedDataSourceIdToTitle.set(k, v);
});
this.setState({
dataSourceIdToTitle: mergedDataSourceIdToTitle,
isLoading: false,
options,
});
} else {
this.setState({
isLoading: false,
options,
});
}

if (onNoIndexPatterns && searchValue === '' && options.length === 0) {
onNoIndexPatterns();
}
}
}, 300);

const [isDataSetNavigatorOpen, setIsDataSetNavigatorOpen] = useState(false);
const [clusterList, setClusterList] = useState<SimpleSavedObject[]>([]);
const [indexList, setIndexList] = useState<DataSetOption[]>([]);
Expand All @@ -103,24 +151,13 @@ export const DataSetNavigator = ({ savedObjectsClient, indexPatterns, onSubmit }
const [indexPatternList, setIndexPatternList] = useState<DataSetOption[]>([]);
const search = getSearchService();
const uiService = getUiService();
const queryService = getQueryService();
const indexPatternsService = getIndexPatterns();

const onButtonClick = () => setIsDataSetNavigatorOpen((isOpen) => !isOpen);
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);
onSubmit(ds);
closePopover();
Expand Down Expand Up @@ -148,15 +185,15 @@ export const DataSetNavigator = ({ savedObjectsClient, indexPatterns, onSubmit }
}, [indexPatternsService]);

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

useEffect(() => {
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,
Expand Down
13 changes: 13 additions & 0 deletions src/plugins/data/public/ui/dataset_navigator/fetch_clusters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { SavedObjectsClientContract } from 'opensearch-dashboards/public';

export const fetchClusters = async (savedObjectsClient: SavedObjectsClientContract) => {
return await savedObjectsClient.find({
type: 'data-source',
perPage: 10000,
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { SavedObjectsClientContract } from 'opensearch-dashboards/public';

export const fetchIndexPatterns = async (
client: SavedObjectsClientContract,
search: string,
fields: string[]
) => {
const resp = await client.find({
type: 'index-pattern',
fields,
search: `${search}*`,
searchFields: ['title'],
perPage: 100,
});
return resp.savedObjects;
};
67 changes: 67 additions & 0 deletions src/plugins/data/public/ui/dataset_navigator/fetch_indices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { map, scan } from 'rxjs/operators';
import { ISearchStart } from '../../search';

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

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;
};
Loading

0 comments on commit f34cc7a

Please sign in to comment.