Fix #4251: Ingestion button redirects to airflow (#4322)

This commit is contained in:
darth-coder00 2022-04-21 22:33:27 +05:30 committed by GitHub
parent f4e6d08812
commit 1e76aae76b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 115 additions and 21 deletions

View File

@ -61,6 +61,10 @@ export const fetchSandboxConfig = (): Promise<AxiosResponse> => {
return APIClient.get('/config/sandbox'); return APIClient.get('/config/sandbox');
}; };
export const fetchAirflowConfig = (): Promise<AxiosResponse> => {
return APIClient.get('/config/airflow');
};
export const getSuggestions: Function = ( export const getSuggestions: Function = (
queryString: string, queryString: string,
searchIndex?: string searchIndex?: string

View File

@ -29,6 +29,7 @@ import {
} from '../../generated/entity/services/ingestionPipelines/ingestionPipeline'; } from '../../generated/entity/services/ingestionPipelines/ingestionPipeline';
import { useAuth } from '../../hooks/authHooks'; import { useAuth } from '../../hooks/authHooks';
import { isEven } from '../../utils/CommonUtils'; import { isEven } from '../../utils/CommonUtils';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { showInfoToast } from '../../utils/ToastUtils'; import { showInfoToast } from '../../utils/ToastUtils';
import AddIngestion from '../AddIngestion/AddIngestion.component'; import AddIngestion from '../AddIngestion/AddIngestion.component';
import { Button } from '../buttons/Button/Button'; import { Button } from '../buttons/Button/Button';
@ -41,6 +42,7 @@ import EntityDeleteModal from '../Modals/EntityDeleteModal/EntityDeleteModal';
import { IngestionProps, ModifiedConfig } from './ingestion.interface'; import { IngestionProps, ModifiedConfig } from './ingestion.interface';
const Ingestion: React.FC<IngestionProps> = ({ const Ingestion: React.FC<IngestionProps> = ({
airflowEndpoint,
serviceDetails, serviceDetails,
serviceName, serviceName,
serviceCategory, serviceCategory,
@ -270,6 +272,7 @@ const Ingestion: React.FC<IngestionProps> = ({
<th className="tableHead-cell">Type</th> <th className="tableHead-cell">Type</th>
<th className="tableHead-cell">Schedule</th> <th className="tableHead-cell">Schedule</th>
<th className="tableHead-cell">Recent Runs</th> <th className="tableHead-cell">Recent Runs</th>
<th className="tableHead-cell">Airflow DAG</th>
<th className="tableHead-cell">Actions</th> <th className="tableHead-cell">Actions</th>
</tr> </tr>
</thead> </thead>
@ -311,7 +314,30 @@ const Ingestion: React.FC<IngestionProps> = ({
<td className="tableBody-cell"> <td className="tableBody-cell">
<div className="tw-flex">{getStatuses(ingestion)}</div> <div className="tw-flex">{getStatuses(ingestion)}</div>
</td> </td>
<td className="tableBody-cell">
{airflowEndpoint ? (
<NonAdminAction
position="bottom"
title={TITLE_FOR_NON_ADMIN_ACTION}>
<a
className="link-text tw-mr-2"
data-testid="airflow-tree-view"
href={`${airflowEndpoint}/tree?dag_id=${ingestion.name}`}
rel="noopener noreferrer"
target="_blank">
View
<SVGIcons
alt="external-link"
className="tw-align-middle tw-ml-1"
icon={Icons.EXTERNAL_LINK}
width="12px"
/>
</a>
</NonAdminAction>
) : (
<span className="tw-text-grey-muted">No endpoint</span>
)}
</td>
<td className="tableBody-cell"> <td className="tableBody-cell">
<NonAdminAction <NonAdminAction
position="bottom" position="bottom"

View File

@ -92,6 +92,7 @@ describe('Test Ingestion page', () => {
<Ingestion <Ingestion
isRequiredDetailsAvailable isRequiredDetailsAvailable
addIngestion={mockFunction} addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1} currrentPage={1}
deleteIngestion={mockDeleteIngestion} deleteIngestion={mockDeleteIngestion}
ingestionList={ ingestionList={
@ -132,6 +133,7 @@ describe('Test Ingestion page', () => {
<Ingestion <Ingestion
isRequiredDetailsAvailable isRequiredDetailsAvailable
addIngestion={mockFunction} addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1} currrentPage={1}
deleteIngestion={mockDeleteIngestion} deleteIngestion={mockDeleteIngestion}
ingestionList={ ingestionList={
@ -163,12 +165,13 @@ describe('Test Ingestion page', () => {
expect(ingestionTable).toBeInTheDocument(); expect(ingestionTable).toBeInTheDocument();
expect(tableHeaderContainer).toBeInTheDocument(); expect(tableHeaderContainer).toBeInTheDocument();
expect(tableHeaders.length).toBe(5); expect(tableHeaders.length).toBe(6);
expect(tableHeaders).toStrictEqual([ expect(tableHeaders).toStrictEqual([
'Name', 'Name',
'Type', 'Type',
'Schedule', 'Schedule',
'Recent Runs', 'Recent Runs',
'Airflow DAG',
'Actions', 'Actions',
]); ]);
expect(runButton).toBeInTheDocument(); expect(runButton).toBeInTheDocument();
@ -186,6 +189,7 @@ describe('Test Ingestion page', () => {
<Ingestion <Ingestion
isRequiredDetailsAvailable isRequiredDetailsAvailable
addIngestion={mockFunction} addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1} currrentPage={1}
deleteIngestion={mockDeleteIngestion} deleteIngestion={mockDeleteIngestion}
ingestionList={ ingestionList={
@ -220,6 +224,7 @@ describe('Test Ingestion page', () => {
<Ingestion <Ingestion
isRequiredDetailsAvailable isRequiredDetailsAvailable
addIngestion={mockFunction} addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1} currrentPage={1}
deleteIngestion={mockDeleteIngestion} deleteIngestion={mockDeleteIngestion}
ingestionList={ ingestionList={
@ -258,6 +263,7 @@ describe('Test Ingestion page', () => {
<Ingestion <Ingestion
isRequiredDetailsAvailable isRequiredDetailsAvailable
addIngestion={mockFunction} addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1} currrentPage={1}
deleteIngestion={mockDeleteIngestion} deleteIngestion={mockDeleteIngestion}
ingestionList={ ingestionList={
@ -305,4 +311,33 @@ describe('Test Ingestion page', () => {
expect(ingestionModal).toBeInTheDocument(); expect(ingestionModal).toBeInTheDocument();
}); });
it('Airflow DAG view button should be present if endpoint is available', async () => {
const { container } = render(
<Ingestion
isRequiredDetailsAvailable
addIngestion={mockFunction}
airflowEndpoint="http://localhost"
currrentPage={1}
deleteIngestion={mockDeleteIngestion}
ingestionList={
mockIngestionWorkFlow.data.data as unknown as IngestionPipeline[]
}
paging={mockPaging}
pagingHandler={mockPaginghandler}
serviceCategory={ServiceCategory.DASHBOARD_SERVICES}
serviceDetails={mockService}
serviceList={[]}
triggerIngestion={mockTriggerIngestion}
updateIngestion={mockFunction}
/>,
{
wrapper: MemoryRouter,
}
);
const viewButton = await findByTestId(container, 'airflow-tree-view');
expect(viewButton).toBeInTheDocument();
});
}); });

View File

@ -54,6 +54,7 @@ export interface IngestionData {
} }
export interface IngestionProps { export interface IngestionProps {
airflowEndpoint: string;
serviceDetails: DataObj; serviceDetails: DataObj;
serviceName?: string; serviceName?: string;
serviceCategory: ServiceCategory; serviceCategory: ServiceCategory;

View File

@ -57,6 +57,8 @@ const jsonData = {
'deploy-ingestion-error': 'Error while deploying ingestion workflow!', 'deploy-ingestion-error': 'Error while deploying ingestion workflow!',
'fetch-airflow-config-error':
'Error occurred while fetching airflow configs!',
'fetch-auth-config-error': 'Error occurred while fetching auth configs!', 'fetch-auth-config-error': 'Error occurred while fetching auth configs!',
'fetch-chart-error': 'Error while fetching charts!', 'fetch-chart-error': 'Error while fetching charts!',
'fetch-dashboard-details-error': 'Error while fetching dashboard details!', 'fetch-dashboard-details-error': 'Error while fetching dashboard details!',

View File

@ -29,6 +29,7 @@ import {
triggerIngestionPipelineById, triggerIngestionPipelineById,
updateIngestionPipeline, updateIngestionPipeline,
} from '../../axiosAPIs/ingestionPipelineAPI'; } from '../../axiosAPIs/ingestionPipelineAPI';
import { fetchAirflowConfig } from '../../axiosAPIs/miscAPI';
import { getPipelines } from '../../axiosAPIs/pipelineAPI'; import { getPipelines } from '../../axiosAPIs/pipelineAPI';
import { getServiceByFQN, updateService } from '../../axiosAPIs/serviceAPI'; import { getServiceByFQN, updateService } from '../../axiosAPIs/serviceAPI';
import { getTopics } from '../../axiosAPIs/topicsAPI'; import { getTopics } from '../../axiosAPIs/topicsAPI';
@ -113,6 +114,7 @@ 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 getCountLabel = () => { const getCountLabel = () => {
switch (serviceName) { switch (serviceName) {
@ -234,6 +236,25 @@ const ServicePage: FunctionComponent = () => {
.finally(() => setIsloading(false)); .finally(() => setIsloading(false));
}; };
const getAirflowEndpoint = () => {
fetchAirflowConfig()
.then((res) => {
if (res.data?.apiEndpoint) {
setAirflowEndpoint(res.data.apiEndpoint);
} else {
setAirflowEndpoint('');
throw jsonData['api-error-messages']['unexpected-server-response'];
}
})
.catch((err: AxiosError) => {
showErrorToast(
err,
jsonData['api-error-messages']['fetch-airflow-config-error']
);
});
};
const triggerIngestionById = ( const triggerIngestionById = (
id: string, id: string,
displayName: string displayName: string
@ -689,6 +710,7 @@ const ServicePage: FunctionComponent = () => {
// getDatabaseServices(); // getDatabaseServices();
getAllIngestionWorkflows(); getAllIngestionWorkflows();
} }
getAirflowEndpoint();
}, []); }, []);
const onCancel = () => { const onCancel = () => {
@ -942,11 +964,15 @@ const ServicePage: FunctionComponent = () => {
</Fragment> </Fragment>
)} )}
{activeTab === 2 && ( {activeTab === 2 &&
(isUndefined(airflowEndpoint) ? (
<Loader />
) : (
<div data-testid="ingestion-container"> <div data-testid="ingestion-container">
<Ingestion <Ingestion
isRequiredDetailsAvailable isRequiredDetailsAvailable
addIngestion={onAddIngestionSave} addIngestion={onAddIngestionSave}
airflowEndpoint={airflowEndpoint}
currrentPage={ingestionCurrentPage} currrentPage={ingestionCurrentPage}
deleteIngestion={deleteIngestionById} deleteIngestion={deleteIngestionById}
ingestionList={ingestions} ingestionList={ingestions}
@ -960,7 +986,7 @@ const ServicePage: FunctionComponent = () => {
updateIngestion={updateIngestion} updateIngestion={updateIngestion}
/> />
</div> </div>
)} ))}
{activeTab === 3 && (isAdminUser || isAuthDisabled) && ( {activeTab === 3 && (isAdminUser || isAuthDisabled) && (
<ServiceConfig <ServiceConfig