Skip to content

Commit 1c12bde

Browse files
committed
feat(TopicData): add tab for topic data
1 parent 3a93f8c commit 1c12bde

File tree

29 files changed

+1122
-35
lines changed

29 files changed

+1122
-35
lines changed

src/components/EmptyState/EmptyState.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828

2929
margin: 0 auto;
3030
}
31+
&_position_left {
32+
margin: unset;
33+
}
3134
}
3235

3336
&__image {

src/containers/Storage/EmptyFilter/EmptyFilter.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,18 @@ interface EmptyFilterProps {
1010
message?: string;
1111
showAll?: string;
1212
onShowAll?: VoidFunction;
13+
image?: React.ReactNode;
1314
}
1415

1516
export const EmptyFilter = ({
1617
title,
1718
message = i18n('default_message'),
1819
showAll = i18n('default_button_label'),
1920
onShowAll,
21+
image = <Illustration name="thumbsUp" />,
2022
}: EmptyFilterProps) => (
2123
<EmptyState
22-
image={<Illustration name="thumbsUp" />}
24+
image={image}
2325
position="left"
2426
title={title}
2527
description={message}

src/containers/Tenant/Diagnostics/Consumers/Consumers.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
selectPreparedConsumersData,
1111
selectPreparedTopicStats,
1212
topicApi,
13-
} from '../../../../store/reducers/topic';
13+
} from '../../../../store/reducers/topic/topic';
1414
import type {EPathType} from '../../../../types/api/schema';
1515
import {cn} from '../../../../utils/cn';
1616
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';

src/containers/Tenant/Diagnostics/Diagnostics.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import React from 'react';
33
import {Tabs} from '@gravity-ui/uikit';
44
import {Helmet} from 'react-helmet-async';
55
import {Link} from 'react-router-dom';
6-
import {StringParam, useQueryParams} from 'use-query-params';
76

