diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ApiServiceRest.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ApiServiceRest.spec.ts index 1eaab361c99..cd2409e6de9 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ApiServiceRest.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/ApiServiceRest.spec.ts @@ -19,6 +19,7 @@ import { toastNotification, uuid, } from '../../utils/common'; +import { testConnection } from '../../utils/serviceIngestion'; import { settingClick } from '../../utils/sidebar'; const apiServiceConfig = { @@ -55,6 +56,7 @@ test.describe('API service', () => { .fill(apiServiceConfig.openAPISchemaURL); await page.locator('#root\\/token').fill(apiServiceConfig.token); + await testConnection(page); await page.getByTestId('submit-btn').click(); const autoPilotApplicationRequest = page.waitForRequest( diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/ingestion/MlFlowIngestionClass.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/ingestion/MlFlowIngestionClass.ts index 8a184a301a1..0cc2e963fef 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/ingestion/MlFlowIngestionClass.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/ingestion/MlFlowIngestionClass.ts @@ -26,7 +26,7 @@ class MlFlowIngestionClass extends ServiceBaseClass { shouldAddDefaultFilters?: boolean; }) { const { - shouldTestConnection = false, + shouldTestConnection = true, shouldAddIngestion = false, shouldAddDefaultFilters = false, } = extraParams ?? {}; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/ingestion/ServiceBaseClass.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/ingestion/ServiceBaseClass.ts index 2a2ea79e676..54debb5452b 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/ingestion/ServiceBaseClass.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/ingestion/ServiceBaseClass.ts @@ -104,6 +104,8 @@ class ServiceBaseClass { await this.fillConnectionDetails(page); if (this.shouldTestConnection) { + expect(page.getByTestId('next-button')).not.toBeVisible(); + await testConnection(page); } diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/serviceIngestion.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/serviceIngestion.ts index 5df0503133d..35242dc5a45 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/serviceIngestion.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/serviceIngestion.ts @@ -159,12 +159,19 @@ export const testConnection = async (page: Page) => { const warningBadge = page.locator('[data-testid="warning-badge"]'); - await expect(successBadge.or(warningBadge)).toBeVisible({ + const failBadge = page.locator('[data-testid="fail-badge"]'); + + await expect(successBadge.or(warningBadge).or(failBadge)).toBeVisible({ timeout: 2.5 * 60 * 1000, }); await expect(page.getByTestId('messag-text')).toContainText( - /Connection test was successful.|Test connection partially successful: Some steps had failures, we will only ingest partial metadata. Click here to view details./g + new RegExp( + 'Connection test was successful.|' + + 'Test connection partially successful: Some steps had failures, we will only ingest partial metadata. Click here to view details.|' + + 'Test connection failed, please validate your connection and permissions for the failed steps.', + 'g' + ) ); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/ServiceConfig/ConnectionConfigForm.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/ServiceConfig/ConnectionConfigForm.tsx index 6fe02c009f4..6ade3dca28b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/ServiceConfig/ConnectionConfigForm.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/ServiceConfig/ConnectionConfigForm.tsx @@ -37,6 +37,7 @@ import { getFilteredSchema, getUISchemaWithNestedDefaultFilterFieldsHidden, } from '../../../../utils/ServiceConnectionUtils'; +import { shouldTestConnection } from '../../../../utils/ServiceUtils'; import AirflowMessageBanner from '../../../common/AirflowMessageBanner/AirflowMessageBanner'; import BooleanFieldTemplate from '../../../common/Form/JSONSchema/JSONSchemaTemplate/BooleanFieldTemplate'; import WorkflowArrayFieldTemplate from '../../../common/Form/JSONSchema/JSONSchemaTemplate/WorkflowArrayFieldTemplate'; @@ -60,10 +61,17 @@ const ConnectionConfigForm = ({ const { inlineAlertDetails } = useApplicationStore(); const { t } = useTranslation(); const [ingestionRunner, setIngestionRunner] = useState(); + const { isAirflowAvailable, platform } = useAirflowStatus(); + const allowTestConn = useMemo(() => { + return shouldTestConnection(serviceType); + }, [serviceType]); + + const [hasTestedConnection, setHasTestedConnection] = useState( + !isAirflowAvailable || !allowTestConn || disableTestConnection + ); const formRef = useRef>(null); - const { isAirflowAvailable, platform } = useAirflowStatus(); const [hostIp, setHostIp] = useState(); const fetchHostIp = async () => { @@ -153,6 +161,10 @@ const ConnectionConfigForm = ({ } }, [formRef.current?.state?.formData]); + const handleTestConnection = () => { + setHasTestedConnection(true); + }; + return ( @@ -160,6 +172,7 @@ const ConnectionConfigForm = ({ cancelText={cancelText ?? ''} fields={customFields} formData={validConfig} + hasTestedConnection={hasTestedConnection} okText={okText ?? ''} ref={formRef} schema={schemaWithoutDefaultFilterPatternFields} @@ -190,19 +203,18 @@ const ConnectionConfigForm = ({ type="info" /> )} - {!isEmpty(connSch.schema) && - isAirflowAvailable && - formRef.current?.state?.formData && ( - formRef.current?.state?.formData} - hostIp={hostIp} - isTestingDisabled={disableTestConnection} - serviceCategory={serviceCategory} - serviceName={data?.name} - onValidateFormRequiredFields={handleRequiredFieldsValidation} - /> - )} + {!isEmpty(connSch.schema) && ( + formRef.current?.state?.formData} + hostIp={hostIp} + isTestingDisabled={disableTestConnection} + serviceCategory={serviceCategory} + serviceName={data?.name} + onTestConnection={handleTestConnection} + onValidateFormRequiredFields={handleRequiredFieldsValidation} + /> + )} {!isUndefined(inlineAlertDetails) && ( )} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/FormBuilder/FormBuilder.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/FormBuilder/FormBuilder.tsx index 51d2ee67874..c3af1199930 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/FormBuilder/FormBuilder.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/FormBuilder/FormBuilder.tsx @@ -42,6 +42,7 @@ export interface Props extends FormProps { status?: LoadingState; onCancel?: () => void; useSelectWidget?: boolean; + hasTestedConnection?: boolean; } const FormBuilder = forwardRef( @@ -61,6 +62,7 @@ const FormBuilder = forwardRef( onFocus, useSelectWidget = false, children, + hasTestedConnection, ...props }, ref @@ -94,6 +96,9 @@ const FormBuilder = forwardRef( }; const submitButton = useMemo(() => { + if (hasTestedConnection === false) { + return null; + } if (status === 'waiting') { return ( ); } - }, [status, isLoading, okText]); + }, [status, isLoading, okText, hasTestedConnection]); return (
boolean; + onTestConnection?: () => void; hostIp?: string; } diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/TestConnection/TestConnection.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/TestConnection/TestConnection.tsx index 346bfbab3ca..bdb52bac6bd 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/TestConnection/TestConnection.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/TestConnection/TestConnection.tsx @@ -70,6 +70,7 @@ const TestConnection: FC = ({ onValidateFormRequiredFields, shouldValidateForm = true, showDetails = true, + onTestConnection, hostIp, }) => { const { t } = useTranslation(); @@ -372,6 +373,8 @@ const TestConnection: FC = ({ if (workflowId) { await handleDeleteWorkflow(workflowId); } + } finally { + onTestConnection?.(); } }; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/AddServicePage/AddServicePage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/AddServicePage/AddServicePage.component.tsx index e5054dabc24..78480153491 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/AddServicePage/AddServicePage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/AddServicePage/AddServicePage.component.tsx @@ -80,7 +80,6 @@ const AddServicePage = () => { const [saveServiceState, setSaveServiceState] = useState('initial'); const [activeField, setActiveField] = useState(''); - const slashedBreadcrumb = getAddServiceEntityBreadcrumb(serviceCategory); const handleServiceTypeClick = (type: string) => {