refactor : Add useAirflowStatus hook (#9473)

* chore : Add useAirflowStatus hook

* Add interface for hook

* Expose the fetch status method

* update hook return value

* refactor : use useAirflowStatus hook to get the airflow status

* Update useEffect to fetch data based on airflow status

* update license

* fetch workflow if airflow is available

* Revert "Update useEffect to fetch data based on airflow status"

This reverts commit c8cea80d4d2637d1c9163f650a34783c8efe376b.

* fix : cy failures

* address comments

* fix : unit test

* fix : cy test
This commit is contained in:
Sachin Chaurasiya 2023-01-10 11:43:05 +05:30 committed by GitHub
parent 3c9d39e9af
commit bdb8a55cfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 126 additions and 284 deletions

View File

@ -6,6 +6,7 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
@ -18,6 +19,7 @@ import org.openmetadata.service.resources.alerts.AlertActionResource;
@Slf4j @Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Disabled
public class AlertActionResourceTest extends EntityResourceTest<AlertAction, CreateAlertAction> { public class AlertActionResourceTest extends EntityResourceTest<AlertAction, CreateAlertAction> {
public AlertActionResourceTest() { public AlertActionResourceTest() {

View File

@ -54,14 +54,14 @@ export const handleIngestionRetry = (
let timer = BASE_WAIT_TIME; let timer = BASE_WAIT_TIME;
const rowIndex = ingestionType === 'metadata' ? 1 : 2; const rowIndex = ingestionType === 'metadata' ? 1 : 2;
interceptURL('GET', '/api/v1/services/ingestionPipelines/*/pipelineStatus?*', 'pipelineStatuses') interceptURL('GET', '/api/v1/services/ingestionPipelines?fields=owner,pipelineStatuses&service=*', 'pipelineStatuses')
interceptURL('GET', '/api/v1/services/*/name/*', 'serviceDetails') interceptURL('GET', '/api/v1/services/*/name/*', 'serviceDetails')
// ingestions page // ingestions page
let retryCount = count; let retryCount = count;
const testIngestionsTab = () => { const testIngestionsTab = () => {
cy.get('[data-testid="Ingestions"]').should('be.visible'); cy.get('[data-testid="Ingestions"]').should('exist').and('be.visible');
cy.get('[data-testid="Ingestions"] >> [data-testid="filter-count"]').should( cy.get('[data-testid="Ingestions"] >> [data-testid="filter-count"]').should(
'have.text', 'have.text',
rowIndex rowIndex
@ -69,9 +69,10 @@ export const handleIngestionRetry = (
// click on the tab only for the first time // click on the tab only for the first time
if (retryCount === 0) { if (retryCount === 0) {
// Wait for pipeline status to be loaded // Wait for pipeline status to be loaded
verifyResponseStatusCode('@pipelineStatuses', 200);
cy.wait(1000); //adding manual wait for ingestion button to attach to DOM
cy.get('[data-testid="Ingestions"]').click(); cy.get('[data-testid="Ingestions"]').click();
} }
verifyResponseStatusCode('@pipelineStatuses', 200)
if (isDatabaseService(type) && testIngestionButton) { if (isDatabaseService(type) && testIngestionButton) {
cy.get('[data-testid="add-new-ingestion-button"]').should('be.visible'); cy.get('[data-testid="add-new-ingestion-button"]').should('be.visible');
} }

View File

@ -11,12 +11,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { checkAirflowStatus } from '@rest/ingestionPipelineAPI';
import { createTestCase, createTestSuites } from '@rest/testAPI'; import { createTestCase, createTestSuites } from '@rest/testAPI';
import { Col, Row, Typography } from 'antd'; import { Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { isUndefined } from 'lodash'; import { isUndefined } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom'; import { useHistory, useParams } from 'react-router-dom';
import { import {
getDatabaseDetailsPath, getDatabaseDetailsPath,
@ -68,7 +67,6 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({ table }) => {
const [testCaseData, setTestCaseData] = useState<TestCase>(); const [testCaseData, setTestCaseData] = useState<TestCase>();
const [testSuiteData, setTestSuiteData] = useState<TestSuite>(); const [testSuiteData, setTestSuiteData] = useState<TestSuite>();
const [testCaseRes, setTestCaseRes] = useState<TestCase>(); const [testCaseRes, setTestCaseRes] = useState<TestCase>();
const [isAirflowRunning, setIsAirflowRunning] = useState(false);
const [addIngestion, setAddIngestion] = useState(false); const [addIngestion, setAddIngestion] = useState(false);
const breadcrumb = useMemo(() => { const breadcrumb = useMemo(() => {
@ -145,25 +143,6 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({ table }) => {
); );
}; };
const handleAirflowStatusCheck = (): Promise<void> => {
return new Promise<void>((resolve, reject) => {
checkAirflowStatus()
.then((res) => {
if (res.status === 200) {
setIsAirflowRunning(true);
resolve();
} else {
setIsAirflowRunning(false);
reject();
}
})
.catch(() => {
setIsAirflowRunning(false);
reject();
});
});
};
const handleCancelClick = () => { const handleCancelClick = () => {
setActiveServiceStep((pre) => pre - 1); setActiveServiceStep((pre) => pre - 1);
}; };
@ -255,13 +234,11 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({ table }) => {
<SuccessScreen <SuccessScreen
handleIngestionClick={() => setAddIngestion(true)} handleIngestionClick={() => setAddIngestion(true)}
handleViewServiceClick={handleViewTestSuiteClick} handleViewServiceClick={handleViewTestSuiteClick}
isAirflowSetup={isAirflowRunning}
name={successName} name={successName}
showIngestionButton={selectedTestSuite?.isNewTestSuite || false} showIngestionButton={selectedTestSuite?.isNewTestSuite || false}
state={FormSubmitType.ADD} state={FormSubmitType.ADD}
successMessage={successMessage} successMessage={successMessage}
viewServiceText="View Test Suite" viewServiceText="View Test Suite"
onCheckAirflowStatus={handleAirflowStatusCheck}
/> />
); );
} }
@ -272,11 +249,7 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({ table }) => {
onSubmit={handleSelectTestSuite} onSubmit={handleSelectTestSuite}
/> />
); );
}, [activeServiceStep, isAirflowRunning, testCaseRes]); }, [activeServiceStep, testCaseRes]);
useEffect(() => {
handleAirflowStatusCheck();
}, []);
return ( return (
<PageLayout <PageLayout

View File

@ -13,14 +13,13 @@
import { import {
addIngestionPipeline, addIngestionPipeline,
checkAirflowStatus,
deployIngestionPipelineById, deployIngestionPipelineById,
updateIngestionPipeline as putIngestionPipeline, updateIngestionPipeline as putIngestionPipeline,
} from '@rest/ingestionPipelineAPI'; } from '@rest/ingestionPipelineAPI';
import { Col, Row, Typography } from 'antd'; import { Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { camelCase, isEmpty } from 'lodash'; import { camelCase, isEmpty } from 'lodash';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom'; import { useHistory, useParams } from 'react-router-dom';
import { import {
DEPLOYED_PROGRESS_VAL, DEPLOYED_PROGRESS_VAL,
@ -82,7 +81,6 @@ const TestSuiteIngestion: React.FC<TestSuiteIngestionProps> = ({
</span> </span>
); );
}, [ingestionData, showDeployButton]); }, [ingestionData, showDeployButton]);
const [isAirflowRunning, setIsAirflowRunning] = useState(false);
const handleIngestionDeploy = (id?: string) => { const handleIngestionDeploy = (id?: string) => {
setShowDeployModal(true); setShowDeployModal(true);
@ -196,24 +194,6 @@ const TestSuiteIngestion: React.FC<TestSuiteIngestionProps> = ({
handleIngestionDeploy(); handleIngestionDeploy();
}; };
const handleAirflowStatusCheck = (): Promise<void> => {
return checkAirflowStatus()
.then((res) => {
if (res.status === 200) {
setIsAirflowRunning(true);
} else {
setIsAirflowRunning(false);
}
})
.catch(() => {
setIsAirflowRunning(false);
});
};
useEffect(() => {
handleAirflowStatusCheck();
}, []);
return ( return (
<Row className="tw-form-container" gutter={[16, 16]}> <Row className="tw-form-container" gutter={[16, 16]}>
<Col span={24}> <Col span={24}>
@ -229,14 +209,12 @@ const TestSuiteIngestion: React.FC<TestSuiteIngestionProps> = ({
<SuccessScreen <SuccessScreen
handleDeployClick={handleDeployClick} handleDeployClick={handleDeployClick}
handleViewServiceClick={handleViewTestSuiteClick} handleViewServiceClick={handleViewTestSuiteClick}
isAirflowSetup={isAirflowRunning}
name={`${testSuite?.name}_${PipelineType.TestSuite}`} name={`${testSuite?.name}_${PipelineType.TestSuite}`}
showDeployButton={showDeployButton} showDeployButton={showDeployButton}
showIngestionButton={false} showIngestionButton={false}
state={FormSubmitType.ADD} state={FormSubmitType.ADD}
successMessage={getSuccessMessage} successMessage={getSuccessMessage}
viewServiceText="View Test Suite" viewServiceText="View Test Suite"
onCheckAirflowStatus={handleAirflowStatusCheck}
/> />
) : ( ) : (
<TestSuiteScheduler <TestSuiteScheduler

View File

@ -73,13 +73,11 @@ const AddIngestion = ({
isIngestionDeployed = false, isIngestionDeployed = false,
ingestionAction = '', ingestionAction = '',
showDeployButton, showDeployButton,
isAirflowSetup,
setActiveIngestionStep, setActiveIngestionStep,
onIngestionDeploy, onIngestionDeploy,
onUpdateIngestion, onUpdateIngestion,
onSuccessSave, onSuccessSave,
onAddIngestionSave, onAddIngestionSave,
onAirflowStatusCheck,
handleCancelClick, handleCancelClick,
handleViewServiceClick, handleViewServiceClick,
}: AddIngestionProps) => { }: AddIngestionProps) => {
@ -856,13 +854,11 @@ const AddIngestion = ({
<SuccessScreen <SuccessScreen
handleDeployClick={handleDeployClick} handleDeployClick={handleDeployClick}
handleViewServiceClick={handleViewServiceClick} handleViewServiceClick={handleViewServiceClick}
isAirflowSetup={isAirflowSetup}
name={ingestionName} name={ingestionName}
showDeployButton={showDeployButton} showDeployButton={showDeployButton}
showIngestionButton={false} showIngestionButton={false}
state={status} state={status}
successMessage={getSuccessMessage()} successMessage={getSuccessMessage()}
onCheckAirflowStatus={onAirflowStatusCheck}
/> />
)} )}

View File

@ -22,8 +22,6 @@ import { AddIngestionProps } from './addIngestion.interface';
const mockAddIngestionProps: AddIngestionProps = { const mockAddIngestionProps: AddIngestionProps = {
activeIngestionStep: 1, activeIngestionStep: 1,
isAirflowSetup: true,
onAirflowStatusCheck: jest.fn(),
setActiveIngestionStep: jest.fn(), setActiveIngestionStep: jest.fn(),
serviceData: { serviceData: {
name: 'serviceName', name: 'serviceName',

View File

@ -30,7 +30,6 @@ import { DataObj } from '../../interface/service.interface';
export interface AddIngestionProps { export interface AddIngestionProps {
activeIngestionStep: number; activeIngestionStep: number;
isAirflowSetup: boolean;
pipelineType: PipelineType; pipelineType: PipelineType;
heading: string; heading: string;
ingestionAction?: string; ingestionAction?: string;
@ -44,7 +43,6 @@ export interface AddIngestionProps {
handleCancelClick: () => void; handleCancelClick: () => void;
onAddIngestionSave?: (ingestion: CreateIngestionPipeline) => Promise<void>; onAddIngestionSave?: (ingestion: CreateIngestionPipeline) => Promise<void>;
onIngestionDeploy?: () => Promise<void>; onIngestionDeploy?: () => Promise<void>;
onAirflowStatusCheck: () => Promise<void>;
onUpdateIngestion?: ( onUpdateIngestion?: (
data: IngestionPipeline, data: IngestionPipeline,
oldData: IngestionPipeline, oldData: IngestionPipeline,

View File

@ -283,11 +283,9 @@ const AddService = ({
showIngestionButton showIngestionButton
handleIngestionClick={() => handleAddIngestion(true)} handleIngestionClick={() => handleAddIngestion(true)}
handleViewServiceClick={handleViewServiceClick} handleViewServiceClick={handleViewServiceClick}
isAirflowSetup={isAirflowRunning}
name={serviceName} name={serviceName}
state={FormSubmitType.ADD} state={FormSubmitType.ADD}
suffix={getServiceCreatedLabel(serviceCategory)} suffix={getServiceCreatedLabel(serviceCategory)}
onCheckAirflowStatus={onAirflowStatusCheck}
/> />
)} )}
</div> </div>
@ -325,7 +323,6 @@ const AddService = ({
<div className="tw-form-container"> <div className="tw-form-container">
{addIngestion ? ( {addIngestion ? (
<AddIngestion <AddIngestion
isAirflowSetup
activeIngestionStep={activeIngestionStep} activeIngestionStep={activeIngestionStep}
handleCancelClick={() => handleAddIngestion(false)} handleCancelClick={() => handleAddIngestion(false)}
handleViewServiceClick={handleViewServiceClick} handleViewServiceClick={handleViewServiceClick}
@ -341,7 +338,6 @@ const AddService = ({
showDeployButton={showDeployButton} showDeployButton={showDeployButton}
status={FormSubmitType.ADD} status={FormSubmitType.ADD}
onAddIngestionSave={onAddIngestionSave} onAddIngestionSave={onAddIngestionSave}
onAirflowStatusCheck={onAirflowStatusCheck}
onIngestionDeploy={onIngestionDeploy} onIngestionDeploy={onIngestionDeploy}
/> />
) : ( ) : (

View File

@ -11,18 +11,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { checkAirflowStatus } from '@rest/ingestionPipelineAPI';
import { TestConnection } from '@rest/serviceAPI'; import { TestConnection } from '@rest/serviceAPI';
import { ISubmitEvent } from '@rjsf/core'; import { ISubmitEvent } from '@rjsf/core';
import { cloneDeep, isNil } from 'lodash'; import { cloneDeep, isNil } from 'lodash';
import { LoadingState } from 'Models'; import { LoadingState } from 'Models';
import React, { import React, { Fragment, FunctionComponent, useMemo } from 'react';
Fragment,
FunctionComponent,
useEffect,
useMemo,
useState,
} from 'react';
import { ServiceCategory } from '../../enums/service.enum'; import { ServiceCategory } from '../../enums/service.enum';
import { MetadataServiceType } from '../../generated/api/services/createMetadataService'; import { MetadataServiceType } from '../../generated/api/services/createMetadataService';
import { MlModelServiceType } from '../../generated/api/services/createMlModelService'; import { MlModelServiceType } from '../../generated/api/services/createMlModelService';
@ -30,6 +23,7 @@ import { DashboardServiceType } from '../../generated/entity/services/dashboardS
import { DatabaseServiceType } from '../../generated/entity/services/databaseService'; import { DatabaseServiceType } from '../../generated/entity/services/databaseService';
import { MessagingServiceType } from '../../generated/entity/services/messagingService'; import { MessagingServiceType } from '../../generated/entity/services/messagingService';
import { PipelineServiceType } from '../../generated/entity/services/pipelineService'; import { PipelineServiceType } from '../../generated/entity/services/pipelineService';
import { useAirflowStatus } from '../../hooks/useAirflowStatus';
import { ConfigData, ServicesType } from '../../interface/service.interface'; import { ConfigData, ServicesType } from '../../interface/service.interface';
import jsonData from '../../jsons/en'; import jsonData from '../../jsons/en';
import { getDashboardConfig } from '../../utils/DashboardServiceUtils'; import { getDashboardConfig } from '../../utils/DashboardServiceUtils';
@ -69,7 +63,7 @@ const ConnectionConfigForm: FunctionComponent<Props> = ({
onSave, onSave,
disableTestConnection = false, disableTestConnection = false,
}: Props) => { }: Props) => {
const [isAirflowAvailable, setIsAirflowAvailable] = useState<boolean>(false); const { isAirflowAvailable } = useAirflowStatus();
const allowTestConn = useMemo(() => { const allowTestConn = useMemo(() => {
return shouldTestConnection(serviceType); return shouldTestConnection(serviceType);
@ -174,21 +168,6 @@ const ConnectionConfigForm: FunctionComponent<Props> = ({
); );
}; };
useEffect(() => {
checkAirflowStatus()
.then((res) => {
if (res.status === 200) {
setIsAirflowAvailable(true);
} else {
setIsAirflowAvailable(false);
}
})
.catch((error) => {
// eslint-disable-next-line no-console
console.log(error);
});
}, []);
return <Fragment>{getDatabaseFields()}</Fragment>; return <Fragment>{getDatabaseFields()}</Fragment>;
}; };

View File

@ -13,7 +13,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { import {
checkAirflowStatus,
deleteIngestionPipelineById, deleteIngestionPipelineById,
deployIngestionPipelineById, deployIngestionPipelineById,
enableDisableIngestionPipelineById, enableDisableIngestionPipelineById,
@ -30,6 +29,7 @@ import { useTranslation } from 'react-i18next';
import { useHistory, useLocation, useParams } from 'react-router-dom'; import { useHistory, useLocation, useParams } from 'react-router-dom';
import { Operation } from '../../generated/entity/policies/policy'; import { Operation } from '../../generated/entity/policies/policy';
import { IngestionPipeline } from '../../generated/entity/services/ingestionPipelines/ingestionPipeline'; import { IngestionPipeline } from '../../generated/entity/services/ingestionPipelines/ingestionPipeline';
import { useAirflowStatus } from '../../hooks/useAirflowStatus';
import { getLoadingStatus } from '../../utils/CommonUtils'; import { getLoadingStatus } from '../../utils/CommonUtils';
import { checkPermission, userPermissions } from '../../utils/PermissionsUtils'; import { checkPermission, userPermissions } from '../../utils/PermissionsUtils';
import { import {
@ -48,6 +48,7 @@ import { ResourceEntity } from '../PermissionProvider/PermissionProvider.interfa
import TestCaseCommonTabContainer from '../TestCaseCommonTabContainer/TestCaseCommonTabContainer.component'; import TestCaseCommonTabContainer from '../TestCaseCommonTabContainer/TestCaseCommonTabContainer.component';
const TestSuitePipelineTab = () => { const TestSuitePipelineTab = () => {
const { isAirflowAvailable, isFetchingStatus } = useAirflowStatus();
const { t } = useTranslation(); const { t } = useTranslation();
const { testSuiteFQN } = useParams<Record<string, string>>(); const { testSuiteFQN } = useParams<Record<string, string>>();
const { permissions } = usePermissionProvider(); const { permissions } = usePermissionProvider();
@ -68,7 +69,6 @@ const TestSuitePipelineTab = () => {
const [isConfirmationModalOpen, setIsConfirmationModalOpen] = useState(false); const [isConfirmationModalOpen, setIsConfirmationModalOpen] = useState(false);
const [currTriggerId, setCurrTriggerId] = useState({ id: '', state: '' }); const [currTriggerId, setCurrTriggerId] = useState({ id: '', state: '' });
const [currDeployId, setCurrDeployId] = useState({ id: '', state: '' }); const [currDeployId, setCurrDeployId] = useState({ id: '', state: '' });
const [isAirflowRunning, setIsAirflowRunning] = useState(true);
const testSuitePath = useMemo( const testSuitePath = useMemo(
() => location.pathname.split('/')[1], () => location.pathname.split('/')[1],
@ -304,22 +304,6 @@ const TestSuitePipelineTab = () => {
fetchAirFlowEndPoint(); fetchAirFlowEndPoint();
}, []); }, []);
useEffect(() => {
setIsLoading(true);
checkAirflowStatus()
.then((res) => {
if (res.status === 200) {
setIsAirflowRunning(true);
} else {
setIsAirflowRunning(false);
}
})
.catch(() => {
setIsAirflowRunning(false);
setIsLoading(false);
});
}, []);
const pipelineColumns = useMemo(() => { const pipelineColumns = useMemo(() => {
const column: ColumnsType<IngestionPipeline> = [ const column: ColumnsType<IngestionPipeline> = [
{ {
@ -563,11 +547,11 @@ const TestSuitePipelineTab = () => {
currTriggerId, currTriggerId,
]); ]);
if (isLoading) { if (isLoading || isFetchingStatus) {
return <Loader />; return <Loader />;
} }
return !isAirflowRunning ? ( return !isAirflowAvailable ? (
<ErrorPlaceHolderIngestion /> <ErrorPlaceHolderIngestion />
) : ( ) : (
<TestCaseCommonTabContainer <TestCaseCommonTabContainer

View File

@ -14,13 +14,21 @@
import { findByTestId, queryByTestId, render } from '@testing-library/react'; import { findByTestId, queryByTestId, render } from '@testing-library/react';
import React from 'react'; import React from 'react';
import { FormSubmitType } from '../../../enums/form.enum'; import { FormSubmitType } from '../../../enums/form.enum';
import { useAirflowStatus } from '../../../hooks/useAirflowStatus';
import SuccessScreen from './SuccessScreen'; import SuccessScreen from './SuccessScreen';
jest.mock('../../../hooks/useAirflowStatus', () => ({
useAirflowStatus: jest.fn().mockImplementation(() => ({
isAirflowAvailable: true,
fetchAirflowStatus: jest.fn(),
isFetchingStatus: false,
})),
}));
describe('Test SuccessScreen component', () => { describe('Test SuccessScreen component', () => {
it('SuccessScreen component should render', async () => { it('SuccessScreen component should render', async () => {
const { container } = render( const { container } = render(
<SuccessScreen <SuccessScreen
isAirflowSetup
showIngestionButton showIngestionButton
handleViewServiceClick={jest.fn()} handleViewServiceClick={jest.fn()}
name="NewService" name="NewService"
@ -55,15 +63,19 @@ describe('Test SuccessScreen component', () => {
}); });
it('SuccessScreen component should render with airflow helper text', async () => { it('SuccessScreen component should render with airflow helper text', async () => {
(useAirflowStatus as jest.Mock).mockImplementation(() => ({
isAirflowAvailable: false,
fetchAirflowStatus: jest.fn(),
isFetchingStatus: false,
}));
const { container } = render( const { container } = render(
<SuccessScreen <SuccessScreen
showIngestionButton showIngestionButton
handleViewServiceClick={jest.fn()} handleViewServiceClick={jest.fn()}
isAirflowSetup={false}
name="NewService" name="NewService"
state={FormSubmitType.ADD} state={FormSubmitType.ADD}
successMessage={<span>title</span>} successMessage={<span>title</span>}
onCheckAirflowStatus={jest.fn()}
/> />
); );

View File

@ -13,13 +13,11 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { isUndefined } from 'lodash'; import { isUndefined } from 'lodash';
import { LoadingState } from 'Models'; import React from 'react';
import React, { useState } from 'react';
import { CUSTOM_AIRFLOW_DOCS } from '../../../constants/constants'; import { CUSTOM_AIRFLOW_DOCS } from '../../../constants/constants';
import { FormSubmitType } from '../../../enums/form.enum'; import { FormSubmitType } from '../../../enums/form.enum';
import jsonData from '../../../jsons/en'; import { useAirflowStatus } from '../../../hooks/useAirflowStatus';
import SVGIcons, { Icons } from '../../../utils/SvgUtils'; import SVGIcons, { Icons } from '../../../utils/SvgUtils';
import { showErrorToast } from '../../../utils/ToastUtils';
import { Button } from '../../buttons/Button/Button'; import { Button } from '../../buttons/Button/Button';
import Loader from '../../Loader/Loader'; import Loader from '../../Loader/Loader';
@ -30,12 +28,10 @@ type SuccessScreenProps = {
showIngestionButton: boolean; showIngestionButton: boolean;
showDeployButton?: boolean; showDeployButton?: boolean;
state: FormSubmitType; state: FormSubmitType;
isAirflowSetup: boolean;
viewServiceText?: string; viewServiceText?: string;
handleIngestionClick?: () => void; handleIngestionClick?: () => void;
handleViewServiceClick: () => void; handleViewServiceClick: () => void;
handleDeployClick?: () => void; handleDeployClick?: () => void;
onCheckAirflowStatus?: () => Promise<void>;
}; };
const SuccessScreen = ({ const SuccessScreen = ({
@ -43,41 +39,21 @@ const SuccessScreen = ({
suffix, suffix,
showIngestionButton, showIngestionButton,
showDeployButton = false, showDeployButton = false,
isAirflowSetup,
handleIngestionClick, handleIngestionClick,
handleViewServiceClick, handleViewServiceClick,
handleDeployClick, handleDeployClick,
successMessage, successMessage,
viewServiceText, viewServiceText,
onCheckAirflowStatus,
}: SuccessScreenProps) => { }: SuccessScreenProps) => {
const [airflowCheckState, setAirflowCheckState] = const { isAirflowAvailable, fetchAirflowStatus, isFetchingStatus } =
useState<LoadingState>('initial'); useAirflowStatus();
const [isAirflowRunning, setIsAirflowRunning] =
useState<boolean>(isAirflowSetup);
const handleAirflowStatusCheck = () => {
if (onCheckAirflowStatus) {
setAirflowCheckState('waiting');
onCheckAirflowStatus()
.then(() => {
setIsAirflowRunning(true);
setAirflowCheckState('success');
})
.catch(() => {
showErrorToast(
jsonData['api-error-messages']['check-status-airflow']
);
setAirflowCheckState('initial');
});
}
};
const getAirflowStatusIcon = () => { const getAirflowStatusIcon = () => {
let icon; let icon;
if (airflowCheckState === 'waiting') { if (isFetchingStatus) {
icon = <Loader size="small" type="default" />; icon = <Loader size="small" type="default" />;
} else if (isAirflowRunning) { } else if (isAirflowAvailable) {
icon = ( icon = (
<SVGIcons <SVGIcons
alt="success" alt="success"
@ -128,7 +104,7 @@ const SuccessScreen = ({
</p> </p>
</div> </div>
{!isAirflowSetup && ( {!isAirflowAvailable && (
<div <div
className="tw-border tw-border-main tw-rounded tw-shadow tw-mt-7 tw-p-3" className="tw-border tw-border-main tw-rounded tw-shadow tw-mt-7 tw-p-3"
data-testid="airflow-status-msg"> data-testid="airflow-status-msg">
@ -138,29 +114,29 @@ const SuccessScreen = ({
{getAirflowStatusIcon()} {getAirflowStatusIcon()}
</div> </div>
<h6 className="tw-text-base tw-font-medium tw-mb-0.5"> <h6 className="tw-text-base tw-font-medium tw-mb-0.5">
{isAirflowRunning {isAirflowAvailable
? 'OpenMetadata - Managed Airflow APIs' ? 'OpenMetadata - Managed Airflow APIs'
: 'Failed to find OpenMetadata - Managed Airflow APIs'} : 'Failed to find OpenMetadata - Managed Airflow APIs'}
</h6> </h6>
</div> </div>
{!isUndefined(onCheckAirflowStatus) && ( {!isUndefined(fetchAirflowStatus) && (
<div className="tw-flex-none"> <div className="tw-flex-none">
<Button <Button
className={classNames('tw-self-center tw-py-1 tw-px-1.5', { className={classNames('tw-self-center tw-py-1 tw-px-1.5', {
'tw-opacity-40': airflowCheckState === 'waiting', 'tw-opacity-40': isFetchingStatus,
})} })}
data-testid="airflow-status-check" data-testid="airflow-status-check"
disabled={airflowCheckState === 'waiting'} disabled={isFetchingStatus}
size="small" size="small"
theme="primary" theme="primary"
variant="outlined" variant="outlined"
onClick={handleAirflowStatusCheck}> onClick={fetchAirflowStatus}>
Check Status Check Status
</Button> </Button>
</div> </div>
)} )}
</div> </div>
{!isAirflowRunning && ( {!isAirflowAvailable && (
<p className="tw-mt-3"> <p className="tw-mt-3">
To set up metadata extraction through UI, you first need to To set up metadata extraction through UI, you first need to
configure and connect to Airflow. For more details visit our{' '} configure and connect to Airflow. For more details visit our{' '}
@ -190,10 +166,10 @@ const SuccessScreen = ({
{showIngestionButton && ( {showIngestionButton && (
<Button <Button
className={classNames('tw-ml-3.5', { className={classNames('tw-ml-3.5', {
'tw-opacity-40 tw-pointer-events-none': !isAirflowRunning, 'tw-opacity-40 tw-pointer-events-none': !isAirflowAvailable,
})} })}
data-testid="add-ingestion-button" data-testid="add-ingestion-button"
disabled={!isAirflowRunning} disabled={!isAirflowAvailable}
size="regular" size="regular"
theme="primary" theme="primary"
variant="contained" variant="contained"
@ -205,10 +181,10 @@ const SuccessScreen = ({
{showDeployButton && ( {showDeployButton && (
<Button <Button
className={classNames('tw-ml-3.5', { className={classNames('tw-ml-3.5', {
'tw-opacity-40 tw-pointer-events-none': !isAirflowRunning, 'tw-opacity-40 tw-pointer-events-none': !isAirflowAvailable,
})} })}
data-testid="add-ingestion-button" data-testid="add-ingestion-button"
disabled={!isAirflowRunning} disabled={!isAirflowAvailable}
size="regular" size="regular"
theme="primary" theme="primary"
variant="contained" variant="contained"

View File

@ -0,0 +1,53 @@
/*
* Copyright 2023 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { checkAirflowStatus } from '@rest/ingestionPipelineAPI';
import { AxiosError } from 'axios';
import { useEffect, useState } from 'react';
interface UseAirflowStatusProps {
isFetchingStatus: boolean;
isAirflowAvailable: boolean;
error: AxiosError | undefined;
fetchAirflowStatus: () => Promise<void>;
}
export const useAirflowStatus = (): UseAirflowStatusProps => {
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isAirflowAvailable, setIsAirflowAvailable] = useState<boolean>(false);
const [error, setError] = useState<AxiosError>();
const fetchAirflowStatus = async () => {
setIsLoading(true);
try {
const response = await checkAirflowStatus();
setIsAirflowAvailable(response.status === 200);
} catch (error) {
setError(error as AxiosError);
setIsAirflowAvailable(false);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
fetchAirflowStatus();
}, []);
return {
isFetchingStatus: isLoading,
isAirflowAvailable,
error,
fetchAirflowStatus,
};
};

View File

@ -20,7 +20,6 @@ import PageLayoutV1 from '@components/containers/PageLayoutV1';
import Loader from '@components/Loader/Loader'; import Loader from '@components/Loader/Loader';
import { import {
addIngestionPipeline, addIngestionPipeline,
checkAirflowStatus,
deployIngestionPipelineById, deployIngestionPipelineById,
getIngestionPipelineByFqn, getIngestionPipelineByFqn,
} from '@rest/ingestionPipelineAPI'; } from '@rest/ingestionPipelineAPI';
@ -45,6 +44,7 @@ import { IngestionActionMessage } from '../../enums/ingestion.enum';
import { ServiceCategory } from '../../enums/service.enum'; import { ServiceCategory } from '../../enums/service.enum';
import { CreateIngestionPipeline } from '../../generated/api/services/ingestionPipelines/createIngestionPipeline'; import { CreateIngestionPipeline } from '../../generated/api/services/ingestionPipelines/createIngestionPipeline';
import { PipelineType } from '../../generated/entity/services/ingestionPipelines/ingestionPipeline'; import { PipelineType } from '../../generated/entity/services/ingestionPipelines/ingestionPipeline';
import { useAirflowStatus } from '../../hooks/useAirflowStatus';
import { DataObj } from '../../interface/service.interface'; import { DataObj } from '../../interface/service.interface';
import jsonData from '../../jsons/en'; import jsonData from '../../jsons/en';
import { getEntityMissingError } from '../../utils/CommonUtils'; import { getEntityMissingError } from '../../utils/CommonUtils';
@ -58,6 +58,7 @@ import {
import { showErrorToast } from '../../utils/ToastUtils'; import { showErrorToast } from '../../utils/ToastUtils';
const AddIngestionPage = () => { const AddIngestionPage = () => {
const { isAirflowAvailable, fetchAirflowStatus } = useAirflowStatus();
const { ingestionType, serviceFQN, serviceCategory } = const { ingestionType, serviceFQN, serviceCategory } =
useParams<{ [key: string]: string }>(); useParams<{ [key: string]: string }>();
const { t } = useTranslation(); const { t } = useTranslation();
@ -77,7 +78,6 @@ const AddIngestionPage = () => {
const [slashedBreadcrumb, setSlashedBreadcrumb] = useState< const [slashedBreadcrumb, setSlashedBreadcrumb] = useState<
TitleBreadcrumbProps['titleLinks'] TitleBreadcrumbProps['titleLinks']
>([]); >([]);
const [isAirflowRunning, setIsAirflowRunning] = useState(true);
const fetchServiceDetails = () => { const fetchServiceDetails = () => {
getServiceByFQN(serviceCategory, serviceFQN) getServiceByFQN(serviceCategory, serviceFQN)
@ -177,33 +177,6 @@ const AddIngestionPage = () => {
}); });
}; };
const onAirflowStatusCheck = (): Promise<void> => {
return new Promise<void>((resolve, reject) => {
checkAirflowStatus()
.then((res) => {
if (res.status === 200) {
resolve();
} else {
reject();
}
})
.catch(() => reject());
});
};
const fetchAirflowStatusCheck = () => {
return new Promise<void>((resolve) => {
onAirflowStatusCheck()
.then(() => {
setIsAirflowRunning(true);
})
.catch(() => {
setIsAirflowRunning(false);
})
.finally(() => resolve());
});
};
const goToService = () => { const goToService = () => {
history.push( history.push(
getServiceDetailsPath(serviceFQN, serviceCategory, 'ingestions') getServiceDetailsPath(serviceFQN, serviceCategory, 'ingestions')
@ -274,7 +247,6 @@ const AddIngestionPage = () => {
)} )}
ingestionAction={ingestionAction} ingestionAction={ingestionAction}
ingestionProgress={ingestionProgress} ingestionProgress={ingestionProgress}
isAirflowSetup={isAirflowRunning}
isIngestionCreated={isIngestionCreated} isIngestionCreated={isIngestionCreated}
isIngestionDeployed={isIngestionDeployed} isIngestionDeployed={isIngestionDeployed}
pipelineType={ingestionType as PipelineType} pipelineType={ingestionType as PipelineType}
@ -286,7 +258,6 @@ const AddIngestionPage = () => {
showDeployButton={showIngestionButton} showDeployButton={showIngestionButton}
status={FormSubmitType.ADD} status={FormSubmitType.ADD}
onAddIngestionSave={onAddIngestionSave} onAddIngestionSave={onAddIngestionSave}
onAirflowStatusCheck={onAirflowStatusCheck}
onIngestionDeploy={onIngestionDeploy} onIngestionDeploy={onIngestionDeploy}
/> />
</div> </div>
@ -300,7 +271,7 @@ const AddIngestionPage = () => {
ingestionType as PipelineType, ingestionType as PipelineType,
isDeployed(), isDeployed(),
false, false,
isAirflowRunning isAirflowAvailable
)} )}
</div> </div>
</PageLayoutV1> </PageLayoutV1>
@ -310,7 +281,7 @@ const AddIngestionPage = () => {
}; };
useEffect(() => { useEffect(() => {
fetchAirflowStatusCheck().finally(() => { fetchAirflowStatus().finally(() => {
fetchServiceDetails(); fetchServiceDetails();
}); });
}, [serviceCategory, serviceFQN]); }, [serviceCategory, serviceFQN]);

View File

@ -16,7 +16,6 @@ import { TitleBreadcrumbProps } from '@components/common/title-breadcrumb/title-
import PageContainerV1 from '@components/containers/PageContainerV1'; import PageContainerV1 from '@components/containers/PageContainerV1';
import { import {
addIngestionPipeline, addIngestionPipeline,
checkAirflowStatus,
deployIngestionPipelineById, deployIngestionPipelineById,
getIngestionPipelineByFqn, getIngestionPipelineByFqn,
} from '@rest/ingestionPipelineAPI'; } from '@rest/ingestionPipelineAPI';
@ -35,6 +34,7 @@ import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.const
import { IngestionActionMessage } from '../../enums/ingestion.enum'; import { IngestionActionMessage } from '../../enums/ingestion.enum';
import { ServiceCategory } from '../../enums/service.enum'; import { ServiceCategory } from '../../enums/service.enum';
import { CreateIngestionPipeline } from '../../generated/api/services/ingestionPipelines/createIngestionPipeline'; import { CreateIngestionPipeline } from '../../generated/api/services/ingestionPipelines/createIngestionPipeline';
import { useAirflowStatus } from '../../hooks/useAirflowStatus';
import { DataObj } from '../../interface/service.interface'; import { DataObj } from '../../interface/service.interface';
import jsonData from '../../jsons/en'; import jsonData from '../../jsons/en';
import { getSettingPath } from '../../utils/RouterUtils'; import { getSettingPath } from '../../utils/RouterUtils';
@ -42,6 +42,7 @@ import { getServiceRouteFromServiceType } from '../../utils/ServiceUtils';
import { showErrorToast } from '../../utils/ToastUtils'; import { showErrorToast } from '../../utils/ToastUtils';
const AddServicePage = () => { const AddServicePage = () => {
const { fetchAirflowStatus } = useAirflowStatus();
const { serviceCategory } = useParams<{ [key: string]: string }>(); const { serviceCategory } = useParams<{ [key: string]: string }>();
const [newServiceData, setNewServiceData] = useState<ServicesUpdateRequest>(); const [newServiceData, setNewServiceData] = useState<ServicesUpdateRequest>();
const [ingestionProgress, setIngestionProgress] = useState(0); const [ingestionProgress, setIngestionProgress] = useState(0);
@ -61,20 +62,6 @@ const AddServicePage = () => {
setAddIngestion(value); setAddIngestion(value);
}; };
const onAirflowStatusCheck = (): Promise<void> => {
return new Promise<void>((resolve, reject) => {
checkAirflowStatus()
.then((res) => {
if (res.status === 200) {
resolve();
} else {
reject();
}
})
.catch(() => reject());
});
};
const onAddServiceSave = (data: DataObj) => { const onAddServiceSave = (data: DataObj) => {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
postService(serviceCategory, data) postService(serviceCategory, data)
@ -198,7 +185,7 @@ const AddServicePage = () => {
slashedBreadcrumb={slashedBreadcrumb} slashedBreadcrumb={slashedBreadcrumb}
onAddIngestionSave={onAddIngestionSave} onAddIngestionSave={onAddIngestionSave}
onAddServiceSave={onAddServiceSave} onAddServiceSave={onAddServiceSave}
onAirflowStatusCheck={onAirflowStatusCheck} onAirflowStatusCheck={fetchAirflowStatus}
onIngestionDeploy={onIngestionDeploy} onIngestionDeploy={onIngestionDeploy}
/> />
</div> </div>

View File

@ -19,7 +19,6 @@ import PageContainerV1 from '@components/containers/PageContainerV1';
import PageLayoutV1 from '@components/containers/PageLayoutV1'; import PageLayoutV1 from '@components/containers/PageLayoutV1';
import Loader from '@components/Loader/Loader'; import Loader from '@components/Loader/Loader';
import { import {
checkAirflowStatus,
deployIngestionPipelineById, deployIngestionPipelineById,
getIngestionPipelineByFqn, getIngestionPipelineByFqn,
updateIngestionPipeline, updateIngestionPipeline,
@ -47,6 +46,7 @@ import {
IngestionPipeline, IngestionPipeline,
PipelineType, PipelineType,
} from '../../generated/entity/services/ingestionPipelines/ingestionPipeline'; } from '../../generated/entity/services/ingestionPipelines/ingestionPipeline';
import { useAirflowStatus } from '../../hooks/useAirflowStatus';
import { DataObj } from '../../interface/service.interface'; import { DataObj } from '../../interface/service.interface';
import jsonData from '../../jsons/en'; import jsonData from '../../jsons/en';
import { getEntityMissingError } from '../../utils/CommonUtils'; import { getEntityMissingError } from '../../utils/CommonUtils';
@ -60,6 +60,7 @@ import {
import { showErrorToast } from '../../utils/ToastUtils'; import { showErrorToast } from '../../utils/ToastUtils';
const EditIngestionPage = () => { const EditIngestionPage = () => {
const { isAirflowAvailable, fetchAirflowStatus } = useAirflowStatus();
const { ingestionFQN, ingestionType, serviceFQN, serviceCategory } = const { ingestionFQN, ingestionType, serviceFQN, serviceCategory } =
useParams<{ [key: string]: string }>(); useParams<{ [key: string]: string }>();
const history = useHistory(); const history = useHistory();
@ -80,7 +81,6 @@ const EditIngestionPage = () => {
const [slashedBreadcrumb, setSlashedBreadcrumb] = useState< const [slashedBreadcrumb, setSlashedBreadcrumb] = useState<
TitleBreadcrumbProps['titleLinks'] TitleBreadcrumbProps['titleLinks']
>([]); >([]);
const [isAirflowRunning, setIsAirflowRunning] = useState(true);
const fetchServiceDetails = () => { const fetchServiceDetails = () => {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
@ -210,33 +210,6 @@ const EditIngestionPage = () => {
}); });
}; };
const onAirflowStatusCheck = (): Promise<void> => {
return new Promise<void>((resolve, reject) => {
checkAirflowStatus()
.then((res) => {
if (res.status === 200) {
resolve();
} else {
reject();
}
})
.catch(() => reject());
});
};
const fetchAirflowStatusCheck = () => {
return new Promise<void>((resolve) => {
onAirflowStatusCheck()
.then(() => {
setIsAirflowRunning(true);
})
.catch(() => {
setIsAirflowRunning(false);
})
.finally(() => resolve());
});
};
const goToService = () => { const goToService = () => {
history.push( history.push(
getServiceDetailsPath(serviceFQN, serviceCategory, 'ingestions') getServiceDetailsPath(serviceFQN, serviceCategory, 'ingestions')
@ -307,7 +280,6 @@ const EditIngestionPage = () => {
)} )}
ingestionAction={ingestionAction} ingestionAction={ingestionAction}
ingestionProgress={ingestionProgress} ingestionProgress={ingestionProgress}
isAirflowSetup={isAirflowRunning}
isIngestionCreated={isIngestionCreated} isIngestionCreated={isIngestionCreated}
isIngestionDeployed={isIngestionDeployed} isIngestionDeployed={isIngestionDeployed}
pipelineType={ingestionType as PipelineType} pipelineType={ingestionType as PipelineType}
@ -318,7 +290,6 @@ const EditIngestionPage = () => {
} }
showDeployButton={showIngestionButton} showDeployButton={showIngestionButton}
status={FormSubmitType.EDIT} status={FormSubmitType.EDIT}
onAirflowStatusCheck={onAirflowStatusCheck}
onIngestionDeploy={onIngestionDeploy} onIngestionDeploy={onIngestionDeploy}
onSuccessSave={goToService} onSuccessSave={goToService}
onUpdateIngestion={onEditIngestionSave} onUpdateIngestion={onEditIngestionSave}
@ -334,7 +305,7 @@ const EditIngestionPage = () => {
ingestionType as PipelineType, ingestionType as PipelineType,
isDeployed(), isDeployed(),
true, true,
isAirflowRunning isAirflowAvailable
)} )}
</div> </div>
</PageLayoutV1> </PageLayoutV1>
@ -344,7 +315,7 @@ const EditIngestionPage = () => {
}; };
useEffect(() => { useEffect(() => {
fetchAirflowStatusCheck().finally(() => { fetchAirflowStatus().finally(() => {
fetchData(); fetchData();
}); });
}, [serviceCategory, serviceFQN]); }, [serviceCategory, serviceFQN]);

View File

@ -21,11 +21,10 @@ import SuccessScreen from '@components/common/success-screen/SuccessScreen';
import TitleBreadcrumb from '@components/common/title-breadcrumb/title-breadcrumb.component'; import TitleBreadcrumb from '@components/common/title-breadcrumb/title-breadcrumb.component';
import PageLayoutV1 from '@components/containers/PageLayoutV1'; import PageLayoutV1 from '@components/containers/PageLayoutV1';
import IngestionStepper from '@components/IngestionStepper/IngestionStepper.component'; import IngestionStepper from '@components/IngestionStepper/IngestionStepper.component';
import { checkAirflowStatus } from '@rest/ingestionPipelineAPI';
import { createTestSuites } from '@rest/testAPI'; import { createTestSuites } from '@rest/testAPI';
import { Col, Row, Space, Typography } from 'antd'; import { Col, Row, Space, Typography } from 'antd';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { import {
@ -46,17 +45,8 @@ const TestSuiteStepper = () => {
const history = useHistory(); const history = useHistory();
const [activeServiceStep, setActiveServiceStep] = useState(1); const [activeServiceStep, setActiveServiceStep] = useState(1);
const [testSuiteResponse, setTestSuiteResponse] = useState<TestSuite>(); const [testSuiteResponse, setTestSuiteResponse] = useState<TestSuite>();
const [isAirflowRunning, setIsAirflowRunning] = useState<boolean>(false);
const [addIngestion, setAddIngestion] = useState<boolean>(false);
const handleAirflowStatusCheck = async (): Promise<void> => { const [addIngestion, setAddIngestion] = useState<boolean>(false);
try {
await checkAirflowStatus();
setIsAirflowRunning(true);
} catch (error) {
showErrorToast(error as AxiosError);
}
};
const handleViewTestSuiteClick = () => { const handleViewTestSuiteClick = () => {
history.push(getTestSuitePath(testSuiteResponse?.fullyQualifiedName || '')); history.push(getTestSuitePath(testSuiteResponse?.fullyQualifiedName || ''));
@ -84,21 +74,15 @@ const TestSuiteStepper = () => {
showIngestionButton showIngestionButton
handleIngestionClick={() => setAddIngestion(true)} handleIngestionClick={() => setAddIngestion(true)}
handleViewServiceClick={handleViewTestSuiteClick} handleViewServiceClick={handleViewTestSuiteClick}
isAirflowSetup={isAirflowRunning}
name={testSuiteResponse?.name || ''} name={testSuiteResponse?.name || ''}
state={FormSubmitType.ADD} state={FormSubmitType.ADD}
viewServiceText="View Test Suite" viewServiceText="View Test Suite"
onCheckAirflowStatus={handleAirflowStatusCheck}
/> />
); );
} }
return <AddTestSuiteForm onSubmit={onSubmitTestSuite} />; return <AddTestSuiteForm onSubmit={onSubmitTestSuite} />;
}, [activeServiceStep, isAirflowRunning]); }, [activeServiceStep]);
useEffect(() => {
handleAirflowStatusCheck();
}, []);
return ( return (
<div data-testid="test-suite-stepper-container"> <div data-testid="test-suite-stepper-container">

View File

@ -33,7 +33,6 @@ import TagsViewer from '@components/tags-viewer/tags-viewer';
import { getDashboards } from '@rest/dashboardAPI'; import { getDashboards } from '@rest/dashboardAPI';
import { getDatabases } from '@rest/databaseAPI'; import { getDatabases } from '@rest/databaseAPI';
import { import {
checkAirflowStatus,
deleteIngestionPipelineById, deleteIngestionPipelineById,
deployIngestionPipelineById, deployIngestionPipelineById,
enableDisableIngestionPipelineById, enableDisableIngestionPipelineById,
@ -84,6 +83,7 @@ import { IngestionPipeline } from '../../generated/entity/services/ingestionPipe
import { MetadataServiceType } from '../../generated/entity/services/metadataService'; import { MetadataServiceType } from '../../generated/entity/services/metadataService';
import { EntityReference } from '../../generated/type/entityReference'; import { EntityReference } from '../../generated/type/entityReference';
import { Paging } from '../../generated/type/paging'; import { Paging } from '../../generated/type/paging';
import { useAirflowStatus } from '../../hooks/useAirflowStatus';
import { ConfigData, ServicesType } from '../../interface/service.interface'; import { ConfigData, ServicesType } from '../../interface/service.interface';
import jsonData from '../../jsons/en'; import jsonData from '../../jsons/en';
import { getEntityMissingError, getEntityName } from '../../utils/CommonUtils'; import { getEntityMissingError, getEntityName } from '../../utils/CommonUtils';
@ -111,6 +111,7 @@ import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
export type ServicePageData = Database | Topic | Dashboard | Mlmodel | Pipeline; export type ServicePageData = Database | Topic | Dashboard | Mlmodel | Pipeline;
const ServicePage: FunctionComponent = () => { const ServicePage: FunctionComponent = () => {
const { isAirflowAvailable } = useAirflowStatus();
const { serviceFQN, serviceType, serviceCategory, tab } = const { serviceFQN, serviceType, serviceCategory, tab } =
useParams() as Record<string, string>; useParams() as Record<string, string>;
const { getEntityPermissionByFqn } = usePermissionProvider(); const { getEntityPermissionByFqn } = usePermissionProvider();
@ -139,7 +140,6 @@ const ServicePage: FunctionComponent = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [ingestionCurrentPage, setIngestionCurrentPage] = useState(1); const [ingestionCurrentPage, setIngestionCurrentPage] = useState(1);
const [airflowEndpoint, setAirflowEndpoint] = useState<string>(); const [airflowEndpoint, setAirflowEndpoint] = useState<string>();
const [isAirflowRunning, setIsAirflowRunning] = useState(false);
const [connectionDetails, setConnectionDetails] = useState<ConfigData>(); const [connectionDetails, setConnectionDetails] = useState<ConfigData>();
const [schemaCount, setSchemaCount] = useState<number>(0); const [schemaCount, setSchemaCount] = useState<number>(0);
@ -460,20 +460,6 @@ const ServicePage: FunctionComponent = () => {
}); });
}; };
const getAirflowStatus = () => {
return new Promise<void>((resolve, reject) => {
checkAirflowStatus()
.then((res) => {
if (res.status === 200) {
resolve();
} else {
reject();
}
})
.catch(() => reject());
});
};
const getOtherDetails = (paging?: string) => { const getOtherDetails = (paging?: string) => {
switch (serviceName) { switch (serviceName) {
case ServiceCategory.DATABASE_SERVICES: { case ServiceCategory.DATABASE_SERVICES: {
@ -691,15 +677,6 @@ const ServicePage: FunctionComponent = () => {
if (tabs[currentTabIndex]?.isProtected) { if (tabs[currentTabIndex]?.isProtected) {
activeTabHandler(1); activeTabHandler(1);
} }
getAirflowStatus()
.then(() => {
setIsAirflowRunning(true);
getAllIngestionWorkflows();
})
.catch(() => {
setIsAirflowRunning(false);
});
} }
}, [servicePermission]); }, [servicePermission]);
@ -829,7 +806,7 @@ const ServicePage: FunctionComponent = () => {
}; };
const getIngestionTab = () => { const getIngestionTab = () => {
if (!isAirflowRunning) { if (!isAirflowAvailable) {
return <ErrorPlaceHolderIngestion />; return <ErrorPlaceHolderIngestion />;
} else if (isUndefined(airflowEndpoint)) { } else if (isUndefined(airflowEndpoint)) {
return <Loader />; return <Loader />;
@ -970,6 +947,12 @@ const ServicePage: FunctionComponent = () => {
]; ];
}, []); }, []);
useEffect(() => {
if (isAirflowAvailable) {
getAllIngestionWorkflows();
}
}, [isAirflowAvailable]);
return ( return (
<PageContainerV1> <PageContainerV1>
{isLoading ? ( {isLoading ? (
@ -1153,7 +1136,7 @@ const ServicePage: FunctionComponent = () => {
})} })}
</Button> </Button>
</Tooltip> </Tooltip>
{allowTestConn && isAirflowRunning && ( {allowTestConn && isAirflowAvailable && (
<Tooltip <Tooltip
title={ title={
servicePermission.EditAll servicePermission.EditAll