87
import {AutoRefreshControl} from '../../../components/AutoRefreshControl/AutoRefreshControl';
9-
import {useFeatureFlagsAvailable} from '../../../store/reducers/capabilities/hooks';
8+
import {
9+
useFeatureFlagsAvailable,
10+
useTopicDataAvailable,
11+
} from '../../../store/reducers/capabilities/hooks';
1012
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
1113
import {setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
1214
import type {AdditionalNodesProps, AdditionalTenantsProps} from '../../../types/additionalProps';
@@ -19,19 +21,19 @@ import {Operations} from '../../Operations';
1921
import {PaginatedStorage} from '../../Storage/PaginatedStorage';
2022
import {Tablets} from '../../Tablets/Tablets';
2123
import {SchemaViewer} from '../Schema/SchemaViewer/SchemaViewer';
22-
import {TenantTabsGroups, getTenantPath} from '../TenantPages';
2324
import {isDatabaseEntityType} from '../utils/schema';
2425

2526
import {Configs} from './Configs/Configs';
2627
import {Consumers} from './Consumers';
2728
import Describe from './Describe/Describe';
2829
import DetailedOverview from './DetailedOverview/DetailedOverview';
29-
import {getDataBasePages, getPagesByType} from './DiagnosticsPages';
30+
import {getPagesByType, useDiagnosticsPageLinkGetter} from './DiagnosticsPages';
3031
import {HotKeys} from './HotKeys/HotKeys';
3132
import {NetworkWrapper} from './Network/NetworkWrapper';
3233
import {Partitions} from './Partitions/Partitions';
3334
import {TopQueries} from './TopQueries';
3435
import {TopShards} from './TopShards';
36+
import {TopicData} from './TopicData/TopicData';
3537

3638
import './Diagnostics.scss';
3739

@@ -53,18 +55,17 @@ function Diagnostics(props: DiagnosticsProps) {
5355
(state) => state.tenant,
5456
);
5557

56-
const [queryParams] = useQueryParams({
57-
database: StringParam,
58-
schema: StringParam,
59-
backend: StringParam,
60-
clusterName: StringParam,
61-
});
58+
const getDiagnosticsPageLink = useDiagnosticsPageLinkGetter();
6259

6360
const tenantName = isDatabaseEntityType(props.type) ? props.path : props.tenantName;
64-
const isDatabase = isDatabaseEntityType(props.type) || props.path === props.tenantName;
6561

6662
const hasFeatureFlags = useFeatureFlagsAvailable();
67-
const pages = isDatabase ? getDataBasePages({hasFeatureFlags}) : getPagesByType(props.type);
63+
const hasTopicData = useTopicDataAvailable();
64+
const pages = getPagesByType(props.type, {
65+
hasFeatureFlags,
66+
hasTopicData,
67+
isTopLevel: props.path === props.tenantName,
68+
});
6869
let activeTab = pages.find((el) => el.id === diagnosticsTab);
6970
if (!activeTab) {
7071
activeTab = pages[0];
@@ -141,6 +142,9 @@ function Diagnostics(props: DiagnosticsProps) {
141142
case TENANT_DIAGNOSTICS_TABS_IDS.partitions: {
142143
return <Partitions path={path} database={tenantName} />;
143144
}
145+
case TENANT_DIAGNOSTICS_TABS_IDS.topicData: {
146+
return <TopicData path={path} database={tenantName} parentRef={containerRef} />;
147+
}
144148
case TENANT_DIAGNOSTICS_TABS_IDS.configs: {
145149
return <Configs database={tenantName} />;
146150
}
@@ -161,10 +165,7 @@ function Diagnostics(props: DiagnosticsProps) {
161165
items={pages}
162166
activeTab={activeTab?.id}
163167
wrapTo={({id}, node) => {
164-
const path = getTenantPath({
165-
...queryParams,
166-
[TenantTabsGroups.diagnosticsTab]: id,
167-
});
168+
const path = getDiagnosticsPageLink(id);
168169

169170
return (
170171
<Link to={path} key={id} className={b('tab')}>

src/containers/Tenant/Diagnostics/DiagnosticsPages.ts

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
import React from 'react';
2+
3+
import {StringParam, useQueryParams} from 'use-query-params';
4+
15
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
26
import type {TenantDiagnosticsTab} from '../../../store/reducers/tenant/types';
37
import {EPathType} from '../../../types/api/schema';
8+
import type {TenantQuery} from '../TenantPages';
9+
import {TenantTabsGroups, getTenantPath} from '../TenantPages';
10+
import {isDatabaseEntityType, isTopicEntityType} from '../utils/schema';
411

512
type Page = {
613
id: TenantDiagnosticsTab;
@@ -69,6 +76,10 @@ const partitions = {
6976
id: TENANT_DIAGNOSTICS_TABS_IDS.partitions,
7077
title: 'Partitions',
7178
};
79+
const topicData = {
80+
id: TENANT_DIAGNOSTICS_TABS_IDS.topicData,
81+
title: 'Data',
82+
};
7283

7384
const configs = {
7485
id: TENANT_DIAGNOSTICS_TABS_IDS.configs,
@@ -103,7 +114,7 @@ const COLUMN_TABLE_PAGES = [overview, schema, topShards, nodes, tablets, describ
103114
const DIR_PAGES = [overview, topShards, nodes, describe];
104115

105116
const CDC_STREAM_PAGES = [overview, consumers, partitions, nodes, tablets, describe];
106-
const TOPIC_PAGES = [overview, consumers, partitions, nodes, tablets, describe];
117+
const TOPIC_PAGES = [overview, consumers, partitions, topicData, nodes, tablets, describe];
107118

108119
const EXTERNAL_DATA_SOURCE_PAGES = [overview, describe];
109120
const EXTERNAL_TABLE_PAGES = [overview, schema, describe];
@@ -139,10 +150,44 @@ const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
139150
[EPathType.EPathTypeResourcePool]: DIR_PAGES,
140151
};
141152

142-
export const getPagesByType = (type?: EPathType) => (type && pathTypeToPages[type]) || DIR_PAGES;
143-
144-
export const getDataBasePages = ({hasFeatureFlags}: {hasFeatureFlags?: boolean}) => {
145-
return hasFeatureFlags
146-
? DATABASE_PAGES
147-
: DATABASE_PAGES.filter((item) => item.id !== TENANT_DIAGNOSTICS_TABS_IDS.configs);
153+
export const getPagesByType = (
154+
type?: EPathType,
155+
options?: {hasFeatureFlags?: boolean; hasTopicData?: boolean; isTopLevel?: boolean},
156+
) => {
157+
if (!type || !pathTypeToPages[type]) {
158+
return DIR_PAGES;
159+
}
160+
let pages = pathTypeToPages[type];
161+
if (isTopicEntityType(type) && !options?.hasTopicData) {
162+
return pages?.filter((item) => item.id !== TENANT_DIAGNOSTICS_TABS_IDS.topicData);
163+
}
164+
if (isDatabaseEntityType(type) || options?.isTopLevel) {
165+
pages = DATABASE_PAGES;
166+
if (!options?.hasFeatureFlags) {
167+
return pages.filter((item) => item.id !== TENANT_DIAGNOSTICS_TABS_IDS.configs);
168+
}
169+
}
170+
return pages;
171+
};
172+
173+
export const useDiagnosticsPageLinkGetter = () => {
174+
const [queryParams] = useQueryParams({
175+
database: StringParam,
176+
schema: StringParam,
177+
backend: StringParam,
178+
clusterName: StringParam,
179+
});
180+
181+
const getLink = React.useCallback(
182+
(tab: string, params?: TenantQuery) => {
183+
return getTenantPath({
184+
...queryParams,
185+
[TenantTabsGroups.diagnosticsTab]: tab,
186+
...params,
187+
});
188+
},
189+
[queryParams],
190+
);
191+
192+
return getLink;
148193
};

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {LabelWithPopover} from '../../../../../components/LabelWithPopover';
77
import {LagPopoverContent} from '../../../../../components/LagPopoverContent';
88
import {Loader} from '../../../../../components/Loader';
99
import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
10-
import {selectPreparedTopicStats, topicApi} from '../../../../../store/reducers/topic';
10+
import {selectPreparedTopicStats, topicApi} from '../../../../../store/reducers/topic/topic';
1111
import type {IPreparedTopicStats} from '../../../../../types/store/topic';
1212
import {cn} from '../../../../../utils/cn';
1313
import {formatBps, formatBytes} from '../../../../../utils/dataFormatters/dataFormatters';
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {DefinitionList, Dialog} from '@gravity-ui/uikit';
2+
3+
import type {TopicMessageMetadataItem} from '../../../../types/api/topic';
4+
5+
import i18n from './i18n';
6+
import {b} from './utils/constants';
7+
8+
interface FullValueProps {
9+
onClose: () => void;
10+
value?: string | TopicMessageMetadataItem[];
11+
}
12+
13+
export function FullValue({onClose, value}: FullValueProps) {
14+
const renderContent = () => {
15+
if (typeof value === 'string') {
16+
return value;
17+
}
18+
return (
19+
<DefinitionList responsive>
20+
{value?.map((item, index) => (
21+
<DefinitionList.Item key={index} name={item.Key}>
22+
{item.Value}
23+
</DefinitionList.Item>
24+
))}
25+
</DefinitionList>
26+
);
27+
};
28+
29+
return (
30+
<Dialog open={value !== undefined} onClose={onClose} className={b('full-value')}>
31+
<Dialog.Header caption={i18n('label_full-value')} />
32+
<Dialog.Divider />
33+
<Dialog.Body>{renderContent()}</Dialog.Body>
34+
</Dialog>
35+
);
36+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.ydb-diagnostics-topic-data {
2+
&__partition-select {
3+
min-width: 150px;
4+
}
5+
6+
&__full-value {
7+
max-width: 70vw;
8+
max-height: 80vh;
9+
10+
word-break: break-all;
11+
}
12+
&__date-picker {
13+
min-width: 265px;
14+
}
15+
}

0 commit comments

Comments
 (0)