Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {useClusterBaseInfo} from '../../../store/reducers/cluster/cluster';
import type {Node} from '../../Node/Node';
import {useClusterData} from '../useClusterData';
import {useAdditionalNodeProps} from '../useClusterData';

export function ExtendedNode({component: NodeComponent}: {component: typeof Node}) {
const {additionalNodesProps} = useClusterData();
const {balancer} = useClusterBaseInfo();
const {additionalNodesProps} = useAdditionalNodeProps({balancer});

return <NodeComponent additionalNodesProps={additionalNodesProps} />;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {MonitoringButton} from '../../../components/MonitoringButton/MonitoringButton';
import {useClusterBaseInfo} from '../../../store/reducers/cluster/cluster';
import type {ETenantType} from '../../../types/api/tenant';
import type {GetMonitoringLink} from '../../../utils/monitoring';
import type {Tenant} from '../../Tenant/Tenant';
import {useClusterData} from '../useClusterData';
import {useAdditionalNodeProps} from '../useClusterData';

export interface ExtendedTenantProps {
component: typeof Tenant;
Expand All @@ -13,7 +14,8 @@ export function ExtendedTenant({
component: TenantComponent,
getMonitoringLink,
}: ExtendedTenantProps) {
const {additionalNodesProps, cluster, monitoring} = useClusterData();
const {balancer, monitoring} = useClusterBaseInfo();
const {additionalNodesProps} = useAdditionalNodeProps({balancer});

const additionalTenantProps = {
getMonitoringLink: (dbName?: string, dbType?: ETenantType) => {
Expand All @@ -22,7 +24,6 @@ export function ExtendedTenant({
monitoring,
dbName,
dbType,
clusterName: cluster?.Name,
});
return href ? <MonitoringButton href={href} visible={true} /> : null;
}
Expand Down
21 changes: 11 additions & 10 deletions src/containers/AppWithClusters/useClusterData.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React from 'react';

import {useLocation} from 'react-router-dom';
import {StringParam, useQueryParam} from 'use-query-params';

import {parseQuery} from '../../routes';
import {clustersApi} from '../../store/reducers/clusters/clusters';
import {getAdditionalNodesProps} from '../../utils/additionalProps';
import {USE_CLUSTER_BALANCER_AS_BACKEND_KEY} from '../../utils/constants';
import {useSetting} from '../../utils/hooks';

export function useClusterData() {
const location = useLocation();
const {clusterName} = parseQuery(location);
const [clusterName] = useQueryParam('clusterName', StringParam);

const {data} = clustersApi.useGetClustersListQuery(undefined);

Expand All @@ -21,16 +19,19 @@ export function useClusterData() {

const {solomon: monitoring, balancer, versions, cluster} = info || {};

const [useClusterBalancerAsBackend] = useSetting<boolean>(USE_CLUSTER_BALANCER_AS_BACKEND_KEY);

const additionalNodesProps = getAdditionalNodesProps(balancer, useClusterBalancerAsBackend);

return {
monitoring,
balancer,
versions,
cluster,
useClusterBalancerAsBackend,
additionalNodesProps,
...useAdditionalNodeProps({balancer}),
};
}

export function useAdditionalNodeProps({balancer}: {balancer?: string}) {
const [useClusterBalancerAsBackend] = useSetting<boolean>(USE_CLUSTER_BALANCER_AS_BACKEND_KEY);

const additionalNodesProps = getAdditionalNodesProps(balancer, useClusterBalancerAsBackend);

return {additionalNodesProps, useClusterBalancerAsBackend};
}
14 changes: 3 additions & 11 deletions src/containers/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import React from 'react';

import {Breadcrumbs} from '@gravity-ui/uikit';
import {get} from 'lodash';
import {StringParam, useQueryParams} from 'use-query-params';

import {InternalLink} from '../../components/InternalLink';
import {LinkWithIcon} from '../../components/LinkWithIcon/LinkWithIcon';
import {backend, customBackend} from '../../store';
import {clusterApi} from '../../store/reducers/cluster/cluster';
import {useClusterBaseInfo} from '../../store/reducers/cluster/cluster';
import {cn} from '../../utils/cn';
import {DEVELOPER_UI_TITLE} from '../../utils/constants';
import {useTypedSelector} from '../../utils/hooks';
Expand All @@ -32,18 +30,12 @@ interface HeaderProps {
}

function Header({mainPage}: HeaderProps) {
const [queryParams] = useQueryParams({clusterName: StringParam});

const singleClusterMode = useTypedSelector((state) => state.singleClusterMode);
const {page, pageBreadcrumbsOptions} = useTypedSelector((state) => state.header);

const clusterInfo = clusterApi.useGetClusterInfoQuery(queryParams.clusterName ?? undefined);
const clusterInfo = useClusterBaseInfo();

const clusterName = get(
clusterInfo,
['currentData', 'clusterData', 'Name'],
queryParams.clusterName,
);
const clusterName = clusterInfo.title || clusterInfo.name;

const breadcrumbItems = React.useMemo(() => {
const rawBreadcrumbs: RawBreadcrumbItem[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,4 @@
@include query-buttons-animations();
}
}

&__trace-link {
&_loading {
color: var(--g-color-text-secondary);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {cn} from '../../../../utils/cn';
import {getStringifiedData} from '../../../../utils/dataFormatters/dataFormatters';
import {useTypedDispatch} from '../../../../utils/hooks';
import {parseQueryError} from '../../../../utils/query';
import {ClusterModeGuard} from '../../../ClusterModeGuard';
import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';
import {SimplifiedPlan} from '../ExplainResult/components/SimplifiedPlan/SimplifiedPlan';
import {ResultIssues} from '../Issues/Issues';
Expand Down Expand Up @@ -275,9 +274,7 @@ export function ExecuteResult({
</Button>
</React.Fragment>
) : null}
<ClusterModeGuard mode="multi">
<TraceButton traceId={data?.traceId} />
</ClusterModeGuard>
{data?.traceId ? <TraceButton traceId={data.traceId} /> : null}
</div>
<div className={b('controls-left')}>
{renderClipboardButton()}
Expand Down
61 changes: 19 additions & 42 deletions src/containers/Tenant/Query/ExecuteResult/TraceButton.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,27 @@
import React from 'react';

import {ArrowUpRightFromSquare} from '@gravity-ui/icons';
import {Button} from '@gravity-ui/uikit';
import {StringParam, useQueryParams} from 'use-query-params';

import {LinkWithIcon} from '../../../../components/LinkWithIcon/LinkWithIcon';
import {clusterApi} from '../../../../store/reducers/cluster/cluster';
import {useClusterBaseInfo} from '../../../../store/reducers/cluster/cluster';
import {traceApi} from '../../../../store/reducers/trace';
import type {TClusterInfo} from '../../../../types/api/cluster';
import {cn} from '../../../../utils/cn';
import {SECOND_IN_MS} from '../../../../utils/constants';
import {useDelayed} from '../../../../utils/hooks/useDelayed';
import {replaceParams} from '../utils/replaceParams';

import i18n from './i18n';

const b = cn('ydb-query-execute-result');

const TIME_BEFORE_CHECK = 15 * SECOND_IN_MS;

interface TraceUrlButtonProps {
traceId?: string;
}

function hasValidTraceCheckUrl(cluster?: TClusterInfo): cluster is {TraceCheck: {url: string}} {
return Boolean(cluster && cluster.TraceCheck && typeof cluster.TraceCheck.url === 'string');
}

function hasValidTraceViewUrl(cluster?: TClusterInfo): cluster is {TraceView: {url: string}} {
return Boolean(cluster && cluster.TraceView && typeof cluster.TraceView.url === 'string');
traceId: string;
}

export function TraceButton({traceId}: TraceUrlButtonProps) {
const [queryParams] = useQueryParams({clusterName: StringParam});
const {traceCheck, traceView} = useClusterBaseInfo();

const {data: {clusterData: cluster} = {}} = clusterApi.useGetClusterInfoQuery(
queryParams.clusterName ?? undefined,
{skip: !traceId},
);

const hasTraceCheck = Boolean(hasValidTraceCheckUrl(cluster) && traceId);

const checkTraceUrl =
traceId && hasValidTraceCheckUrl(cluster)
? replaceParams(cluster.TraceCheck.url, {traceId})
: '';
const checkTraceUrl = traceCheck?.url ? replaceParams(traceCheck.url, {traceId}) : '';
const traceUrl = traceView?.url ? replaceParams(traceView.url, {traceId}) : '';

// We won't get any trace data at first 15 seconds for sure
const [readyToFetch, resetDelay] = useDelayed(TIME_BEFORE_CHECK);
Expand All @@ -52,28 +30,27 @@ export function TraceButton({traceId}: TraceUrlButtonProps) {
resetDelay();
}, [traceId, resetDelay]);

const {currentData: traceData, error: traceError} = traceApi.useCheckTraceQuery(
const {isFetching} = traceApi.useCheckTraceQuery(
{url: checkTraceUrl},
{skip: !hasTraceCheck || !readyToFetch},
{skip: !checkTraceUrl || !readyToFetch},
);

const traceUrl =
hasValidTraceViewUrl(cluster) && traceId
? replaceParams(cluster.TraceView.url, {traceId})
: '';

if (!traceUrl) {
return null;
}

const loading = !readyToFetch || isFetching;
return (
<Button view="flat-secondary" loading={!traceData && !traceError}>
<LinkWithIcon
className={b('trace-link', {loading: !traceData && !traceError})}
title={i18n('trace')}
url={traceUrl}
external
/>
<Button
view={loading ? 'flat-secondary' : 'flat-info'}
loading={loading}
href={traceUrl}
target="_blank"
>
{i18n('trace')}
<Button.Icon>
<ArrowUpRightFromSquare />
</Button.Icon>
</Button>
);
}
48 changes: 38 additions & 10 deletions src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import type {TComputeInfo} from '../types/api/compute';
import type {DescribeConsumerResult} from '../types/api/consumer';
import type {HealthCheckAPIResponse} from '../types/api/healthcheck';
import type {JsonHotKeysResponse} from '../types/api/hotkeys';
import type {MetaCluster, MetaClusters, MetaTenants} from '../types/api/meta';
import type {
MetaCluster,
MetaClusters,
MetaGeneralClusterInfo,
MetaTenants,
} from '../types/api/meta';
import type {ModifyDiskResponse} from '../types/api/modifyDisk';
import type {TNetInfo} from '../types/api/netInfo';
import type {TNodesInfo} from '../types/api/nodes';
Expand Down Expand Up @@ -749,13 +754,6 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
);
}

// used if not single cluster mode
getClustersList(_?: never, {signal}: {signal?: AbortSignal} = {}) {
return this.get<MetaClusters>(`${META_BACKEND || ''}/meta/clusters`, null, {
requestConfig: {signal},
});
}

createSchemaDirectory(
{database, path}: {database: string; path: string},
{signal}: {signal?: AbortSignal} = {},
Expand All @@ -772,9 +770,26 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
},
);
}

getClustersList(_?: never, __: {signal?: AbortSignal} = {}): Promise<MetaClusters> {
throw new Error('Method is not implemented.');
}

getClusterBaseInfo(
_clusterName: string,
_opts: AxiosOptions = {},
): Promise<MetaGeneralClusterInfo> {
throw new Error('Method is not implemented.');
}
}

export class YdbWebVersionAPI extends YdbEmbeddedAPI {
getClustersList(_?: never, {signal}: {signal?: AbortSignal} = {}) {
return this.get<MetaClusters>(`${META_BACKEND || ''}/meta/clusters`, null, {
requestConfig: {signal},
});
}

getClusterInfo(clusterName: string, {signal}: AxiosOptions = {}) {
return this.get<MetaCluster>(
`${META_BACKEND || ''}/meta/cluster`,
Expand All @@ -785,15 +800,28 @@ export class YdbWebVersionAPI extends YdbEmbeddedAPI {
).then(parseMetaCluster);
}

getTenants(clusterName: string, {concurrentId, signal}: AxiosOptions = {}) {
getTenants(clusterName: string, {signal}: AxiosOptions = {}) {
return this.get<MetaTenants>(
`${META_BACKEND || ''}/meta/cp_databases`,
{
cluster_name: clusterName,
},
{concurrentId, requestConfig: {signal}},
{requestConfig: {signal}},
).then(parseMetaTenants);
}

getClusterBaseInfo(
clusterName: string,
{concurrentId, signal}: AxiosOptions = {},
): Promise<MetaGeneralClusterInfo> {
return this.get<MetaGeneralClusterInfo[]>(
`${META_BACKEND || ''}/meta/db_clusters`,
{
name: clusterName,
},
{concurrentId, requestConfig: {signal}},
).then((data) => data[0]);
}
}

export function createApi({webVersion = false, withCredentials = false} = {}) {
Expand Down
Loading