diff --git a/openmetadata-ui/src/main/resources/ui/src/components/buttons/Button/Button.tsx b/openmetadata-ui/src/main/resources/ui/src/components/buttons/Button/Button.tsx index 3b6bfefb90f..87471162235 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/buttons/Button/Button.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/buttons/Button/Button.tsx @@ -17,6 +17,9 @@ import React, { FunctionComponent } from 'react'; import { ButtonProps, Ref } from './Button.interface'; import { button } from './Button.styles'; +/** + * @deprecated use AntD button instead + */ export const Button: FunctionComponent = React.forwardRef< Ref, ButtonProps diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/service/index.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/service/index.test.tsx index 4a512a06360..ecfe590010a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/service/index.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/service/index.test.tsx @@ -149,6 +149,7 @@ jest.mock('../../axiosAPIs/serviceAPI', () => ({ .fn() .mockImplementation(() => Promise.resolve(mockData)), updateService: jest.fn().mockImplementation(() => Promise.resolve()), + TestConnection: jest.fn().mockImplementation(() => Promise.resolve()), })); jest.mock('../../axiosAPIs/databaseAPI', () => ({ @@ -205,6 +206,7 @@ jest.mock('../../utils/ServiceUtils', () => ({ serviceTypeLogo: jest.fn().mockReturnValue('img/path'), isRequiredDetailsAvailableForIngestion: jest.fn().mockReturnValue(true), getDeleteEntityMessage: jest.fn().mockReturnValue('Delete message'), + shouldTestConnection: jest.fn().mockReturnValue(true), })); jest.mock( diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/service/index.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/service/index.tsx index 22167dfff0a..f9fab078ddb 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/service/index.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/service/index.tsx @@ -11,12 +11,18 @@ * limitations under the License. */ -import { Col, Row, Space, Tooltip } from 'antd'; +import { Button, Col, Row, Space, Tooltip } from 'antd'; import { AxiosError } from 'axios'; import classNames from 'classnames'; import { isEmpty, isNil, isUndefined, startCase } from 'lodash'; import { ExtraInfo, ServiceOption, ServiceTypes } from 'Models'; -import React, { Fragment, FunctionComponent, useEffect, useState } from 'react'; +import React, { + Fragment, + FunctionComponent, + useEffect, + useMemo, + useState, +} from 'react'; import { Link, useHistory, useParams } from 'react-router-dom'; import { getDashboards } from '../../axiosAPIs/dashboardAPI'; import { getDatabases } from '../../axiosAPIs/databaseAPI'; @@ -31,9 +37,13 @@ import { import { fetchAirflowConfig } from '../../axiosAPIs/miscAPI'; import { getMlmodels } from '../../axiosAPIs/mlModelAPI'; import { getPipelines } from '../../axiosAPIs/pipelineAPI'; -import { getServiceByFQN, updateService } from '../../axiosAPIs/serviceAPI'; +import { + getServiceByFQN, + TestConnection, + updateService, +} from '../../axiosAPIs/serviceAPI'; import { getTopics } from '../../axiosAPIs/topicsAPI'; -import { Button } from '../../components/buttons/Button/Button'; +import { Button as LegacyButton } from '../../components/buttons/Button/Button'; import DeleteWidgetModal from '../../components/common/DeleteWidget/DeleteWidgetModal'; import Description from '../../components/common/description/Description'; import EntitySummaryDetails from '../../components/common/EntitySummaryDetails/EntitySummaryDetails'; @@ -91,14 +101,16 @@ import { getResourceEntityFromServiceCategory, getServiceCategoryFromType, getServiceRouteFromServiceType, + getTestConnectionType, servicePageTabs, serviceTypeLogo, setServiceSchemaCount, setServiceTableCount, + shouldTestConnection, } from '../../utils/ServiceUtils'; import { IcDeleteColored } from '../../utils/SvgUtils'; import { getEntityLink, getUsagePercentile } from '../../utils/TableUtils'; -import { showErrorToast } from '../../utils/ToastUtils'; +import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils'; export type ServicePageData = Database | Topic | Dashboard; @@ -139,6 +151,13 @@ const ServicePage: FunctionComponent = () => { const [servicePermission, setServicePermission] = useState(DEFAULT_ENTITY_PERMISSION); + const [isTestingConnection, setIsTestingConnection] = + useState(false); + + const allowTestConn = useMemo(() => { + return shouldTestConnection(serviceType); + }, [serviceType]); + const fetchServicePermission = async () => { setIsLoading(true); try { @@ -683,6 +702,34 @@ const ServicePage: FunctionComponent = () => { } }; + const checkTestConnect = async () => { + if (connectionDetails) { + setIsTestingConnection(true); + try { + const response = await TestConnection( + connectionDetails, + getTestConnectionType(serviceCategory as ServiceCategory) + ); + // This api only responds with status 200 on success + // No data sent on api success + if (response.status === 200) { + showSuccessToast( + jsonData['api-success-messages']['test-connection-success'] + ); + } else { + throw jsonData['api-error-messages']['unexpected-server-response']; + } + } catch (error) { + showErrorToast( + error as AxiosError, + jsonData['api-error-messages']['test-connection-error'] + ); + } finally { + setIsTestingConnection(false); + } + } + }; + useEffect(() => { setServiceName( (serviceCategory as ServiceTypes) || @@ -964,7 +1011,7 @@ const ServicePage: FunctionComponent = () => { ? 'Delete' : NO_PERMISSION_FOR_ACTION }> - + { {activeTab === 3 && ( <> -
+ { : NO_PERMISSION_FOR_ACTION }> -
+ {allowTestConn && isAirflowRunning && ( + + + + )} +