Skip to content

Commit 9308686

Browse files
feat(Diagnostics): split CDC and its implementation (#2281)
1 parent 025d5ff commit 9308686

File tree

10 files changed

+69
-261
lines changed

10 files changed

+69
-261
lines changed

src/containers/Tenant/Diagnostics/Describe/Describe.tsx

Lines changed: 12 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
import {ClipboardButton} from '@gravity-ui/uikit';
2-
import {shallowEqual} from 'react-redux';
32

43
import {ResponseError} from '../../../../components/Errors/ResponseError';
54
import {JsonViewer} from '../../../../components/JsonViewer/JsonViewer';
65
import {useUnipikaConvert} from '../../../../components/JsonViewer/unipika/unipika';
76
import {Loader} from '../../../../components/Loader';
8-
import {
9-
selectSchemaMergedChildrenPaths,
10-
useGetMultiOverviewQuery,
11-
} from '../../../../store/reducers/overview/overview';
12-
import type {EPathType} from '../../../../types/api/schema';
7+
import {overviewApi} from '../../../../store/reducers/overview/overview';
138
import {cn} from '../../../../utils/cn';
14-
import {useAutoRefreshInterval, useTypedSelector} from '../../../../utils/hooks';
15-
import {isEntityWithMergedImplementation} from '../../utils/schema';
9+
import {useAutoRefreshInterval} from '../../../../utils/hooks';
1610

1711
import './Describe.scss';
1812

@@ -21,63 +15,39 @@ const b = cn('ydb-describe');
2115
interface IDescribeProps {
2216
path: string;
2317
database: string;
24-
type?: EPathType;
2518
}
2619

27-
const Describe = ({path, database, type}: IDescribeProps) => {
20+
const Describe = ({path, database}: IDescribeProps) => {
2821
const [autoRefreshInterval] = useAutoRefreshInterval();
2922

30-
const isEntityWithMergedImpl = isEntityWithMergedImplementation(type);
31-
32-
const mergedChildrenPaths = useTypedSelector(
33-
(state) => selectSchemaMergedChildrenPaths(state, path, type, database),
34-
shallowEqual,
23+
const {currentData, isFetching, error} = overviewApi.useGetOverviewQuery(
24+
{path, database},
25+
{pollingInterval: autoRefreshInterval},
3526
);
3627

37-
let paths: string[] = [];
38-
if (!isEntityWithMergedImpl) {
39-
paths = [path];
40-
} else if (mergedChildrenPaths) {
41-
paths = [path, ...mergedChildrenPaths];
42-
}
43-
44-
const {mergedDescribe, loading, error} = useGetMultiOverviewQuery({
45-
paths,
46-
autoRefreshInterval,
47-
database,
48-
});
49-
50-
let preparedDescribeData: Object | undefined;
51-
if (mergedDescribe) {
52-
const paths = Object.keys(mergedDescribe);
53-
if (paths.length === 1) {
54-
preparedDescribeData = mergedDescribe[paths[0]];
55-
} else {
56-
preparedDescribeData = mergedDescribe;
57-
}
58-
}
28+
const loading = isFetching && currentData === undefined;
5929

60-
const convertedValue = useUnipikaConvert(preparedDescribeData);
30+
const convertedValue = useUnipikaConvert(currentData);
6131

62-
if (loading || (isEntityWithMergedImpl && !mergedChildrenPaths)) {
32+
if (loading) {
6333
return <Loader size="m" />;
6434
}
6535

66-
if (!preparedDescribeData && !error) {
36+
if (!currentData && !error) {
6737
return <div className={b('message-container')}>Empty</div>;
6838
}
6939

7040
return (
7141
<div className={b()}>
7242
{error ? <ResponseError error={error} /> : null}
73-
{preparedDescribeData ? (
43+
{currentData ? (
7444
<div className={b('result')}>
7545
<JsonViewer
7646
value={convertedValue}
7747
extraTools={
7848
<ClipboardButton
7949
view="flat-secondary"
80-
text={JSON.stringify(preparedDescribeData)}
50+
text={JSON.stringify(currentData)}
8151
/>
8252
}
8353
search

src/containers/Tenant/Diagnostics/Diagnostics.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
1414
import {setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
1515
import type {AdditionalNodesProps, AdditionalTenantsProps} from '../../../types/additionalProps';
16-
import type {EPathType} from '../../../types/api/schema';
16+
import type {EPathSubType, EPathType} from '../../../types/api/schema';
1717
import {cn} from '../../../utils/cn';
1818
import {useTypedDispatch, useTypedSelector} from '../../../utils/hooks';
1919
import {Heatmap} from '../../Heatmap';
@@ -40,6 +40,7 @@ import './Diagnostics.scss';
4040

4141
interface DiagnosticsProps {
4242
type?: EPathType;
43+
subType?: EPathSubType;
4344
tenantName: string;
4445
path: string;
4546
additionalTenantProps?: AdditionalTenantsProps;
@@ -62,7 +63,7 @@ function Diagnostics(props: DiagnosticsProps) {
6263

6364
const hasFeatureFlags = useFeatureFlagsAvailable();
6465
const hasTopicData = useTopicDataAvailable();
65-
const pages = getPagesByType(props.type, {
66+
const pages = getPagesByType(props.type, props.subType, {
6667
hasFeatureFlags,
6768
hasTopicData,
6869
isTopLevel: props.path === props.tenantName,
@@ -129,7 +130,7 @@ function Diagnostics(props: DiagnosticsProps) {
129130
);
130131
}
131132
case TENANT_DIAGNOSTICS_TABS_IDS.describe: {
132-
return <Describe path={path} database={tenantName} type={type} />;
133+
return <Describe path={path} database={tenantName} />;
133134
}
134135
case TENANT_DIAGNOSTICS_TABS_IDS.hotKeys: {
135136
return <HotKeys path={path} database={tenantName} />;

src/containers/Tenant/Diagnostics/DiagnosticsPages.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {StringParam, useQueryParams} from 'use-query-params';
44

55
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
66
import type {TenantDiagnosticsTab} from '../../../store/reducers/tenant/types';
7-
import {EPathType} from '../../../types/api/schema';
7+
import {EPathSubType, EPathType} from '../../../types/api/schema';
88
import type {TenantQuery} from '../TenantPages';
99
import {TenantTabsGroups, getTenantPath} from '../TenantPages';
1010
import {isDatabaseEntityType, isTopicEntityType} from '../utils/schema';
@@ -113,7 +113,8 @@ const COLUMN_TABLE_PAGES = [overview, schema, topShards, nodes, tablets, describ
113113

114114
const DIR_PAGES = [overview, topShards, nodes, describe];
115115

116-
const CDC_STREAM_PAGES = [overview, consumers, partitions, nodes, tablets, describe];
116+
const CDC_STREAM_PAGES = [overview, consumers, partitions, nodes, describe];
117+
const CDC_STREAM_IMPL_PAGES = [overview, nodes, tablets, describe];
117118
const TOPIC_PAGES = [overview, consumers, partitions, topicData, nodes, tablets, describe];
118119

119120
const EXTERNAL_DATA_SOURCE_PAGES = [overview, describe];
@@ -149,15 +150,23 @@ const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
149150
[EPathType.EPathTypeTransfer]: TRANSFER_PAGES,
150151
[EPathType.EPathTypeResourcePool]: DIR_PAGES,
151152
};
153+
const pathSubTypeToPages: Record<EPathSubType, Page[] | undefined> = {
154+
[EPathSubType.EPathSubTypeStreamImpl]: CDC_STREAM_IMPL_PAGES,
155+
156+
[EPathSubType.EPathSubTypeSyncIndexImplTable]: undefined,
157+
[EPathSubType.EPathSubTypeAsyncIndexImplTable]: undefined,
158+
[EPathSubType.EPathSubTypeEmpty]: undefined,
159+
};
152160

153161
export const getPagesByType = (
154162
type?: EPathType,
163+
subType?: EPathSubType,
155164
options?: {hasFeatureFlags?: boolean; hasTopicData?: boolean; isTopLevel?: boolean},
156165
) => {
157-
if (!type || !pathTypeToPages[type]) {
158-
return DIR_PAGES;
159-
}
160-
let pages = pathTypeToPages[type];
166+
const subTypePages = subType ? pathSubTypeToPages[subType] : undefined;
167+
const typePages = type ? pathTypeToPages[type] : undefined;
168+
let pages = subTypePages || typePages || DIR_PAGES;
169+
161170
if (isTopicEntityType(type) && !options?.hasTopicData) {
162171
return pages?.filter((item) => item.id !== TENANT_DIAGNOSTICS_TABS_IDS.topicData);
163172
}

src/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/ChangefeedInfo.tsx

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,9 @@ import {
77
import type {TEvDescribeSchemeResult} from '../../../../../types/api/schema';
88
import {getEntityName} from '../../../utils';
99
import {TopicStats} from '../TopicStats';
10-
import {prepareTopicSchemaInfo} from '../utils';
1110

12-
const prepareChangefeedInfo = (
13-
changefeedData?: TEvDescribeSchemeResult,
14-
topicData?: TEvDescribeSchemeResult,
15-
): Array<InfoViewerItem> => {
16-
if (!changefeedData && !topicData) {
11+
const prepareChangefeedInfo = (changefeedData?: TEvDescribeSchemeResult): Array<InfoViewerItem> => {
12+
if (!changefeedData) {
1713
return [];
1814
}
1915

@@ -25,17 +21,14 @@ const prepareChangefeedInfo = (
2521
Mode,
2622
Format,
2723
});
28-
const topicInfo = prepareTopicSchemaInfo(topicData);
29-
30-
const info = [...changefeedInfo, ...topicInfo];
3124

3225
const createStep = changefeedData?.PathDescription?.Self?.CreateStep;
3326

3427
if (Number(createStep)) {
35-
info.unshift(formatCommonItem('CreateStep', createStep));
28+
changefeedInfo.unshift(formatCommonItem('CreateStep', createStep));
3629
}
3730

38-
return info;
31+
return changefeedInfo;
3932
};
4033

4134
interface ChangefeedProps {
@@ -46,16 +39,16 @@ interface ChangefeedProps {
4639
}
4740

4841
/** Displays overview for CDCStream EPathType */
49-
export const ChangefeedInfo = ({path, database, data, topic}: ChangefeedProps) => {
42+
export const ChangefeedInfo = ({path, database, data}: ChangefeedProps) => {
5043
const entityName = getEntityName(data?.PathDescription);
5144

52-
if (!data || !topic) {
45+
if (!data) {
5346
return <div className="error">No {entityName} data</div>;
5447
}
5548

5649
return (
5750
<div>
58-
<InfoViewer title={entityName} info={prepareChangefeedInfo(data, topic)} />
51+
<InfoViewer title={entityName} info={prepareChangefeedInfo(data)} />
5952
<TopicStats path={path} database={database} />
6053
</div>
6154
);

src/containers/Tenant/Diagnostics/Overview/Overview.tsx

Lines changed: 12 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
import React from 'react';
22

3-
import {shallowEqual} from 'react-redux';
4-
53
import {ResponseError} from '../../../../components/Errors/ResponseError';
64
import {TableIndexInfo} from '../../../../components/InfoViewer/schemaInfo';
75
import {Loader} from '../../../../components/Loader';
8-
import {
9-
selectSchemaMergedChildrenPaths,
10-
useGetMultiOverviewQuery,
11-
} from '../../../../store/reducers/overview/overview';
6+
import {overviewApi} from '../../../../store/reducers/overview/overview';
127
import {EPathType} from '../../../../types/api/schema';
13-
import {useAutoRefreshInterval, useTypedSelector} from '../../../../utils/hooks';
8+
import {useAutoRefreshInterval} from '../../../../utils/hooks';
149
import {ExternalDataSourceInfo} from '../../Info/ExternalDataSource/ExternalDataSource';
1510
import {ExternalTableInfo} from '../../Info/ExternalTable/ExternalTable';
1611
import {ViewInfo} from '../../Info/View/View';
17-
import {isEntityWithMergedImplementation} from '../../utils/schema';
1812

1913
import {AsyncReplicationInfo} from './AsyncReplicationInfo';
2014
import {ChangefeedInfo} from './ChangefeedInfo';
@@ -31,37 +25,15 @@ interface OverviewProps {
3125
function Overview({type, path, database}: OverviewProps) {
3226
const [autoRefreshInterval] = useAutoRefreshInterval();
3327

34-
const isEntityWithMergedImpl = isEntityWithMergedImplementation(type);
35-
36-
// shallowEqual prevents rerenders when new schema data is loaded
37-
const mergedChildrenPaths = useTypedSelector(
38-
(state) => selectSchemaMergedChildrenPaths(state, path, type, database),
39-
shallowEqual,
28+
const {currentData, isFetching, error} = overviewApi.useGetOverviewQuery(
29+
{path, database},
30+
{pollingInterval: autoRefreshInterval},
4031
);
4132

42-
let paths: string[] = [];
43-
if (!isEntityWithMergedImpl) {
44-
paths = [path];
45-
} else if (mergedChildrenPaths) {
46-
paths = [path, ...mergedChildrenPaths];
47-
}
48-
49-
const {
50-
mergedDescribe,
51-
loading: entityLoading,
52-
error,
53-
} = useGetMultiOverviewQuery({
54-
paths,
55-
database,
56-
autoRefreshInterval,
57-
});
58-
59-
const rawData = mergedDescribe[path];
60-
61-
const entityNotReady = isEntityWithMergedImpl && !mergedChildrenPaths;
33+
const loading = isFetching && currentData === undefined;
6234

6335
const renderContent = () => {
64-
const data = rawData ?? undefined;
36+
const data = currentData ?? undefined;
6537
// verbose mapping to guarantee a correct render for new path types
6638
// TS will error when a new type is added but not mapped here
6739
const pathTypeToComponent: Record<EPathType, (() => React.ReactNode) | undefined> = {
@@ -74,20 +46,9 @@ function Overview({type, path, database}: OverviewProps) {
7446
[EPathType.EPathTypeExtSubDomain]: undefined,
7547
[EPathType.EPathTypeColumnStore]: undefined,
7648
[EPathType.EPathTypeColumnTable]: undefined,
77-
[EPathType.EPathTypeCdcStream]: () => {
78-
const topicPath = mergedChildrenPaths?.[0];
79-
if (topicPath) {
80-
return (
81-
<ChangefeedInfo
82-
path={path}
83-
database={database}
84-
data={data}
85-
topic={mergedDescribe?.[topicPath] ?? undefined}
86-
/>
87-
);
88-
}
89-
return undefined;
90-
},
49+
[EPathType.EPathTypeCdcStream]: () => (
50+
<ChangefeedInfo path={path} database={database} data={data} />
51+
),
9152
[EPathType.EPathTypePersQueueGroup]: () => (
9253
<TopicInfo data={data} path={path} database={database} />
9354
),
@@ -103,14 +64,14 @@ function Overview({type, path, database}: OverviewProps) {
10364
return (type && pathTypeToComponent[type]?.()) || <TableInfo data={data} type={type} />;
10465
};
10566

106-
if (entityLoading || entityNotReady) {
67+
if (loading) {
10768
return <Loader size="m" />;
10869
}
10970

11071
return (
11172
<React.Fragment>
11273
{error ? <ResponseError error={error} /> : null}
113-
{error && !rawData ? null : renderContent()}
74+
{error && !currentData ? null : renderContent()}
11475
</React.Fragment>
11576
);
11677
}

src/containers/Tenant/Diagnostics/Overview/TopicInfo/TopicInfo.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {InfoViewer} from '../../../../../components/InfoViewer';
2+
import {EPathSubType} from '../../../../../types/api/schema';
23
import type {TEvDescribeSchemeResult} from '../../../../../types/api/schema';
34
import {getEntityName} from '../../../utils';
45
import {TopicStats} from '../TopicStats';
@@ -18,10 +19,19 @@ export const TopicInfo = ({data, path, database}: TopicInfoProps) => {
1819
return <div className="error">No {entityName} data</div>;
1920
}
2021

22+
const renderStats = () => {
23+
// In case of stream impl we display stats in CDC info tab instead
24+
if (data.PathDescription?.Self?.PathSubType === EPathSubType.EPathSubTypeStreamImpl) {
25+
return null;
26+
}
27+
28+
return <TopicStats path={path} database={database} />;
29+
};
30+
2131
return (
2232
<div>
2333
<InfoViewer title={entityName} info={prepareTopicSchemaInfo(data)} />
24-
<TopicStats path={path} database={database} />
34+
{renderStats()}
2535
</div>
2636
);
2737
};

0 commit comments

Comments
 (0)