mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-18 14:06:59 +00:00
Addressing service page changes (#2421)
* Addressing service page changes * Reverting unnecessary change * Minor change
This commit is contained in:
parent
3aefe3636b
commit
e7e5a4dd2c
@ -24,7 +24,7 @@ export const getAirflowPipelines = (
|
|||||||
serviceFilter?: string,
|
serviceFilter?: string,
|
||||||
paging?: string
|
paging?: string
|
||||||
): Promise<AxiosResponse> => {
|
): Promise<AxiosResponse> => {
|
||||||
const service = `"service="${serviceFilter}`;
|
const service = `service=${serviceFilter}`;
|
||||||
const url = `${getURLWithQueryFields(
|
const url = `${getURLWithQueryFields(
|
||||||
'/airflowPipeline',
|
'/airflowPipeline',
|
||||||
arrQueryFields,
|
arrQueryFields,
|
||||||
|
@ -15,13 +15,7 @@ import classNames from 'classnames';
|
|||||||
import cronstrue from 'cronstrue';
|
import cronstrue from 'cronstrue';
|
||||||
import { capitalize, isNil, lowerCase } from 'lodash';
|
import { capitalize, isNil, lowerCase } from 'lodash';
|
||||||
import React, { Fragment, useCallback, useState } from 'react';
|
import React, { Fragment, useCallback, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { TITLE_FOR_NON_ADMIN_ACTION } from '../../constants/constants';
|
||||||
import {
|
|
||||||
getServiceDetailsPath,
|
|
||||||
TITLE_FOR_NON_ADMIN_ACTION,
|
|
||||||
} from '../../constants/constants';
|
|
||||||
import { NoDataFoundPlaceHolder } from '../../constants/services.const';
|
|
||||||
import { ServiceCategory } from '../../enums/service.enum';
|
|
||||||
import {
|
import {
|
||||||
AirflowPipeline,
|
AirflowPipeline,
|
||||||
ConfigObject,
|
ConfigObject,
|
||||||
@ -42,6 +36,7 @@ import { Props } from './ingestion.interface';
|
|||||||
|
|
||||||
const Ingestion: React.FC<Props> = ({
|
const Ingestion: React.FC<Props> = ({
|
||||||
serviceType = '',
|
serviceType = '',
|
||||||
|
serviceName,
|
||||||
ingestionList,
|
ingestionList,
|
||||||
serviceList,
|
serviceList,
|
||||||
deleteIngestion,
|
deleteIngestion,
|
||||||
@ -183,13 +178,6 @@ const Ingestion: React.FC<Props> = ({
|
|||||||
setIsConfirmationModalOpen(true);
|
setIsConfirmationModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getServiceTypeFromName = (serviceName = ''): string => {
|
|
||||||
return (
|
|
||||||
serviceList.find((service) => service.name === serviceName)
|
|
||||||
?.serviceType || ''
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSearchedIngestions = useCallback(() => {
|
const getSearchedIngestions = useCallback(() => {
|
||||||
const sText = lowerCase(searchText);
|
const sText = lowerCase(searchText);
|
||||||
|
|
||||||
@ -290,7 +278,6 @@ const Ingestion: React.FC<Props> = ({
|
|||||||
<tr className="tableHead-row" data-testid="table-header">
|
<tr className="tableHead-row" data-testid="table-header">
|
||||||
<th className="tableHead-cell">Name</th>
|
<th className="tableHead-cell">Name</th>
|
||||||
<th className="tableHead-cell">Type</th>
|
<th className="tableHead-cell">Type</th>
|
||||||
<th className="tableHead-cell">Service</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">Next Run</th> */}
|
{/* <th className="tableHead-cell">Next Run</th> */}
|
||||||
@ -307,17 +294,6 @@ const Ingestion: React.FC<Props> = ({
|
|||||||
key={index}>
|
key={index}>
|
||||||
<td className="tableBody-cell">{ingestion.name}</td>
|
<td className="tableBody-cell">{ingestion.name}</td>
|
||||||
<td className="tableBody-cell">{ingestion.pipelineType}</td>
|
<td className="tableBody-cell">{ingestion.pipelineType}</td>
|
||||||
<td className="tableBody-cell">
|
|
||||||
<Link
|
|
||||||
to={getServiceDetailsPath(
|
|
||||||
ingestion.service.name as string,
|
|
||||||
getServiceTypeFromName(ingestion.service.name),
|
|
||||||
// TODO: Add logic below to select service-cat if necessary
|
|
||||||
ServiceCategory.DATABASE_SERVICES
|
|
||||||
)}>
|
|
||||||
{ingestion.service.name}
|
|
||||||
</Link>
|
|
||||||
</td>
|
|
||||||
<td className="tableBody-cell">
|
<td className="tableBody-cell">
|
||||||
<PopOver
|
<PopOver
|
||||||
html={
|
html={
|
||||||
@ -414,9 +390,6 @@ const Ingestion: React.FC<Props> = ({
|
|||||||
) : (
|
) : (
|
||||||
<div className="tw-flex tw-items-center tw-flex-col">
|
<div className="tw-flex tw-items-center tw-flex-col">
|
||||||
<div className="tw-mt-24">
|
<div className="tw-mt-24">
|
||||||
<img alt="No Service" src={NoDataFoundPlaceHolder} width={250} />
|
|
||||||
</div>
|
|
||||||
<div className="tw-mt-11">
|
|
||||||
<p className="tw-text-lg tw-text-center">
|
<p className="tw-text-lg tw-text-center">
|
||||||
{`No ingestion workflows found ${
|
{`No ingestion workflows found ${
|
||||||
searchText ? `for "${searchText}"` : ''
|
searchText ? `for "${searchText}"` : ''
|
||||||
@ -436,7 +409,7 @@ const Ingestion: React.FC<Props> = ({
|
|||||||
ingestionList={ingestionList}
|
ingestionList={ingestionList}
|
||||||
ingestionTypes={getAirflowPipelineTypeOption()}
|
ingestionTypes={getAirflowPipelineTypeOption()}
|
||||||
name=""
|
name=""
|
||||||
service=""
|
service={serviceName}
|
||||||
serviceList={serviceList.map((s) => ({
|
serviceList={serviceList.map((s) => ({
|
||||||
name: s.name,
|
name: s.name,
|
||||||
serviceType: s.serviceType,
|
serviceType: s.serviceType,
|
||||||
@ -452,6 +425,7 @@ const Ingestion: React.FC<Props> = ({
|
|||||||
ingestionList={ingestionList}
|
ingestionList={ingestionList}
|
||||||
ingestionTypes={getAirflowPipelineTypes(serviceType) || []}
|
ingestionTypes={getAirflowPipelineTypes(serviceType) || []}
|
||||||
selectedIngestion={updateSelection.ingestion}
|
selectedIngestion={updateSelection.ingestion}
|
||||||
|
service={serviceName}
|
||||||
serviceList={serviceList.map((s) => ({
|
serviceList={serviceList.map((s) => ({
|
||||||
name: s.name,
|
name: s.name,
|
||||||
serviceType: s.serviceType,
|
serviceType: s.serviceType,
|
||||||
|
@ -50,6 +50,7 @@ export interface IngestionData {
|
|||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
serviceType?: string;
|
serviceType?: string;
|
||||||
|
serviceName?: string;
|
||||||
paging: Paging;
|
paging: Paging;
|
||||||
ingestionList: Array<AirflowPipeline>;
|
ingestionList: Array<AirflowPipeline>;
|
||||||
serviceList: Array<DatabaseService>;
|
serviceList: Array<DatabaseService>;
|
||||||
|
@ -27,7 +27,6 @@ import {
|
|||||||
getCurrentUserId,
|
getCurrentUserId,
|
||||||
getSeparator,
|
getSeparator,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
import { getIngestionTypeList } from '../../utils/ServiceUtils';
|
|
||||||
import SVGIcons from '../../utils/SvgUtils';
|
import SVGIcons from '../../utils/SvgUtils';
|
||||||
import { Button } from '../buttons/Button/Button';
|
import { Button } from '../buttons/Button/Button';
|
||||||
import CronEditor from '../common/CronEditor/CronEditor';
|
import CronEditor from '../common/CronEditor/CronEditor';
|
||||||
@ -87,10 +86,6 @@ const PreviewSection = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getServiceName = (service: string) => {
|
|
||||||
return service.split('$$').splice(1).join('$$');
|
|
||||||
};
|
|
||||||
|
|
||||||
const getIngestionName = (name: string) => {
|
const getIngestionName = (name: string) => {
|
||||||
const nameString = name.trim().replace(/\s+/g, '_');
|
const nameString = name.trim().replace(/\s+/g, '_');
|
||||||
|
|
||||||
@ -100,7 +95,7 @@ const getIngestionName = (name: string) => {
|
|||||||
const IngestionModal: React.FC<IngestionModalProps> = ({
|
const IngestionModal: React.FC<IngestionModalProps> = ({
|
||||||
isUpdating,
|
isUpdating,
|
||||||
header,
|
header,
|
||||||
serviceList = [], // TODO: remove default assignment after resolving prop validation warning
|
service,
|
||||||
ingestionTypes,
|
ingestionTypes,
|
||||||
ingestionList,
|
ingestionList,
|
||||||
onCancel,
|
onCancel,
|
||||||
@ -121,14 +116,11 @@ const IngestionModal: React.FC<IngestionModalProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const [ingestionName, setIngestionName] = useState<string>(
|
const [ingestionName, setIngestionName] = useState<string>(
|
||||||
selectedIngestion?.name || ''
|
selectedIngestion?.name || service || ''
|
||||||
);
|
);
|
||||||
const [ingestionType, setIngestionType] = useState<string>(
|
const [ingestionType, setIngestionType] = useState<string>(
|
||||||
selectedIngestion?.pipelineType || ''
|
selectedIngestion?.pipelineType || ''
|
||||||
);
|
);
|
||||||
const [ingestionService, setIngestionService] = useState<string>(
|
|
||||||
selectedIngestion?.service.name || ''
|
|
||||||
);
|
|
||||||
const [pipelineConfig] = useState(
|
const [pipelineConfig] = useState(
|
||||||
(selectedIngestion?.pipelineConfig.config || {}) as ConfigObject
|
(selectedIngestion?.pipelineConfig.config || {}) as ConfigObject
|
||||||
);
|
);
|
||||||
@ -171,16 +163,6 @@ const IngestionModal: React.FC<IngestionModalProps> = ({
|
|||||||
isPipelineNameExists: false,
|
isPipelineNameExists: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const isPipelineExists = () => {
|
|
||||||
return ingestionList.some(
|
|
||||||
(i) =>
|
|
||||||
i.service.name === getServiceName(ingestionService) &&
|
|
||||||
i.pipelineType === ingestionType &&
|
|
||||||
i.service.name !== selectedIngestion?.name &&
|
|
||||||
i.service.displayName === selectedIngestion?.pipelineType
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const isPipeLineNameExists = () => {
|
const isPipeLineNameExists = () => {
|
||||||
return ingestionList.some(
|
return ingestionList.some(
|
||||||
(i) =>
|
(i) =>
|
||||||
@ -196,17 +178,9 @@ const IngestionModal: React.FC<IngestionModalProps> = ({
|
|||||||
const name = event.target.name;
|
const name = event.target.name;
|
||||||
|
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'name':
|
|
||||||
setIngestionName(value);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'selectService':
|
|
||||||
setIngestionService(value);
|
|
||||||
setIngestionType('');
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'ingestionType':
|
case 'ingestionType':
|
||||||
setIngestionType(value);
|
setIngestionType(value);
|
||||||
|
setIngestionName(`${service}_${value}`);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -228,28 +202,14 @@ const IngestionModal: React.FC<IngestionModalProps> = ({
|
|||||||
let isValid = false;
|
let isValid = false;
|
||||||
switch (activeStep) {
|
switch (activeStep) {
|
||||||
case 1:
|
case 1:
|
||||||
isValid = Boolean(
|
isValid = Boolean(ingestionName && ingestionType);
|
||||||
ingestionName && ingestionType && !isPipelineExists()
|
|
||||||
);
|
|
||||||
setShowErrorMsg({
|
setShowErrorMsg({
|
||||||
...showErrorMsg,
|
...showErrorMsg,
|
||||||
name: !ingestionName,
|
name: !ingestionName,
|
||||||
ingestionType: !ingestionType,
|
ingestionType: !ingestionType,
|
||||||
selectService: !ingestionService,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
// case 2:
|
|
||||||
// isValid = Boolean(username && password && host && database);
|
|
||||||
// setShowErrorMsg({
|
|
||||||
// ...showErrorMsg,
|
|
||||||
// username: !username,
|
|
||||||
// password: !password,
|
|
||||||
// host: !host,
|
|
||||||
// database: !database,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// break;
|
|
||||||
case 2:
|
case 2:
|
||||||
isValid = Boolean(ingestionSchedule);
|
isValid = Boolean(ingestionSchedule);
|
||||||
setShowErrorMsg({
|
setShowErrorMsg({
|
||||||
@ -267,91 +227,6 @@ const IngestionModal: React.FC<IngestionModalProps> = ({
|
|||||||
|
|
||||||
const getActiveStepFields = (activeStep: number) => {
|
const getActiveStepFields = (activeStep: number) => {
|
||||||
switch (activeStep) {
|
switch (activeStep) {
|
||||||
case 10:
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<Field>
|
|
||||||
<label className="tw-block" htmlFor="name">
|
|
||||||
{requiredField('Name:')}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
className={classNames('tw-form-inputs tw-px-3 tw-py-1', {
|
|
||||||
'tw-cursor-not-allowed': isUpdating,
|
|
||||||
})}
|
|
||||||
data-testid="name"
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
placeholder="Ingestion name"
|
|
||||||
readOnly={isUpdating}
|
|
||||||
type="text"
|
|
||||||
value={ingestionName}
|
|
||||||
onChange={handleValidation}
|
|
||||||
/>
|
|
||||||
{showErrorMsg.name && errorMsg('Ingestion Name is required')}
|
|
||||||
{showErrorMsg.isPipelineNameExists &&
|
|
||||||
errorMsg(`Ingestion with similar name already exists.`)}
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
<Field>
|
|
||||||
<label className="tw-block" htmlFor="selectService">
|
|
||||||
{requiredField('Select Service:')}
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className={classNames('tw-form-inputs tw-px-3 tw-py-1', {
|
|
||||||
'tw-cursor-not-allowed': isUpdating,
|
|
||||||
})}
|
|
||||||
data-testid="select-service"
|
|
||||||
disabled={isUpdating}
|
|
||||||
id="selectService"
|
|
||||||
name="selectService"
|
|
||||||
value={ingestionService}
|
|
||||||
onChange={handleValidation}>
|
|
||||||
<option value="">Select Service</option>
|
|
||||||
{serviceList.map((service, index) => (
|
|
||||||
<option
|
|
||||||
key={index}
|
|
||||||
value={`${service.serviceType}$$${service.name}`}>
|
|
||||||
{service.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
{showErrorMsg.selectService && errorMsg('Service is required')}
|
|
||||||
</Field>
|
|
||||||
<Field>
|
|
||||||
<label className="tw-block " htmlFor="ingestionType">
|
|
||||||
{requiredField('Type of ingestion:')}
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className={classNames('tw-form-inputs tw-px-3 tw-py-1', {
|
|
||||||
'tw-cursor-not-allowed': !ingestionService,
|
|
||||||
})}
|
|
||||||
data-testid="ingestion-type"
|
|
||||||
disabled={!ingestionService || isUpdating}
|
|
||||||
id="ingestionType"
|
|
||||||
name="ingestionType"
|
|
||||||
value={ingestionType}
|
|
||||||
onChange={handleValidation}>
|
|
||||||
<option value="">Select ingestion type</option>
|
|
||||||
{(
|
|
||||||
getIngestionTypeList(ingestionService?.split('$$')?.[0]) || []
|
|
||||||
).map((service, index) => (
|
|
||||||
<option key={index} value={service}>
|
|
||||||
{service}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
{showErrorMsg.ingestionType &&
|
|
||||||
errorMsg('Ingestion Type is required')}
|
|
||||||
{showErrorMsg.isPipelineExists &&
|
|
||||||
errorMsg(
|
|
||||||
`Ingestion with service ${getServiceName(
|
|
||||||
ingestionService
|
|
||||||
)} and ingestion-type ${ingestionType} already exists `
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
@ -360,17 +235,16 @@ const IngestionModal: React.FC<IngestionModalProps> = ({
|
|||||||
{requiredField('Name:')}
|
{requiredField('Name:')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
className={classNames('tw-form-inputs tw-px-3 tw-py-1', {
|
disabled
|
||||||
'tw-cursor-not-allowed': isUpdating,
|
className={classNames(
|
||||||
})}
|
'tw-form-inputs tw-px-3 tw-py-1 tw-cursor-not-allowed'
|
||||||
|
)}
|
||||||
data-testid="name"
|
data-testid="name"
|
||||||
id="name"
|
id="name"
|
||||||
name="name"
|
name="name"
|
||||||
placeholder="Ingestion name"
|
placeholder="Ingestion name"
|
||||||
readOnly={isUpdating}
|
|
||||||
type="text"
|
type="text"
|
||||||
value={ingestionName}
|
value={ingestionName}
|
||||||
onChange={handleValidation}
|
|
||||||
/>
|
/>
|
||||||
{showErrorMsg.name && errorMsg('Ingestion Name is required')}
|
{showErrorMsg.name && errorMsg('Ingestion Name is required')}
|
||||||
{showErrorMsg.isPipelineNameExists &&
|
{showErrorMsg.isPipelineNameExists &&
|
||||||
@ -400,12 +274,6 @@ const IngestionModal: React.FC<IngestionModalProps> = ({
|
|||||||
</select>
|
</select>
|
||||||
{showErrorMsg.ingestionType &&
|
{showErrorMsg.ingestionType &&
|
||||||
errorMsg('Ingestion Type is required')}
|
errorMsg('Ingestion Type is required')}
|
||||||
{showErrorMsg.isPipelineExists &&
|
|
||||||
errorMsg(
|
|
||||||
`Ingestion with service ${getServiceName(
|
|
||||||
ingestionService
|
|
||||||
)} and ingestion-type ${ingestionType} already exists `
|
|
||||||
)}
|
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
@ -679,27 +547,6 @@ const IngestionModal: React.FC<IngestionModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onSaveHandler = (triggerIngestion = false) => {
|
const onSaveHandler = (triggerIngestion = false) => {
|
||||||
// const ingestionData = {
|
|
||||||
// ingestionType: ingestionType,
|
|
||||||
// displayName: ingestionName,
|
|
||||||
// name: getIngestionName(ingestionName),
|
|
||||||
// service: { name: getServiceName(ingestionService), id: '', type: '' },
|
|
||||||
// startDate: startDate || getCurrentDate(),
|
|
||||||
// endDate: endDate || '',
|
|
||||||
// scheduleInterval: ingestionSchedule,
|
|
||||||
// forceDeploy: true,
|
|
||||||
// connectorConfig: {
|
|
||||||
// database: database,
|
|
||||||
// enableDataProfiler: excludeDataProfiler,
|
|
||||||
// excludeFilterPattern: excludeFilterPattern,
|
|
||||||
// host: host,
|
|
||||||
// includeFilterPattern: includeFilterPattern,
|
|
||||||
// includeViews: includeViews,
|
|
||||||
// password: password,
|
|
||||||
// username: username,
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
|
|
||||||
const ingestionObj: AirflowPipeline = {
|
const ingestionObj: AirflowPipeline = {
|
||||||
name: ingestionName,
|
name: ingestionName,
|
||||||
pipelineConfig: {
|
pipelineConfig: {
|
||||||
@ -762,7 +609,7 @@ const IngestionModal: React.FC<IngestionModalProps> = ({
|
|||||||
// isPipelineExists: isPipelineExists(),
|
// isPipelineExists: isPipelineExists(),
|
||||||
isPipelineNameExists: isPipeLineNameExists(),
|
isPipelineNameExists: isPipeLineNameExists(),
|
||||||
});
|
});
|
||||||
}, [ingestionType, ingestionService, ingestionName]);
|
}, [ingestionType, ingestionName]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (endDate) {
|
if (endDate) {
|
||||||
|
@ -23,6 +23,7 @@ import React, {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import { ONLY_NUMBER_REGEX } from '../../../constants/constants';
|
||||||
import { serviceTypes } from '../../../constants/services.const';
|
import { serviceTypes } from '../../../constants/services.const';
|
||||||
import {
|
import {
|
||||||
DashboardServiceType,
|
DashboardServiceType,
|
||||||
@ -37,6 +38,7 @@ import {
|
|||||||
import { DatabaseService } from '../../../generated/entity/services/databaseService';
|
import { DatabaseService } from '../../../generated/entity/services/databaseService';
|
||||||
import { MessagingService } from '../../../generated/entity/services/messagingService';
|
import { MessagingService } from '../../../generated/entity/services/messagingService';
|
||||||
import { PipelineService } from '../../../generated/entity/services/pipelineService';
|
import { PipelineService } from '../../../generated/entity/services/pipelineService';
|
||||||
|
import { PipelineType } from '../../../generated/operations/pipelines/airflowPipeline';
|
||||||
import { useAuth } from '../../../hooks/authHooks';
|
import { useAuth } from '../../../hooks/authHooks';
|
||||||
import {
|
import {
|
||||||
errorMsg,
|
errorMsg,
|
||||||
@ -146,6 +148,7 @@ type ErrorMsg = {
|
|||||||
selectService: boolean;
|
selectService: boolean;
|
||||||
name: boolean;
|
name: boolean;
|
||||||
url?: boolean;
|
url?: boolean;
|
||||||
|
port?: boolean;
|
||||||
driverClass?: boolean;
|
driverClass?: boolean;
|
||||||
broker?: boolean;
|
broker?: boolean;
|
||||||
dashboardUrl?: boolean;
|
dashboardUrl?: boolean;
|
||||||
@ -296,7 +299,12 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
const [existingNames] = useState(generateName(serviceList));
|
const [existingNames] = useState(generateName(serviceList));
|
||||||
const [selectService, setSelectService] = useState(data?.serviceType || '');
|
const [selectService, setSelectService] = useState(data?.serviceType || '');
|
||||||
const [name, setName] = useState(data?.name || '');
|
const [name, setName] = useState(data?.name || '');
|
||||||
const [url, setUrl] = useState(data?.databaseConnection?.hostPort || '');
|
const [url, setUrl] = useState(
|
||||||
|
data?.databaseConnection?.hostPort.split(':')[0] || ''
|
||||||
|
);
|
||||||
|
const [port, setPort] = useState(
|
||||||
|
data?.databaseConnection?.hostPort.split(':')[1] || ''
|
||||||
|
);
|
||||||
const [database, setDatabase] = useState(
|
const [database, setDatabase] = useState(
|
||||||
data?.databaseConnection?.database || ''
|
data?.databaseConnection?.database || ''
|
||||||
);
|
);
|
||||||
@ -329,6 +337,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
selectService: false,
|
selectService: false,
|
||||||
name: false,
|
name: false,
|
||||||
url: false,
|
url: false,
|
||||||
|
port: false,
|
||||||
driverClass: false,
|
driverClass: false,
|
||||||
broker: false,
|
broker: false,
|
||||||
dashboardUrl: false,
|
dashboardUrl: false,
|
||||||
@ -386,6 +395,14 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
|
|
||||||
case 'name':
|
case 'name':
|
||||||
setName(value);
|
setName(value);
|
||||||
|
setIngestionTypeList(
|
||||||
|
ingestionTypeList?.map((d) => {
|
||||||
|
return {
|
||||||
|
...d,
|
||||||
|
ingestionName: `${value}_${PipelineType.Metadata}`,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -394,6 +411,13 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'port':
|
||||||
|
if (ONLY_NUMBER_REGEX.test(value) || value === '') {
|
||||||
|
setPort(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -452,7 +476,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
dataObj = {
|
dataObj = {
|
||||||
...dataObj,
|
...dataObj,
|
||||||
databaseConnection: {
|
databaseConnection: {
|
||||||
hostPort: url,
|
hostPort: `${url}:${port}`,
|
||||||
connectionArguments: getKeyValueObject(connectionArguments),
|
connectionArguments: getKeyValueObject(connectionArguments),
|
||||||
connectionOptions: getKeyValueObject(connectionOptions),
|
connectionOptions: getKeyValueObject(connectionOptions),
|
||||||
database: database,
|
database: database,
|
||||||
@ -556,7 +580,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
generateSampleData: value.ingestSampleData,
|
generateSampleData: value.ingestSampleData,
|
||||||
enableDataProfiler: value.enableDataProfiler,
|
enableDataProfiler: value.enableDataProfiler,
|
||||||
schemaFilterPattern:
|
schemaFilterPattern:
|
||||||
!isEmpty(schemaIncludePattern) &&
|
!isEmpty(schemaIncludePattern) ||
|
||||||
!isEmpty(schemaExcludePattern)
|
!isEmpty(schemaExcludePattern)
|
||||||
? {
|
? {
|
||||||
includes: !isEmpty(schemaIncludePattern)
|
includes: !isEmpty(schemaIncludePattern)
|
||||||
@ -572,7 +596,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
tableFilterPattern:
|
tableFilterPattern:
|
||||||
!isEmpty(tableIncludePattern) &&
|
!isEmpty(tableIncludePattern) ||
|
||||||
!isEmpty(tableExcludePattern)
|
!isEmpty(tableExcludePattern)
|
||||||
? {
|
? {
|
||||||
includes: !isEmpty(tableIncludePattern)
|
includes: !isEmpty(tableIncludePattern)
|
||||||
@ -625,10 +649,11 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
setMsg = {
|
setMsg = {
|
||||||
...setMsg,
|
...setMsg,
|
||||||
url: !url,
|
url: !url,
|
||||||
|
port: !port,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid = Boolean(url);
|
isValid = Boolean(url && port);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ServiceCategory.MESSAGING_SERVICES:
|
case ServiceCategory.MESSAGING_SERVICES:
|
||||||
@ -759,21 +784,37 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="tw-mt-4 tw-grid tw-grid-cols-3 tw-gap-2 ">
|
<div className="tw-mt-4 tw-grid tw-grid-cols-3 tw-gap-2 ">
|
||||||
<div className="tw-col-span-3">
|
<div className="tw-col-span-2">
|
||||||
<label className="tw-block tw-form-label" htmlFor="url">
|
<label className="tw-block tw-form-label" htmlFor="url">
|
||||||
{requiredField('Host Port:')}
|
{requiredField('Host:')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
className="tw-form-inputs tw-px-3 tw-py-1"
|
className="tw-form-inputs tw-px-3 tw-py-1"
|
||||||
data-testid="url"
|
data-testid="url"
|
||||||
id="url"
|
id="url"
|
||||||
name="url"
|
name="url"
|
||||||
placeholder="http(s)://hostname:port"
|
placeholder="hostname"
|
||||||
type="text"
|
type="text"
|
||||||
value={url}
|
value={url}
|
||||||
onChange={handleValidation}
|
onChange={handleValidation}
|
||||||
/>
|
/>
|
||||||
{showErrorMsg.url && errorMsg('Host port is required')}
|
{showErrorMsg.url && errorMsg('Host name is required')}
|
||||||
|
</div>
|
||||||
|
<div className="">
|
||||||
|
<label className="tw-block tw-form-label" htmlFor="port">
|
||||||
|
{requiredField('Port:')}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
className="tw-form-inputs tw-px-3 tw-py-1"
|
||||||
|
data-testid="port"
|
||||||
|
id="port"
|
||||||
|
name="port"
|
||||||
|
placeholder="port"
|
||||||
|
type="text"
|
||||||
|
value={port}
|
||||||
|
onChange={handleValidation}
|
||||||
|
/>
|
||||||
|
{showErrorMsg.port && errorMsg('Port is required')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Field>
|
<Field>
|
||||||
@ -1271,9 +1312,13 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
case ServiceCategory.DATABASE_SERVICES:
|
case ServiceCategory.DATABASE_SERVICES:
|
||||||
data = [
|
data = [
|
||||||
{
|
{
|
||||||
key: 'Host Port',
|
key: 'Host',
|
||||||
value: url,
|
value: url,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'Port',
|
||||||
|
value: port,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (username) {
|
if (username) {
|
||||||
@ -1553,7 +1598,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
if (ingestionTypeList) {
|
if (ingestionTypeList) {
|
||||||
let noErrorListCount = 0;
|
let noErrorListCount = 0;
|
||||||
const newFormValue = ingestionTypeList.map((value) => {
|
const newFormValue = ingestionTypeList.map((value) => {
|
||||||
if (isEmpty(value.ingestionName)) {
|
if (isEmpty(value.ingestionName) && value.isIngestionActive) {
|
||||||
isValid = false;
|
isValid = false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -1707,11 +1752,9 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
{requiredField('Ingestion name:')}
|
{requiredField('Ingestion name:')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
|
disabled
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'tw-form-inputs tw-px-3 tw-py-1',
|
'tw-form-inputs tw-px-3 tw-py-1 tw-cursor-not-allowed'
|
||||||
{
|
|
||||||
'tw-cursor-not-allowed': false,
|
|
||||||
}
|
|
||||||
)}
|
)}
|
||||||
data-testid="ingestionName"
|
data-testid="ingestionName"
|
||||||
id="ingestionName"
|
id="ingestionName"
|
||||||
@ -1719,18 +1762,11 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
placeholder="Ingestion name"
|
placeholder="Ingestion name"
|
||||||
type="text"
|
type="text"
|
||||||
value={type.ingestionName}
|
value={type.ingestionName}
|
||||||
onChange={(e) => {
|
|
||||||
const newFormValues = [...ingestionTypeList];
|
|
||||||
newFormValues[id].ingestionName = e.target.value;
|
|
||||||
newFormValues[id].showError = Boolean(e.target.value);
|
|
||||||
setIngestionTypeList(newFormValues);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
{type.showError &&
|
{type.showError &&
|
||||||
|
type.isIngestionActive &&
|
||||||
isEmpty(type.ingestionName) &&
|
isEmpty(type.ingestionName) &&
|
||||||
errorMsg('Ingestion Name is required')}
|
errorMsg('Ingestion Name is required')}
|
||||||
{/* {showErrorMsg.isPipelineNameExists &&
|
|
||||||
errorMsg(`Ingestion with similar name already exists.`)} */}
|
|
||||||
</Field>
|
</Field>
|
||||||
<Field>
|
<Field>
|
||||||
{getSeparator('Table Filter Pattern')}
|
{getSeparator('Table Filter Pattern')}
|
||||||
@ -1994,9 +2030,9 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
|
|
||||||
{Boolean(ingestionTypeList && ingestionTypeList.length) && (
|
{Boolean(ingestionTypeList && ingestionTypeList.length) && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{ingestionTypeList?.map((value) => {
|
{ingestionTypeList?.map((value, i) => {
|
||||||
return value.isIngestionActive ? (
|
return value.isIngestionActive ? (
|
||||||
<>
|
<Fragment key={i}>
|
||||||
<PreviewSection
|
<PreviewSection
|
||||||
className="tw-mb-4 tw-mt-4"
|
className="tw-mb-4 tw-mt-4"
|
||||||
data={[
|
data={[
|
||||||
@ -2082,10 +2118,8 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
header="Schema Filter Patterns"
|
header="Schema Filter Patterns"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</Fragment>
|
||||||
) : (
|
) : null;
|
||||||
<></>
|
|
||||||
);
|
|
||||||
})}
|
})}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
|
@ -39,7 +39,7 @@ const Description = ({
|
|||||||
owner,
|
owner,
|
||||||
hasEditAccess,
|
hasEditAccess,
|
||||||
onDescriptionEdit,
|
onDescriptionEdit,
|
||||||
description,
|
description = '',
|
||||||
isEdit,
|
isEdit,
|
||||||
onCancel,
|
onCancel,
|
||||||
onDescriptionUpdate,
|
onDescriptionUpdate,
|
||||||
|
@ -51,6 +51,8 @@ const PLACEHOLDER_ROUTE_ENTITY_FQN = ':entityFQN';
|
|||||||
|
|
||||||
export const pagingObject = { after: '', before: '' };
|
export const pagingObject = { after: '', before: '' };
|
||||||
|
|
||||||
|
export const ONLY_NUMBER_REGEX = /^[0-9\b]+$/;
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
export const tiers = [
|
export const tiers = [
|
||||||
{ key: 'Tier.Tier1', doc_count: 0 },
|
{ key: 'Tier.Tier1', doc_count: 0 },
|
||||||
|
@ -65,7 +65,6 @@ import { EntityReference } from '../../generated/type/entityReference';
|
|||||||
import useToastContext from '../../hooks/useToastContext';
|
import useToastContext from '../../hooks/useToastContext';
|
||||||
import { isEven } from '../../utils/CommonUtils';
|
import { isEven } from '../../utils/CommonUtils';
|
||||||
import {
|
import {
|
||||||
getFrequencyTime,
|
|
||||||
getIsIngestionEnable,
|
getIsIngestionEnable,
|
||||||
getServiceCategoryFromType,
|
getServiceCategoryFromType,
|
||||||
serviceTypeLogo,
|
serviceTypeLogo,
|
||||||
@ -108,9 +107,23 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
const [ingestionPaging, setIngestionPaging] = useState<Paging>({} as Paging);
|
const [ingestionPaging, setIngestionPaging] = useState<Paging>({} as Paging);
|
||||||
const showToast = useToastContext();
|
const showToast = useToastContext();
|
||||||
|
|
||||||
|
const getCountLabel = () => {
|
||||||
|
switch (serviceName) {
|
||||||
|
case ServiceCategory.DASHBOARD_SERVICES:
|
||||||
|
return 'Dashboards';
|
||||||
|
case ServiceCategory.MESSAGING_SERVICES:
|
||||||
|
return 'Topics';
|
||||||
|
case ServiceCategory.PIPELINE_SERVICES:
|
||||||
|
return 'Pipelines';
|
||||||
|
case ServiceCategory.DATABASE_SERVICES:
|
||||||
|
default:
|
||||||
|
return 'Databases';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
name: 'Database',
|
name: getCountLabel(),
|
||||||
icon: {
|
icon: {
|
||||||
alt: 'schema',
|
alt: 'schema',
|
||||||
name: 'icon-database',
|
name: 'icon-database',
|
||||||
@ -119,6 +132,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
},
|
},
|
||||||
isProtected: false,
|
isProtected: false,
|
||||||
position: 1,
|
position: 1,
|
||||||
|
count: instanceCount,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Ingestions',
|
name: 'Ingestions',
|
||||||
@ -131,6 +145,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
isHidden: !isIngestionEnable,
|
isHidden: !isIngestionEnable,
|
||||||
isProtected: false,
|
isProtected: false,
|
||||||
position: 2,
|
position: 2,
|
||||||
|
count: ingestions.length,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -152,7 +167,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getAllIngestionWorkflows = (paging?: string) => {
|
const getAllIngestionWorkflows = (paging?: string) => {
|
||||||
getAirflowPipelines(['owner, tags, status'], serviceName, paging)
|
getAirflowPipelines(['owner, tags, status'], serviceFQN, paging)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.data.data) {
|
if (res.data.data) {
|
||||||
setIngestions(res.data.data);
|
setIngestions(res.data.data);
|
||||||
@ -412,19 +427,6 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
|
|
||||||
const getOptionalFields = (): JSX.Element => {
|
const getOptionalFields = (): JSX.Element => {
|
||||||
switch (serviceName) {
|
switch (serviceName) {
|
||||||
case ServiceCategory.DATABASE_SERVICES: {
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
<span className="tw-text-grey-muted tw-font-normal">
|
|
||||||
Driver Class :
|
|
||||||
</span>{' '}
|
|
||||||
<span className="tw-pl-1tw-font-normal ">
|
|
||||||
{serviceDetails?.jdbc?.driverClass || '--'}
|
|
||||||
</span>
|
|
||||||
<span className="tw-mx-3 tw-text-grey-muted">•</span>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case ServiceCategory.MESSAGING_SERVICES: {
|
case ServiceCategory.MESSAGING_SERVICES: {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -613,6 +615,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case ServiceCategory.DATABASE_SERVICES:
|
||||||
default: {
|
default: {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
@ -841,20 +844,6 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
getAllIngestionWorkflows(pagingString);
|
getAllIngestionWorkflows(pagingString);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCountLabel = () => {
|
|
||||||
switch (serviceName) {
|
|
||||||
case ServiceCategory.DASHBOARD_SERVICES:
|
|
||||||
return 'Dashboards';
|
|
||||||
case ServiceCategory.MESSAGING_SERVICES:
|
|
||||||
return 'Topics';
|
|
||||||
case ServiceCategory.PIPELINE_SERVICES:
|
|
||||||
return 'Pipelines';
|
|
||||||
case ServiceCategory.DATABASE_SERVICES:
|
|
||||||
default:
|
|
||||||
return 'Databases';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
@ -866,7 +855,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
|
|
||||||
<div className="tw-flex tw-gap-1 tw-mb-2 tw-mt-1 tw-ml-7">
|
<div className="tw-flex tw-gap-1 tw-mb-2 tw-mt-1 tw-ml-7">
|
||||||
{getOptionalFields()}
|
{getOptionalFields()}
|
||||||
<span>
|
{/* <span>
|
||||||
<span className="tw-text-grey-muted tw-font-normal">
|
<span className="tw-text-grey-muted tw-font-normal">
|
||||||
Ingestion :
|
Ingestion :
|
||||||
</span>{' '}
|
</span>{' '}
|
||||||
@ -885,7 +874,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
{getCountLabel()} :
|
{getCountLabel()} :
|
||||||
</span>{' '}
|
</span>{' '}
|
||||||
<span className="tw-pl-1 tw-font-normal">{instanceCount}</span>
|
<span className="tw-pl-1 tw-font-normal">{instanceCount}</span>
|
||||||
</span>
|
</span> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -992,6 +981,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
paging={ingestionPaging}
|
paging={ingestionPaging}
|
||||||
pagingHandler={ingestionPagingHandler}
|
pagingHandler={ingestionPagingHandler}
|
||||||
serviceList={serviceList}
|
serviceList={serviceList}
|
||||||
|
serviceName={serviceFQN}
|
||||||
serviceType={serviceDetails?.serviceType}
|
serviceType={serviceDetails?.serviceType}
|
||||||
triggerIngestion={triggerIngestionById}
|
triggerIngestion={triggerIngestionById}
|
||||||
updateIngestion={updateIngestion}
|
updateIngestion={updateIngestion}
|
||||||
|
@ -58,6 +58,7 @@ import {
|
|||||||
import { DatabaseService } from '../../generated/entity/services/databaseService';
|
import { DatabaseService } from '../../generated/entity/services/databaseService';
|
||||||
import { MessagingService } from '../../generated/entity/services/messagingService';
|
import { MessagingService } from '../../generated/entity/services/messagingService';
|
||||||
import { PipelineService } from '../../generated/entity/services/pipelineService';
|
import { PipelineService } from '../../generated/entity/services/pipelineService';
|
||||||
|
import { PipelineType } from '../../generated/operations/pipelines/airflowPipeline';
|
||||||
import { useAuth } from '../../hooks/authHooks';
|
import { useAuth } from '../../hooks/authHooks';
|
||||||
import useToastContext from '../../hooks/useToastContext';
|
import useToastContext from '../../hooks/useToastContext';
|
||||||
import {
|
import {
|
||||||
@ -65,7 +66,6 @@ import {
|
|||||||
getCountBadge,
|
getCountBadge,
|
||||||
getServiceLogo,
|
getServiceLogo,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
import { getFrequencyTime } from '../../utils/ServiceUtils';
|
|
||||||
import SVGIcons from '../../utils/SvgUtils';
|
import SVGIcons from '../../utils/SvgUtils';
|
||||||
|
|
||||||
type ServiceRecord = {
|
type ServiceRecord = {
|
||||||
@ -261,13 +261,23 @@ const ServicesPage = () => {
|
|||||||
...ingestion.service,
|
...ingestion.service,
|
||||||
id: serviceId,
|
id: serviceId,
|
||||||
},
|
},
|
||||||
|
pipelineType: PipelineType.Metadata,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.allSettled(promises).then(() => {
|
Promise.allSettled(promises).then(
|
||||||
|
(response: PromiseSettledResult<AxiosResponse>[]) => {
|
||||||
|
response.map((data) => {
|
||||||
|
data.status === 'rejected' &&
|
||||||
|
showToast({
|
||||||
|
variant: 'error',
|
||||||
|
body: data.reason || 'Something went wrong!',
|
||||||
|
});
|
||||||
|
});
|
||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
setEditData(undefined);
|
setEditData(undefined);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
setEditData(undefined);
|
setEditData(undefined);
|
||||||
@ -551,18 +561,7 @@ const ServicesPage = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{getOptionalFields(service)}
|
{getOptionalFields(service)}
|
||||||
<div
|
|
||||||
className="tw-mb-1"
|
|
||||||
data-testid="service-ingestion">
|
|
||||||
<label className="tw-mb-0">Ingestion:</label>
|
|
||||||
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body">
|
|
||||||
{service.ingestionSchedule?.repeatFrequency
|
|
||||||
? getFrequencyTime(
|
|
||||||
service.ingestionSchedule.repeatFrequency
|
|
||||||
)
|
|
||||||
: '--'}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="" data-testid="service-type">
|
<div className="" data-testid="service-type">
|
||||||
<label className="tw-mb-0">Type:</label>
|
<label className="tw-mb-0">Type:</label>
|
||||||
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body">
|
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user