mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-13 09:48:19 +00:00
This commit is contained in:
parent
452771c34e
commit
950c3a5992
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
After Width: | Height: | Size: 130 KiB |
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.366 9.2C3.1035 9.07325 2.8105 9 2.5 9C1.39725 9 0.5 9.89725 0.5 11C0.5 12.1027 1.39725 13 2.5 13C3.192 13 3.80275 12.6465 4.162 12.1108L6.05125 13.0565C6.01875 13.1993 6 13.3475 6 13.5C6 14.6027 6.89725 15.5 8 15.5C9.10275 15.5 10 14.6027 10 13.5C10 13.0855 9.87325 12.7002 9.65625 12.3805L12.311 9.60475C12.644 9.85175 13.0545 10 13.5 10C14.6027 10 15.5 9.10275 15.5 8C15.5 6.89725 14.6027 6 13.5 6C13.0385 6 12.6145 6.1585 12.2755 6.422L9.578 3.7245C9.8415 3.3855 10 2.9615 10 2.5C10 1.39725 9.10275 0.5 8 0.5C6.89725 0.5 6 1.39725 6 2.5C6 2.652 6.0185 2.79975 6.051 2.94225L4.278 3.58825C3.9455 2.943 3.27425 2.5 2.5 2.5C1.39725 2.5 0.5 3.39725 0.5 4.5C0.5 5.60275 1.39725 6.5 2.5 6.5C2.7845 6.5 3.05475 6.4395 3.3 6.33175L4.22025 7.8805L3.366 9.2ZM2.5 12.5C1.67275 12.5 1 11.8273 1 11C1 10.1727 1.67275 9.5 2.5 9.5C3.32725 9.5 4 10.1727 4 11C4 11.8273 3.32725 12.5 2.5 12.5ZM4.38475 11.6628C4.458 11.455 4.5 11.2325 4.5 11C4.5 10.3867 4.222 9.83775 3.78625 9.47075L4.50525 8.36025L6.673 12.008C6.4905 12.1705 6.33775 12.365 6.2245 12.5837L4.38475 11.6628ZM8 4.5C8.4615 4.5 8.8855 4.3415 9.2245 4.078L11.9222 6.77575C11.7605 6.98375 11.6395 7.224 11.5697 7.4855L9.99925 7.2695C9.999 7.263 10 7.2565 10 7.25C10 6.14725 9.10275 5.25 8 5.25C7.308 5.25 6.697 5.6035 6.338 6.13925L6.03975 5.99025L7.13425 4.3C7.3965 4.42675 7.6895 4.5 8 4.5ZM8.25 11.5173V9.2325C9.0625 9.1305 9.7235 8.54 9.9305 7.7645L11.501 7.9805C11.501 7.987 11.5 7.9935 11.5 8C11.5 8.4775 11.6685 8.91575 11.9487 9.26L9.32375 12.0048C9.0295 11.744 8.65925 11.5688 8.25 11.5173V11.5173ZM8 5.75C8.82725 5.75 9.5 6.42275 9.5 7.25C9.5 8.07725 8.82725 8.75 8 8.75C7.17275 8.75 6.5 8.07725 6.5 7.25C6.5 6.42275 7.17275 5.75 8 5.75V5.75ZM6.11525 6.58725C6.042 6.795 6 7.0175 6 7.25C6 8.268 6.765 9.109 7.75 9.23275V11.5175C7.513 11.5472 7.28925 11.6183 7.0855 11.7235L4.8085 7.89175L5.76625 6.41275L6.11525 6.58725ZM8 15C7.17275 15 6.5 14.3273 6.5 13.5C6.5 12.6727 7.17275 12 8 12C8.82725 12 9.5 12.6727 9.5 13.5C9.5 14.3273 8.82725 15 8 15ZM13.5 6.5C14.3273 6.5 15 7.17275 15 8C15 8.82725 14.3273 9.5 13.5 9.5C12.6727 9.5 12 8.82725 12 8C12 7.17275 12.6727 6.5 13.5 6.5ZM8 1C8.82725 1 9.5 1.67275 9.5 2.5C9.5 3.32725 8.82725 4 8 4C7.17275 4 6.5 3.32725 6.5 2.5C6.5 1.67275 7.17275 1 8 1ZM6.222 3.41175C6.34425 3.649 6.5115 3.85875 6.71375 4.02925L5.58975 5.76525L4.38475 5.16275C4.458 4.955 4.5 4.7325 4.5 4.5C4.5 4.348 4.4815 4.20025 4.449 4.05775L6.222 3.41175ZM1 4.5C1 3.67275 1.67275 3 2.5 3C3.32725 3 4 3.67275 4 4.5C4 5.32725 3.32725 6 2.5 6C1.67275 6 1 5.32725 1 4.5ZM3.72875 6.07475C3.89625 5.94375 4.04325 5.78775 4.162 5.61075L5.31625 6.18775L4.5235 7.412L3.72875 6.07475Z" fill="#37352F" stroke="#37352F" stroke-width="0.3"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { isNil } from 'lodash';
|
||||
import { Mlmodel } from '../generated/entity/data/mlmodel';
|
||||
import { getURLWithQueryFields } from '../utils/APIUtils';
|
||||
import APIClient from './index';
|
||||
@ -25,6 +26,39 @@ export const getMlModelByFQN: Function = (
|
||||
return APIClient.get(url);
|
||||
};
|
||||
|
||||
export const getMlmodels = (
|
||||
serviceName: string,
|
||||
paging: string,
|
||||
arrQueryFields: string[]
|
||||
): Promise<AxiosResponse> => {
|
||||
const url = `${getURLWithQueryFields(
|
||||
`/mlmodels`,
|
||||
arrQueryFields
|
||||
)}&service=${serviceName}${paging ? paging : ''}`;
|
||||
|
||||
return APIClient.get(url);
|
||||
};
|
||||
|
||||
export const getAllMlModal = (
|
||||
paging: string,
|
||||
arrQueryFields: string,
|
||||
limit?: number
|
||||
): Promise<AxiosResponse> => {
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
if (!isNil(limit)) {
|
||||
searchParams.set('limit', `${limit}`);
|
||||
}
|
||||
|
||||
const url = getURLWithQueryFields(
|
||||
`/mlmodels`,
|
||||
arrQueryFields,
|
||||
`${searchParams.toString()}${paging ? `&${paging}` : ''}`
|
||||
);
|
||||
|
||||
return APIClient.get(url);
|
||||
};
|
||||
|
||||
export const patchMlModelDetails: Function = (
|
||||
id: string,
|
||||
data: Mlmodel
|
||||
|
@ -14,7 +14,10 @@
|
||||
import classNames from 'classnames';
|
||||
import { startCase } from 'lodash';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { serviceTypes } from '../../../constants/services.const';
|
||||
import {
|
||||
excludedService,
|
||||
serviceTypes,
|
||||
} from '../../../constants/services.const';
|
||||
import { ServiceCategory } from '../../../enums/service.enum';
|
||||
import { errorMsg, getServiceLogo } from '../../../utils/CommonUtils';
|
||||
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
||||
@ -51,7 +54,11 @@ const SelectServiceType = ({
|
||||
? serviceCategory
|
||||
: allCategory[0];
|
||||
setCategory(selectedCategory);
|
||||
setSelectedConnectors(serviceTypes[selectedCategory]);
|
||||
setSelectedConnectors(
|
||||
serviceTypes[selectedCategory].filter(
|
||||
(service) => !excludedService.find((e) => e === service)
|
||||
)
|
||||
);
|
||||
}, [serviceCategory]);
|
||||
|
||||
return (
|
||||
|
@ -621,7 +621,7 @@ const Entitylineage: FunctionComponent<EntityLineageProp> = ({
|
||||
};
|
||||
} else {
|
||||
const updatedColumnsLineage: ColumnLineage[] =
|
||||
currentEdge.columnsLineage.map((l) => {
|
||||
currentEdge.columnsLineage?.map((l) => {
|
||||
if (l.toColumn === targetHandle) {
|
||||
return {
|
||||
...l,
|
||||
@ -633,7 +633,7 @@ const Entitylineage: FunctionComponent<EntityLineageProp> = ({
|
||||
}
|
||||
|
||||
return l;
|
||||
});
|
||||
}) || [];
|
||||
if (
|
||||
!updatedColumnsLineage.find((l) => l.toColumn === targetHandle)
|
||||
) {
|
||||
|
@ -26,14 +26,17 @@ import React, {
|
||||
import AppState from '../../AppState';
|
||||
import {
|
||||
getDashboardDetailsPath,
|
||||
getServiceDetailsPath,
|
||||
getTeamAndUserDetailsPath,
|
||||
} from '../../constants/constants';
|
||||
import { EntityType } from '../../enums/entity.enum';
|
||||
import { ServiceCategory } from '../../enums/service.enum';
|
||||
import { OwnerType } from '../../enums/user.enum';
|
||||
import { Mlmodel } from '../../generated/entity/data/mlmodel';
|
||||
import { EntityReference } from '../../generated/type/entityReference';
|
||||
import { LabelType, State, TagLabel } from '../../generated/type/tagLabel';
|
||||
import { getEntityName, getEntityPlaceHolder } from '../../utils/CommonUtils';
|
||||
import { serviceTypeLogo } from '../../utils/ServiceUtils';
|
||||
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
@ -83,8 +86,19 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
|
||||
const mlModelTags = useMemo(() => {
|
||||
return getTagsWithoutTier(mlModelDetail.tags || []);
|
||||
}, [mlModelDetail.tags]);
|
||||
|
||||
const slashedMlModelName: TitleBreadcrumbProps['titleLinks'] = [
|
||||
{
|
||||
name: mlModelDetail.service.name || '',
|
||||
url: mlModelDetail.service.name
|
||||
? getServiceDetailsPath(
|
||||
mlModelDetail.service.name,
|
||||
ServiceCategory.ML_MODAL_SERVICES
|
||||
)
|
||||
: '',
|
||||
imgSrc: mlModelDetail.serviceType
|
||||
? serviceTypeLogo(mlModelDetail.serviceType || '')
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
name: getEntityName(mlModelDetail as unknown as EntityReference),
|
||||
url: '',
|
||||
|
@ -30,6 +30,7 @@ type Props = {
|
||||
countDashboards: number;
|
||||
countPipelines: number;
|
||||
countServices: number;
|
||||
countMlModal: number;
|
||||
countTables: number;
|
||||
countTopics: number;
|
||||
countTeams: number;
|
||||
@ -47,6 +48,7 @@ type Summary = {
|
||||
const MyAssetStats: FunctionComponent<Props> = ({
|
||||
countDashboards,
|
||||
countPipelines,
|
||||
countMlModal,
|
||||
countServices,
|
||||
countTables,
|
||||
countTopics,
|
||||
@ -85,6 +87,13 @@ const MyAssetStats: FunctionComponent<Props> = ({
|
||||
link: getExplorePathWithSearch(undefined, 'pipelines'),
|
||||
dataTestId: 'pipelines',
|
||||
},
|
||||
mlModal: {
|
||||
icon: Icons.MLMODAL,
|
||||
data: 'ML Models',
|
||||
count: countMlModal,
|
||||
link: getExplorePathWithSearch(undefined, 'mlmodels'),
|
||||
dataTestId: 'mlmodels',
|
||||
},
|
||||
service: {
|
||||
icon: Icons.SERVICE,
|
||||
data: 'Services',
|
||||
|
@ -38,6 +38,7 @@ const mockProp = {
|
||||
countTeams: 7,
|
||||
countTopics: 13,
|
||||
countUsers: 100,
|
||||
countMlModal: 2,
|
||||
};
|
||||
|
||||
describe('Test MyDataHeader Component', () => {
|
||||
@ -51,14 +52,14 @@ describe('Test MyDataHeader Component', () => {
|
||||
expect(myDataHeader).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should have 7 data summary details', () => {
|
||||
it('Should have 8 data summary details', () => {
|
||||
const { container } = render(<MyAssetStats {...mockProp} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const dataSummary = getAllByTestId(container, /-summary$/);
|
||||
|
||||
expect(dataSummary.length).toBe(7);
|
||||
expect(dataSummary.length).toBe(8);
|
||||
});
|
||||
|
||||
it('OnClick it should redirect to respective page', () => {
|
||||
@ -72,6 +73,7 @@ describe('Test MyDataHeader Component', () => {
|
||||
const topics = getByTestId(container, 'topics');
|
||||
const dashboards = getByTestId(container, 'dashboards');
|
||||
const pipelines = getByTestId(container, 'pipelines');
|
||||
const mlmodel = getByTestId(container, 'mlmodels');
|
||||
const service = getByTestId(container, 'service');
|
||||
const user = getByTestId(container, 'user');
|
||||
const terms = getByTestId(container, 'terms');
|
||||
@ -80,6 +82,7 @@ describe('Test MyDataHeader Component', () => {
|
||||
expect(topics).toHaveAttribute('href', '/explore/topics/');
|
||||
expect(dashboards).toHaveAttribute('href', '/explore/dashboards/');
|
||||
expect(pipelines).toHaveAttribute('href', '/explore/pipelines/');
|
||||
expect(mlmodel).toHaveAttribute('href', '/explore/mlmodels/');
|
||||
expect(service).toHaveAttribute('href', '/services');
|
||||
expect(user).toHaveAttribute(
|
||||
'href',
|
||||
|
@ -51,6 +51,7 @@ const MyData: React.FC<MyDataProps> = ({
|
||||
countTeams,
|
||||
countUsers,
|
||||
ownedData,
|
||||
countMlModal,
|
||||
followedData,
|
||||
feedData,
|
||||
feedFilter,
|
||||
@ -108,6 +109,7 @@ const MyData: React.FC<MyDataProps> = ({
|
||||
<div className="tw-mt-4">
|
||||
<MyAssetStats
|
||||
countDashboards={countDashboards}
|
||||
countMlModal={countMlModal}
|
||||
countPipelines={countPipelines}
|
||||
countServices={countServices}
|
||||
countTables={countTables}
|
||||
|
@ -25,6 +25,7 @@ export interface MyDataProps {
|
||||
countTopics: number;
|
||||
countTeams: number;
|
||||
countUsers: number;
|
||||
countMlModal: number;
|
||||
countDashboards: number;
|
||||
followedDataCount: number;
|
||||
ownedDataCount: number;
|
||||
|
@ -328,6 +328,7 @@ const mockProp: MyDataProps = {
|
||||
countTopics: 5,
|
||||
countTeams: 7,
|
||||
countUsers: 100,
|
||||
countMlModal: 2,
|
||||
followedDataCount: 5,
|
||||
ownedDataCount: 5,
|
||||
error: '',
|
||||
|
@ -17,6 +17,7 @@ import { LoadingState } from 'Models';
|
||||
import React, { Fragment, FunctionComponent, useMemo } from 'react';
|
||||
import { TestConnection } from '../../axiosAPIs/serviceAPI';
|
||||
import { ServiceCategory } from '../../enums/service.enum';
|
||||
import { MlModelServiceType } from '../../generated/api/services/createMlModelService';
|
||||
import {
|
||||
DashboardService,
|
||||
DashboardServiceType,
|
||||
@ -29,6 +30,7 @@ import {
|
||||
MessagingService,
|
||||
MessagingServiceType,
|
||||
} from '../../generated/entity/services/messagingService';
|
||||
import { MlmodelService } from '../../generated/entity/services/mlmodelService';
|
||||
import {
|
||||
PipelineService,
|
||||
PipelineServiceType,
|
||||
@ -39,6 +41,7 @@ import { getDashboardConfig } from '../../utils/DashboardServiceUtils';
|
||||
import { getDatabaseConfig } from '../../utils/DatabaseServiceUtils';
|
||||
import { formatFormDataForSubmit } from '../../utils/JSONSchemaFormUtils';
|
||||
import { getMessagingConfig } from '../../utils/MessagingServiceUtils';
|
||||
import { getMlmodelConfig } from '../../utils/MlmodelServiceUtils';
|
||||
import { getPipelineConfig } from '../../utils/PipelineServiceUtils';
|
||||
import {
|
||||
getTestConnectionType,
|
||||
@ -52,7 +55,8 @@ interface Props {
|
||||
| DatabaseService
|
||||
| MessagingService
|
||||
| DashboardService
|
||||
| PipelineService;
|
||||
| PipelineService
|
||||
| MlmodelService;
|
||||
okText?: string;
|
||||
cancelText?: string;
|
||||
serviceType: string;
|
||||
@ -142,6 +146,11 @@ const ConnectionConfigForm: FunctionComponent<Props> = ({
|
||||
case ServiceCategory.PIPELINE_SERVICES: {
|
||||
connSch = getPipelineConfig(serviceType as PipelineServiceType);
|
||||
|
||||
break;
|
||||
}
|
||||
case ServiceCategory.ML_MODAL_SERVICES: {
|
||||
connSch = getMlmodelConfig(serviceType as MlModelServiceType);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,13 @@ import { EntityType } from '../../enums/entity.enum';
|
||||
import { DashboardServiceType } from '../../generated/entity/services/dashboardService';
|
||||
import { DatabaseServiceType } from '../../generated/entity/services/databaseService';
|
||||
import { MessagingServiceType } from '../../generated/entity/services/messagingService';
|
||||
import { MlModelServiceType } from '../../generated/entity/services/mlmodelService';
|
||||
import { PipelineServiceType } from '../../generated/entity/services/pipelineService';
|
||||
import { ConfigData } from '../../interface/service.interface';
|
||||
import { getDashboardConfig } from '../../utils/DashboardServiceUtils';
|
||||
import { getDatabaseConfig } from '../../utils/DatabaseServiceUtils';
|
||||
import { getMessagingConfig } from '../../utils/MessagingServiceUtils';
|
||||
import { getMlmodelConfig } from '../../utils/MlmodelServiceUtils';
|
||||
import { getPipelineConfig } from '../../utils/PipelineServiceUtils';
|
||||
import PopOver from '../common/popover/PopOver';
|
||||
|
||||
@ -143,6 +145,10 @@ const ServiceConnectionDetails = ({
|
||||
case EntityType.PIPELINE_SERVICE:
|
||||
setSchema(getPipelineConfig(serviceFQN as PipelineServiceType).schema);
|
||||
|
||||
break;
|
||||
case EntityType.MLMODEL_SERVICE:
|
||||
setSchema(getMlmodelConfig(serviceFQN as MlModelServiceType).schema);
|
||||
|
||||
break;
|
||||
}
|
||||
}, [serviceCategory, serviceFQN]);
|
||||
|
@ -30,6 +30,7 @@ import kafka from '../assets/img/service-icon-kafka.png';
|
||||
import looker from '../assets/img/service-icon-looker.png';
|
||||
import mariadb from '../assets/img/service-icon-mariadb.png';
|
||||
import metabase from '../assets/img/service-icon-metabase.png';
|
||||
import mlflow from '../assets/img/service-icon-mlflow.png';
|
||||
import mssql from '../assets/img/service-icon-mssql.png';
|
||||
import oracle from '../assets/img/service-icon-oracle.png';
|
||||
import postgres from '../assets/img/service-icon-post.png';
|
||||
@ -41,6 +42,7 @@ import query from '../assets/img/service-icon-query.png';
|
||||
import redash from '../assets/img/service-icon-redash.png';
|
||||
import redshift from '../assets/img/service-icon-redshift.png';
|
||||
import salesforce from '../assets/img/service-icon-salesforce.png';
|
||||
import scikit from '../assets/img/service-icon-scikit.png';
|
||||
import singlestore from '../assets/img/service-icon-singlestore.png';
|
||||
import snowflakes from '../assets/img/service-icon-snowflakes.png';
|
||||
import mysql from '../assets/img/service-icon-sql.png';
|
||||
@ -57,6 +59,7 @@ import topicDefault from '../assets/svg/topic.svg';
|
||||
import { DashboardServiceType } from '../generated/entity/services/dashboardService';
|
||||
import { DatabaseServiceType } from '../generated/entity/services/databaseService';
|
||||
import { MessagingServiceType } from '../generated/entity/services/messagingService';
|
||||
import { MlModelServiceType } from '../generated/entity/services/mlmodelService';
|
||||
import { PipelineServiceType } from '../generated/entity/services/pipelineService';
|
||||
|
||||
export const NoDataFoundPlaceHolder = noDataFound;
|
||||
@ -90,6 +93,8 @@ export const DRUID = druid;
|
||||
export const DYNAMODB = dynamodb;
|
||||
export const SINGLESTORE = singlestore;
|
||||
export const SALESFORCE = salesforce;
|
||||
export const MLFLOW = mlflow;
|
||||
export const SCIKIT = scikit;
|
||||
export const DELTALAKE = deltalake;
|
||||
export const DEFAULT_SERVICE = iconDefaultService;
|
||||
|
||||
@ -103,12 +108,13 @@ export const PIPELINE_DEFAULT = pipelineDefault;
|
||||
|
||||
export const PLUS = plus;
|
||||
export const NOSERVICE = noService;
|
||||
|
||||
export const excludedService = [MlModelServiceType.Sklearn];
|
||||
export const serviceTypes: Record<ServiceTypes, Array<string>> = {
|
||||
databaseServices: Object.values(DatabaseServiceType),
|
||||
messagingServices: Object.values(MessagingServiceType),
|
||||
dashboardServices: Object.values(DashboardServiceType),
|
||||
pipelineServices: Object.values(PipelineServiceType),
|
||||
mlmodelServices: Object.values(MlModelServiceType),
|
||||
};
|
||||
|
||||
export const arrServiceTypes: Array<ServiceTypes> = [
|
||||
@ -116,6 +122,7 @@ export const arrServiceTypes: Array<ServiceTypes> = [
|
||||
'messagingServices',
|
||||
'dashboardServices',
|
||||
'pipelineServices',
|
||||
'mlmodelServices',
|
||||
];
|
||||
|
||||
export const servicesDisplayName = {
|
||||
@ -123,6 +130,7 @@ export const servicesDisplayName = {
|
||||
messagingServices: 'Messaging Service',
|
||||
dashboardServices: 'Dashboard Service',
|
||||
pipelineServices: 'Pipeline Service',
|
||||
mlmodelServices: 'ML Model Service',
|
||||
};
|
||||
|
||||
export const STEPS_FOR_ADD_SERVICE: Array<StepperStepType> = [
|
||||
|
@ -25,6 +25,7 @@ export enum EntityType {
|
||||
MESSAGING_SERVICE = 'messagingService',
|
||||
DASHBOARD_SERVICE = 'dashboardService',
|
||||
PIPELINE_SERVICE = 'pipelineService',
|
||||
MLMODEL_SERVICE = 'mlmodelService',
|
||||
WEBHOOK = 'webhook',
|
||||
MLMODEL = 'mlmodel',
|
||||
TYPE = 'type',
|
||||
|
@ -16,6 +16,7 @@ export enum ServiceCategory {
|
||||
MESSAGING_SERVICES = 'messagingServices',
|
||||
DASHBOARD_SERVICES = 'dashboardServices',
|
||||
PIPELINE_SERVICES = 'pipelineServices',
|
||||
ML_MODAL_SERVICES = 'mlmodelServices',
|
||||
}
|
||||
|
||||
export enum IngestionType {
|
||||
|
@ -15,6 +15,7 @@ import { DynamicObj, Paging } from 'Models';
|
||||
import { DashboardService } from '../generated/entity/services/dashboardService';
|
||||
import { DatabaseService } from '../generated/entity/services/databaseService';
|
||||
import { MessagingService } from '../generated/entity/services/messagingService';
|
||||
import { MlmodelService } from '../generated/entity/services/mlmodelService';
|
||||
import { PipelineService } from '../generated/entity/services/pipelineService';
|
||||
|
||||
export interface IngestionSchedule {
|
||||
@ -60,13 +61,15 @@ export interface EditObj {
|
||||
export type ServiceDataObj = { name: string } & Partial<DatabaseService> &
|
||||
Partial<MessagingService> &
|
||||
Partial<DashboardService> &
|
||||
Partial<PipelineService>;
|
||||
Partial<PipelineService> &
|
||||
Partial<MlmodelService>;
|
||||
|
||||
export type DataService =
|
||||
| DatabaseService
|
||||
| MessagingService
|
||||
| DashboardService
|
||||
| PipelineService;
|
||||
| PipelineService
|
||||
| MlmodelService;
|
||||
|
||||
export interface ServiceResponse {
|
||||
data: Array<ServiceDataObj>;
|
||||
@ -76,4 +79,5 @@ export interface ServiceResponse {
|
||||
export type ConfigData = Partial<DatabaseService['connection']> &
|
||||
Partial<MessagingService['connection']> &
|
||||
Partial<DashboardService['connection']> &
|
||||
Partial<PipelineService['connection']>;
|
||||
Partial<PipelineService['connection']> &
|
||||
Partial<MlmodelService['connection']>;
|
||||
|
@ -399,7 +399,8 @@ declare module 'Models' {
|
||||
| 'databaseServices'
|
||||
| 'messagingServices'
|
||||
| 'dashboardServices'
|
||||
| 'pipelineServices';
|
||||
| 'pipelineServices'
|
||||
| 'mlmodelServices';
|
||||
|
||||
export type SampleData = {
|
||||
columns: Array<string>;
|
||||
|
@ -41,9 +41,46 @@ export const mockServiceDetails = {
|
||||
href: 'http://pipelineServices',
|
||||
},
|
||||
},
|
||||
{
|
||||
collection: {
|
||||
name: 'mlmodelServices',
|
||||
documentation: 'MlModel service collection',
|
||||
href: 'http://localhost:8585/api/v1/services/mlmodelServices',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const mockMlmodelService = {
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
id: 'b59a9acb-6c90-481e-afd9-ec0f208c4f35',
|
||||
name: 'mlflow_svc',
|
||||
fullyQualifiedName: 'mlflow_svc',
|
||||
serviceType: 'Mlflow',
|
||||
description: 'description for mlflow_svc',
|
||||
version: 0.4,
|
||||
updatedAt: 1655890983668,
|
||||
updatedBy: 'anonymous',
|
||||
connection: {
|
||||
config: {
|
||||
type: 'Mlflow',
|
||||
registryUri: 'http://localhost:8088',
|
||||
trackingUri: 'http://localhost:8088',
|
||||
supportsMetadataExtraction: null,
|
||||
},
|
||||
},
|
||||
href: 'http://localhost:8585/api/v1/services/mlmodelServices/b59a9acb-6c90-481e-afd9-ec0f208c4f35',
|
||||
deleted: false,
|
||||
},
|
||||
],
|
||||
paging: {
|
||||
total: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const mockDatabaseService = {
|
||||
data: {
|
||||
data: [
|
||||
|
@ -22,6 +22,7 @@ import AppState from '../../AppState';
|
||||
import { getAllDashboards } from '../../axiosAPIs/dashboardAPI';
|
||||
import { getFeedsWithFilter, postFeedById } from '../../axiosAPIs/feedsAPI';
|
||||
import { fetchSandboxConfig, searchData } from '../../axiosAPIs/miscAPI';
|
||||
import { getAllMlModal } from '../../axiosAPIs/mlModelAPI';
|
||||
import { getAllPipelines } from '../../axiosAPIs/pipelineAPI';
|
||||
import { getAllTables } from '../../axiosAPIs/tableAPI';
|
||||
import { getTeams } from '../../axiosAPIs/teamsAPI';
|
||||
@ -60,6 +61,7 @@ const MyDataPage = () => {
|
||||
const [countTopics, setCountTopics] = useState<number>();
|
||||
const [countDashboards, setCountDashboards] = useState<number>();
|
||||
const [countPipelines, setCountPipelines] = useState<number>();
|
||||
const [countMlModal, setCountMlModal] = useState<number>();
|
||||
const [countUsers, setCountUsers] = useState<number>();
|
||||
const [countTeams, setCountTeams] = useState<number>();
|
||||
|
||||
@ -171,6 +173,23 @@ const MyDataPage = () => {
|
||||
);
|
||||
setCountDashboards(0);
|
||||
});
|
||||
|
||||
// limit=0 will fetch empty data list with total count
|
||||
getAllMlModal('', '', 0)
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
setCountMlModal(res.data.paging.total);
|
||||
} else {
|
||||
throw jsonData['api-error-messages']['unexpected-server-response'];
|
||||
}
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
showErrorToast(
|
||||
err,
|
||||
jsonData['api-error-messages']['unexpected-server-response']
|
||||
);
|
||||
setCountMlModal(0);
|
||||
});
|
||||
};
|
||||
|
||||
const fetchTeamsAndUsersCount = () => {
|
||||
@ -415,10 +434,12 @@ const MyDataPage = () => {
|
||||
!isUndefined(countDashboards) &&
|
||||
!isUndefined(countPipelines) &&
|
||||
!isUndefined(countTeams) &&
|
||||
!isUndefined(countMlModal) &&
|
||||
!isUndefined(countUsers) ? (
|
||||
<Fragment>
|
||||
<MyData
|
||||
countDashboards={countDashboards}
|
||||
countMlModal={countMlModal}
|
||||
countPipelines={countPipelines}
|
||||
countServices={countServices}
|
||||
countTables={countTables}
|
||||
|
@ -111,6 +111,16 @@ jest.mock('../../axiosAPIs/pipelineAPI', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/mlModelAPI', () => ({
|
||||
getAllMlModal: jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
data: [],
|
||||
},
|
||||
})
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/userAPI', () => ({
|
||||
getUsers: jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
triggerIngestionPipelineById,
|
||||
} from '../../axiosAPIs/ingestionPipelineAPI';
|
||||
import { fetchAirflowConfig } from '../../axiosAPIs/miscAPI';
|
||||
import { getMlmodels } from '../../axiosAPIs/mlModelAPI';
|
||||
import { getPipelines } from '../../axiosAPIs/pipelineAPI';
|
||||
import { getServiceByFQN, updateService } from '../../axiosAPIs/serviceAPI';
|
||||
import { getTopics } from '../../axiosAPIs/topicsAPI';
|
||||
@ -57,6 +58,7 @@ import { ServiceCategory } from '../../enums/service.enum';
|
||||
import { OwnerType } from '../../enums/user.enum';
|
||||
import { Dashboard } from '../../generated/entity/data/dashboard';
|
||||
import { Database } from '../../generated/entity/data/database';
|
||||
import { Mlmodel } from '../../generated/entity/data/mlmodel';
|
||||
import { Pipeline } from '../../generated/entity/data/pipeline';
|
||||
import { Topic } from '../../generated/entity/data/topic';
|
||||
import { DatabaseService } from '../../generated/entity/services/databaseService';
|
||||
@ -129,6 +131,8 @@ const ServicePage: FunctionComponent = () => {
|
||||
return 'Topics';
|
||||
case ServiceCategory.PIPELINE_SERVICES:
|
||||
return 'Pipelines';
|
||||
case ServiceCategory.ML_MODAL_SERVICES:
|
||||
return 'Models';
|
||||
case ServiceCategory.DATABASE_SERVICES:
|
||||
default:
|
||||
return 'Databases';
|
||||
@ -420,6 +424,26 @@ const ServicePage: FunctionComponent = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const fetchMlModal = (paging = '') => {
|
||||
setIsloading(true);
|
||||
getMlmodels(serviceFQN, paging, ['owner', 'tags'])
|
||||
.then((res: AxiosResponse) => {
|
||||
if (res.data.data) {
|
||||
setData(res.data.data);
|
||||
setPaging(res.data.paging);
|
||||
setInstanceCount(res.data.paging.total);
|
||||
setIsloading(false);
|
||||
} else {
|
||||
setData([]);
|
||||
setPaging(pagingObject);
|
||||
setIsloading(false);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setIsloading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const getAirflowStatus = () => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
checkAirflowStatus()
|
||||
@ -456,6 +480,11 @@ const ServicePage: FunctionComponent = () => {
|
||||
|
||||
break;
|
||||
}
|
||||
case ServiceCategory.ML_MODAL_SERVICES: {
|
||||
fetchMlModal(paging);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -472,6 +501,9 @@ const ServicePage: FunctionComponent = () => {
|
||||
case ServiceCategory.PIPELINE_SERVICES:
|
||||
return getEntityLink(SearchIndex.PIPELINE, fqn);
|
||||
|
||||
case ServiceCategory.ML_MODAL_SERVICES:
|
||||
return getEntityLink(SearchIndex.MLMODEL, fqn);
|
||||
|
||||
case ServiceCategory.DATABASE_SERVICES:
|
||||
default:
|
||||
return `/database/${fqn}`;
|
||||
@ -520,6 +552,16 @@ const ServicePage: FunctionComponent = () => {
|
||||
</>
|
||||
);
|
||||
}
|
||||
case ServiceCategory.ML_MODAL_SERVICES: {
|
||||
return (
|
||||
<>
|
||||
<th className="tableHead-cell">Model Name</th>
|
||||
<th className="tableHead-cell">Description</th>
|
||||
<th className="tableHead-cell">Owner</th>
|
||||
<th className="tableHead-cell">Tags</th>
|
||||
</>
|
||||
);
|
||||
}
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
@ -594,6 +636,24 @@ const ServicePage: FunctionComponent = () => {
|
||||
</td>
|
||||
);
|
||||
}
|
||||
case ServiceCategory.ML_MODAL_SERVICES: {
|
||||
const mlmodal = data as Mlmodel;
|
||||
|
||||
return (
|
||||
<td className="tableBody-cell">
|
||||
{mlmodal.tags && mlmodal.tags?.length > 0 ? (
|
||||
<TagsViewer
|
||||
showStartWith={false}
|
||||
sizeCap={-1}
|
||||
tags={mlmodal.tags}
|
||||
type="border"
|
||||
/>
|
||||
) : (
|
||||
'--'
|
||||
)}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ import {
|
||||
mockLookerService,
|
||||
mockMessagingService,
|
||||
mockMetabaseService,
|
||||
mockMlmodelService,
|
||||
mockPipelineService,
|
||||
mockPowerBIService,
|
||||
mockPulsarService,
|
||||
@ -81,6 +82,9 @@ jest.mock('../../axiosAPIs/serviceAPI', () => ({
|
||||
case 'pipelineServices':
|
||||
return Promise.resolve(mockPipelineService);
|
||||
|
||||
case 'mlmodelServices':
|
||||
return Promise.resolve(mockMlmodelService);
|
||||
|
||||
default:
|
||||
return Promise.resolve(mockDashboardService);
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ import { ServiceCategory } from '../../enums/service.enum';
|
||||
import { DashboardService } from '../../generated/entity/services/dashboardService';
|
||||
import { DatabaseService } from '../../generated/entity/services/databaseService';
|
||||
import { MessagingService } from '../../generated/entity/services/messagingService';
|
||||
import { MlmodelService } from '../../generated/entity/services/mlmodelService';
|
||||
import { PipelineService } from '../../generated/entity/services/pipelineService';
|
||||
import { EntityReference } from '../../generated/type/entityReference';
|
||||
import { Paging } from '../../generated/type/paging';
|
||||
@ -71,6 +72,7 @@ type ServiceRecord = {
|
||||
messagingServices: Array<MessagingService>;
|
||||
dashboardServices: Array<DashboardService>;
|
||||
pipelineServices: Array<PipelineService>;
|
||||
mlmodelServices: Array<MlmodelService>;
|
||||
};
|
||||
|
||||
type ServicePagingRecord = {
|
||||
@ -78,6 +80,7 @@ type ServicePagingRecord = {
|
||||
messagingServices: Paging;
|
||||
dashboardServices: Paging;
|
||||
pipelineServices: Paging;
|
||||
mlmodelServices: Paging;
|
||||
};
|
||||
|
||||
export type ApiData = {
|
||||
@ -104,12 +107,14 @@ const ServicesPage = () => {
|
||||
messagingServices: pagingObject,
|
||||
dashboardServices: pagingObject,
|
||||
pipelineServices: pagingObject,
|
||||
mlmodelServices: pagingObject,
|
||||
});
|
||||
const [services, setServices] = useState<ServiceRecord>({
|
||||
databaseServices: [],
|
||||
messagingServices: [],
|
||||
dashboardServices: [],
|
||||
pipelineServices: [],
|
||||
mlmodelServices: [],
|
||||
});
|
||||
const [serviceList, setServiceList] = useState<Array<ServiceDataObj>>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
@ -121,6 +126,7 @@ const ServicesPage = () => {
|
||||
messagingServices: 0,
|
||||
dashboardServices: 0,
|
||||
pipelineServices: 0,
|
||||
mlmodelServices: 0,
|
||||
});
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
@ -170,6 +176,7 @@ const ServicesPage = () => {
|
||||
messagingServices: servicePaging.messagingServices.total || 0,
|
||||
dashboardServices: servicePaging.dashboardServices.total || 0,
|
||||
pipelineServices: servicePaging.pipelineServices.total || 0,
|
||||
mlmodelServices: servicePaging.mlmodelServices.total || 0,
|
||||
});
|
||||
setServiceList(
|
||||
serviceRecord[serviceName] as unknown as Array<ServiceDataObj>
|
||||
@ -190,14 +197,14 @@ const ServicesPage = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
showErrorToast(
|
||||
err,
|
||||
jsonData['api-error-messages']['fetch-services-error']
|
||||
);
|
||||
});
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
}
|
||||
};
|
||||
|
||||
@ -255,7 +262,7 @@ const ServicesPage = () => {
|
||||
onClick={() => {
|
||||
handleTabChange(tab.name);
|
||||
}}>
|
||||
<p className="tw-text-center tw-self-center label-category">
|
||||
<p className="tw-text-center tw-mb-0 tw-self-center label-category">
|
||||
{tab.displayName}
|
||||
</p>
|
||||
|
||||
@ -322,6 +329,31 @@ const ServicesPage = () => {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
case ServiceCategory.ML_MODAL_SERVICES: {
|
||||
const mlmodel = service as unknown as MlmodelService;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="tw-mb-1 tw-truncate" data-testid="additional-field">
|
||||
<label className="tw-mb-0">Registry:</label>
|
||||
<span
|
||||
className=" tw-ml-1 tw-font-normal tw-text-grey-body"
|
||||
data-testid="pipeline-url">
|
||||
{mlmodel.connection.config?.registryUri}
|
||||
</span>
|
||||
</div>
|
||||
<div className="tw-mb-1 tw-truncate" data-testid="additional-field">
|
||||
<label className="tw-mb-0">Tracking:</label>
|
||||
<span
|
||||
className=" tw-ml-1 tw-font-normal tw-text-grey-body"
|
||||
data-testid="pipeline-url">
|
||||
{mlmodel.connection.config?.trackingUri}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
default: {
|
||||
return <></>;
|
||||
}
|
||||
@ -416,7 +448,7 @@ const ServicesPage = () => {
|
||||
{serviceList.map((service, index) => (
|
||||
<Card key={index} style={leftPanelAntCardStyle}>
|
||||
<div
|
||||
className="tw-flex tw-py-2 tw-px-3 tw-justify-between tw-text-grey-muted"
|
||||
className="tw-flex tw-justify-between tw-text-grey-muted"
|
||||
data-testid="service-card">
|
||||
<div className="tw-flex tw-flex-col tw-justify-between tw-truncate">
|
||||
<div>
|
||||
|
@ -127,6 +127,7 @@ const TourPage = () => {
|
||||
return (
|
||||
<MyData
|
||||
countDashboards={10}
|
||||
countMlModal={2}
|
||||
countPipelines={8}
|
||||
countServices={4}
|
||||
countTables={21}
|
||||
|
@ -216,7 +216,7 @@
|
||||
}
|
||||
|
||||
.tw-form-container {
|
||||
@apply tw-bg-white tw-py-7 tw-px-5 tw-border tw-rounded-lg tw-shadow-form;
|
||||
@apply tw-bg-white tw-py-7 tw-px-5 tw-border tw-rounded-lg tw-shadow-form tw-w-700;
|
||||
}
|
||||
|
||||
/* Dropdown CSS start */
|
||||
|
@ -186,7 +186,7 @@ export const getLineageDataV1 = (
|
||||
const targetType = nodes.find((n) => edge.toEntity === n.id);
|
||||
|
||||
if (!isUndefined(edge.lineageDetails)) {
|
||||
edge.lineageDetails.columnsLineage.forEach((e) => {
|
||||
edge.lineageDetails.columnsLineage?.forEach((e) => {
|
||||
const toColumn = e.toColumn || '';
|
||||
if (e.fromColumns && e.fromColumns.length > 0) {
|
||||
e.fromColumns.forEach((fromColumn) => {
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 { cloneDeep } from 'lodash';
|
||||
import { COMMON_UI_SCHEMA } from '../constants/services.const';
|
||||
import { MlModelServiceType } from '../generated/entity/services/mlmodelService';
|
||||
import mlflowConnection from '../jsons/connectionSchemas/connections/mlmodel/mlflowConnection.json';
|
||||
import sklearnConnection from '../jsons/connectionSchemas/connections/mlmodel/sklearnConnection.json';
|
||||
|
||||
export const getMlmodelConfig = (type: MlModelServiceType) => {
|
||||
let schema = {};
|
||||
const uiSchema = { ...COMMON_UI_SCHEMA };
|
||||
switch (type) {
|
||||
case MlModelServiceType.Mlflow: {
|
||||
schema = mlflowConnection;
|
||||
|
||||
break;
|
||||
}
|
||||
case MlModelServiceType.Sklearn: {
|
||||
schema = sklearnConnection;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cloneDeep({ schema, uiSchema });
|
||||
};
|
@ -52,6 +52,7 @@ import {
|
||||
LOOKER,
|
||||
MARIADB,
|
||||
METABASE,
|
||||
MLFLOW,
|
||||
MSSQL,
|
||||
MYSQL,
|
||||
ORACLE,
|
||||
@ -64,6 +65,7 @@ import {
|
||||
REDASH,
|
||||
REDSHIFT,
|
||||
SALESFORCE,
|
||||
SCIKIT,
|
||||
serviceTypes,
|
||||
SINGLESTORE,
|
||||
SNOWFLAKE,
|
||||
@ -76,6 +78,7 @@ import {
|
||||
} 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';
|
||||
@ -186,6 +189,12 @@ export const serviceTypeLogo = (type: string) => {
|
||||
|
||||
case PipelineServiceType.Prefect:
|
||||
return PREFECT;
|
||||
|
||||
case MlModelServiceType.Mlflow:
|
||||
return MLFLOW;
|
||||
|
||||
case MlModelServiceType.Sklearn:
|
||||
return SCIKIT;
|
||||
default: {
|
||||
let logo;
|
||||
if (serviceTypes.messagingServices.includes(type)) {
|
||||
|
@ -110,6 +110,7 @@ import LogoMonogram from '../assets/svg/logo-monogram.svg';
|
||||
import Logo from '../assets/svg/logo.svg';
|
||||
import IconManageColor from '../assets/svg/manage-color.svg';
|
||||
import IconMinus from '../assets/svg/minus.svg';
|
||||
import IconMlModal from '../assets/svg/mlmodal.svg';
|
||||
import IconPaperPlanePrimary from '../assets/svg/paper-plane-primary.svg';
|
||||
import IconPaperPlane from '../assets/svg/paper-plane.svg';
|
||||
import IconPendingBadge from '../assets/svg/pending-badge.svg';
|
||||
@ -238,6 +239,7 @@ export const Icons = {
|
||||
EXTERNAL_LINK_GREY: 'external-link-grey',
|
||||
PROFILER: 'icon-profiler',
|
||||
PIPELINE: 'pipeline',
|
||||
MLMODAL: 'mlmodal',
|
||||
PIPELINE_GREY: 'pipeline-grey',
|
||||
DBTMODEL_GREY: 'dbtmodel-grey',
|
||||
DBTMODEL_LIGHT_GREY: 'dbtmodel-light-grey',
|
||||
@ -570,6 +572,10 @@ const SVGIcons: FunctionComponent<Props> = ({
|
||||
case Icons.TOPIC:
|
||||
IconComponent = IconTopic;
|
||||
|
||||
break;
|
||||
case Icons.MLMODAL:
|
||||
IconComponent = IconMlModal;
|
||||
|
||||
break;
|
||||
case Icons.DASHBOARD:
|
||||
IconComponent = IconDashboard;
|
||||
|
@ -173,6 +173,7 @@ module.exports = {
|
||||
'screen-xxl': '2160px',
|
||||
'full-hd': '1080px',
|
||||
600: '600px',
|
||||
700: '700px',
|
||||
},
|
||||
minWidth: {
|
||||
badgeCount: '30px',
|
||||
|
Loading…
x
Reference in New Issue
Block a user