diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/AirflowMessageBanner/AirflowMessageBanner.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/AirflowMessageBanner/AirflowMessageBanner.test.tsx index 182a0beb5af..4d13c4fa95f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/AirflowMessageBanner/AirflowMessageBanner.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/AirflowMessageBanner/AirflowMessageBanner.test.tsx @@ -11,6 +11,7 @@ * limitations under the License. */ import { render, screen } from '@testing-library/react'; +import { AIRFLOW_HYBRID } from '../../../constants/constants'; import { useAirflowStatus } from '../../../context/AirflowStatusProvider/AirflowStatusProvider'; import AirflowMessageBanner from './AirflowMessageBanner'; @@ -20,6 +21,8 @@ jest.mock( useAirflowStatus: jest.fn().mockImplementation(() => ({ reason: 'reason message', isAirflowAvailable: false, + isFetchingStatus: false, + platform: 'unknown', })), }) ); @@ -31,10 +34,12 @@ describe('Test Airflow Message Banner', () => { expect(screen.getByTestId('no-airflow-placeholder')).toBeInTheDocument(); }); - it('Should not render the banner if airflow is available', () => { + it('Should not render the banner if airflow is available and platform is not hybrid', () => { (useAirflowStatus as jest.Mock).mockImplementationOnce(() => ({ reason: 'reason message', isAirflowAvailable: true, + isFetchingStatus: false, + platform: 'unknown', })); render(); @@ -42,4 +47,104 @@ describe('Test Airflow Message Banner', () => { screen.queryByTestId('no-airflow-placeholder') ).not.toBeInTheDocument(); }); + + describe('Hybrid Runner Scenarios', () => { + it('Should render the banner for hybrid runner even when platform is available (status 200)', () => { + (useAirflowStatus as jest.Mock).mockImplementationOnce(() => ({ + reason: 'Hybrid runner is configured correctly', + isAirflowAvailable: true, + isFetchingStatus: false, + platform: AIRFLOW_HYBRID, + })); + render(); + + expect(screen.getByTestId('no-airflow-placeholder')).toBeInTheDocument(); + expect(screen.getByTestId('viewer-container')).toBeInTheDocument(); + }); + + it('Should render the banner for hybrid runner when platform is not available', () => { + (useAirflowStatus as jest.Mock).mockImplementationOnce(() => ({ + reason: 'Hybrid runner configuration error', + isAirflowAvailable: false, + isFetchingStatus: false, + platform: AIRFLOW_HYBRID, + })); + render(); + + expect(screen.getByTestId('no-airflow-placeholder')).toBeInTheDocument(); + expect(screen.getByTestId('viewer-container')).toBeInTheDocument(); + }); + + it('Should not render the banner for hybrid runner if reason is empty', () => { + (useAirflowStatus as jest.Mock).mockImplementationOnce(() => ({ + reason: '', + isAirflowAvailable: true, + isFetchingStatus: false, + platform: AIRFLOW_HYBRID, + })); + render(); + + expect( + screen.queryByTestId('no-airflow-placeholder') + ).not.toBeInTheDocument(); + }); + }); + + describe('Common Scenarios', () => { + it('Should not render the banner if fetching status', () => { + (useAirflowStatus as jest.Mock).mockImplementationOnce(() => ({ + reason: 'reason message', + isAirflowAvailable: false, + isFetchingStatus: true, + platform: 'unknown', + })); + render(); + + expect( + screen.queryByTestId('no-airflow-placeholder') + ).not.toBeInTheDocument(); + }); + + it('Should not render the banner if reason is empty', () => { + (useAirflowStatus as jest.Mock).mockImplementationOnce(() => ({ + reason: '', + isAirflowAvailable: false, + isFetchingStatus: false, + platform: 'unknown', + })); + render(); + + expect( + screen.queryByTestId('no-airflow-placeholder') + ).not.toBeInTheDocument(); + }); + + it('Should not render the banner if reason is null', () => { + (useAirflowStatus as jest.Mock).mockImplementationOnce(() => ({ + reason: null, + isAirflowAvailable: false, + isFetchingStatus: false, + platform: 'unknown', + })); + render(); + + expect( + screen.queryByTestId('no-airflow-placeholder') + ).not.toBeInTheDocument(); + }); + + it('Should render the banner if platform is not available and reason is not empty', () => { + (useAirflowStatus as jest.Mock).mockImplementationOnce(() => ({ + reason: 'Some error occurred', + isAirflowAvailable: false, + isFetchingStatus: false, + platform: 'unknown', + })); + render(); + + expect( + screen.queryByTestId('no-airflow-placeholder') + ).toBeInTheDocument(); + }); + }); }); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/AirflowMessageBanner/AirflowMessageBanner.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/AirflowMessageBanner/AirflowMessageBanner.tsx index 64dfd103bc1..ba1c0139546 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/AirflowMessageBanner/AirflowMessageBanner.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/AirflowMessageBanner/AirflowMessageBanner.tsx @@ -15,14 +15,22 @@ import classNames from 'classnames'; import { isEmpty } from 'lodash'; import { FC } from 'react'; import { ReactComponent as IconRetry } from '../../../assets/svg/ic-retry-icon.svg'; +import { AIRFLOW_HYBRID } from '../../../constants/constants'; import { useAirflowStatus } from '../../../context/AirflowStatusProvider/AirflowStatusProvider'; import RichTextEditorPreviewerV1 from '../RichTextEditor/RichTextEditorPreviewerV1'; import './airflow-message-banner.less'; const AirflowMessageBanner: FC = ({ className }) => { - const { reason, isAirflowAvailable, isFetchingStatus } = useAirflowStatus(); + const { reason, isAirflowAvailable, isFetchingStatus, platform } = + useAirflowStatus(); - if (isAirflowAvailable || isFetchingStatus || isEmpty(reason)) { + if (isFetchingStatus || isEmpty(reason)) { + return null; + } + + // For hybrid runner, always show the banner even if status is 200 + // For other platforms, only show when Airflow is not available + if (platform !== AIRFLOW_HYBRID && isAirflowAvailable) { return null; }