mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-14 02:08:54 +00:00
599 lines
14 KiB
TypeScript
599 lines
14 KiB
TypeScript
/*
|
|
* Copyright 2021 Collate
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import { AxiosResponse } from 'axios';
|
|
import cryptoRandomString from 'crypto-random-string-with-promisify-polyfill';
|
|
import {
|
|
Bucket,
|
|
DynamicFormFieldType,
|
|
DynamicObj,
|
|
ServiceCollection,
|
|
ServiceData,
|
|
ServicesData,
|
|
ServiceTypes,
|
|
} from 'Models';
|
|
import React from 'react';
|
|
import { getServiceDetails, getServices } from '../axiosAPIs/serviceAPI';
|
|
import {
|
|
addMetadataIngestionGuide,
|
|
addProfilerIngestionGuide,
|
|
addServiceGuide,
|
|
addServiceGuideWOAirflow,
|
|
addUsageIngestionGuide,
|
|
} from '../constants/service-guide.constant';
|
|
import {
|
|
AIRFLOW,
|
|
arrServiceTypes,
|
|
ATHENA,
|
|
AZURESQL,
|
|
BIGQUERY,
|
|
CLICKHOUSE,
|
|
DASHBOARD_DEFAULT,
|
|
DATABASE_DEFAULT,
|
|
DATABRICK,
|
|
DEFAULT_SERVICE,
|
|
DELTALAKE,
|
|
DRUID,
|
|
DYNAMODB,
|
|
GLUE,
|
|
HIVE,
|
|
IBMDB2,
|
|
KAFKA,
|
|
LOOKER,
|
|
MARIADB,
|
|
METABASE,
|
|
MLFLOW,
|
|
MSSQL,
|
|
MYSQL,
|
|
ORACLE,
|
|
PIPELINE_DEFAULT,
|
|
POSTGRES,
|
|
POWERBI,
|
|
PREFECT,
|
|
PRESTO,
|
|
PULSAR,
|
|
REDASH,
|
|
REDSHIFT,
|
|
SALESFORCE,
|
|
SCIKIT,
|
|
serviceTypes,
|
|
SINGLESTORE,
|
|
SNOWFLAKE,
|
|
SQLITE,
|
|
SUPERSET,
|
|
TABLEAU,
|
|
TOPIC_DEFAULT,
|
|
TRINO,
|
|
VERTICA,
|
|
} from '../constants/services.const';
|
|
import { ServiceCategory } from '../enums/service.enum';
|
|
import { ConnectionType } from '../generated/api/services/ingestionPipelines/testServiceConnection';
|
|
import { MlModelServiceType } from '../generated/entity/data/mlmodel';
|
|
import { DashboardServiceType } from '../generated/entity/services/dashboardService';
|
|
import { DatabaseServiceType } from '../generated/entity/services/databaseService';
|
|
import { PipelineType as IngestionPipelineType } from '../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
|
import { MessagingServiceType } from '../generated/entity/services/messagingService';
|
|
import { PipelineServiceType } from '../generated/entity/services/pipelineService';
|
|
import { ServiceResponse } from '../interface/service.interface';
|
|
|
|
export const serviceTypeLogo = (type: string) => {
|
|
switch (type) {
|
|
case DatabaseServiceType.Mysql:
|
|
return MYSQL;
|
|
|
|
case DatabaseServiceType.Redshift:
|
|
return REDSHIFT;
|
|
|
|
case DatabaseServiceType.BigQuery:
|
|
return BIGQUERY;
|
|
|
|
case DatabaseServiceType.Hive:
|
|
return HIVE;
|
|
|
|
case DatabaseServiceType.Postgres:
|
|
return POSTGRES;
|
|
|
|
case DatabaseServiceType.Oracle:
|
|
return ORACLE;
|
|
|
|
case DatabaseServiceType.Snowflake:
|
|
return SNOWFLAKE;
|
|
|
|
case DatabaseServiceType.Mssql:
|
|
return MSSQL;
|
|
|
|
case DatabaseServiceType.Athena:
|
|
return ATHENA;
|
|
|
|
case DatabaseServiceType.Presto:
|
|
return PRESTO;
|
|
|
|
case DatabaseServiceType.Trino:
|
|
return TRINO;
|
|
|
|
case DatabaseServiceType.Glue:
|
|
return GLUE;
|
|
|
|
case DatabaseServiceType.MariaDB:
|
|
return MARIADB;
|
|
|
|
case DatabaseServiceType.Vertica:
|
|
return VERTICA;
|
|
|
|
case DatabaseServiceType.AzureSQL:
|
|
return AZURESQL;
|
|
|
|
case DatabaseServiceType.Clickhouse:
|
|
return CLICKHOUSE;
|
|
|
|
case DatabaseServiceType.Databricks:
|
|
return DATABRICK;
|
|
|
|
case DatabaseServiceType.Db2:
|
|
return IBMDB2;
|
|
|
|
case DatabaseServiceType.Druid:
|
|
return DRUID;
|
|
|
|
case DatabaseServiceType.DynamoDB:
|
|
return DYNAMODB;
|
|
|
|
case DatabaseServiceType.SingleStore:
|
|
return SINGLESTORE;
|
|
|
|
case DatabaseServiceType.SQLite:
|
|
return SQLITE;
|
|
|
|
case DatabaseServiceType.Salesforce:
|
|
return SALESFORCE;
|
|
|
|
case DatabaseServiceType.DeltaLake:
|
|
return DELTALAKE;
|
|
|
|
case MessagingServiceType.Kafka:
|
|
return KAFKA;
|
|
|
|
case MessagingServiceType.Pulsar:
|
|
return PULSAR;
|
|
|
|
case DashboardServiceType.Superset:
|
|
return SUPERSET;
|
|
|
|
case DashboardServiceType.Looker:
|
|
return LOOKER;
|
|
|
|
case DashboardServiceType.Tableau:
|
|
return TABLEAU;
|
|
|
|
case DashboardServiceType.Redash:
|
|
return REDASH;
|
|
|
|
case DashboardServiceType.Metabase:
|
|
return METABASE;
|
|
|
|
case DashboardServiceType.PowerBI:
|
|
return POWERBI;
|
|
|
|
case PipelineServiceType.Airflow:
|
|
return AIRFLOW;
|
|
|
|
case PipelineServiceType.Prefect:
|
|
return PREFECT;
|
|
|
|
case MlModelServiceType.Mlflow:
|
|
return MLFLOW;
|
|
|
|
case MlModelServiceType.Sklearn:
|
|
return SCIKIT;
|
|
default: {
|
|
let logo;
|
|
if (serviceTypes.messagingServices.includes(type)) {
|
|
logo = TOPIC_DEFAULT;
|
|
} else if (serviceTypes.dashboardServices.includes(type)) {
|
|
logo = DASHBOARD_DEFAULT;
|
|
} else if (serviceTypes.pipelineServices.includes(type)) {
|
|
logo = PIPELINE_DEFAULT;
|
|
} else if (serviceTypes.databaseServices.includes(type)) {
|
|
logo = DATABASE_DEFAULT;
|
|
} else {
|
|
logo = DEFAULT_SERVICE;
|
|
}
|
|
|
|
return logo;
|
|
}
|
|
}
|
|
};
|
|
|
|
export const fromISOString = (isoValue = '') => {
|
|
if (isoValue) {
|
|
// 'P1DT 0H 0M'
|
|
const [d, hm] = isoValue.split('T');
|
|
const day = +d.replace('D', '').replace('P', '');
|
|
const [h, time] = hm.split('H');
|
|
const minute = +time.replace('M', '');
|
|
|
|
return { day, hour: +h, minute };
|
|
} else {
|
|
return {
|
|
day: 1,
|
|
hour: 0,
|
|
minute: 0,
|
|
};
|
|
}
|
|
};
|
|
|
|
export const getFrequencyTime = (isoDate: string): string => {
|
|
const { day, hour, minute } = fromISOString(isoDate);
|
|
|
|
return `${day}D-${hour}H-${minute}M`;
|
|
};
|
|
|
|
const getAllServiceList = (
|
|
allServiceCollectionArr: Array<ServiceCollection>,
|
|
limit?: number
|
|
): Promise<Array<ServiceResponse>> => {
|
|
// fetch services of all individual collection
|
|
return new Promise<Array<ServiceResponse>>((resolve, reject) => {
|
|
if (allServiceCollectionArr.length) {
|
|
let promiseArr = [];
|
|
promiseArr = allServiceCollectionArr.map((obj) => {
|
|
return getServices(obj.value, limit);
|
|
});
|
|
Promise.allSettled(promiseArr)
|
|
.then((result: PromiseSettledResult<AxiosResponse>[]) => {
|
|
if (result.length) {
|
|
let serviceArr = [];
|
|
serviceArr = result.map((service) =>
|
|
service.status === 'fulfilled'
|
|
? service.value?.data
|
|
: { data: [], paging: { total: 0 } }
|
|
);
|
|
resolve(serviceArr);
|
|
} else {
|
|
resolve([]);
|
|
}
|
|
})
|
|
.catch((err) => reject(err));
|
|
} else {
|
|
resolve([]);
|
|
}
|
|
});
|
|
};
|
|
|
|
export const getAllServices = (
|
|
onlyVisibleServices = true,
|
|
limit?: number
|
|
): Promise<Array<ServiceResponse>> => {
|
|
return new Promise<Array<ServiceResponse>>((resolve, reject) => {
|
|
getServiceDetails().then((res: AxiosResponse) => {
|
|
let allServiceCollectionArr: Array<ServiceCollection> = [];
|
|
if (res.data.data?.length) {
|
|
const arrServiceCat: Array<{ name: string; value: string }> =
|
|
res.data.data.map((service: ServiceData) => {
|
|
return {
|
|
name: service.collection.name,
|
|
value: service.collection.name,
|
|
};
|
|
});
|
|
|
|
if (onlyVisibleServices) {
|
|
allServiceCollectionArr = arrServiceCat.filter((service) =>
|
|
arrServiceTypes.includes(service.name as ServiceTypes)
|
|
);
|
|
} else {
|
|
allServiceCollectionArr = arrServiceCat;
|
|
}
|
|
}
|
|
getAllServiceList(allServiceCollectionArr, limit)
|
|
.then((resAll) => resolve(resAll))
|
|
.catch((err) => reject(err));
|
|
});
|
|
});
|
|
};
|
|
|
|
export const getServiceCategoryFromType = (
|
|
type: string
|
|
): ServiceTypes | undefined => {
|
|
let serviceCategory;
|
|
for (const category in serviceTypes) {
|
|
if (serviceTypes[category as ServiceTypes].includes(type)) {
|
|
serviceCategory = category as ServiceTypes;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return serviceCategory;
|
|
};
|
|
|
|
// Note: This method is deprecated by "getEntityCountByType" of EntityUtils.ts
|
|
export const getEntityCountByService = (buckets: Array<Bucket>) => {
|
|
const entityCounts = {
|
|
tableCount: 0,
|
|
topicCount: 0,
|
|
dashboardCount: 0,
|
|
pipelineCount: 0,
|
|
};
|
|
buckets?.forEach((bucket) => {
|
|
if (serviceTypes.databaseServices.includes(bucket.key)) {
|
|
entityCounts.tableCount += bucket.doc_count;
|
|
} else if (serviceTypes.messagingServices.includes(bucket.key)) {
|
|
entityCounts.topicCount += bucket.doc_count;
|
|
} else if (serviceTypes.dashboardServices.includes(bucket.key)) {
|
|
entityCounts.dashboardCount += bucket.doc_count;
|
|
} else if (serviceTypes.pipelineServices.includes(bucket.key)) {
|
|
entityCounts.pipelineCount += bucket.doc_count;
|
|
}
|
|
});
|
|
|
|
return entityCounts;
|
|
};
|
|
|
|
export const getTotalEntityCountByService = (buckets: Array<Bucket> = []) => {
|
|
let entityCounts = 0;
|
|
buckets.forEach((bucket) => {
|
|
entityCounts += bucket.doc_count;
|
|
});
|
|
|
|
return entityCounts;
|
|
};
|
|
|
|
export const getKeyValuePair = (obj: DynamicObj) => {
|
|
return Object.entries(obj).map((v) => {
|
|
return {
|
|
key: v[0],
|
|
value: v[1],
|
|
};
|
|
});
|
|
};
|
|
|
|
export const getKeyValueObject = (arr: DynamicFormFieldType[]) => {
|
|
const keyValuePair: DynamicObj = {};
|
|
|
|
arr.forEach((obj) => {
|
|
if (obj.key && obj.value) {
|
|
keyValuePair[obj.key] = obj.value;
|
|
}
|
|
});
|
|
|
|
return keyValuePair;
|
|
};
|
|
|
|
export const getHostPortDetails = (hostport: string) => {
|
|
let host = '',
|
|
port = '';
|
|
const newHostPort = hostport.split(':');
|
|
|
|
port = newHostPort.splice(newHostPort.length - 1, 1).join();
|
|
host = newHostPort.join(':');
|
|
|
|
return {
|
|
host,
|
|
port,
|
|
};
|
|
};
|
|
|
|
export const isRequiredDetailsAvailableForIngestion = (
|
|
serviceCategory: ServiceCategory,
|
|
data: ServicesData
|
|
) => {
|
|
switch (serviceCategory) {
|
|
case ServiceCategory.DATABASE_SERVICES: {
|
|
const hostPort = getHostPortDetails(
|
|
data?.databaseConnection?.hostPort || ''
|
|
);
|
|
|
|
return Boolean(hostPort.host && hostPort.port);
|
|
}
|
|
|
|
case ServiceCategory.MESSAGING_SERVICES:
|
|
case ServiceCategory.PIPELINE_SERVICES:
|
|
case ServiceCategory.DASHBOARD_SERVICES:
|
|
return false;
|
|
|
|
default:
|
|
return true;
|
|
}
|
|
};
|
|
|
|
export const servicePageTabs = (entity: string) => [
|
|
{
|
|
name: entity,
|
|
path: entity.toLowerCase(),
|
|
},
|
|
{
|
|
name: 'Ingestions',
|
|
path: 'ingestions',
|
|
},
|
|
{
|
|
name: 'Connection',
|
|
path: 'connection',
|
|
},
|
|
{
|
|
name: 'Manage',
|
|
path: 'manage',
|
|
},
|
|
];
|
|
|
|
export const getCurrentServiceTab = (tab: string) => {
|
|
let currentTab;
|
|
switch (tab) {
|
|
case 'ingestions':
|
|
currentTab = 2;
|
|
|
|
break;
|
|
|
|
case 'connection':
|
|
currentTab = 3;
|
|
|
|
break;
|
|
|
|
case 'manage':
|
|
currentTab = 4;
|
|
|
|
break;
|
|
|
|
case 'entity':
|
|
default:
|
|
currentTab = 1;
|
|
|
|
break;
|
|
}
|
|
|
|
return currentTab;
|
|
};
|
|
|
|
export const getFormattedGuideText = (
|
|
text: string,
|
|
toReplace: string,
|
|
replacement: string,
|
|
isGlobal = false
|
|
) => {
|
|
const regExp = isGlobal ? new RegExp(toReplace, 'g') : new RegExp(toReplace);
|
|
|
|
return text.replace(regExp, replacement);
|
|
};
|
|
|
|
export const getServiceIngestionStepGuide = (
|
|
step: number,
|
|
isIngestion: boolean,
|
|
ingestionName: string,
|
|
serviceName: string,
|
|
ingestionType: IngestionPipelineType,
|
|
showDeployTitle: boolean,
|
|
isUpdated: boolean,
|
|
isAirflowSetup = true
|
|
) => {
|
|
let guide;
|
|
if (isIngestion) {
|
|
switch (ingestionType) {
|
|
case IngestionPipelineType.Usage: {
|
|
guide = addUsageIngestionGuide.find((item) => item.step === step);
|
|
|
|
break;
|
|
}
|
|
case IngestionPipelineType.Profiler: {
|
|
guide = addProfilerIngestionGuide.find((item) => item.step === step);
|
|
|
|
break;
|
|
}
|
|
case IngestionPipelineType.Metadata:
|
|
default: {
|
|
guide = addMetadataIngestionGuide.find((item) => item.step === step);
|
|
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
guide =
|
|
!isAirflowSetup && step === 4
|
|
? addServiceGuideWOAirflow
|
|
: addServiceGuide.find((item) => item.step === step);
|
|
}
|
|
|
|
const getTitle = (title: string) => {
|
|
const update = showDeployTitle
|
|
? title.replace('Added', 'Updated & Deployed')
|
|
: title.replace('Added', 'Updated');
|
|
const newTitle = showDeployTitle
|
|
? title.replace('Added', 'Added & Deployed')
|
|
: title;
|
|
|
|
return isUpdated ? update : newTitle;
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{guide && (
|
|
<>
|
|
<h6 className="tw-heading tw-text-base">{getTitle(guide.title)}</h6>
|
|
<div className="tw-mb-5">
|
|
{isIngestion
|
|
? getFormattedGuideText(
|
|
guide.description,
|
|
'<Ingestion Pipeline Name>',
|
|
`${ingestionName}`
|
|
)
|
|
: getFormattedGuideText(
|
|
guide.description,
|
|
'<Service Name>',
|
|
serviceName
|
|
)}
|
|
</div>
|
|
</>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export const getIngestionName = (
|
|
serviceName: string,
|
|
type: IngestionPipelineType
|
|
) => {
|
|
if (type === IngestionPipelineType.Profiler) {
|
|
return `${serviceName}_${type}_${cryptoRandomString({
|
|
length: 8,
|
|
type: 'alphanumeric',
|
|
})}`;
|
|
} else {
|
|
return `${serviceName}_${type}`;
|
|
}
|
|
};
|
|
|
|
export const shouldTestConnection = (serviceType: string) => {
|
|
return serviceType !== DatabaseServiceType.SampleData;
|
|
};
|
|
|
|
export const getTestConnectionType = (serviceCat: ServiceCategory) => {
|
|
switch (serviceCat) {
|
|
case ServiceCategory.MESSAGING_SERVICES:
|
|
return ConnectionType.Messaging;
|
|
case ServiceCategory.DASHBOARD_SERVICES:
|
|
return ConnectionType.Dashboard;
|
|
case ServiceCategory.PIPELINE_SERVICES:
|
|
return ConnectionType.Pipeline;
|
|
case ServiceCategory.DATABASE_SERVICES:
|
|
default:
|
|
return ConnectionType.Database;
|
|
}
|
|
};
|
|
|
|
export const getServiceCreatedLabel = (serviceCategory: ServiceCategory) => {
|
|
let serviceCat;
|
|
switch (serviceCategory) {
|
|
case ServiceCategory.DATABASE_SERVICES:
|
|
serviceCat = 'database';
|
|
|
|
break;
|
|
case ServiceCategory.MESSAGING_SERVICES:
|
|
serviceCat = 'messaging';
|
|
|
|
break;
|
|
case ServiceCategory.DASHBOARD_SERVICES:
|
|
serviceCat = 'dashboard';
|
|
|
|
break;
|
|
|
|
case ServiceCategory.PIPELINE_SERVICES:
|
|
serviceCat = 'pipeline';
|
|
|
|
break;
|
|
default:
|
|
serviceCat = '';
|
|
|
|
break;
|
|
}
|
|
|
|
return [serviceCat, 'service'].join(' ');
|
|
};
|