From a4a66e20326814511bcb516e5cda6e62702f876d Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Fri, 19 Jul 2024 13:18:21 +0000 Subject: [PATCH] no clue if it works Signed-off-by: Kawika Avilla --- .../create_dataset_navigator.tsx | 23 +- .../dataset_navigator/dataset_navigator.tsx | 302 +++++------------- .../public/ui/query_editor/query_editor.tsx | 12 +- src/plugins/data/public/ui/types.ts | 3 +- src/plugins/data/public/ui/ui_service.ts | 8 +- .../public/components/sidebar/index.tsx | 23 +- 6 files changed, 126 insertions(+), 245 deletions(-) diff --git a/src/plugins/data/public/ui/dataset_navigator/create_dataset_navigator.tsx b/src/plugins/data/public/ui/dataset_navigator/create_dataset_navigator.tsx index d04a5464a486..11f0ff41e073 100644 --- a/src/plugins/data/public/ui/dataset_navigator/create_dataset_navigator.tsx +++ b/src/plugins/data/public/ui/dataset_navigator/create_dataset_navigator.tsx @@ -3,15 +3,26 @@ * SPDX-License-Identifier: Apache-2.0 */ -import _ from 'lodash'; import React from 'react'; - import { SavedObjectsClientContract } from 'src/core/public'; +import { IndexPatternsContract } from 'src/plugins/data/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) => ( - +// Updated function signature to include additional dependencies +export function createDataSetNavigator( + savedObjectsClient: SavedObjectsClientContract, + indexPatternsService: IndexPatternsContract, + search: any +) { + // Return a function that takes props, omitting the dependencies from the props type + return ( + props: Omit + ) => ( + ); } diff --git a/src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx b/src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx index d8647e082f5c..c24e0b7d8e99 100644 --- a/src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx +++ b/src/plugins/data/public/ui/dataset_navigator/dataset_navigator.tsx @@ -3,16 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { Component, useEffect, useState } from 'react'; - +import React, { useEffect, useState } from 'react'; import { EuiButtonEmpty, EuiContextMenu, EuiPopover } from '@elastic/eui'; -import { SavedObjectsClientContract, SimpleSavedObject } from 'opensearch-dashboards/public'; +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import _ from 'lodash'; import { IIndexPattern } from '../..'; -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'; export interface DataSetOption { id: string; @@ -24,186 +21,60 @@ export interface DataSetNavigatorProps { savedObjectsClient: SavedObjectsClientContract; indexPatterns: Array; dataSetId: string; + onDataSetSelected: (dataSet: DataSetOption) => void; } interface DataSetNavigatorState { isLoading: boolean; - options: []; + isOpen: boolean; + clusters: DataSetOption[]; + indices: DataSetOption[]; + indexPatterns: DataSetOption[]; selectedDataSet: DataSetOption | undefined; + selectedCluster: DataSetOption | undefined; searchValue: string | undefined; dataSourceIdToTitle: Map; } -// eslint-disable-next-line import/no-default-export -export default class DataSetNavigator extends Component { - 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) => { - 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) => { - dataSourceIdToTitleToUpdate.set( - dataSourceSavedObject.id, - dataSourceSavedObject.attributes.title - ); - }); - } - - const options = savedObjects.map((indexPatternSavedObject: SimpleSavedObject) => { - 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); - +export const DataSetNavigator = ({ indexPatternsService, savedObjectsClient, search }) => { + 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([]); - const [indexList, setIndexList] = useState([]); - const [selectedCluster, setSelectedCluster] = useState(); - const [selectedDataSet, setSelectedDataSet] = useState({ - id: indexPatterns[0]?.id, - name: indexPatterns[0]?.title, - }); - const [indexPatternList, setIndexPatternList] = useState([]); - const search = getSearchService(); - const uiService = getUiService(); - const queryService = getQueryService(); - const indexPatternsService = getIndexPatterns(); - const onButtonClick = () => setIsDataSetNavigatorOpen((isOpen) => !isOpen); + const onButtonClick = () => setIsDataSetNavigatorOpen(!isDataSetNavigatorOpen); const closePopover = () => setIsDataSetNavigatorOpen(false); - - const onDataSetClick = async (ds: DataSetOption) => { - setSelectedDataSet(ds); - onSubmit(ds); + const onDataSetClick = (dataSet) => { + 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([fetchClusters(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 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 = ( { ); + 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 ( { closePopover={closePopover} anchorPosition="downLeft" > - ({ - 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', - }, - ]} - /> + ); }; + +// eslint-disable-next-line import/no-default-export +export default DataSetNavigator; diff --git a/src/plugins/data/public/ui/query_editor/query_editor.tsx b/src/plugins/data/public/ui/query_editor/query_editor.tsx index 412d82a9db98..a598112d30a4 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -312,13 +312,6 @@ export default class QueryEditorUI extends Component { {this.props.prepend} - - - { appName={this.services.appName} /> + {this.state.isDataSetsVisible && ( + +
+ + )} diff --git a/src/plugins/data/public/ui/types.ts b/src/plugins/data/public/ui/types.ts index d3074163c7bc..73726327c683 100644 --- a/src/plugins/data/public/ui/types.ts +++ b/src/plugins/data/public/ui/types.ts @@ -5,6 +5,7 @@ import { Observable } from 'rxjs'; import { SearchInterceptor } from '../search'; +import { DataSetNavigatorProps } from './dataset_navigator'; import { IndexPatternSelectProps } from './index_pattern_select'; import { StatefulSearchBarProps } from './search_bar'; import { QueryEditorExtensionConfig } from './query_editor/query_editor_extensions'; @@ -70,6 +71,6 @@ export interface IUiStart { * @experimental - Subject to change */ Settings: Settings; - dataSourceContainer$: Observable; + DataSetNavigator: React.ComponentType; container$: Observable; } diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts index b0cfb4852d77..228c202eb50c 100644 --- a/src/plugins/data/public/ui/ui_service.ts +++ b/src/plugins/data/public/ui/ui_service.ts @@ -14,6 +14,7 @@ import { createSearchBar } from './search_bar/create_search_bar'; import { createSettings } from './settings'; import { SuggestionsComponent } from './typeahead'; import { IUiSetup, IUiStart, QueryEnhancement, UiEnhancements } from './types'; +import { createDataSetNavigator } from './dataset_navigator/create_dataset_navigator'; /** @internal */ // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -81,10 +82,15 @@ export class UiService implements Plugin { return { IndexPatternSelect: createIndexPatternSelect(core.savedObjects.client), - DataSetNavigator: createDataSetNavigator(core.savedObjects.client), + DataSetNavigator: createDataSetNavigator( + core.savedObjects.client, + dataServices.indexPatterns, + dataServices.search + ), SearchBar, SuggestionsComponent, Settings, + container$: this.container$, }; } diff --git a/src/plugins/data_explorer/public/components/sidebar/index.tsx b/src/plugins/data_explorer/public/components/sidebar/index.tsx index f4c628a7d70f..da7497a07d7c 100644 --- a/src/plugins/data_explorer/public/components/sidebar/index.tsx +++ b/src/plugins/data_explorer/public/components/sidebar/index.tsx @@ -4,7 +4,7 @@ */ import React, { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { EuiPageSideBar, EuiSplitPanel } from '@elastic/eui'; +import { EuiPageSideBar, EuiPortal, EuiSplitPanel } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { DataSource, DataSourceGroup, DataSourceSelectable } from '../../../../data/public'; import { DataSourceOption } from '../../../../data/public/'; @@ -58,13 +58,7 @@ export const Sidebar: FC = ({ children }) => { return () => { subscriptions.unsubscribe(); }; - }, [ - ui.container$, - containerRef, - setContainerRef, - ui.dataSourceContainer$, - isEnhancementsEnabled, - ]); + }, [ui.container$, containerRef, setContainerRef, isEnhancementsEnabled]); useEffect(() => { let isMounted = true; @@ -93,7 +87,7 @@ export const Sidebar: FC = ({ children }) => { useEffect(() => { if (indexPatternId) { const option = getMatchedOption(dataSourceOptionList, indexPatternId); - setSelectedSources((prev) => (option ? [option] : prev)); + setSelectedSources(option ? [option] : []); } }, [indexPatternId, activeDataSources, dataSourceOptionList]); @@ -153,6 +147,8 @@ export const Sidebar: FC = ({ children }) => { /> ); + const dataSetNavigator = ui.DataSetNavigator; + return ( { borderRadius="none" color="transparent" > + {isEnhancementsEnabled && ( + { + containerRef.current = node; + }} + > + {dataSetNavigator} + + )} {!isEnhancementsEnabled && (