Fix #4362: Deploy Profiler Workflow UI (#4427)

This commit is contained in:
darth-coder00 2022-04-24 05:49:35 +05:30 committed by GitHub
parent a9570a21c6
commit a4ac73e867
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 363 additions and 146 deletions

View File

@ -12,6 +12,7 @@
*/
import { isEmpty, isUndefined } from 'lodash';
import { LoadingState } from 'Models';
import React, { useMemo, useState } from 'react';
import {
INGESTION_SCHEDULER_INITIAL_VALUE,
@ -31,6 +32,7 @@ import {
IngestionPipeline,
} from '../../generated/entity/services/ingestionPipelines/ingestionPipeline';
import { getCurrentDate, getCurrentUserId } from '../../utils/CommonUtils';
import { getIngestionName } from '../../utils/ServiceUtils';
import SuccessScreen from '../common/success-screen/SuccessScreen';
import IngestionStepper from '../IngestionStepper/IngestionStepper.component';
import { AddIngestionProps } from './addIngestion.interface';
@ -53,9 +55,11 @@ const AddIngestion = ({
handleCancelClick,
handleViewServiceClick,
}: AddIngestionProps) => {
const [ingestionName] = useState(
data?.name ?? `${serviceData.name}_${pipelineType}`
const [saveState, setSaveState] = useState<LoadingState>('initial');
const [ingestionName, setIngestionName] = useState(
data?.name ?? getIngestionName(serviceData.name, pipelineType)
);
const [description, setDescription] = useState(data?.description ?? '');
const [repeatFrequency, setRepeatFrequency] = useState(
data?.airflowConfig.scheduleInterval ?? INGESTION_SCHEDULER_INITIAL_VALUE
);
@ -89,6 +93,11 @@ const AddIngestion = ({
(data?.source.sourceConfig.config as ConfigClass)?.chartFilterPattern
)
);
const [showFqnFilter, setShowFqnFilter] = useState(
!isUndefined(
(data?.source.sourceConfig.config as ConfigClass)?.fqnFilterPattern
)
);
const [includeView, setIncludeView] = useState(
Boolean((data?.source.sourceConfig.config as ConfigClass)?.includeViews)
);
@ -121,6 +130,10 @@ const AddIngestion = ({
(data?.source.sourceConfig.config as ConfigClass)?.chartFilterPattern ??
INITIAL_FILTER_PATTERN
);
const [fqnFilterPattern, setFqnFilterPattern] = useState<FilterPattern>(
(data?.source.sourceConfig.config as ConfigClass)?.fqnFilterPattern ??
INITIAL_FILTER_PATTERN
);
const [queryLogDuration, setQueryLogDuration] = useState<number>(
(data?.source.sourceConfig.config as ConfigClass)?.queryLogDuration ?? 1
@ -138,6 +151,12 @@ const AddIngestion = ({
ConfigType.DatabaseUsage
);
}, [data]);
const profilerIngestionType = useMemo(() => {
return (
(data?.source.sourceConfig.config as ConfigClass)?.type ??
ConfigType.Profiler
);
}, [data]);
const getIncludeValue = (value: Array<string>, type: FilterPatternEnum) => {
switch (type) {
@ -163,6 +182,10 @@ const AddIngestion = ({
case FilterPatternEnum.CHART:
setChartFilterPattern({ ...topicFilterPattern, includes: value });
break;
case FilterPatternEnum.FQN:
setFqnFilterPattern({ ...fqnFilterPattern, includes: value });
break;
}
};
@ -190,6 +213,10 @@ const AddIngestion = ({
case FilterPatternEnum.CHART:
setChartFilterPattern({ ...topicFilterPattern, excludes: value });
break;
case FilterPatternEnum.FQN:
setFqnFilterPattern({ ...fqnFilterPattern, excludes: value });
break;
}
};
@ -215,6 +242,10 @@ const AddIngestion = ({
case FilterPatternEnum.CHART:
setShowChartFilter(value);
break;
case FilterPatternEnum.FQN:
setShowFqnFilter(value);
break;
}
};
@ -246,6 +277,38 @@ const AddIngestion = ({
return filterPattern;
};
const getConfigData = (type: PipelineType): ConfigClass => {
switch (type) {
case PipelineType.Usage: {
return {
queryLogDuration,
resultLimit,
stageFileLocation,
type: usageIngestionType,
};
}
case PipelineType.Profiler: {
return {
fqnFilterPattern: getFilterPatternData(fqnFilterPattern),
type: profilerIngestionType,
};
}
case PipelineType.Metadata:
default: {
return {
enableDataProfiler: enableDataProfiler,
generateSampleData: ingestSampleData,
includeViews: includeView,
schemaFilterPattern: getFilterPatternData(schemaFilterPattern),
tableFilterPattern: getFilterPatternData(tableFilterPattern),
chartFilterPattern: getFilterPatternData(chartFilterPattern),
dashboardFilterPattern: getFilterPatternData(dashboardFilterPattern),
topicFilterPattern: getFilterPatternData(topicFilterPattern),
};
}
}
};
const createNewIngestion = () => {
const ingestionDetails: CreateIngestionPipeline = {
airflowConfig: {
@ -266,37 +329,23 @@ const AddIngestion = ({
type: serviceCategory.slice(0, -1),
},
sourceConfig: {
config:
pipelineType === PipelineType.Usage
? {
queryLogDuration,
resultLimit,
stageFileLocation,
type: usageIngestionType,
}
: {
enableDataProfiler: enableDataProfiler,
generateSampleData: ingestSampleData,
includeViews: includeView,
schemaFilterPattern: getFilterPatternData(schemaFilterPattern),
tableFilterPattern: getFilterPatternData(tableFilterPattern),
chartFilterPattern: getFilterPatternData(chartFilterPattern),
dashboardFilterPattern: getFilterPatternData(
dashboardFilterPattern
),
topicFilterPattern: getFilterPatternData(topicFilterPattern),
},
config: getConfigData(pipelineType),
},
};
onAddIngestionSave &&
onAddIngestionSave(ingestionDetails).then(() => {
if (showSuccessScreen) {
setActiveIngestionStep(3);
} else {
onSuccessSave?.();
}
});
if (onAddIngestionSave) {
setSaveState('waiting');
onAddIngestionSave(ingestionDetails)
.then(() => {
setSaveState('success');
if (showSuccessScreen) {
setActiveIngestionStep(3);
} else {
onSuccessSave?.();
}
})
.finally(() => setTimeout(() => setSaveState('initial'), 500));
}
};
const updateIngestion = () => {
@ -314,40 +363,25 @@ const AddIngestion = ({
sourceConfig: {
config: {
...(data.source.sourceConfig.config as ConfigClass),
...(pipelineType === PipelineType.Usage
? {
queryLogDuration,
resultLimit,
stageFileLocation,
type: usageIngestionType,
}
: {
enableDataProfiler: enableDataProfiler,
generateSampleData: ingestSampleData,
includeViews: includeView,
schemaFilterPattern:
getFilterPatternData(schemaFilterPattern),
tableFilterPattern:
getFilterPatternData(tableFilterPattern),
chartFilterPattern:
getFilterPatternData(chartFilterPattern),
dashboardFilterPattern: getFilterPatternData(
dashboardFilterPattern
),
topicFilterPattern:
getFilterPatternData(topicFilterPattern),
}),
...getConfigData(pipelineType),
},
},
},
};
onUpdateIngestion &&
onUpdateIngestion(updatedData, data, data.id as string, data.name).then(
() => {
onSuccessSave?.();
}
);
if (onUpdateIngestion) {
setSaveState('waiting');
onUpdateIngestion(updatedData, data, data.id as string, data.name)
.then(() => {
setSaveState('success');
if (showSuccessScreen) {
setActiveIngestionStep(3);
} else {
onSuccessSave?.();
}
})
.finally(() => setTimeout(() => setSaveState('initial'), 500));
}
}
};
@ -375,14 +409,18 @@ const AddIngestion = ({
<ConfigureIngestion
chartFilterPattern={chartFilterPattern}
dashboardFilterPattern={dashboardFilterPattern}
description={description}
enableDataProfiler={enableDataProfiler}
fqnFilterPattern={fqnFilterPattern}
getExcludeValue={getExcludeValue}
getIncludeValue={getIncludeValue}
handleDescription={(val) => setDescription(val)}
handleEnableDataProfiler={() =>
setEnableDataProfiler((pre) => !pre)
}
handleIncludeView={() => setIncludeView((pre) => !pre)}
handleIngestSampleData={() => setIngestSampleData((pre) => !pre)}
handleIngestionName={(val) => setIngestionName(val)}
handleQueryLogDuration={(val) => setQueryLogDuration(val)}
handleResultLimit={(val) => setResultLimit(val)}
handleShowFilter={handleShowFilter}
@ -397,6 +435,7 @@ const AddIngestion = ({
serviceCategory={serviceCategory}
showChartFilter={showChartFilter}
showDashboardFilter={showDashboardFilter}
showFqnFilter={showFqnFilter}
showSchemaFilter={showSchemaFilter}
showTableFilter={showTableFilter}
showTopicFilter={showTopicFilter}
@ -418,8 +457,9 @@ const AddIngestion = ({
handleStartDateChange={(value: string) => setStartDate(value)}
repeatFrequency={repeatFrequency}
startDate={startDate as string}
status={saveState}
onBack={handleScheduleIntervalBackClick}
onDeloy={handleScheduleIntervalDeployClick}
onDeploy={handleScheduleIntervalDeployClick}
/>
)}

View File

@ -50,6 +50,10 @@ const mockConfigureIngestion: ConfigureIngestionProps = {
includes: [],
excludes: [],
},
fqnFilterPattern: {
includes: [],
excludes: [],
},
includeView: false,
pipelineType: PipelineType.Metadata,
queryLogDuration: 1,
@ -62,7 +66,9 @@ const mockConfigureIngestion: ConfigureIngestionProps = {
showTableFilter: false,
showTopicFilter: false,
showChartFilter: false,
showFqnFilter: false,
handleIncludeView: jest.fn(),
handleIngestionName: jest.fn(),
handleEnableDataProfiler: jest.fn(),
handleIngestSampleData: jest.fn(),
handleQueryLogDuration: jest.fn(),

View File

@ -11,23 +11,28 @@
* limitations under the License.
*/
import React, { Fragment } from 'react';
import { EditorContentRef } from 'Models';
import React, { Fragment, useRef } from 'react';
import { FilterPatternEnum } from '../../../enums/filterPattern.enum';
import { ServiceCategory } from '../../../enums/service.enum';
import { PipelineType } from '../../../generated/entity/services/ingestionPipelines/ingestionPipeline';
import { getSeparator } from '../../../utils/CommonUtils';
import { Button } from '../../buttons/Button/Button';
import FilterPattern from '../../common/FilterPattern/FilterPattern';
import RichTextEditor from '../../common/rich-text-editor/RichTextEditor';
import ToggleSwitchV1 from '../../common/toggle-switch/ToggleSwitchV1';
import { Field } from '../../Field/Field';
import { ConfigureIngestionProps } from '../addIngestion.interface';
const ConfigureIngestion = ({
ingestionName,
description = '',
dashboardFilterPattern,
schemaFilterPattern,
tableFilterPattern,
topicFilterPattern,
chartFilterPattern,
fqnFilterPattern,
includeView,
serviceCategory,
enableDataProfiler,
@ -38,11 +43,14 @@ const ConfigureIngestion = ({
showTableFilter,
showTopicFilter,
showChartFilter,
showFqnFilter,
queryLogDuration,
stageFileLocation,
resultLimit,
getExcludeValue,
getIncludeValue,
handleIngestionName,
handleDescription,
handleShowFilter,
handleEnableDataProfiler,
handleIncludeView,
@ -53,7 +61,9 @@ const ConfigureIngestion = ({
onCancel,
onNext,
}: ConfigureIngestionProps) => {
const getFilterPatternField = () => {
const markdownRef = useRef<EditorContentRef>();
const getMetadataFilterPatternField = () => {
switch (serviceCategory) {
case ServiceCategory.DATABASE_SERVICES:
return (
@ -132,10 +142,27 @@ const ConfigureIngestion = ({
}
};
const getProfilerFilterPatternField = () => {
return (
<Fragment>
<FilterPattern
checked={showFqnFilter}
excludePattern={fqnFilterPattern?.excludes ?? []}
getExcludeValue={getExcludeValue}
getIncludeValue={getIncludeValue}
handleChecked={(value) =>
handleShowFilter(value, FilterPatternEnum.FQN)
}
includePattern={fqnFilterPattern?.includes ?? []}
type={FilterPatternEnum.FQN}
/>
</Fragment>
);
};
const getMetadataFields = () => {
return (
<>
<div>{getFilterPatternField()}</div>
<div>{getMetadataFilterPatternField()}</div>
{getSeparator('')}
<div>
<Field>
@ -252,14 +279,72 @@ const ConfigureIngestion = ({
);
};
const getProfilerFields = () => {
return (
<>
<div>
<Field>
<label className="tw-block tw-form-label tw-mb-1" htmlFor="name">
Name
</label>
<p className="tw-text-grey-muted tw-mt-1 tw-mb-2 tw-text-sm">
Name that identifies this pipeline instance uniquely.
</p>
<input
className="tw-form-inputs tw-px-3 tw-py-1"
data-testid="name"
id="name"
name="name"
type="text"
value={ingestionName}
onChange={(e) => handleIngestionName(e.target.value)}
/>
{getSeparator('')}
</Field>
</div>
<div>{getProfilerFilterPatternField()}</div>
{getSeparator('')}
<div>
<Field>
<label className="tw-block tw-form-label tw-mb-1" htmlFor="name">
Description
</label>
<p className="tw-text-grey-muted tw-mt-1 tw-mb-2 tw-text-sm">
Description of the pipeline.
</p>
<RichTextEditor
data-testid="description"
initialValue={description}
ref={markdownRef}
/>
{getSeparator('')}
</Field>
</div>
</>
);
};
const getIngestionPipelineFields = () => {
if (pipelineType === PipelineType.Usage) {
return getUsageFields();
} else {
return getMetadataFields();
switch (pipelineType) {
case PipelineType.Usage: {
return getUsageFields();
}
case PipelineType.Profiler: {
return getProfilerFields();
}
case PipelineType.Metadata:
default: {
return getMetadataFields();
}
}
};
const handleNext = () => {
handleDescription &&
handleDescription(markdownRef.current?.getEditorContent() || '');
onNext();
};
return (
<div className="tw-px-2" data-testid="configure-ingestion-container">
{getIngestionPipelineFields()}
@ -280,7 +365,7 @@ const ConfigureIngestion = ({
size="regular"
theme="primary"
variant="contained"
onClick={onNext}>
onClick={handleNext}>
<span>Next</span>
</Button>
</Field>

View File

@ -27,6 +27,7 @@ jest.mock('../../common/toggle-switch/ToggleSwitchV1', () => {
});
const mockScheduleIntervalProps: ScheduleIntervalProps = {
status: 'initial',
repeatFrequency: '',
handleRepeatFrequencyChange: jest.fn(),
startDate: '',
@ -34,7 +35,7 @@ const mockScheduleIntervalProps: ScheduleIntervalProps = {
endDate: '',
handleEndDateChange: jest.fn(),
onBack: jest.fn(),
onDeloy: jest.fn(),
onDeploy: jest.fn(),
};
describe('Test ScheduleInterval component', () => {

View File

@ -11,13 +11,16 @@
* limitations under the License.
*/
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React from 'react';
import { Button } from '../../buttons/Button/Button';
import CronEditor from '../../common/CronEditor/CronEditor';
import { Field } from '../../Field/Field';
import Loader from '../../Loader/Loader';
import { ScheduleIntervalProps } from '../addIngestion.interface';
const ScheduleInterval = ({
status,
repeatFrequency,
handleRepeatFrequencyChange,
startDate,
@ -25,7 +28,7 @@ const ScheduleInterval = ({
endDate,
handleEndDateChange,
onBack,
onDeloy,
onDeploy,
}: ScheduleIntervalProps) => {
return (
<div data-testid="schedule-intervel-container">
@ -75,14 +78,34 @@ const ScheduleInterval = ({
<span>Back</span>
</Button>
<Button
data-testid="deploy-button"
size="regular"
theme="primary"
variant="contained"
onClick={onDeloy}>
<span>Deploy</span>
</Button>
{status === 'waiting' ? (
<Button
disabled
className="tw-w-16 tw-h-10 disabled:tw-opacity-100"
size="regular"
theme="primary"
variant="contained">
<Loader size="small" type="white" />
</Button>
) : status === 'success' ? (
<Button
disabled
className="tw-w-16 tw-h-10 disabled:tw-opacity-100"
size="regular"
theme="primary"
variant="contained">
<FontAwesomeIcon icon="check" />
</Button>
) : (
<Button
data-testid="deploy-button"
size="regular"
theme="primary"
variant="contained"
onClick={onDeploy}>
<span>Deploy</span>
</Button>
)}
</Field>
</div>
);

View File

@ -11,6 +11,7 @@
* limitations under the License.
*/
import { LoadingState } from 'Models';
import { FilterPatternEnum } from '../../enums/filterPattern.enum';
import { FormSubmitType } from '../../enums/form.enum';
import { ServiceCategory } from '../../enums/service.enum';
@ -47,12 +48,14 @@ export interface AddIngestionProps {
export interface ConfigureIngestionProps {
ingestionName: string;
description?: string;
serviceCategory: ServiceCategory;
dashboardFilterPattern: FilterPattern;
schemaFilterPattern: FilterPattern;
tableFilterPattern: FilterPattern;
topicFilterPattern: FilterPattern;
chartFilterPattern: FilterPattern;
fqnFilterPattern: FilterPattern;
includeView: boolean;
enableDataProfiler: boolean;
ingestSampleData: boolean;
@ -62,9 +65,12 @@ export interface ConfigureIngestionProps {
showTableFilter: boolean;
showTopicFilter: boolean;
showChartFilter: boolean;
showFqnFilter: boolean;
queryLogDuration: number;
stageFileLocation: string;
resultLimit: number;
handleIngestionName: (value: string) => void;
handleDescription?: (value: string) => void;
handleIncludeView: () => void;
handleEnableDataProfiler: () => void;
handleIngestSampleData: () => void;
@ -79,6 +85,7 @@ export interface ConfigureIngestionProps {
}
export type ScheduleIntervalProps = {
status: LoadingState;
repeatFrequency: string;
handleRepeatFrequencyChange: (value: string) => void;
startDate: string;
@ -86,5 +93,5 @@ export type ScheduleIntervalProps = {
endDate: string;
handleEndDateChange: (value: string) => void;
onBack: () => void;
onDeloy: () => void;
onDeploy: () => void;
};

View File

@ -15,8 +15,8 @@ import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classNames from 'classnames';
import cronstrue from 'cronstrue';
import { capitalize, isNil, lowerCase } from 'lodash';
import React, { useCallback, useState } from 'react';
import { capitalize, isNil, lowerCase, startCase } from 'lodash';
import React, { Fragment, useCallback, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
import {
@ -33,13 +33,14 @@ import {
getAddIngestionPath,
getEditIngestionPath,
} from '../../utils/RouterUtils';
import { dropdownIcon as DropdownIcon } from '../../utils/svgconstant';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { showInfoToast } from '../../utils/ToastUtils';
import { Button } from '../buttons/Button/Button';
import NextPrevious from '../common/next-previous/NextPrevious';
import NonAdminAction from '../common/non-admin-action/NonAdminAction';
import PopOver from '../common/popover/PopOver';
import Searchbar from '../common/searchbar/Searchbar';
import DropDownList from '../dropdown/DropDownList';
import Loader from '../Loader/Loader';
import EntityDeleteModal from '../Modals/EntityDeleteModal/EntityDeleteModal';
import { IngestionProps, ModifiedConfig } from './ingestion.interface';
@ -61,6 +62,7 @@ const Ingestion: React.FC<IngestionProps> = ({
const { isAdminUser } = useAuth();
const { isAuthDisabled } = useAuthContext();
const [searchText, setSearchText] = useState('');
const [showActions, setShowActions] = useState(false);
const [currTriggerId, setCurrTriggerId] = useState({ id: '', state: '' });
const [currDeployId, setCurrDeployId] = useState({ id: '', state: '' });
const [isConfirmationModalOpen, setIsConfirmationModalOpen] = useState(false);
@ -84,9 +86,13 @@ const Ingestion: React.FC<IngestionProps> = ({
pipelineType.push(PipelineType.Metadata);
ingestion?.supportsUsageExtraction &&
pipelineType.push(PipelineType.Usage);
ingestion?.supportsProfiler && pipelineType.push(PipelineType.Profiler);
return pipelineType.reduce((prev, curr) => {
if (ingestionList.find((d) => d.pipelineType === curr)) {
if (
curr !== PipelineType.Profiler &&
ingestionList.find((d) => d.pipelineType === curr)
) {
return prev;
} else {
return [...prev, curr];
@ -94,7 +100,7 @@ const Ingestion: React.FC<IngestionProps> = ({
}, [] as PipelineType[]);
}
return [PipelineType.Metadata, PipelineType.Usage];
return [PipelineType.Metadata, PipelineType.Usage, PipelineType.Profiler];
};
const handleTriggerIngestion = (id: string, displayName: string) => {
@ -160,57 +166,84 @@ const Ingestion: React.FC<IngestionProps> = ({
setIsConfirmationModalOpen(true);
};
const handleAddIngestionClick = () => {
const types = getIngestionPipelineTypeOption();
if (!types.length) {
showInfoToast(
`${serviceName} already has all the supported ingestion jobs added.`
);
} else {
history.push(getAddIngestionPath(serviceCategory, serviceName, types[0]));
const handleAddIngestionClick = (type?: PipelineType) => {
setShowActions(false);
if (type) {
history.push(getAddIngestionPath(serviceCategory, serviceName, type));
}
};
const getAddIngestionButton = () => {
const types = getIngestionPipelineTypeOption();
let buttonText;
const getAddIngestionButton = (type: PipelineType) => {
return (
<Button
className={classNames('tw-h-8 tw-rounded tw-mb-2')}
data-testid="add-new-ingestion-button"
size="small"
theme="primary"
variant="contained"
onClick={() => handleAddIngestionClick(type)}>
Add {startCase(type)} Ingestion
</Button>
);
};
switch (types[0]) {
case PipelineType.Metadata: {
buttonText = 'Add Metadata Ingestion';
break;
}
case PipelineType.Usage: {
buttonText = 'Add Usage Ingestion';
break;
}
case PipelineType.Profiler:
default: {
buttonText = '';
break;
}
}
return buttonText ? (
<NonAdminAction position="bottom" title={TITLE_FOR_NON_ADMIN_ACTION}>
const getAddIngestionDropdown = (types: PipelineType[]) => {
return (
<Fragment>
<Button
className={classNames('tw-h-8 tw-rounded tw-mb-2')}
data-testid="add-new-ingestion-button"
disabled={
getIngestionPipelineTypeOption().length === 0 ||
(!isAdminUser && !isAuthDisabled)
}
size="small"
theme="primary"
variant="contained"
onClick={handleAddIngestionClick}>
{buttonText}
onClick={() => setShowActions((pre) => !pre)}>
Add Ingestion{' '}
{showActions ? (
<DropdownIcon
style={{
transform: 'rotate(180deg)',
marginTop: '2px',
color: '#fff',
}}
/>
) : (
<DropdownIcon
style={{
marginTop: '2px',
color: '#fff',
}}
/>
)}
</Button>
</NonAdminAction>
) : null;
{showActions && (
<DropDownList
horzPosRight
dropDownList={types.map((type) => ({
name: `Add ${startCase(type)} Ingestion`,
value: type,
}))}
onSelect={(_e, value) =>
handleAddIngestionClick(value as PipelineType)
}
/>
)}
</Fragment>
);
};
const getAddIngestionElement = () => {
const types = getIngestionPipelineTypeOption();
let element: JSX.Element | null = null;
if (types.length) {
if (types[0] === PipelineType.Metadata || types.length === 1) {
element = getAddIngestionButton(types[0]);
} else {
element = getAddIngestionDropdown(types);
}
}
return element;
};
const getSearchedIngestions = useCallback(() => {
@ -324,7 +357,7 @@ const Ingestion: React.FC<IngestionProps> = ({
</div>
)}
</div>
<div className="tw-flex">
<div className="tw-flex tw-justify-between">
<div className="tw-w-4/12">
{searchText || getSearchedIngestions().length > 0 ? (
<Searchbar
@ -335,8 +368,10 @@ const Ingestion: React.FC<IngestionProps> = ({
/>
) : null}
</div>
<div className="tw-w-8/12 tw-flex tw-justify-end">
{isRequiredDetailsAvailable && getAddIngestionButton()}
<div className="tw-relative">
{isRequiredDetailsAvailable &&
(isAdminUser || isAuthDisabled) &&
getAddIngestionElement()}
</div>
</div>
{getSearchedIngestions().length ? (

View File

@ -17,4 +17,5 @@ export enum FilterPatternEnum {
CHART = 'chart',
DASHBOARD = 'dashboard',
TOPIC = 'topic',
FQN = 'fqn',
}

View File

@ -210,6 +210,25 @@ const ServicePage: FunctionComponent = () => {
}
};
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 getAllIngestionWorkflows = (paging?: string) => {
setIsloading(true);
getIngestionPipelines(['owner', 'pipelineStatuses'], serviceFQN, paging)
@ -230,25 +249,11 @@ const ServicePage: FunctionComponent = () => {
jsonData['api-error-messages']['fetch-ingestion-error']
);
})
.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'];
.finally(() => {
setIsloading(false);
if (!airflowEndpoint) {
getAirflowEndpoint();
}
})
.catch((err: AxiosError) => {
showErrorToast(
err,
jsonData['api-error-messages']['fetch-airflow-config-error']
);
});
};
@ -678,7 +683,6 @@ const ServicePage: FunctionComponent = () => {
// getDatabaseServices();
getAllIngestionWorkflows();
}
getAirflowEndpoint();
}, []);
const onCancel = () => {

View File

@ -12,6 +12,7 @@
*/
import { AxiosResponse } from 'axios';
import cryptoRandomString from 'crypto-random-string-with-promisify-polyfill';
import {
Bucket,
DynamicFormFieldType,
@ -543,3 +544,17 @@ export const getServiceIngestionStepGuide = (
</>
);
};
export const getIngestionName = (
serviceName: string,
type: IngestionPipelineType
) => {
if (type === IngestionPipelineType.Profiler) {
return `${serviceName}_${type}_${cryptoRandomString({
length: 8,
type: 'alphanumeric',
})}`;
} else {
return `${serviceName}_${type}`;
}
};