mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-05 07:03:07 +00:00
Fixed routes for Service details page (#328)
* Fixed routes for Service details page * Integrated topis api * Broker url and other misc fixes
This commit is contained in:
parent
8dcbcbc171
commit
45b2967a6f
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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 { getURLWithQueryFields } from '../utils/APIUtils';
|
||||||
|
import APIClient from './index';
|
||||||
|
|
||||||
|
export const getTopics: Function = (
|
||||||
|
serviceName: string,
|
||||||
|
paging: string,
|
||||||
|
arrQueryFields: string
|
||||||
|
): Promise<AxiosResponse> => {
|
||||||
|
const url = `${getURLWithQueryFields(
|
||||||
|
`/topics`,
|
||||||
|
arrQueryFields
|
||||||
|
)}&service=${serviceName}${paging ? paging : ''}`;
|
||||||
|
|
||||||
|
return APIClient.get(url);
|
||||||
|
};
|
@ -19,7 +19,10 @@ import classNames from 'classnames';
|
|||||||
import { ServiceTypes } from 'Models';
|
import { ServiceTypes } from 'Models';
|
||||||
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
||||||
import { serviceTypes } from '../../../constants/services.const';
|
import { serviceTypes } from '../../../constants/services.const';
|
||||||
import { ServiceCategory } from '../../../enums/service.enum';
|
import {
|
||||||
|
MessagingServiceType,
|
||||||
|
ServiceCategory,
|
||||||
|
} from '../../../enums/service.enum';
|
||||||
import { fromISOString } from '../../../utils/ServiceUtils';
|
import { fromISOString } from '../../../utils/ServiceUtils';
|
||||||
import { Button } from '../../buttons/Button/Button';
|
import { Button } from '../../buttons/Button/Button';
|
||||||
import MarkdownWithPreview from '../../common/editor/MarkdownWithPreview';
|
import MarkdownWithPreview from '../../common/editor/MarkdownWithPreview';
|
||||||
@ -167,8 +170,8 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
// const [port, setPort] = useState(parseUrl?.port || '');
|
// const [port, setPort] = useState(parseUrl?.port || '');
|
||||||
const [database, setDatabase] = useState(parseUrl?.database || '');
|
const [database, setDatabase] = useState(parseUrl?.database || '');
|
||||||
const [driverClass, setDriverClass] = useState(data?.driverClass || 'jdbc');
|
const [driverClass, setDriverClass] = useState(data?.driverClass || 'jdbc');
|
||||||
const [broker, setBroker] = useState(
|
const [brokers, setBrokers] = useState(
|
||||||
data?.brokers?.length ? data.brokers[0] : ''
|
data?.brokers?.length ? data.brokers.join(', ') : ''
|
||||||
);
|
);
|
||||||
const [schemaRegistry, setSchemaRegistry] = useState(
|
const [schemaRegistry, setSchemaRegistry] = useState(
|
||||||
data?.schemaRegistry || ''
|
data?.schemaRegistry || ''
|
||||||
@ -188,6 +191,13 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
});
|
});
|
||||||
const [sameNameError, setSameNameError] = useState(false);
|
const [sameNameError, setSameNameError] = useState(false);
|
||||||
const markdownRef = useRef<EditorContentRef>();
|
const markdownRef = useRef<EditorContentRef>();
|
||||||
|
|
||||||
|
const getBrokerUrlPlaceholder = (): string => {
|
||||||
|
return selectService === MessagingServiceType.PULSAR
|
||||||
|
? 'eg.: hostname:port'
|
||||||
|
: 'eg.: hostname1:port1, hostname2:port2';
|
||||||
|
};
|
||||||
|
|
||||||
const handleChangeFrequency = (
|
const handleChangeFrequency = (
|
||||||
event: React.ChangeEvent<HTMLSelectElement>
|
event: React.ChangeEvent<HTMLSelectElement>
|
||||||
) => {
|
) => {
|
||||||
@ -289,7 +299,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
{
|
{
|
||||||
setMsg = {
|
setMsg = {
|
||||||
...setMsg,
|
...setMsg,
|
||||||
broker: !broker,
|
broker: !brokers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,7 +339,10 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
{
|
{
|
||||||
dataObj = {
|
dataObj = {
|
||||||
...dataObj,
|
...dataObj,
|
||||||
brokers: [broker],
|
brokers:
|
||||||
|
selectService === MessagingServiceType.PULSAR
|
||||||
|
? [brokers]
|
||||||
|
: brokers.split(',').map((broker) => broker.trim()),
|
||||||
schemaRegistry: schemaRegistry,
|
schemaRegistry: schemaRegistry,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -354,6 +367,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
className="tw-form-inputs tw-px-3 tw-py-1"
|
className="tw-form-inputs tw-px-3 tw-py-1"
|
||||||
id="url"
|
id="url"
|
||||||
name="url"
|
name="url"
|
||||||
|
placeholder="eg.: username:password@hostname:port"
|
||||||
type="text"
|
type="text"
|
||||||
value={url}
|
value={url}
|
||||||
onChange={handleValidation}
|
onChange={handleValidation}
|
||||||
@ -416,6 +430,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
className="tw-form-inputs tw-px-3 tw-py-1"
|
className="tw-form-inputs tw-px-3 tw-py-1"
|
||||||
id="database"
|
id="database"
|
||||||
name="database"
|
name="database"
|
||||||
|
placeholder="Enter database name"
|
||||||
type="text"
|
type="text"
|
||||||
value={database}
|
value={database}
|
||||||
onChange={(e) => setDatabase(e.target.value)}
|
onChange={(e) => setDatabase(e.target.value)}
|
||||||
@ -460,9 +475,10 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
className="tw-form-inputs tw-px-3 tw-py-1"
|
className="tw-form-inputs tw-px-3 tw-py-1"
|
||||||
id="broker"
|
id="broker"
|
||||||
name="broker"
|
name="broker"
|
||||||
|
placeholder={getBrokerUrlPlaceholder()}
|
||||||
type="text"
|
type="text"
|
||||||
value={broker}
|
value={brokers}
|
||||||
onChange={(e) => setBroker(e.target.value)}
|
onChange={(e) => setBrokers(e.target.value)}
|
||||||
/>
|
/>
|
||||||
{showErrorMsg.broker && errorMsg('Broker url is required')}
|
{showErrorMsg.broker && errorMsg('Broker url is required')}
|
||||||
</div>
|
</div>
|
||||||
@ -474,6 +490,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
className="tw-form-inputs tw-px-3 tw-py-1"
|
className="tw-form-inputs tw-px-3 tw-py-1"
|
||||||
id="schema-registry"
|
id="schema-registry"
|
||||||
name="schema-registry"
|
name="schema-registry"
|
||||||
|
placeholder="eg.: hostname:port"
|
||||||
type="text"
|
type="text"
|
||||||
value={schemaRegistry}
|
value={schemaRegistry}
|
||||||
onChange={(e) => setSchemaRegistry(e.target.value)}
|
onChange={(e) => setSchemaRegistry(e.target.value)}
|
||||||
@ -546,6 +563,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
className="tw-form-inputs tw-px-3 tw-py-1"
|
className="tw-form-inputs tw-px-3 tw-py-1"
|
||||||
id="name"
|
id="name"
|
||||||
name="name"
|
name="name"
|
||||||
|
placeholder="Enter service name"
|
||||||
type="text"
|
type="text"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={handleValidation}
|
onChange={handleValidation}
|
||||||
|
@ -33,15 +33,15 @@ const TitleBreadcrumb: FunctionComponent<TitleBreadcrumbProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={index}>
|
<li key={index}>
|
||||||
|
{link.imgSrc ? (
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
className="tw-inline tw-h-5 tw-w-5 tw-mr-2"
|
||||||
|
src={link.imgSrc}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
{index < titleLinks.length - 1 ? (
|
{index < titleLinks.length - 1 ? (
|
||||||
<>
|
<>
|
||||||
{link.imgSrc ? (
|
|
||||||
<img
|
|
||||||
alt=""
|
|
||||||
className="tw-inline tw-h-5 tw-w-5 tw-mr-2"
|
|
||||||
src={link.imgSrc}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<Link className={classes} to={link.url}>
|
<Link className={classes} to={link.url}>
|
||||||
{link.name}
|
{link.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -36,6 +36,7 @@ const PLACEHOLDER_ROUTE_DATASET_FQN = ':datasetFQN';
|
|||||||
const PLACEHOLDER_ROUTE_TOPIC_FQN = ':topicFQN';
|
const PLACEHOLDER_ROUTE_TOPIC_FQN = ':topicFQN';
|
||||||
const PLACEHOLDER_ROUTE_DATABASE_FQN = ':databaseFQN';
|
const PLACEHOLDER_ROUTE_DATABASE_FQN = ':databaseFQN';
|
||||||
const PLACEHOLDER_ROUTE_SERVICE_FQN = ':serviceFQN';
|
const PLACEHOLDER_ROUTE_SERVICE_FQN = ':serviceFQN';
|
||||||
|
const PLACEHOLDER_ROUTE_SERVICE_TYPE = ':serviceType';
|
||||||
const PLACEHOLDER_ROUTE_SEARCHQUERY = ':searchQuery';
|
const PLACEHOLDER_ROUTE_SEARCHQUERY = ':searchQuery';
|
||||||
|
|
||||||
export const pagingObject = { after: '', before: '' };
|
export const pagingObject = { after: '', before: '' };
|
||||||
@ -101,7 +102,7 @@ export const ROUTES = {
|
|||||||
STORE: '/store',
|
STORE: '/store',
|
||||||
FEEDS: '/feeds',
|
FEEDS: '/feeds',
|
||||||
DUMMY: '/dummy',
|
DUMMY: '/dummy',
|
||||||
SERVICE: `/service/${PLACEHOLDER_ROUTE_SERVICE_FQN}`,
|
SERVICE: `/service/${PLACEHOLDER_ROUTE_SERVICE_TYPE}/${PLACEHOLDER_ROUTE_SERVICE_FQN}`,
|
||||||
SERVICES: '/services',
|
SERVICES: '/services',
|
||||||
USERS: '/users',
|
USERS: '/users',
|
||||||
SCORECARD: '/scorecard',
|
SCORECARD: '/scorecard',
|
||||||
@ -129,9 +130,14 @@ export const getDatasetDetailsPath = (
|
|||||||
return `${path}${columnName ? `#${columnName}` : ''}`;
|
return `${path}${columnName ? `#${columnName}` : ''}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getServiceDetailsPath = (serviceFQN: string) => {
|
export const getServiceDetailsPath = (
|
||||||
|
serviceFQN: string,
|
||||||
|
serviceType: string
|
||||||
|
) => {
|
||||||
let path = ROUTES.SERVICE;
|
let path = ROUTES.SERVICE;
|
||||||
path = path.replace(PLACEHOLDER_ROUTE_SERVICE_FQN, serviceFQN);
|
path = path
|
||||||
|
.replace(PLACEHOLDER_ROUTE_SERVICE_TYPE, serviceType)
|
||||||
|
.replace(PLACEHOLDER_ROUTE_SERVICE_FQN, serviceFQN);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
};
|
};
|
||||||
|
@ -29,6 +29,7 @@ import redshift from '../assets/img/service-icon-redshift.png';
|
|||||||
import snowflakes from '../assets/img/service-icon-snowflakes.png';
|
import snowflakes from '../assets/img/service-icon-snowflakes.png';
|
||||||
import mysql from '../assets/img/service-icon-sql.png';
|
import mysql from '../assets/img/service-icon-sql.png';
|
||||||
import plus from '../assets/svg/plus.svg';
|
import plus from '../assets/svg/plus.svg';
|
||||||
|
import { ServiceCategory } from '../enums/service.enum';
|
||||||
|
|
||||||
export const MYSQL = mysql;
|
export const MYSQL = mysql;
|
||||||
export const MSSQL = mssql;
|
export const MSSQL = mssql;
|
||||||
@ -67,3 +68,14 @@ export const servicesDisplayName = {
|
|||||||
databaseServices: 'Database Service',
|
databaseServices: 'Database Service',
|
||||||
messagingServices: 'Messaging Service',
|
messagingServices: 'Messaging Service',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const routeServiceTypes = [
|
||||||
|
{
|
||||||
|
param: 'database',
|
||||||
|
type: ServiceCategory.DATABASE_SERVICES,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
param: 'messaging',
|
||||||
|
type: ServiceCategory.MESSAGING_SERVICES,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
@ -50,12 +50,13 @@ declare module 'Models' {
|
|||||||
|
|
||||||
export type ServiceOption = {
|
export type ServiceOption = {
|
||||||
id: string;
|
id: string;
|
||||||
|
brokers?: Array<string>;
|
||||||
description: string;
|
description: string;
|
||||||
ingestionSchedule?: {
|
ingestionSchedule?: {
|
||||||
repeatFrequency: string;
|
repeatFrequency: string;
|
||||||
startDate: string;
|
startDate: string;
|
||||||
};
|
};
|
||||||
jdbc: { connectionUrl: string; driverClass: string };
|
jdbc?: { connectionUrl: string; driverClass: string };
|
||||||
name: string;
|
name: string;
|
||||||
serviceType: string;
|
serviceType: string;
|
||||||
};
|
};
|
||||||
|
@ -115,7 +115,10 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
{
|
{
|
||||||
name: resService.data.name,
|
name: resService.data.name,
|
||||||
url: resService.data.name
|
url: resService.data.name
|
||||||
? getServiceDetailsPath(resService.data.name)
|
? getServiceDetailsPath(
|
||||||
|
resService.data.name,
|
||||||
|
resService.data.serviceType
|
||||||
|
)
|
||||||
: '',
|
: '',
|
||||||
imgSrc: resService.data.serviceType
|
imgSrc: resService.data.serviceType
|
||||||
? serviceTypeLogo(resService.data.serviceType)
|
? serviceTypeLogo(resService.data.serviceType)
|
||||||
|
@ -327,7 +327,10 @@ const MyDataDetailsPage = () => {
|
|||||||
{
|
{
|
||||||
name: resService.data.name,
|
name: resService.data.name,
|
||||||
url: resService.data.name
|
url: resService.data.name
|
||||||
? getServiceDetailsPath(resService.data.name)
|
? getServiceDetailsPath(
|
||||||
|
resService.data.name,
|
||||||
|
resService.data.serviceType
|
||||||
|
)
|
||||||
: '',
|
: '',
|
||||||
imgSrc: resService.data.serviceType
|
imgSrc: resService.data.serviceType
|
||||||
? serviceTypeLogo(resService.data.serviceType)
|
? serviceTypeLogo(resService.data.serviceType)
|
||||||
|
@ -19,27 +19,38 @@ import { AxiosError, AxiosResponse } from 'axios';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { isNull, isUndefined } from 'lodash';
|
import { isNull, isUndefined } from 'lodash';
|
||||||
import { Database, Paging, ServiceOption } from 'Models';
|
import { Database, Paging, ServiceOption } from 'Models';
|
||||||
import React, { FunctionComponent, useEffect, useState } from 'react';
|
import React, { Fragment, FunctionComponent, useEffect, useState } from 'react';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
import { Link, useParams } from 'react-router-dom';
|
||||||
import { getDatabases } from '../../axiosAPIs/databaseAPI';
|
import { getDatabases } from '../../axiosAPIs/databaseAPI';
|
||||||
import { getServiceByFQN, updateService } from '../../axiosAPIs/serviceAPI';
|
import { getServiceByFQN, updateService } from '../../axiosAPIs/serviceAPI';
|
||||||
|
import { getTopics } from '../../axiosAPIs/topicsAPI';
|
||||||
import NextPrevious from '../../components/common/next-previous/NextPrevious';
|
import NextPrevious from '../../components/common/next-previous/NextPrevious';
|
||||||
|
import PopOver from '../../components/common/popover/PopOver';
|
||||||
import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer';
|
import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer';
|
||||||
import TitleBreadcrumb from '../../components/common/title-breadcrumb/title-breadcrumb.component';
|
import TitleBreadcrumb from '../../components/common/title-breadcrumb/title-breadcrumb.component';
|
||||||
import { TitleBreadcrumbProps } from '../../components/common/title-breadcrumb/title-breadcrumb.interface';
|
import { TitleBreadcrumbProps } from '../../components/common/title-breadcrumb/title-breadcrumb.interface';
|
||||||
import PageContainer from '../../components/containers/PageContainer';
|
import PageContainer from '../../components/containers/PageContainer';
|
||||||
import Loader from '../../components/Loader/Loader';
|
import Loader from '../../components/Loader/Loader';
|
||||||
import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
||||||
|
import Tags from '../../components/tags/tags';
|
||||||
import { pagingObject } from '../../constants/constants';
|
import { pagingObject } from '../../constants/constants';
|
||||||
|
import { ServiceCategory } from '../../enums/service.enum';
|
||||||
|
import { Topic } from '../../generated/entity/data/topic';
|
||||||
import useToastContext from '../../hooks/useToastContext';
|
import useToastContext from '../../hooks/useToastContext';
|
||||||
import { isEven } from '../../utils/CommonUtils';
|
import { isEven } from '../../utils/CommonUtils';
|
||||||
import { getFrequencyTime, serviceTypeLogo } from '../../utils/ServiceUtils';
|
import {
|
||||||
|
getFrequencyTime,
|
||||||
|
getServiceCategoryFromType,
|
||||||
|
serviceTypeLogo,
|
||||||
|
} from '../../utils/ServiceUtils';
|
||||||
import SVGIcons from '../../utils/SvgUtils';
|
import SVGIcons from '../../utils/SvgUtils';
|
||||||
import { getUsagePercentile } from '../../utils/TableUtils';
|
import { getUsagePercentile } from '../../utils/TableUtils';
|
||||||
|
|
||||||
const ServicePage: FunctionComponent = () => {
|
const ServicePage: FunctionComponent = () => {
|
||||||
const { serviceFQN } = useParams() as Record<string, string>;
|
const { serviceFQN, serviceType } = useParams() as Record<string, string>;
|
||||||
const [serviceName] = useState('databaseServices');
|
const [serviceName, setServiceName] = useState(
|
||||||
|
getServiceCategoryFromType(serviceType)
|
||||||
|
);
|
||||||
const [slashedTableName, setSlashedTableName] = useState<
|
const [slashedTableName, setSlashedTableName] = useState<
|
||||||
TitleBreadcrumbProps['titleLinks']
|
TitleBreadcrumbProps['titleLinks']
|
||||||
>([]);
|
>([]);
|
||||||
@ -47,7 +58,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
const [description, setDescription] = useState('');
|
const [description, setDescription] = useState('');
|
||||||
const [serviceDetails, setServiceDetails] = useState<ServiceOption>();
|
const [serviceDetails, setServiceDetails] = useState<ServiceOption>();
|
||||||
const [data, setData] = useState<Array<Database>>([]);
|
const [data, setData] = useState<Array<Database>>([]);
|
||||||
const [isLoading, setIsloading] = useState(false);
|
const [isLoading, setIsloading] = useState(true);
|
||||||
const [paging, setPaging] = useState<Paging>(pagingObject);
|
const [paging, setPaging] = useState<Paging>(pagingObject);
|
||||||
const showToast = useToastContext();
|
const showToast = useToastContext();
|
||||||
|
|
||||||
@ -70,6 +81,179 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchTopics = (paging?: string) => {
|
||||||
|
setIsloading(true);
|
||||||
|
getTopics(serviceFQN, paging, ['owner', 'service', 'tags'])
|
||||||
|
.then((res: AxiosResponse) => {
|
||||||
|
if (res.data.data) {
|
||||||
|
setData(res.data.data);
|
||||||
|
setPaging(res.data.paging);
|
||||||
|
setIsloading(false);
|
||||||
|
} else {
|
||||||
|
setData([]);
|
||||||
|
setPaging(pagingObject);
|
||||||
|
setIsloading(false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setIsloading(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOtherDetails = (paging?: string) => {
|
||||||
|
switch (serviceName) {
|
||||||
|
case ServiceCategory.DATABASE_SERVICES: {
|
||||||
|
fetchDatabases(paging);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServiceCategory.MESSAGING_SERVICES: {
|
||||||
|
fetchTopics(paging);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOptionalFields = (): JSX.Element => {
|
||||||
|
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-inline-block tw-text-gray-400">•</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case ServiceCategory.MESSAGING_SERVICES: {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
<span className="tw-text-grey-muted tw-font-normal">Brokers :</span>{' '}
|
||||||
|
<span className="tw-pl-1tw-font-normal ">
|
||||||
|
{serviceDetails?.brokers?.length ? (
|
||||||
|
<>
|
||||||
|
{serviceDetails.brokers.slice(0, 3).join(', ')}
|
||||||
|
{serviceDetails.brokers.length > 3 ? (
|
||||||
|
<PopOver
|
||||||
|
html={
|
||||||
|
<div className="tw-text-left">
|
||||||
|
{serviceDetails.brokers
|
||||||
|
.slice(3)
|
||||||
|
.map((broker, index) => (
|
||||||
|
<Fragment key={index}>
|
||||||
|
<span className="tw-block tw-py-1">
|
||||||
|
{broker}
|
||||||
|
</span>
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
position="bottom"
|
||||||
|
theme="light"
|
||||||
|
trigger="click">
|
||||||
|
<span className="show-more tw-ml-1">...</span>
|
||||||
|
</PopOver>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
'--'
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span className="tw-mx-3 tw-inline-block tw-text-gray-400">•</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTableHeaders = (): JSX.Element => {
|
||||||
|
switch (serviceName) {
|
||||||
|
case ServiceCategory.DATABASE_SERVICES: {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<th className="tableHead-cell">Database Name</th>
|
||||||
|
<th className="tableHead-cell">Description</th>
|
||||||
|
<th className="tableHead-cell">Owner</th>
|
||||||
|
<th className="tableHead-cell">Usage</th>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case ServiceCategory.MESSAGING_SERVICES: {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<th className="tableHead-cell">Topic Name</th>
|
||||||
|
<th className="tableHead-cell">Description</th>
|
||||||
|
<th className="tableHead-cell">Owner</th>
|
||||||
|
<th className="tableHead-cell">Tags</th>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOptionalTableCells = (data: Database | Topic) => {
|
||||||
|
switch (serviceName) {
|
||||||
|
case ServiceCategory.DATABASE_SERVICES: {
|
||||||
|
const database = data as Database;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<td className="tableBody-cell">
|
||||||
|
<p>
|
||||||
|
{getUsagePercentile(
|
||||||
|
database.usageSummary.weeklyStats.percentileRank
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case ServiceCategory.MESSAGING_SERVICES: {
|
||||||
|
const topic = data as Topic;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<td className="tableBody-cell">
|
||||||
|
{topic.tags && topic.tags?.length > 0
|
||||||
|
? topic.tags.map((tag, tagIndex) => (
|
||||||
|
<PopOver
|
||||||
|
key={tagIndex}
|
||||||
|
position="top"
|
||||||
|
size="small"
|
||||||
|
title={tag.labelType}
|
||||||
|
trigger="mouseenter">
|
||||||
|
<Tags
|
||||||
|
className="tw-bg-gray-200"
|
||||||
|
tag={`#${
|
||||||
|
tag.tagFQN?.startsWith('Tier.Tier')
|
||||||
|
? tag.tagFQN.split('.')[1]
|
||||||
|
: tag.tagFQN
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</PopOver>
|
||||||
|
))
|
||||||
|
: '--'}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setServiceName(getServiceCategoryFromType(serviceType));
|
||||||
|
}, [serviceType]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getServiceByFQN(serviceName, serviceFQN).then(
|
getServiceByFQN(serviceName, serviceFQN).then(
|
||||||
(resService: AxiosResponse) => {
|
(resService: AxiosResponse) => {
|
||||||
@ -84,13 +268,10 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
activeTitle: true,
|
activeTitle: true,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
getOtherDetails();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}, []);
|
}, [serviceFQN, serviceName]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchDatabases();
|
|
||||||
}, [serviceFQN]);
|
|
||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
setIsEdit(false);
|
setIsEdit(false);
|
||||||
@ -129,7 +310,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
const pagingString = `&${cursorType}=${
|
const pagingString = `&${cursorType}=${
|
||||||
paging[cursorType as keyof typeof paging]
|
paging[cursorType as keyof typeof paging]
|
||||||
}`;
|
}`;
|
||||||
fetchDatabases(pagingString);
|
getOtherDetails(pagingString);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -142,17 +323,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
<TitleBreadcrumb titleLinks={slashedTableName} />
|
<TitleBreadcrumb titleLinks={slashedTableName} />
|
||||||
|
|
||||||
<div className="tw-flex tw-gap-1 tw-mb-2 tw-mt-1">
|
<div className="tw-flex tw-gap-1 tw-mb-2 tw-mt-1">
|
||||||
<span>
|
{getOptionalFields()}
|
||||||
<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-inline-block tw-text-gray-400">
|
|
||||||
•
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span>
|
<span>
|
||||||
<span className="tw-text-grey-muted tw-font-normal">
|
<span className="tw-text-grey-muted tw-font-normal">
|
||||||
Ingestion :
|
Ingestion :
|
||||||
@ -163,7 +334,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
? getFrequencyTime(
|
? getFrequencyTime(
|
||||||
serviceDetails.ingestionSchedule.repeatFrequency
|
serviceDetails.ingestionSchedule.repeatFrequency
|
||||||
)
|
)
|
||||||
: 'N/A'}
|
: '--'}
|
||||||
</span>
|
</span>
|
||||||
<span className="tw-mx-3 tw-inline-block tw-text-gray-400">
|
<span className="tw-mx-3 tw-inline-block tw-text-gray-400">
|
||||||
•
|
•
|
||||||
@ -223,12 +394,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
className="tw-bg-white tw-w-full tw-mb-4"
|
className="tw-bg-white tw-w-full tw-mb-4"
|
||||||
data-testid="database-tables">
|
data-testid="database-tables">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="tableHead-row">
|
<tr className="tableHead-row">{getTableHeaders()}</tr>
|
||||||
<th className="tableHead-cell">Database Name</th>
|
|
||||||
<th className="tableHead-cell">Description</th>
|
|
||||||
<th className="tableHead-cell">Owner</th>
|
|
||||||
<th className="tableHead-cell">Usage</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="tableBody">
|
<tbody className="tableBody">
|
||||||
{data.length > 0 ? (
|
{data.length > 0 ? (
|
||||||
@ -259,13 +425,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
<td className="tableBody-cell">
|
<td className="tableBody-cell">
|
||||||
<p>{database?.owner?.name || '--'}</p>
|
<p>{database?.owner?.name || '--'}</p>
|
||||||
</td>
|
</td>
|
||||||
<td className="tableBody-cell">
|
{getOptionalTableCells(database)}
|
||||||
<p>
|
|
||||||
{getUsagePercentile(
|
|
||||||
database.usageSummary.weeklyStats.percentileRank
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
|
@ -292,7 +292,11 @@ const ServicesPage = () => {
|
|||||||
className="tw-card tw-flex tw-py-2 tw-px-3 tw-justify-between tw-text-grey-muted"
|
className="tw-card tw-flex tw-py-2 tw-px-3 tw-justify-between tw-text-grey-muted"
|
||||||
key={index}>
|
key={index}>
|
||||||
<div className="tw-flex-auto">
|
<div className="tw-flex-auto">
|
||||||
<Link to={getServiceDetailsPath(service.name)}>
|
<Link
|
||||||
|
to={getServiceDetailsPath(
|
||||||
|
service.name,
|
||||||
|
service.serviceType
|
||||||
|
)}>
|
||||||
<button>
|
<button>
|
||||||
<h6 className="tw-text-base tw-text-grey-body tw-font-medium">
|
<h6 className="tw-text-base tw-text-grey-body tw-font-medium">
|
||||||
{service.name}
|
{service.name}
|
||||||
@ -318,7 +322,7 @@ const ServicesPage = () => {
|
|||||||
? getFrequencyTime(
|
? getFrequencyTime(
|
||||||
service.ingestionSchedule.repeatFrequency
|
service.ingestionSchedule.repeatFrequency
|
||||||
)
|
)
|
||||||
: 'N/A'}
|
: '--'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="">
|
<div className="">
|
||||||
@ -359,9 +363,9 @@ const ServicesPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<div
|
<div
|
||||||
className="tw-cursor-pointer tw-card tw-flex tw-flex-col tw-justify-center tw-items-center tw-py-2"
|
className="tw-cursor-pointer tw-card tw-flex tw-flex-col tw-justify-center tw-items-center tw-py-6"
|
||||||
onClick={() => handleAddService()}>
|
onClick={() => handleAddService()}>
|
||||||
<img alt="" src={PLUS} />
|
<img alt="Add service" src={PLUS} />
|
||||||
<p className="tw-text-base tw-font-normal tw-mt-4">
|
<p className="tw-text-base tw-font-normal tw-mt-4">
|
||||||
Add new {servicesDisplayName[serviceName]}
|
Add new {servicesDisplayName[serviceName]}
|
||||||
</p>
|
</p>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { AxiosResponse } from 'axios';
|
import { AxiosResponse } from 'axios';
|
||||||
import { ServiceCollection, ServiceData } from 'Models';
|
import { ServiceCollection, ServiceData, ServiceTypes } from 'Models';
|
||||||
import { getServiceDetails, getServices } from '../axiosAPIs/serviceAPI';
|
import { getServiceDetails, getServices } from '../axiosAPIs/serviceAPI';
|
||||||
import { ServiceDataObj } from '../components/Modals/AddServiceModal/AddServiceModal';
|
import { ServiceDataObj } from '../components/Modals/AddServiceModal/AddServiceModal';
|
||||||
import {
|
import {
|
||||||
@ -12,6 +12,7 @@ import {
|
|||||||
POSTGRES,
|
POSTGRES,
|
||||||
PULSAR,
|
PULSAR,
|
||||||
REDSHIFT,
|
REDSHIFT,
|
||||||
|
serviceTypes,
|
||||||
SERVICE_DEFAULT,
|
SERVICE_DEFAULT,
|
||||||
SNOWFLAKE,
|
SNOWFLAKE,
|
||||||
} from '../constants/services.const';
|
} from '../constants/services.const';
|
||||||
@ -137,3 +138,18 @@ export const getAllServices = (): Promise<Array<ServiceDataObj>> => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user