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');
};
export const fetchAirflowConfig = (): Promise<AxiosResponse> => {
return APIClient.get('/config/airflow');
};
export const getSuggestions: Function = (
queryString: string,
searchIndex?: string

View File

@ -29,6 +29,7 @@ import {
} from '../../generated/entity/services/ingestionPipelines/ingestionPipeline';
import { useAuth } from '../../hooks/authHooks';
import { isEven } from '../../utils/CommonUtils';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { showInfoToast } from '../../utils/ToastUtils';
import AddIngestion from '../AddIngestion/AddIngestion.component';
import { Button } from '../buttons/Button/Button';
@ -41,6 +42,7 @@ import EntityDeleteModal from '../Modals/EntityDeleteModal/EntityDeleteModal';
import { IngestionProps, ModifiedConfig } from './ingestion.interface';
const Ingestion: React.FC<IngestionProps> = ({
airflowEndpoint,
serviceDetails,
serviceName,
serviceCategory,
@ -270,6 +272,7 @@ const Ingestion: React.FC<IngestionProps> = ({
<th className="tableHead-cell">Type</th>
<th className="tableHead-cell">Schedule</th>
<th className="tableHead-cell">Recent Runs</th>
<th className="tableHead-cell">Airflow DAG</th>
<th className="tableHead-cell">Actions</th>
</tr>
</thead>
@ -311,7 +314,30 @@ const Ingestion: React.FC<IngestionProps> = ({
<td className="tableBody-cell">
<div className="tw-flex">{getStatuses(ingestion)}</div>
</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">
<NonAdminAction
position="bottom"

View File

@ -92,6 +92,7 @@ describe('Test Ingestion page', () => {
<Ingestion
isRequiredDetailsAvailable
addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1}
deleteIngestion={mockDeleteIngestion}
ingestionList={
@ -132,6 +133,7 @@ describe('Test Ingestion page', () => {
<Ingestion
isRequiredDetailsAvailable
addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1}
deleteIngestion={mockDeleteIngestion}
ingestionList={
@ -163,12 +165,13 @@ describe('Test Ingestion page', () => {
expect(ingestionTable).toBeInTheDocument();
expect(tableHeaderContainer).toBeInTheDocument();
expect(tableHeaders.length).toBe(5);
expect(tableHeaders.length).toBe(6);
expect(tableHeaders).toStrictEqual([
'Name',
'Type',
'Schedule',
'Recent Runs',
'Airflow DAG',
'Actions',
]);
expect(runButton).toBeInTheDocument();
@ -186,6 +189,7 @@ describe('Test Ingestion page', () => {
<Ingestion
isRequiredDetailsAvailable
addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1}
deleteIngestion={mockDeleteIngestion}
ingestionList={
@ -220,6 +224,7 @@ describe('Test Ingestion page', () => {
<Ingestion
isRequiredDetailsAvailable
addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1}
deleteIngestion={mockDeleteIngestion}
ingestionList={
@ -258,6 +263,7 @@ describe('Test Ingestion page', () => {
<Ingestion
isRequiredDetailsAvailable
addIngestion={mockFunction}
airflowEndpoint=""
currrentPage={1}
deleteIngestion={mockDeleteIngestion}
ingestionList={
@ -305,4 +311,33 @@ describe('Test Ingestion page', () => {
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 {
airflowEndpoint: string;
serviceDetails: DataObj;
serviceName?: string;
serviceCategory: ServiceCategory;

View File

@ -57,6 +57,8 @@ const jsonData = {
'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-chart-error': 'Error while fetching charts!',
'fetch-dashboard-details-error': 'Error while fetching dashboard details!',

View File

@ -29,6 +29,7 @@ import {
triggerIngestionPipelineById,
updateIngestionPipeline,
} from '../../axiosAPIs/ingestionPipelineAPI';
import { fetchAirflowConfig } from '../../axiosAPIs/miscAPI';
import { getPipelines } from '../../axiosAPIs/pipelineAPI';
import { getServiceByFQN, updateService } from '../../axiosAPIs/serviceAPI';
import { getTopics } from '../../axiosAPIs/topicsAPI';
@ -113,6 +114,7 @@ const ServicePage: FunctionComponent = () => {
const [currentPage, setCurrentPage] = useState(1);
const [ingestionCurrentPage, setIngestionCurrentPage] = useState(1);
const [airflowEndpoint, setAirflowEndpoint] = useState<string>();
const getCountLabel = () => {
switch (serviceName) {
@ -234,6 +236,25 @@ const ServicePage: FunctionComponent = () => {
.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 = (
id: string,
displayName: string
@ -689,6 +710,7 @@ const ServicePage: FunctionComponent = () => {
// getDatabaseServices();
getAllIngestionWorkflows();
}
getAirflowEndpoint();
}, []);
const onCancel = () => {
@ -942,25 +964,29 @@ const ServicePage: FunctionComponent = () => {
</Fragment>
)}
{activeTab === 2 && (
<div data-testid="ingestion-container">
<Ingestion
isRequiredDetailsAvailable
addIngestion={onAddIngestionSave}
currrentPage={ingestionCurrentPage}
deleteIngestion={deleteIngestionById}
ingestionList={ingestions}
paging={ingestionPaging}
pagingHandler={ingestionPagingHandler}
serviceCategory={serviceName as ServiceCategory}
serviceDetails={serviceDetails as DataObj}
serviceList={serviceList}
serviceName={serviceFQN}
triggerIngestion={triggerIngestionById}
updateIngestion={updateIngestion}
/>
</div>
)}
{activeTab === 2 &&
(isUndefined(airflowEndpoint) ? (
<Loader />
) : (
<div data-testid="ingestion-container">
<Ingestion
isRequiredDetailsAvailable
addIngestion={onAddIngestionSave}
airflowEndpoint={airflowEndpoint}
currrentPage={ingestionCurrentPage}
deleteIngestion={deleteIngestionById}
ingestionList={ingestions}
paging={ingestionPaging}
pagingHandler={ingestionPagingHandler}
serviceCategory={serviceName as ServiceCategory}
serviceDetails={serviceDetails as DataObj}
serviceList={serviceList}
serviceName={serviceFQN}
triggerIngestion={triggerIngestionById}
updateIngestion={updateIngestion}
/>
</div>
))}
{activeTab === 3 && (isAdminUser || isAuthDisabled) && (
<ServiceConfig