diff --git a/common/types/data_connections.ts b/common/types/data_connections.ts index 66c756d3a..a5585aca7 100644 --- a/common/types/data_connections.ts +++ b/common/types/data_connections.ts @@ -121,6 +121,7 @@ export interface CachedDataSource { lastUpdated: string; // date string in UTC format status: CachedDataSourceStatus; databases: CachedDatabase[]; + dataSourceMDSId?: string; } export interface DataSourceCacheData { @@ -143,6 +144,7 @@ export interface CachedAccelerationByDataSource { accelerations: CachedAcceleration[]; lastUpdated: string; // date string in UTC format status: CachedDataSourceStatus; + dataSourceMDSId?: string; } export interface AccelerationsCacheData { @@ -240,6 +242,13 @@ export interface CreateAccelerationForm { export interface LoadCachehookOutput { loadStatus: DirectQueryLoadingStatus; - startLoading: (dataSourceName: string, databaseName?: string, tableName?: string) => void; + startLoading: (params: StartLoadingParams) => void; stopLoading: () => void; } + +export interface StartLoadingParams { + dataSourceName: string; + dataSourceMDSId?: string; + databaseName?: string; + tableName?: string; +} diff --git a/common/utils/shared.ts b/common/utils/shared.ts index 0729946c8..d85aab000 100644 --- a/common/utils/shared.ts +++ b/common/utils/shared.ts @@ -18,6 +18,9 @@ export function get(obj: Record, path: string, default } export function addBackticksIfNeeded(input: string): string { + if (input === undefined) { + return ''; + } // Check if the string already has backticks if (input.startsWith('`') && input.endsWith('`')) { return input; // Return the string as it is diff --git a/public/components/datasources/components/manage/accelerations/acceleration_details_flyout.tsx b/public/components/datasources/components/manage/accelerations/acceleration_details_flyout.tsx index 76294a209..c28f7055a 100644 --- a/public/components/datasources/components/manage/accelerations/acceleration_details_flyout.tsx +++ b/public/components/datasources/components/manage/accelerations/acceleration_details_flyout.tsx @@ -16,24 +16,25 @@ import { EuiText, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; +import { OpenSearchDashboardsResponse } from '../../../../../../../../src/core/server/http/router'; +import { CachedAcceleration } from '../../../../../../common/types/data_connections'; +import { coreRefs } from '../../../../../framework/core_refs'; +import { AccelerationActionOverlay } from './acceleration_action_overlay'; +import { useAccelerationOperation } from './acceleration_operation'; import { AccelerationDetailsTab } from './flyout_modules/acceleration_details_tab'; import { AccelerationSchemaTab } from './flyout_modules/accelerations_schema_tab'; import { - onDiscoverIconClick, AccelerationActionType, getAccelerationName, + onDiscoverIconClick, } from './utils/acceleration_utils'; -import { coreRefs } from '../../../../../framework/core_refs'; -import { OpenSearchDashboardsResponse } from '../../../../../../../../src/core/server/http/router'; -import { CachedAcceleration } from '../../../../../../common/types/data_connections'; -import { useAccelerationOperation } from './acceleration_operation'; -import { AccelerationActionOverlay } from './acceleration_action_overlay'; export interface AccelerationDetailsFlyoutProps { acceleration: CachedAcceleration; dataSourceName: string; resetFlyout: () => void; handleRefresh?: () => void; + dataSourceMDSId?: string; } const getMappings = (index: string): Promise | undefined => { diff --git a/public/components/datasources/components/manage/accelerations/acceleration_table.tsx b/public/components/datasources/components/manage/accelerations/acceleration_table.tsx index 266d77c8f..e3e386d3a 100644 --- a/public/components/datasources/components/manage/accelerations/acceleration_table.tsx +++ b/public/components/datasources/components/manage/accelerations/acceleration_table.tsx @@ -18,27 +18,29 @@ import { EuiText, } from '@elastic/eui'; import React, { useCallback, useEffect, useState } from 'react'; -import { - onDiscoverIconClick, - AccelerationStatus, - ACC_LOADING_MSG, - ACC_PANEL_TITLE, - ACC_PANEL_DESC, - getAccelerationName, - AccelerationActionType, - CreateAccelerationFlyoutButton, -} from './utils/acceleration_utils'; -import { getRenderAccelerationDetailsFlyout } from '../../../../../plugin'; -import { CatalogCacheManager } from '../../../../../framework/catalog_cache/cache_manager'; import { CachedAcceleration, CachedDataSourceStatus, } from '../../../../../../common/types/data_connections'; import { DirectQueryLoadingStatus } from '../../../../../../common/types/explorer'; -import { AccelerationActionOverlay } from './acceleration_action_overlay'; +import { CatalogCacheManager } from '../../../../../framework/catalog_cache/cache_manager'; +import { + getRenderAccelerationDetailsFlyout, + getRenderCreateAccelerationFlyout, +} from '../../../../../plugin'; import { isCatalogCacheFetching } from '../associated_objects/utils/associated_objects_tab_utils'; -import { getRenderCreateAccelerationFlyout } from '../../../../../plugin'; +import { AccelerationActionOverlay } from './acceleration_action_overlay'; import { useAccelerationOperation } from './acceleration_operation'; +import { + ACC_LOADING_MSG, + ACC_PANEL_DESC, + ACC_PANEL_TITLE, + AccelerationActionType, + AccelerationStatus, + CreateAccelerationFlyoutButton, + getAccelerationName, + onDiscoverIconClick, +} from './utils/acceleration_utils'; interface AccelerationTableProps { dataSourceName: string; @@ -108,7 +110,7 @@ export const AccelerationTable = ({ !isCatalogCacheFetching(accelerationsLoadStatus) ) { setIsRefreshing(true); - startLoadingAccelerations(dataSourceName); + startLoadingAccelerations({ dataSourceName }); } else { setAccelerations(cachedDataSource.accelerations); setUpdatedTime(cachedDataSource.lastUpdated); diff --git a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/create/create_acceleration.tsx b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/create/create_acceleration.tsx index 582307b33..507c6fe95 100644 --- a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/create/create_acceleration.tsx +++ b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/create/create_acceleration.tsx @@ -45,6 +45,7 @@ export interface CreateAccelerationProps { resetFlyout: () => void; databaseName?: string; tableName?: string; + dataSourceMDSId?: string; refreshHandler?: () => void; } @@ -53,6 +54,7 @@ export const CreateAcceleration = ({ resetFlyout, databaseName, tableName, + dataSourceMDSId, refreshHandler, }: CreateAccelerationProps) => { const { setToast } = useToast(); @@ -141,12 +143,22 @@ export const CreateAcceleration = ({ if (dataTable !== '') { setTableFieldsLoading(true); try { - const cachedTable = CatalogCacheManager.getTable(dataSource, database, dataTable); + const cachedTable = CatalogCacheManager.getTable( + dataSource, + database, + dataTable, + dataSourceMDSId + ); if (cachedTable.columns) { loadColumnsToAccelerationForm(cachedTable); setTableFieldsLoading(false); } else { - startLoading(dataSource, database, dataTable); + startLoading({ + dataSourceName: dataSource, + dataSourceMDSId, + databaseName: database, + tableName: dataTable, + }); } } catch (error) { setToast('Your cache is outdated, refresh databases and tables', 'warning'); @@ -173,7 +185,8 @@ export const CreateAcceleration = ({ cachedTable = CatalogCacheManager.getTable( accelerationFormData.dataSource, accelerationFormData.database, - accelerationFormData.dataTable + accelerationFormData.dataTable, + dataSourceMDSId ); } catch (error) { setToast('Your cache is outdated, refresh databases and tables', 'warning'); @@ -218,6 +231,7 @@ export const CreateAcceleration = ({ selectedDatasource={selectedDatasource} dataSourcesPreselected={dataSourcesPreselected} tableFieldsLoading={tableFieldsLoading} + dataSourceMDSId={dataSourceMDSId} /> { setIsLoading(true); - startDatabasesLoading(dataSourceName); + startDatabasesLoading({ dataSourceName }); }; useEffect(() => { diff --git a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/selectors/selector_helpers/load_objects.tsx b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/selectors/selector_helpers/load_objects.tsx index 9366af2bc..7976196c0 100644 --- a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/selectors/selector_helpers/load_objects.tsx +++ b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/selectors/selector_helpers/load_objects.tsx @@ -65,8 +65,8 @@ export const SelectorLoadObjects = ({ tableStatus: true, accelerationsStatus: true, }); - startLoadingTables(dataSourceName, databaseName); - startLoadingAccelerations(dataSourceName); + startLoadingTables({ dataSourceName, databaseName }); + startLoadingAccelerations({ dataSourceName }); }; useEffect(() => { diff --git a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/selectors/source_selector.tsx b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/selectors/source_selector.tsx index d086b0c28..9f127faf5 100644 --- a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/selectors/source_selector.tsx +++ b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/selectors/source_selector.tsx @@ -20,13 +20,13 @@ import React, { useEffect, useState } from 'react'; import { CoreStart } from '../../../../../../../../../../src/core/public'; import { DATACONNECTIONS_BASE } from '../../../../../../../../common/constants/shared'; import { - CachedDatabase, CachedDataSourceStatus, + CachedDatabase, CreateAccelerationForm, } from '../../../../../../../../common/types/data_connections'; import { CatalogCacheManager } from '../../../../../../../framework/catalog_cache/cache_manager'; import { useToast } from '../../../../../../common/toast'; -import { hasError, validateDatabase, validateDataTable } from '../create/utils'; +import { hasError, validateDataTable, validateDatabase } from '../create/utils'; import { SelectorLoadDatabases } from './selector_helpers/load_databases'; import { SelectorLoadObjects } from './selector_helpers/load_objects'; @@ -37,6 +37,7 @@ interface AccelerationDataSourceSelectorProps { selectedDatasource: string; dataSourcesPreselected: boolean; tableFieldsLoading: boolean; + dataSourceMDSId?: string; } export const AccelerationDataSourceSelector = ({ @@ -46,6 +47,7 @@ export const AccelerationDataSourceSelector = ({ selectedDatasource, dataSourcesPreselected, tableFieldsLoading, + dataSourceMDSId, }: AccelerationDataSourceSelectorProps) => { const { setToast } = useToast(); const [databases, setDatabases] = useState>>([]); @@ -72,7 +74,7 @@ export const AccelerationDataSourceSelector = ({ const loadDataSource = () => { setLoadingComboBoxes({ ...loadingComboBoxes, dataSource: true }); http - .get(DATACONNECTIONS_BASE) + .get(DATACONNECTIONS_BASE + `/dataSourceMDSId=${dataSourceMDSId}`) .then((res) => { const isValidDataSource = res.some( (connection: any) => diff --git a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/query_visual_editor.tsx b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/query_visual_editor.tsx index 5089afc2e..9586be97f 100644 --- a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/query_visual_editor.tsx +++ b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/query_visual_editor.tsx @@ -14,12 +14,14 @@ interface QueryVisualEditorProps { accelerationFormData: CreateAccelerationForm; setAccelerationFormData: React.Dispatch>; tableFieldsLoading: boolean; + dataSourceMDSId?: string; } export const QueryVisualEditor = ({ accelerationFormData, setAccelerationFormData, tableFieldsLoading, + dataSourceMDSId, }: QueryVisualEditorProps) => { return tableFieldsLoading ? ( <> @@ -38,6 +40,7 @@ export const QueryVisualEditor = ({ )} {accelerationFormData.accelerationIndexType === 'covering' && ( diff --git a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/skipping_index/generate_fields.tsx b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/skipping_index/generate_fields.tsx index 5eda5b73a..fd4aa5445 100644 --- a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/skipping_index/generate_fields.tsx +++ b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/skipping_index/generate_fields.tsx @@ -26,6 +26,7 @@ interface GenerateFieldsProps { setAccelerationFormData: React.Dispatch>; isSkippingtableLoading: boolean; setIsSkippingtableLoading: React.Dispatch; + dataSourceMDSId?: string; } export const GenerateFields = ({ @@ -33,6 +34,7 @@ export const GenerateFields = ({ setAccelerationFormData, isSkippingtableLoading, setIsSkippingtableLoading, + dataSourceMDSId, }: GenerateFieldsProps) => { const [isGenerateRun, setIsGenerateRun] = useState(false); const { loadStatus, startLoading, stopLoading: _stopLoading, pollingResult } = useDirectQuery(); @@ -84,7 +86,7 @@ export const GenerateFields = ({ )}`, datasource: accelerationFormData.dataSource, }; - startLoading(requestPayload); + startLoading(requestPayload, dataSourceMDSId); setIsSkippingtableLoading(true); setIsGenerateRun(true); setReplaceDefinitionModal(<>); diff --git a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/skipping_index/skipping_index_builder.tsx b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/skipping_index/skipping_index_builder.tsx index 3fb9bc72b..680279590 100644 --- a/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/skipping_index/skipping_index_builder.tsx +++ b/public/components/datasources/components/manage/accelerations/create_accelerations_flyout/visual_editors/skipping_index/skipping_index_builder.tsx @@ -30,11 +30,13 @@ import { GenerateFields } from './generate_fields'; interface SkippingIndexBuilderProps { accelerationFormData: CreateAccelerationForm; setAccelerationFormData: React.Dispatch>; + dataSourceMDSId?: string; } export const SkippingIndexBuilder = ({ accelerationFormData, setAccelerationFormData, + dataSourceMDSId, }: SkippingIndexBuilderProps) => { const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(20); @@ -200,6 +202,7 @@ export const SkippingIndexBuilder = ({ setIsSkippingtableLoading={setIsSkippingtableLoading} accelerationFormData={accelerationFormData} setAccelerationFormData={setAccelerationFormData} + dataSourceMDSId={dataSourceMDSId} /> diff --git a/public/components/datasources/components/manage/accelerations/utils/acceleration_utils.tsx b/public/components/datasources/components/manage/accelerations/utils/acceleration_utils.tsx index 84b674739..23ededc73 100644 --- a/public/components/datasources/components/manage/accelerations/utils/acceleration_utils.tsx +++ b/public/components/datasources/components/manage/accelerations/utils/acceleration_utils.tsx @@ -3,14 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React from 'react'; import { EuiButton, EuiHealth } from '@elastic/eui'; +import React from 'react'; +import { DATA_SOURCE_TYPES } from '../../../../../../../common/constants/data_sources'; import { CachedAcceleration } from '../../../../../../../common/types/data_connections'; import { redirectToExplorerOSIdx, redirectToExplorerWithDataSrc, } from '../../associated_objects/utils/associated_objects_tab_utils'; -import { DATA_SOURCE_TYPES } from '../../../../../../../common/constants/data_sources'; export const ACC_PANEL_TITLE = 'Accelerations'; export const ACC_PANEL_DESC = @@ -93,6 +93,7 @@ export const CreateAccelerationFlyoutButton = ({ dataSourceName: string; renderCreateAccelerationFlyout: ( dataSource: string, + dataSourceMDSId?: string, databaseName?: string, tableName?: string, handleRefresh?: () => void @@ -103,7 +104,13 @@ export const CreateAccelerationFlyoutButton = ({ <> - renderCreateAccelerationFlyout(dataSourceName, undefined, undefined, handleRefresh) + renderCreateAccelerationFlyout( + dataSourceName, + undefined, + undefined, + undefined, + handleRefresh + ) } fill > diff --git a/public/components/datasources/components/manage/associated_objects/associated_objects_details_flyout.tsx b/public/components/datasources/components/manage/associated_objects/associated_objects_details_flyout.tsx index 8b2ce15e8..5cd641411 100644 --- a/public/components/datasources/components/manage/associated_objects/associated_objects_details_flyout.tsx +++ b/public/components/datasources/components/manage/associated_objects/associated_objects_details_flyout.tsx @@ -3,58 +3,59 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useEffect, useState } from 'react'; import { - EuiFlyoutBody, - EuiFlyoutHeader, - EuiSpacer, - EuiText, - EuiIcon, + EuiButton, EuiButtonEmpty, - EuiFlexItem, - EuiFlexGroup, EuiDescriptionList, - EuiDescriptionListTitle, EuiDescriptionListDescription, + EuiDescriptionListTitle, + EuiEmptyPrompt, + EuiFlexGroup, + EuiFlexItem, + EuiFlyoutBody, + EuiFlyoutHeader, EuiHorizontalRule, - EuiTitle, - EuiTableFieldDataColumnType, + EuiIcon, EuiInMemoryTable, EuiLink, - EuiButton, - EuiEmptyPrompt, + EuiSpacer, + EuiTableFieldDataColumnType, + EuiText, + EuiTitle, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; +import React, { useEffect, useState } from 'react'; +import { DATA_SOURCE_TYPES } from '../../../../../../common/constants/data_sources'; import { AssociatedObject, CachedAcceleration, CachedColumn, } from '../../../../../../common/types/data_connections'; -import { - isCatalogCacheFetching, - redirectToExplorerWithDataSrc, -} from './utils/associated_objects_tab_utils'; +import { DirectQueryLoadingStatus } from '../../../../../../common/types/explorer'; +import { useToast } from '../../../../../../public/components/common/toast'; +import { useLoadTableColumnsToCache } from '../../../../../../public/framework/catalog_cache/cache_loader'; +import { CatalogCacheManager } from '../../../../../../public/framework/catalog_cache/cache_manager'; import { getRenderAccelerationDetailsFlyout, getRenderCreateAccelerationFlyout, } from '../../../../../plugin'; import { AccelerationStatus, getAccelerationName } from '../accelerations/utils/acceleration_utils'; import { - ACCE_NO_DATA_TITLE, ACCE_NO_DATA_DESCRIPTION, + ACCE_NO_DATA_TITLE, CREATE_ACCELERATION_DESCRIPTION, } from '../associated_objects/utils/associated_objects_tab_utils'; -import { DATA_SOURCE_TYPES } from '../../../../../../common/constants/data_sources'; -import { useLoadTableColumnsToCache } from '../../../../../../public/framework/catalog_cache/cache_loader'; -import { CatalogCacheManager } from '../../../../../../public/framework/catalog_cache/cache_manager'; -import { DirectQueryLoadingStatus } from '../../../../../../common/types/explorer'; -import { useToast } from '../../../../../../public/components/common/toast'; +import { + isCatalogCacheFetching, + redirectToExplorerWithDataSrc, +} from './utils/associated_objects_tab_utils'; export interface AssociatedObjectsFlyoutProps { tableDetail: AssociatedObject; datasourceName: string; resetFlyout: () => void; handleRefresh?: () => void; + dataSourceMDSId?: string; } export const AssociatedObjectsDetailsFlyout = ({ @@ -62,6 +63,7 @@ export const AssociatedObjectsDetailsFlyout = ({ datasourceName, resetFlyout, handleRefresh, + dataSourceMDSId, }: AssociatedObjectsFlyoutProps) => { const { loadStatus, startLoading } = useLoadTableColumnsToCache(); const [tableColumns, setTableColumns] = useState([]); @@ -93,6 +95,7 @@ export const AssociatedObjectsDetailsFlyout = ({ onClick={() => renderCreateAccelerationFlyout( datasourceName, + '', tableDetail.database, tableDetail.name, handleRefresh @@ -152,7 +155,9 @@ export const AssociatedObjectsDetailsFlyout = ({ const name = getAccelerationName(item, datasourceName); return ( renderAccelerationDetailsFlyout(item, datasourceName, handleRefresh)} + onClick={() => + renderAccelerationDetailsFlyout(item, datasourceName, handleRefresh, dataSourceMDSId) + } > {name} @@ -193,6 +198,7 @@ export const AssociatedObjectsDetailsFlyout = ({ onClick={() => renderCreateAccelerationFlyout( datasourceName, + '', tableDetail.database, tableDetail.name, handleRefresh @@ -235,7 +241,11 @@ export const AssociatedObjectsDetailsFlyout = ({ if (tables?.columns) { setTableColumns(tables?.columns); } else { - startLoading(datasourceName, tableDetail.database, tableDetail.name); + startLoading({ + dataSourceName: datasourceName, + databaseName: tableDetail.database, + tableName: tableDetail.name, + }); } } catch (error) { console.error(error); diff --git a/public/components/datasources/components/manage/associated_objects/associated_objects_tab.tsx b/public/components/datasources/components/manage/associated_objects/associated_objects_tab.tsx index bd8936872..31ddabeb9 100644 --- a/public/components/datasources/components/manage/associated_objects/associated_objects_tab.tsx +++ b/public/components/datasources/components/manage/associated_objects/associated_objects_tab.tsx @@ -3,19 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useEffect, useState } from 'react'; -import _ from 'lodash'; import { - EuiPanel, EuiFlexGroup, EuiFlexItem, - EuiText, EuiHorizontalRule, - EuiSpacer, + EuiPanel, EuiSelectable, + EuiSpacer, + EuiText, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { useToast } from '../../../../../../public/components/common/toast'; +import React, { useEffect, useState } from 'react'; import { ACCELERATION_INDEX_TYPES } from '../../../../../../common/constants/data_sources'; import { AssociatedObject, @@ -27,25 +25,26 @@ import { CachedTable, DatasourceDetails, } from '../../../../../../common/types/data_connections'; -import { AccelerationsRecommendationCallout } from './accelerations_recommendation_callout'; -import { - ASSC_OBJ_PANEL_TITLE, - ASSC_OBJ_PANEL_DESCRIPTION, - ASSC_OBJ_FRESH_MSG, - isCatalogCacheFetching, -} from './utils/associated_objects_tab_utils'; import { DirectQueryLoadingStatus } from '../../../../../../common/types/explorer'; -import { AssociatedObjectsTabEmpty } from './utils/associated_objects_tab_empty'; -import { AssociatedObjectsTabLoading } from './utils/associated_objects_tab_loading'; -import { AssociatedObjectsRefreshButton } from './utils/associated_objects_refresh_button'; +import { useToast } from '../../../../../../public/components/common/toast'; import { CatalogCacheManager } from '../../../../../../public/framework/catalog_cache/cache_manager'; -import { AssociatedObjectsTable } from './modules/associated_objects_table'; +import { getRenderCreateAccelerationFlyout } from '../../../../../../public/plugin'; import { CreateAccelerationFlyoutButton, getAccelerationName, } from '../accelerations/utils/acceleration_utils'; -import { getRenderCreateAccelerationFlyout } from '../../../../../../public/plugin'; +import { AccelerationsRecommendationCallout } from './accelerations_recommendation_callout'; +import { AssociatedObjectsTable } from './modules/associated_objects_table'; +import { AssociatedObjectsRefreshButton } from './utils/associated_objects_refresh_button'; +import { AssociatedObjectsTabEmpty } from './utils/associated_objects_tab_empty'; import { AssociatedObjectsTabFailure } from './utils/associated_objects_tab_failure'; +import { AssociatedObjectsTabLoading } from './utils/associated_objects_tab_loading'; +import { + ASSC_OBJ_FRESH_MSG, + ASSC_OBJ_PANEL_DESCRIPTION, + ASSC_OBJ_PANEL_TITLE, + isCatalogCacheFetching, +} from './utils/associated_objects_tab_utils'; export interface AssociatedObjectsTabProps { datasource: DatasourceDetails; @@ -101,7 +100,7 @@ export const AssociatedObjectsTab: React.FC = (props) const onRefreshButtonClick = () => { if (!isCatalogCacheFetching(databasesLoadStatus, tablesLoadStatus, accelerationsLoadStatus)) { - startLoadingDatabases(datasource.name); + startLoadingDatabases({ databaseName: datasource.name }); setIsRefreshing(true); } }; diff --git a/public/components/hooks/use_polling.ts b/public/components/hooks/use_polling.ts index cf53684e8..30127fa0f 100644 --- a/public/components/hooks/use_polling.ts +++ b/public/components/hooks/use_polling.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { useState, useRef, useEffect } from 'react'; +import { useEffect, useRef, useState } from 'react'; type FetchFunction = (params?: P) => Promise; @@ -111,7 +111,7 @@ export function usePolling( try { const result = await fetchFunction(params); setData(result); - + console.log(result); // Check the success condition and stop polling if it's met if (onPollingSuccess && onPollingSuccess(result, configurations)) { stopPolling(); diff --git a/public/framework/catalog_cache/cache_loader.test.tsx b/public/framework/catalog_cache/cache_loader.test.tsx index 694e3936c..a8a2f2e32 100644 --- a/public/framework/catalog_cache/cache_loader.test.tsx +++ b/public/framework/catalog_cache/cache_loader.test.tsx @@ -66,12 +66,15 @@ describe('loadCacheTests', () => { updateDatabasesToCache(dataSourceName, pollingResult); // Verify that addOrUpdateDataSource is called with the correct parameters - expect(CatalogCacheManager.addOrUpdateDataSource).toHaveBeenCalledWith({ - name: dataSourceName, - databases: [], - lastUpdated: expect.any(String), - status: CachedDataSourceStatus.Failed, - }); + expect(CatalogCacheManager.addOrUpdateDataSource).toHaveBeenCalledWith( + { + name: dataSourceName, + databases: [], + lastUpdated: expect.any(String), + status: CachedDataSourceStatus.Failed, + }, + undefined + ); }); it('should update cache with new databases when polling result is not null', () => { @@ -79,15 +82,28 @@ describe('loadCacheTests', () => { updateDatabasesToCache(dataSourceName, mockShowDatabasesPollingResult); // Verify that addOrUpdateDataSource is called with the correct parameters - expect(CatalogCacheManager.addOrUpdateDataSource).toHaveBeenCalledWith({ - name: dataSourceName, - databases: [ - { name: 'Database1', tables: [], lastUpdated: '', status: CachedDataSourceStatus.Empty }, - { name: 'Database2', tables: [], lastUpdated: '', status: CachedDataSourceStatus.Empty }, - ], - lastUpdated: expect.any(String), - status: CachedDataSourceStatus.Updated, - }); + expect(CatalogCacheManager.addOrUpdateDataSource).toHaveBeenCalledWith( + { + name: dataSourceName, + databases: [ + { + name: 'Database1', + tables: [], + lastUpdated: '', + status: CachedDataSourceStatus.Empty, + }, + { + name: 'Database2', + tables: [], + lastUpdated: '', + status: CachedDataSourceStatus.Empty, + }, + ], + lastUpdated: expect.any(String), + status: CachedDataSourceStatus.Updated, + }, + undefined + ); }); }); @@ -97,19 +113,22 @@ describe('loadCacheTests', () => { const databaseName = 'TestDatabase'; const pollingResult = null; - CatalogCacheManager.addOrUpdateDataSource({ - databases: [ - { - name: databaseName, - lastUpdated: '', - status: CachedDataSourceStatus.Empty, - tables: [], - }, - ], - name: dataSourceName, - lastUpdated: new Date().toUTCString(), - status: CachedDataSourceStatus.Updated, - }); + CatalogCacheManager.addOrUpdateDataSource( + { + databases: [ + { + name: databaseName, + lastUpdated: '', + status: CachedDataSourceStatus.Empty, + tables: [], + }, + ], + name: dataSourceName, + lastUpdated: new Date().toUTCString(), + status: CachedDataSourceStatus.Updated, + }, + undefined + ); updateTablesToCache(dataSourceName, databaseName, pollingResult); // Verify that updateDatabase is called with the correct parameters @@ -120,7 +139,8 @@ describe('loadCacheTests', () => { tables: [], lastUpdated: expect.any(String), status: CachedDataSourceStatus.Failed, - }) + }), + undefined ); }); @@ -151,7 +171,8 @@ describe('loadCacheTests', () => { tables: [{ name: 'http_logs1' }, { name: 'http_logs2' }], lastUpdated: expect.any(String), status: CachedDataSourceStatus.Updated, - }) + }), + undefined ); }); }); diff --git a/public/framework/catalog_cache/cache_loader.tsx b/public/framework/catalog_cache/cache_loader.tsx index 481e777b8..f1775eb90 100644 --- a/public/framework/catalog_cache/cache_loader.tsx +++ b/public/framework/catalog_cache/cache_loader.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { ASYNC_POLLING_INTERVAL, SPARK_HIVE_TABLE_REGEX, @@ -16,6 +16,7 @@ import { CachedDataSourceStatus, CachedTable, LoadCacheType, + StartLoadingParams, } from '../../../common/types/data_connections'; import { DirectQueryLoadingStatus, DirectQueryRequest } from '../../../common/types/explorer'; import { getAsyncSessionId, setAsyncSessionId } from '../../../common/utils/query_session_utils'; @@ -32,18 +33,26 @@ import { CatalogCacheManager } from './cache_manager'; export const updateDatabasesToCache = ( dataSourceName: string, - pollingResult: AsyncPollingResult + pollingResult: AsyncPollingResult, + dataSourceMDSId?: string ) => { - const cachedDataSource = CatalogCacheManager.getOrCreateDataSource(dataSourceName); + const cachedDataSource = CatalogCacheManager.getOrCreateDataSource( + dataSourceName, + dataSourceMDSId + ); const currentTime = new Date().toUTCString(); if (!pollingResult) { - CatalogCacheManager.addOrUpdateDataSource({ - ...cachedDataSource, - databases: [], - lastUpdated: currentTime, - status: CachedDataSourceStatus.Failed, - }); + CatalogCacheManager.addOrUpdateDataSource( + { + ...cachedDataSource, + databases: [], + lastUpdated: currentTime, + status: CachedDataSourceStatus.Failed, + ...(dataSourceMDSId && { dataSourceMDSId }), + }, + dataSourceMDSId + ); return; } @@ -55,30 +64,43 @@ export const updateDatabasesToCache = ( status: CachedDataSourceStatus.Empty, })); - CatalogCacheManager.addOrUpdateDataSource({ - ...cachedDataSource, - databases: newDatabases, - lastUpdated: currentTime, - status: CachedDataSourceStatus.Updated, - }); + CatalogCacheManager.addOrUpdateDataSource( + { + ...cachedDataSource, + databases: newDatabases, + lastUpdated: currentTime, + status: CachedDataSourceStatus.Updated, + ...(dataSourceMDSId && { dataSourceMDSId }), + }, + dataSourceMDSId + ); }; export const updateTablesToCache = ( dataSourceName: string, databaseName: string, - pollingResult: AsyncPollingResult + pollingResult: AsyncPollingResult, + dataSourceMDSId?: string ) => { try { - const cachedDatabase = CatalogCacheManager.getDatabase(dataSourceName, databaseName); + const cachedDatabase = CatalogCacheManager.getDatabase( + dataSourceName, + databaseName, + dataSourceMDSId + ); const currentTime = new Date().toUTCString(); if (!pollingResult) { - CatalogCacheManager.updateDatabase(dataSourceName, { - ...cachedDatabase, - tables: [], - lastUpdated: currentTime, - status: CachedDataSourceStatus.Failed, - }); + CatalogCacheManager.updateDatabase( + dataSourceName, + { + ...cachedDatabase, + tables: [], + lastUpdated: currentTime, + status: CachedDataSourceStatus.Failed, + }, + dataSourceMDSId + ); return; } @@ -89,12 +111,16 @@ export const updateTablesToCache = ( name: row.tableName, })); - CatalogCacheManager.updateDatabase(dataSourceName, { - ...cachedDatabase, - tables: newTables, - lastUpdated: currentTime, - status: CachedDataSourceStatus.Updated, - }); + CatalogCacheManager.updateDatabase( + dataSourceName, + { + ...cachedDatabase, + tables: newTables, + lastUpdated: currentTime, + status: CachedDataSourceStatus.Updated, + }, + dataSourceMDSId + ); } catch (error) { console.error(error); } @@ -102,7 +128,8 @@ export const updateTablesToCache = ( export const updateAccelerationsToCache = ( dataSourceName: string, - pollingResult: AsyncPollingResult + pollingResult: AsyncPollingResult, + dataSourceMDSId?: string ) => { const currentTime = new Date().toUTCString(); @@ -112,6 +139,7 @@ export const updateAccelerationsToCache = ( accelerations: [], lastUpdated: currentTime, status: CachedDataSourceStatus.Failed, + ...(dataSourceMDSId && { dataSourceMDSId }), }); return; } @@ -133,6 +161,7 @@ export const updateAccelerationsToCache = ( accelerations: newAccelerations, lastUpdated: currentTime, status: CachedDataSourceStatus.Updated, + ...(dataSourceMDSId && { dataSourceMDSId }), }); }; @@ -140,13 +169,18 @@ export const updateTableColumnsToCache = ( dataSourceName: string, databaseName: string, tableName: string, - pollingResult: AsyncPollingResult + pollingResult: AsyncPollingResult, + dataSourceMDSId?: string ) => { try { if (!pollingResult) { return; } - const cachedDatabase = CatalogCacheManager.getDatabase(dataSourceName, databaseName); + const cachedDatabase = CatalogCacheManager.getDatabase( + dataSourceName, + databaseName, + dataSourceMDSId + ); const currentTime = new Date().toUTCString(); const combinedData: Array<{ col_name: string; data_type: string }> = combineSchemaAndDatarows( @@ -170,12 +204,16 @@ export const updateTableColumnsToCache = ( ); if (cachedDatabase.status === CachedDataSourceStatus.Updated) { - CatalogCacheManager.updateDatabase(dataSourceName, { - ...cachedDatabase, - tables: newTables, - lastUpdated: currentTime, - status: CachedDataSourceStatus.Updated, - }); + CatalogCacheManager.updateDatabase( + dataSourceName, + { + ...cachedDatabase, + tables: newTables, + lastUpdated: currentTime, + status: CachedDataSourceStatus.Updated, + }, + dataSourceMDSId + ); } } catch (error) { console.error(error); @@ -187,20 +225,27 @@ export const updateToCache = ( loadCacheType: LoadCacheType, dataSourceName: string, databaseName?: string, - tableName?: string + tableName?: string, + dataSourceMDSId?: string ) => { switch (loadCacheType) { case 'databases': - updateDatabasesToCache(dataSourceName, pollResults); + updateDatabasesToCache(dataSourceName, pollResults, dataSourceMDSId); break; case 'tables': - updateTablesToCache(dataSourceName, databaseName!, pollResults); + updateTablesToCache(dataSourceName, databaseName!, pollResults, dataSourceMDSId); break; case 'accelerations': - updateAccelerationsToCache(dataSourceName, pollResults); + updateAccelerationsToCache(dataSourceName, pollResults, dataSourceMDSId); break; case 'tableColumns': - updateTableColumnsToCache(dataSourceName, databaseName!, tableName!, pollResults); + updateTableColumnsToCache( + dataSourceName, + databaseName!, + tableName!, + pollResults, + dataSourceMDSId + ); default: break; } @@ -245,6 +290,7 @@ export const useLoadToCache = (loadCacheType: LoadCacheType) => { const [loadStatus, setLoadStatus] = useState( DirectQueryLoadingStatus.INITIAL ); + const dataSourceMDSClientId = useRef(''); const { data: pollingResult, @@ -253,7 +299,7 @@ export const useLoadToCache = (loadCacheType: LoadCacheType) => { startPolling, stopPolling: stopLoading, } = usePolling((params) => { - return sqlService.fetchWithJobId(params); + return sqlService.fetchWithJobId(params, dataSourceMDSClientId.current); }, ASYNC_POLLING_INTERVAL); const onLoadingFailed = () => { @@ -263,15 +309,22 @@ export const useLoadToCache = (loadCacheType: LoadCacheType) => { loadCacheType, currentDataSourceName, currentDatabaseName, - currentTableName + currentTableName, + dataSourceMDSClientId.current ); }; - const startLoading = (dataSourceName: string, databaseName?: string, tableName?: string) => { + const startLoading = ({ + dataSourceName, + dataSourceMDSId, + databaseName, + tableName, + }: StartLoadingParams) => { setLoadStatus(DirectQueryLoadingStatus.SCHEDULED); setCurrentDataSourceName(dataSourceName); setCurrentDatabaseName(databaseName); setCurrentTableName(tableName); + dataSourceMDSClientId.current = dataSourceMDSId || ''; let requestPayload: DirectQueryRequest = { lang: 'sql', @@ -283,10 +336,10 @@ export const useLoadToCache = (loadCacheType: LoadCacheType) => { if (sessionId) { requestPayload = { ...requestPayload, sessionId }; } - sqlService - .fetch(requestPayload) + .fetch(requestPayload, dataSourceMDSId) .then((result) => { + console.log(result); setAsyncSessionId(dataSourceName, getObjValue(result, 'sessionId', null)); if (result.queryId) { startPolling({ @@ -325,7 +378,8 @@ export const useLoadToCache = (loadCacheType: LoadCacheType) => { loadCacheType, currentDataSourceName, currentDatabaseName, - currentTableName + currentTableName, + dataSourceMDSClientId.current ); } else if (status === DirectQueryLoadingStatus.FAILED) { onLoadingFailed(); diff --git a/public/framework/catalog_cache/cache_manager.test.tsx b/public/framework/catalog_cache/cache_manager.test.tsx index 0e5755a42..53d06d0f5 100644 --- a/public/framework/catalog_cache/cache_manager.test.tsx +++ b/public/framework/catalog_cache/cache_manager.test.tsx @@ -125,7 +125,10 @@ describe('CatalogCacheManager', () => { }); it('should return default cache object if cache is not found', () => { - const defaultCacheObject = { version: CATALOG_CACHE_VERSION, dataSources: [] }; + const defaultCacheObject = { + version: CATALOG_CACHE_VERSION, + dataSources: [], + }; sessionStorage.removeItem(ASYNC_QUERY_DATASOURCE_CACHE); expect(CatalogCacheManager.getDataSourceCache()).toEqual(defaultCacheObject); }); diff --git a/public/framework/catalog_cache/cache_manager.ts b/public/framework/catalog_cache/cache_manager.ts index ccd0ab506..bcd0dedbf 100644 --- a/public/framework/catalog_cache/cache_manager.ts +++ b/public/framework/catalog_cache/cache_manager.ts @@ -87,11 +87,23 @@ export class CatalogCacheManager { * Adds or updates a data source in the accelerations cache. * @param {CachedAccelerationByDataSource} dataSource - The data source to add or update. */ - static addOrUpdateAccelerationsByDataSource(dataSource: CachedAccelerationByDataSource): void { + static addOrUpdateAccelerationsByDataSource( + dataSource: CachedAccelerationByDataSource, + dataSourceMDSId?: string + ): void { + let index; const accCacheData = this.getAccelerationsCache(); - const index = accCacheData.dataSources.findIndex( - (ds: CachedAccelerationByDataSource) => ds.name === dataSource.name - ); + if (dataSourceMDSId) { + index = accCacheData.dataSources.findIndex( + (ds: CachedAccelerationByDataSource) => + ds.name === dataSource.name && ds.dataSourceMDSId === dataSourceMDSId + ); + } else { + index = accCacheData.dataSources.findIndex( + (ds: CachedAccelerationByDataSource) => + ds.name === dataSource.name && ds.dataSourceMDSId === dataSourceMDSId + ); + } if (index !== -1) { accCacheData.dataSources[index] = dataSource; } else { @@ -107,20 +119,32 @@ export class CatalogCacheManager { * @throws {Error} If the data source is not found. */ static getOrCreateAccelerationsByDataSource( - dataSourceName: string + dataSourceName: string, + dataSourceMDSId?: string ): CachedAccelerationByDataSource { const accCacheData = this.getAccelerationsCache(); - const cachedDataSource = accCacheData.dataSources.find((ds) => ds.name === dataSourceName); + let cachedDataSource; + if (dataSourceMDSId) { + cachedDataSource = accCacheData.dataSources.find( + (ds) => ds.name === dataSourceName && ds.dataSourceMDSId === dataSourceMDSId + ); + } else { + cachedDataSource = accCacheData.dataSources.find((ds) => ds.name === dataSourceName); + } if (cachedDataSource) return cachedDataSource; else { - const defaultDataSourceObject = { + let defaultDataSourceObject: CachedAccelerationByDataSource = { name: dataSourceName, lastUpdated: '', status: CachedDataSourceStatus.Empty, accelerations: [], }; - this.addOrUpdateAccelerationsByDataSource(defaultDataSourceObject); + + if (dataSourceMDSId !== '' && dataSourceMDSId !== undefined) { + defaultDataSourceObject = { ...defaultDataSourceObject, dataSourceMDSId }; + } + this.addOrUpdateAccelerationsByDataSource(defaultDataSourceObject, dataSourceMDSId); return defaultDataSourceObject; } } @@ -129,11 +153,16 @@ export class CatalogCacheManager { * Adds or updates a data source in the cache. * @param {CachedDataSource} dataSource - The data source to add or update. */ - static addOrUpdateDataSource(dataSource: CachedDataSource): void { + static addOrUpdateDataSource(dataSource: CachedDataSource, dataSourceMDSId?: string): void { const cacheData = this.getDataSourceCache(); - const index = cacheData.dataSources.findIndex( - (ds: CachedDataSource) => ds.name === dataSource.name - ); + let index; + if (dataSourceMDSId) { + index = cacheData.dataSources.findIndex( + (ds: CachedDataSource) => + ds.name === dataSource.name && ds.dataSourceMDSId === dataSourceMDSId + ); + } + index = cacheData.dataSources.findIndex((ds: CachedDataSource) => ds.name === dataSource.name); if (index !== -1) { cacheData.dataSources[index] = dataSource; } else { @@ -147,21 +176,30 @@ export class CatalogCacheManager { * @param {string} dataSourceName - The name of the data source. * @returns {CachedDataSource} The retrieved or created data source. */ - static getOrCreateDataSource(dataSourceName: string): CachedDataSource { - const cacheData = this.getDataSourceCache(); - const cachedDataSource = cacheData.dataSources.find( - (ds: CachedDataSource) => ds.name === dataSourceName - ); + static getOrCreateDataSource(dataSourceName: string, dataSourceMDSId?: string): CachedDataSource { + let cachedDataSource; + if (dataSourceMDSId) { + cachedDataSource = this.getDataSourceCache().dataSources.find( + (ds) => ds.dataSourceMDSId === dataSourceMDSId && ds.name === dataSourceName + ); + } else { + cachedDataSource = this.getDataSourceCache().dataSources.find( + (ds) => ds.name === dataSourceName + ); + } if (cachedDataSource) { return cachedDataSource; } else { - const defaultDataSourceObject = { + let defaultDataSourceObject: CachedDataSource = { name: dataSourceName, lastUpdated: '', status: CachedDataSourceStatus.Empty, databases: [], }; - this.addOrUpdateDataSource(defaultDataSourceObject); + if (dataSourceMDSId !== '' && dataSourceMDSId !== undefined) { + defaultDataSourceObject = { ...defaultDataSourceObject, dataSourceMDSId }; + } + this.addOrUpdateDataSource(defaultDataSourceObject, dataSourceMDSId); return defaultDataSourceObject; } } @@ -173,10 +211,21 @@ export class CatalogCacheManager { * @returns {CachedDatabase} The retrieved database. * @throws {Error} If the data source or database is not found. */ - static getDatabase(dataSourceName: string, databaseName: string): CachedDatabase { - const cachedDataSource = this.getDataSourceCache().dataSources.find( - (ds) => ds.name === dataSourceName - ); + static getDatabase( + dataSourceName: string, + databaseName: string, + dataSourceMDSId?: string + ): CachedDatabase { + let cachedDataSource; + if (dataSourceMDSId) { + cachedDataSource = this.getDataSourceCache().dataSources.find( + (ds) => ds.dataSourceMDSId === dataSourceMDSId && ds.name === dataSourceName + ); + } else { + cachedDataSource = this.getDataSourceCache().dataSources.find( + (ds) => ds.name === dataSourceName + ); + } if (!cachedDataSource) { throw new Error('DataSource not found exception: ' + dataSourceName); } @@ -197,8 +246,13 @@ export class CatalogCacheManager { * @returns {Cachedtable} The retrieved database. * @throws {Error} If the data source, database or table is not found. */ - static getTable(dataSourceName: string, databaseName: string, tableName: string): CachedTable { - const cachedDatabase = this.getDatabase(dataSourceName, databaseName); + static getTable( + dataSourceName: string, + databaseName: string, + tableName: string, + dataSourceMDSId?: string + ): CachedTable { + const cachedDatabase = this.getDatabase(dataSourceName, databaseName, dataSourceMDSId); const cachedTable = cachedDatabase.tables!.find((table) => table.name === tableName); if (!cachedTable) { @@ -213,10 +267,22 @@ export class CatalogCacheManager { * @param {CachedDatabase} database - The database to be updated. * @throws {Error} If the data source or database is not found. */ - static updateDatabase(dataSourceName: string, database: CachedDatabase): void { - const cachedDataSource = this.getDataSourceCache().dataSources.find( - (ds) => ds.name === dataSourceName - ); + static updateDatabase( + dataSourceName: string, + database: CachedDatabase, + dataSourceMDSId?: string + ): void { + let cachedDataSource; + if (dataSourceMDSId) { + cachedDataSource = this.getDataSourceCache().dataSources.find( + (ds) => ds.dataSourceMDSId === dataSourceMDSId && ds.name === dataSourceName + ); + } else { + cachedDataSource = this.getDataSourceCache().dataSources.find( + (ds) => ds.name === dataSourceName + ); + } + if (!cachedDataSource) { throw new Error('DataSource not found exception: ' + dataSourceName); } @@ -224,7 +290,7 @@ export class CatalogCacheManager { const index = cachedDataSource.databases.findIndex((db) => db.name === database.name); if (index !== -1) { cachedDataSource.databases[index] = database; - this.addOrUpdateDataSource(cachedDataSource); + this.addOrUpdateDataSource(cachedDataSource, dataSourceMDSId); } else { throw new Error('Database not found exception: ' + database.name); } diff --git a/public/framework/datasources/direct_query_hook.tsx b/public/framework/datasources/direct_query_hook.tsx index a896a5395..8688996c0 100644 --- a/public/framework/datasources/direct_query_hook.tsx +++ b/public/framework/datasources/direct_query_hook.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { ASYNC_POLLING_INTERVAL } from '../../../common/constants/data_sources'; import { DirectQueryLoadingStatus, DirectQueryRequest } from '../../../common/types/explorer'; import { getAsyncSessionId, setAsyncSessionId } from '../../../common/utils/query_session_utils'; @@ -18,6 +18,7 @@ export const useDirectQuery = () => { const [loadStatus, setLoadStatus] = useState( DirectQueryLoadingStatus.SCHEDULED ); + const dataSourceMDSClientId = useRef(''); const { data: pollingResult, @@ -26,10 +27,11 @@ export const useDirectQuery = () => { startPolling, stopPolling: stopLoading, } = usePolling((params) => { - return sqlService.fetchWithJobId(params); + return sqlService.fetchWithJobId(params, dataSourceMDSClientId.current); }, ASYNC_POLLING_INTERVAL); - const startLoading = (requestPayload: DirectQueryRequest) => { + const startLoading = (requestPayload: DirectQueryRequest, dataSourceMDSId?: string) => { + dataSourceMDSClientId.current = dataSourceMDSId || ''; setLoadStatus(DirectQueryLoadingStatus.SCHEDULED); const sessionId = getAsyncSessionId(requestPayload.datasource); @@ -38,7 +40,7 @@ export const useDirectQuery = () => { } sqlService - .fetch(requestPayload) + .fetch(requestPayload, dataSourceMDSId) .then((result) => { setAsyncSessionId(requestPayload.datasource, getObjValue(result, 'sessionId', null)); if (result.queryId) { diff --git a/public/plugin.tsx b/public/plugin.tsx index 0f8b78ad9..08591d8a7 100644 --- a/public/plugin.tsx +++ b/public/plugin.tsx @@ -116,14 +116,24 @@ export const [ getRenderAccelerationDetailsFlyout, setRenderAccelerationDetailsFlyout, ] = createGetterSetter< - (acceleration: CachedAcceleration, dataSourceName: string, handleRefresh?: () => void) => void + ( + acceleration: CachedAcceleration, + dataSourceName: string, + handleRefresh?: () => void, + dataSourceMDSId?: string + ) => void >('renderAccelerationDetailsFlyout'); export const [ getRenderAssociatedObjectsDetailsFlyout, setRenderAssociatedObjectsDetailsFlyout, ] = createGetterSetter< - (tableDetail: AssociatedObject, datasourceName: string, handleRefresh?: () => void) => void + ( + tableDetail: AssociatedObject, + datasourceName: string, + handleRefresh?: () => void, + dataSourceMDSId?: string + ) => void >('renderAssociatedObjectsDetailsFlyout'); export const [ @@ -132,6 +142,7 @@ export const [ ] = createGetterSetter< ( dataSource: string, + dataSourceMDSId?: string, databaseName?: string, tableName?: string, handleRefresh?: () => void @@ -461,7 +472,8 @@ export class ObservabilityPlugin const renderAccelerationDetailsFlyout = ( acceleration: CachedAcceleration, dataSourceName: string, - handleRefresh?: () => void + handleRefresh?: () => void, + dataSourceMDSId?: string ) => { const accelerationDetailsFlyout = core.overlays.openFlyout( toMountPoint( @@ -470,6 +482,7 @@ export class ObservabilityPlugin dataSourceName={dataSourceName} resetFlyout={() => accelerationDetailsFlyout.close()} handleRefresh={handleRefresh} + dataSourceMDSId={dataSourceMDSId} /> ) ); @@ -479,7 +492,8 @@ export class ObservabilityPlugin const renderAssociatedObjectsDetailsFlyout = ( tableDetail: AssociatedObject, datasourceName: string, - handleRefresh?: () => void + handleRefresh?: () => void, + dataSourceMDSId?: string ) => { const associatedObjectsDetailsFlyout = core.overlays.openFlyout( toMountPoint( @@ -488,6 +502,7 @@ export class ObservabilityPlugin datasourceName={datasourceName} resetFlyout={() => associatedObjectsDetailsFlyout.close()} handleRefresh={handleRefresh} + dataSourceMDSId={dataSourceMDSId} /> ) ); @@ -496,6 +511,7 @@ export class ObservabilityPlugin const renderCreateAccelerationFlyout = ( selectedDatasource: string, + dataSourceMDSId?: string, databaseName?: string, tableName?: string, handleRefresh?: () => void @@ -508,6 +524,7 @@ export class ObservabilityPlugin databaseName={databaseName} tableName={tableName} refreshHandler={handleRefresh} + dataSourceMDSId={dataSourceMDSId} /> ) ); diff --git a/public/services/requests/sql.ts b/public/services/requests/sql.ts index 1ec3b3d2a..9b9bd9f93 100644 --- a/public/services/requests/sql.ts +++ b/public/services/requests/sql.ts @@ -12,10 +12,18 @@ export class SQLService { this.http = http; } - fetch = async (params: DirectQueryRequest, errorHandler?: (error: any) => void) => { + fetch = async ( + params: DirectQueryRequest, + dataSourceMDSId?: string, + errorHandler?: (error: any) => void + ) => { + const query = { + dataSourceMDSId, + }; return this.http .post('/api/observability/query/jobs', { body: JSON.stringify(params), + query, }) .catch((error) => { console.error('fetch error: ', error.body); @@ -24,12 +32,18 @@ export class SQLService { }); }; - fetchWithJobId = async (params: { queryId: string }, errorHandler?: (error: any) => void) => { - return this.http.get(`/api/observability/query/jobs/${params.queryId}`).catch((error) => { - console.error('fetch error: ', error.body); - if (errorHandler) errorHandler(error); - throw error; - }); + fetchWithJobId = async ( + params: { queryId: string }, + dataSourceMDSId?: string, + errorHandler?: (error: any) => void + ) => { + return this.http + .get(`/api/observability/query/jobs/${params.queryId}/${dataSourceMDSId}`) + .catch((error) => { + console.error('fetch error: ', error.body); + if (errorHandler) errorHandler(error); + throw error; + }); }; deleteWithJobId = async (params: { queryId: string }, errorHandler?: (error: any) => void) => { diff --git a/public/types.ts b/public/types.ts index d276f0538..cd01d02fd 100644 --- a/public/types.ts +++ b/public/types.ts @@ -53,6 +53,7 @@ export interface ObservabilityStart { ) => void; renderCreateAccelerationFlyout: ( dataSource: string, + dataSourceMDSId?: string, databaseName?: string, tableName?: string, handleRefresh?: () => void diff --git a/server/routes/data_connections/data_connections_router.ts b/server/routes/data_connections/data_connections_router.ts index 2788653de..bd19e8615 100644 --- a/server/routes/data_connections/data_connections_router.ts +++ b/server/routes/data_connections/data_connections_router.ts @@ -15,7 +15,7 @@ import { EDIT, } from '../../../common/constants/shared'; -export function registerDataConnectionsRoute(router: IRouter) { +export function registerDataConnectionsRoute(router: IRouter, dataSourceEnabled: boolean) { router.get( { path: `${DATACONNECTIONS_BASE}/{name}`, @@ -183,14 +183,25 @@ export function registerDataConnectionsRoute(router: IRouter) { router.get( { - path: `${DATACONNECTIONS_BASE}`, - validate: false, + path: `${DATACONNECTIONS_BASE}/dataSourceMDSId={dataSourceMDSId?}`, + validate: { + params: schema.object({ + dataSourceMDSId: schema.maybe(schema.string({ defaultValue: '' })), + }), + }, }, async (context, request, response): Promise => { + const dataSourceMDSId = request.params.dataSourceMDSId; try { - const dataConnectionsresponse = await context.observability_plugin.observabilityClient - .asScoped(request) - .callAsCurrentUser('ppl.getDataConnections'); + let dataConnectionsresponse; + if (dataSourceEnabled && dataSourceMDSId) { + const client = await context.dataSource.opensearch.legacy.getClient(dataSourceMDSId); + dataConnectionsresponse = await client.callAPI('ppl.getDataConnections'); + } else { + dataConnectionsresponse = await context.observability_plugin.observabilityClient + .asScoped(request) + .callAsCurrentUser('ppl.getDataConnections'); + } return response.ok({ body: dataConnectionsresponse, }); diff --git a/server/routes/datasources/datasources_router.ts b/server/routes/datasources/datasources_router.ts index 9a1ba396a..213d4d4d1 100644 --- a/server/routes/datasources/datasources_router.ts +++ b/server/routes/datasources/datasources_router.ts @@ -7,7 +7,7 @@ import { schema } from '@osd/config-schema'; import { IRouter } from '../../../../../src/core/server'; import { JOBS_BASE, OBSERVABILITY_BASE } from '../../../common/constants/shared'; -export function registerDatasourcesRoute(router: IRouter) { +export function registerDatasourcesRoute(router: IRouter, dataSourceEnabled: boolean) { router.post( { path: `${OBSERVABILITY_BASE}${JOBS_BASE}`, @@ -21,15 +21,22 @@ export function registerDatasourcesRoute(router: IRouter) { }, }, async (context, request, response): Promise => { + const dataSourceMDSId = request.url.searchParams.get('dataSourceMDSId'); const params = { body: { ...request.body, }, }; try { - const res = await context.observability_plugin.observabilityClient - .asScoped(request) - .callAsCurrentUser('observability.runDirectQuery', params); + let res; + if (dataSourceEnabled && dataSourceMDSId) { + const client = await context.dataSource.opensearch.legacy.getClient(dataSourceMDSId); + res = await client.callAPI('observability.runDirectQuery', params); + } else { + res = await context.observability_plugin.observabilityClient + .asScoped(request) + .callAsCurrentUser('observability.runDirectQuery', params); + } return response.ok({ body: res, }); @@ -45,20 +52,31 @@ export function registerDatasourcesRoute(router: IRouter) { router.get( { - path: `${OBSERVABILITY_BASE}${JOBS_BASE}/{queryId}`, + path: `${OBSERVABILITY_BASE}${JOBS_BASE}/{queryId}/{dataSourceMDSId?}`, validate: { params: schema.object({ queryId: schema.string(), + dataSourceMDSId: schema.maybe(schema.string({ defaultValue: '' })), }), }, }, async (context, request, response): Promise => { try { - const res = await context.observability_plugin.observabilityClient - .asScoped(request) - .callAsCurrentUser('observability.getJobStatus', { + let res; + if (dataSourceEnabled && request.params.dataSourceMDSId) { + const client = await context.dataSource.opensearch.legacy.getClient( + request.params.dataSourceMDSId + ); + res = await client.callAPI('observability.getJobStatus', { queryId: request.params.queryId, }); + } else { + res = await context.observability_plugin.observabilityClient + .asScoped(request) + .callAsCurrentUser('observability.getJobStatus', { + queryId: request.params.queryId, + }); + } return response.ok({ body: res, }); diff --git a/server/routes/index.ts b/server/routes/index.ts index 0e87b115b..401110d00 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -45,7 +45,7 @@ export function setupRoutes({ router, client }: { router: IRouter; client: ILega registerMetricsRoute(router); registerIntegrationsRoute(router); - registerDataConnectionsRoute(router); - registerDatasourcesRoute(router); + registerDataConnectionsRoute(router, dataSourceEnabled); + registerDatasourcesRoute(router, dataSourceEnabled); registerQueryAssistRoutes(router); }