(USE_CLUSTER_BALANCER_AS_BACKEND_KEY);
return (
diff --git a/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx b/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx
index c96aea58f..bf8dda86c 100644
--- a/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx
+++ b/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx
@@ -1,47 +1,29 @@
-import {useClusterBaseInfo} from '../../../store/reducers/cluster/cluster';
-import type {ETenantType} from '../../../types/api/tenant';
+import type {GetDatabaseLinks} from '../../../uiFactory/types';
import {useAdditionalNodesProps} from '../../../utils/hooks/useAdditionalNodesProps';
import type {GetLogsLink} from '../../../utils/logs';
import type {GetMonitoringLink} from '../../../utils/monitoring';
import type {Tenant} from '../../Tenant/Tenant';
+import {useAdditionalTenantsProps} from '../utils/useAdditionalTenantsProps';
export interface ExtendedTenantProps {
component: typeof Tenant;
getMonitoringLink?: GetMonitoringLink;
getLogsLink?: GetLogsLink;
+ getDatabaseLinks?: GetDatabaseLinks;
}
export function ExtendedTenant({
component: TenantComponent,
getMonitoringLink,
getLogsLink,
+ getDatabaseLinks,
}: ExtendedTenantProps) {
- const {monitoring, logging} = useClusterBaseInfo();
const additionalNodesProps = useAdditionalNodesProps();
-
- const additionalTenantProps = {
- getMonitoringLink: (dbName?: string, dbType?: ETenantType) => {
- if (monitoring && dbName && dbType && getMonitoringLink) {
- return getMonitoringLink({
- monitoring,
- dbName,
- dbType,
- });
- }
-
- return null;
- },
- getLogsLink: (dbName?: string) => {
- if (logging && dbName && getLogsLink) {
- return getLogsLink({
- dbName,
- logging,
- });
- }
-
- return null;
- },
- };
+ const additionalTenantProps = useAdditionalTenantsProps({
+ getMonitoringLink,
+ getLogsLink,
+ getDatabaseLinks,
+ });
return (
(USE_CLUSTER_BALANCER_AS_BACKEND_KEY);
+
+ const {balancer, monitoring, logging, name: clusterName} = clusterInfo;
+
+ const additionalTenantsProps: AdditionalTenantsProps = {};
+ additionalTenantsProps.prepareTenantBackend = (nodeId) => {
+ // Balancer value is used to create path, so it's necessary
+ if (!balancer) {
+ return undefined;
+ }
+
+ if (useClusterBalancerAsBackend) {
+ return prepareBackendFromBalancer(balancer);
+ }
+
+ if (isNil(nodeId)) {
+ return undefined;
+ }
+
+ return getBackendFromBalancerAndNodeId(nodeId, balancer) ?? undefined;
+ };
+
+ if (monitoring && getMonitoringLink) {
+ additionalTenantsProps.getMonitoringLink = (dbName?: string, dbType?: ETenantType) => {
+ if (dbName && dbType) {
+ return getMonitoringLink({monitoring, clusterName, dbName, dbType});
+ }
+
+ return null;
+ };
+ }
+
+ if (logging && getLogsLink) {
+ additionalTenantsProps.getLogsLink = (dbName?: string) => {
+ if (dbName) {
+ return getLogsLink({logging, dbName});
+ }
+
+ return null;
+ };
+ }
+
+ if (getDatabaseLinks) {
+ additionalTenantsProps.getLinks = (dbName?: string, dbType?: ETenantType) => {
+ if (dbName && dbType) {
+ return getDatabaseLinks({clusterInfo, dbName, dbType});
+ }
+ return [];
+ };
+ }
+
+ return additionalTenantsProps;
+}
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx
index 192e22e3a..91b2347eb 100644
--- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx
+++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx
@@ -1,14 +1,13 @@
-import {Flex} from '@gravity-ui/uikit';
+import {Button, Flex, Icon} from '@gravity-ui/uikit';
import {EntityStatus} from '../../../../components/EntityStatus/EntityStatus';
import {LoaderWrapper} from '../../../../components/LoaderWrapper/LoaderWrapper';
-import {LogsButton} from '../../../../components/LogsButton/LogsButton';
-import {MonitoringButton} from '../../../../components/MonitoringButton/MonitoringButton';
import {overviewApi} from '../../../../store/reducers/overview/overview';
import {TENANT_METRICS_TABS_IDS} from '../../../../store/reducers/tenant/constants';
import {tenantApi} from '../../../../store/reducers/tenant/tenant';
import {calculateTenantMetrics} from '../../../../store/reducers/tenants/utils';
import type {AdditionalNodesProps, AdditionalTenantsProps} from '../../../../types/additionalProps';
+import {getDatabaseLinks} from '../../../../utils/additionalProps';
import {TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
import {useAutoRefreshInterval, useTypedSelector} from '../../../../utils/hooks';
import {useClusterNameFromQuery} from '../../../../utils/hooks/useDatabaseFromQuery';
@@ -141,8 +140,7 @@ export function TenantOverview({
}
};
- const monitoringLink = additionalTenantProps?.getMonitoringLink?.(Name, Type);
- const logsLink = additionalTenantProps?.getLogsLink?.(Name);
+ const links = getDatabaseLinks(additionalTenantProps, Name, Type);
return (
@@ -152,8 +150,17 @@ export function TenantOverview({
{renderName()}
- {monitoringLink && }
- {logsLink && }
+ {links.map(({title, url, icon}) => (
+
+ ))}
diff --git a/src/lib.ts b/src/lib.ts
index e76d3fb2c..5e1013c8d 100644
--- a/src/lib.ts
+++ b/src/lib.ts
@@ -33,3 +33,5 @@ export type {
export type {SettingProps, SettingsInfoFieldProps} from './containers/UserSettings/Setting';
export type {AsideNavigationProps} from './containers/AsideNavigation/AsideNavigation';
export type {GetMonitoringLink, GetMonitoringClusterLink} from './utils/monitoring';
+
+export {configureUIFactory} from './uiFactory/uiFactory';
diff --git a/src/services/parsers/parseMetaCluster.ts b/src/services/parsers/parseMetaCluster.ts
index 88561be50..2094af6e3 100644
--- a/src/services/parsers/parseMetaCluster.ts
+++ b/src/services/parsers/parseMetaCluster.ts
@@ -1,6 +1,9 @@
+import type {TTraceView} from '../../types/api/trace';
import {traceViewSchema} from '../../types/api/trace';
-export function parseTraceFields({traceView}: {traceView?: string}) {
+export function parseTraceFields({traceView}: {traceView?: string}): {
+ traceView?: TTraceView;
+} {
try {
return {
traceView: traceView ? traceViewSchema.parse(JSON.parse(traceView)) : undefined,
diff --git a/src/store/reducers/cluster/cluster.ts b/src/store/reducers/cluster/cluster.ts
index a8a378ed7..faa76f42d 100644
--- a/src/store/reducers/cluster/cluster.ts
+++ b/src/store/reducers/cluster/cluster.ts
@@ -158,6 +158,8 @@ export function useClusterBaseInfo() {
};
}
+export type ClusterInfo = ReturnType & Record;
+
const createClusterInfoSelector = createSelector(
(clusterName?: string) => clusterName,
(clusterName) => clusterApi.endpoints.getClusterInfo.select(clusterName),
diff --git a/src/store/reducers/tenant/tenant.ts b/src/store/reducers/tenant/tenant.ts
index 56460b321..23638ce3e 100644
--- a/src/store/reducers/tenant/tenant.ts
+++ b/src/store/reducers/tenant/tenant.ts
@@ -67,7 +67,11 @@ export const tenantApi = api.injectEndpoints({
} else {
tenantData = await window.api.viewer.getTenantInfo({path}, {signal});
}
- return {data: tenantData.TenantInfo?.[0] ?? null};
+ const databases = tenantData.TenantInfo || [];
+ // previous meta versions do not support filtering databases by name
+ const data =
+ databases.find((tenant) => tenant.Name === path) ?? databases[0] ?? null;
+ return {data};
} catch (error) {
return {error};
}
diff --git a/src/types/additionalProps.ts b/src/types/additionalProps.ts
index 600d2cd3d..a34ffd516 100644
--- a/src/types/additionalProps.ts
+++ b/src/types/additionalProps.ts
@@ -1,3 +1,5 @@
+import type {IconData} from '@gravity-ui/uikit';
+
import type {TSystemStateInfo} from './api/nodes';
import type {ETenantType} from './api/tenant';
import type {InfoItem} from './components';
@@ -7,6 +9,12 @@ export interface ClusterLink {
url: string;
}
+export interface DatabaseLink {
+ title: string;
+ url: string;
+ icon: IconData;
+}
+
export interface AdditionalClusterProps {
info?: InfoItem[];
links?: ClusterLink[];
@@ -16,6 +24,7 @@ export interface AdditionalTenantsProps {
prepareTenantBackend?: (nodeId?: string | number) => string | undefined;
getMonitoringLink?: (name?: string, type?: ETenantType) => string | null;
getLogsLink?: (name?: string) => string | null;
+ getLinks?: (name?: string, type?: ETenantType) => DatabaseLink[];
}
export type NodeAddress = Pick;
diff --git a/src/uiFactory/types.ts b/src/uiFactory/types.ts
index a739a9cee..d5ba682cf 100644
--- a/src/uiFactory/types.ts
+++ b/src/uiFactory/types.ts
@@ -3,9 +3,12 @@ import type {
GetHealthcheckViewTitles,
GetHealthcheckViewsOrder,
} from '../containers/Tenant/Healthcheck/shared';
+import type {ClusterInfo} from '../store/reducers/cluster/cluster';
import type {IssuesTree} from '../store/reducers/healthcheckInfo/types';
import type {PreparedTenant} from '../store/reducers/tenants/types';
+import type {ClusterLink, DatabaseLink} from '../types/additionalProps';
import type {MetaBaseClusterInfo} from '../types/api/meta';
+import type {ETenantType} from '../types/api/tenant';
import type {GetLogsLink} from '../utils/logs';
import type {GetMonitoringClusterLink, GetMonitoringLink} from '../utils/monitoring';
@@ -22,6 +25,9 @@ export interface UIFactory {
getMonitoringLink?: GetMonitoringLink;
getMonitoringClusterLink?: GetMonitoringClusterLink;
+ getDatabaseLinks?: GetDatabaseLinks;
+ getClusterLinks?: GetClusterLinks;
+
healthcheck: {
getHealthckechViewTitles: GetHealthcheckViewTitles;
getHealthcheckViewsOrder: GetHealthcheckViewsOrder;
@@ -48,3 +54,11 @@ export type HandleAddCluster = () => Promise;
export type HandleEditCluster = (params: {clusterData: MetaBaseClusterInfo}) => Promise;
export type HandleDeleteCluster = (params: {clusterData: MetaBaseClusterInfo}) => Promise;
+
+export type GetDatabaseLinks = (params: {
+ clusterInfo: ClusterInfo;
+ dbName?: string;
+ dbType?: ETenantType;
+}) => DatabaseLink[];
+
+export type GetClusterLinks = (params: {clusterInfo: ClusterInfo}) => ClusterLink[];
diff --git a/src/utils/additionalProps.ts b/src/utils/additionalProps.ts
index d635d629b..f7996da28 100644
--- a/src/utils/additionalProps.ts
+++ b/src/utils/additionalProps.ts
@@ -1,10 +1,51 @@
+import {FileText} from '@gravity-ui/icons';
+
+import i18n from '../components/TenantNameWrapper/i18n';
import {backend} from '../store';
-import type {AdditionalNodesProps} from '../types/additionalProps';
+import type {
+ AdditionalNodesProps,
+ AdditionalTenantsProps,
+ DatabaseLink,
+} from '../types/additionalProps';
+import type {ETenantType} from '../types/api/tenant';
import {getBackendFromBalancerAndNodeId} from './prepareBackend';
+import monitoringIcon from '../assets/icons/monitoring.svg';
+
export const getAdditionalNodesProps = (balancer = backend): AdditionalNodesProps => {
return {
getNodeRef: (node) => getBackendFromBalancerAndNodeId(node?.NodeId, balancer ?? ''),
};
};
+
+export function getDatabaseLinks(
+ additionalProps?: AdditionalTenantsProps,
+ name?: string,
+ type?: ETenantType,
+) {
+ if (!additionalProps) {
+ return [];
+ }
+
+ const links: DatabaseLink[] = [];
+ if (additionalProps.getMonitoringLink) {
+ const link = additionalProps.getMonitoringLink(name, type);
+ if (link) {
+ links.push({title: i18n('field_monitoring-link'), url: link, icon: monitoringIcon});
+ }
+ }
+
+ if (additionalProps.getLogsLink) {
+ const link = additionalProps.getLogsLink(name);
+ if (link) {
+ links.push({title: i18n('field_logs-link'), url: link, icon: FileText});
+ }
+ }
+
+ if (additionalProps.getLinks) {
+ links.push(...additionalProps.getLinks(name, type));
+ }
+
+ return links;
+}