diff --git a/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx b/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx index 8f3fb6e4431a..c1d0989991ac 100644 --- a/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { EuiSpacer, EuiInMemoryTable, @@ -44,6 +44,11 @@ export const OpenSearchConnectionTable = ({ const [modalVisible, setModalVisible] = useState(false); const [popoversState, setPopoversState] = useState>({}); + useEffect(() => { + // Reset selected items when connectionType changes + setSelectedItems([]); + }, [connectionType, setSelectedItems]); + const filteredDataSources = useMemo(() => { // Reset the item when switching connectionType. setSelectedItems([]); @@ -180,7 +185,11 @@ export const OpenSearchConnectionTable = ({ } > - RELATED CONNECTIONS + + {i18n.translate('workspace.detail.dataSources.recentConnections.title', { + defaultMessage: 'RELATED CONNECTIONS', + })} + ([]); const [toggleIdSelected, setToggleIdSelected] = useState('all'); + const fetchDQC = useFetchDQC(assignedDataSources, http, notifications); - const fetchDQC = useCallback(async () => { + useEffect(() => { setIsLoading(true); - try { - const directQueryConnectionsPromises = assignedDataSources.map((ds) => - getDirectQueryConnections(ds.id, http!) - ); - const directQueryConnectionsResult = await Promise.all(directQueryConnectionsPromises); - const directQueryConnections = directQueryConnectionsResult.flat(); - setDataSourceConnections( - mergeDataSourcesWithConnections(assignedDataSources, directQueryConnections) - ); - } catch (error) { - notifications?.toasts.addDanger( - i18n.translate('workspace.detail.dataSources.error.message', { - defaultMessage: 'Can not fetch direct query connections', - }) - ); - } finally { + fetchDQC().then((res) => { + setDataSourceConnections(res); setIsLoading(false); - } - }, [assignedDataSources, http, notifications?.toasts]); - - useEffect(() => { - fetchDQC(); + }); }, [fetchDQC]); const toggleButtons = [ @@ -100,10 +83,6 @@ export const SelectDataSourceDetailPanel = ({ }, ]; - const onChange = (optionId: string) => { - setToggleIdSelected(optionId); - }; - const handleAssignDataSources = async (dataSources: DataSource[]) => { try { setIsLoading(true); @@ -139,41 +118,44 @@ export const SelectDataSourceDetailPanel = ({ } }; - const handleUnassignDataSources = async (dataSources: DataSourceConnection[]) => { - try { - setIsLoading(true); - const { permissionSettings, selectedDataSources, useCase, ...attributes } = formData; - const savedDataSources = (selectedDataSources ?? [])?.filter( - ({ id }: DataSource) => !dataSources.some((item) => item.id === id) - ); + const handleUnassignDataSources = useCallback( + async (dataSources: DataSourceConnection[]) => { + try { + setIsLoading(true); + const { permissionSettings, selectedDataSources, useCase, ...attributes } = formData; + const savedDataSources = (selectedDataSources ?? [])?.filter( + ({ id }: DataSource) => !dataSources.some((item) => item.id === id) + ); - const result = await workspaceClient.update(currentWorkspace.id, attributes, { - dataSources: savedDataSources.map(({ id }: DataSource) => id), - permissions: convertPermissionSettingsToPermissions(permissionSettings), - }); - if (result?.success) { - notifications?.toasts.addSuccess({ - title: i18n.translate('workspace.detail.dataSources.unassign.success', { - defaultMessage: 'Remove associated OpenSearch connections successfully', + const result = await workspaceClient.update(currentWorkspace.id, attributes, { + dataSources: savedDataSources.map(({ id }: DataSource) => id), + permissions: convertPermissionSettingsToPermissions(permissionSettings), + }); + if (result?.success) { + notifications?.toasts.addSuccess({ + title: i18n.translate('workspace.detail.dataSources.unassign.success', { + defaultMessage: 'Remove associated OpenSearch connections successfully', + }), + }); + setSelectedDataSources(savedDataSources); + } else { + throw new Error( + result?.error ? result?.error : 'Remove associated OpenSearch connections failed' + ); + } + } catch (error) { + notifications?.toasts.addDanger({ + title: i18n.translate('workspace.detail.dataSources.unassign.failed', { + defaultMessage: 'Failed to remove associated OpenSearch connections', }), + text: error instanceof Error ? error.message : JSON.stringify(error), }); - setSelectedDataSources(savedDataSources); - } else { - throw new Error( - result?.error ? result?.error : 'Remove associated OpenSearch connections failed' - ); + } finally { + setIsLoading(false); } - } catch (error) { - notifications?.toasts.addDanger({ - title: i18n.translate('workspace.detail.dataSources.unassign.failed', { - defaultMessage: 'Failed to remove associated OpenSearch connections', - }), - text: error instanceof Error ? error.message : JSON.stringify(error), - }); - } finally { - setIsLoading(false); - } - }; + }, + [currentWorkspace.id, formData, notifications?.toasts, setSelectedDataSources, workspaceClient] + ); const associationButton = ( onChange(id)} + onChange={(id) => setToggleIdSelected(id)} isFullWidth /> diff --git a/src/plugins/workspace/public/hooks.ts b/src/plugins/workspace/public/hooks.ts index 875e9b494f23..93a2e4a38e79 100644 --- a/src/plugins/workspace/public/hooks.ts +++ b/src/plugins/workspace/public/hooks.ts @@ -3,9 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { ApplicationStart, PublicAppInfo } from 'opensearch-dashboards/public'; +import { + ApplicationStart, + HttpSetup, + NotificationsStart, + PublicAppInfo, +} from 'opensearch-dashboards/public'; import { useObservable } from 'react-use'; -import { useMemo } from 'react'; +import { useCallback, useMemo } from 'react'; +import { i18n } from '@osd/i18n'; +import { getDirectQueryConnections, mergeDataSourcesWithConnections } from './utils'; +import { DataSource } from '../common/types'; export function useApplications(applicationInstance: ApplicationStart) { const applications = useObservable(applicationInstance.applications$); @@ -17,3 +25,29 @@ export function useApplications(applicationInstance: ApplicationStart) { return apps; }, [applications]); } + +export const useFetchDQC = ( + assignedDataSources: DataSource[], + http: HttpSetup | undefined, + notifications: NotificationsStart | undefined +) => { + const fetchDQC = useCallback(async () => { + try { + const directQueryConnectionsPromises = assignedDataSources.map((ds) => + getDirectQueryConnections(ds.id, http!) + ); + const directQueryConnectionsResult = await Promise.all(directQueryConnectionsPromises); + const directQueryConnections = directQueryConnectionsResult.flat(); + return mergeDataSourcesWithConnections(assignedDataSources, directQueryConnections); + } catch (error) { + notifications?.toasts.addDanger( + i18n.translate('workspace.detail.dataSources.error.message', { + defaultMessage: 'Cannot fetch direct query connections', + }) + ); + return []; + } + }, [assignedDataSources, http, notifications?.toasts]); + + return fetchDQC; +};