Skip to content

Commit c4a4abf

Browse files
authored
feat(Preview): add preview for topics (#2292)
1 parent 21c7126 commit c4a4abf

File tree

23 files changed

+491
-198
lines changed

23 files changed

+491
-198
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"use-query-params": "^2.2.1",
6060
"uuid": "^10.0.0",
6161
"web-vitals": "^1.1.2",
62-
"ydb-ui-components": "^4.6.0",
62+
"ydb-ui-components": "^4.7.0",
6363
"zod": "^3.24.1"
6464
},
6565
"scripts": {

src/components/EntityStatus/EntityStatus.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export function EntityStatus({
9292
</InternalLink>
9393
);
9494
}
95-
return name && <span className={b('name')}>{name}</span>;
95+
return name && <span className={b('name')}>{renderName(name)}</span>;
9696
};
9797
return (
9898
<div className={b(null, className)}>

src/containers/Tenant/Diagnostics/TopicData/columns/Columns.scss

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,11 @@
11
@use '../../../../../styles/mixins.scss';
22

33
.ydb-diagnostics-topic-data-columns {
4-
&__ts-diff_danger {
5-
color: var(--g-color-text-danger);
6-
}
7-
&__message_clickable {
8-
cursor: pointer;
9-
10-
color: var(--g-color-text-info);
11-
}
124
&__offset {
135
display: inline-flex;
146
align-items: center;
157
gap: var(--g-spacing-1);
16-
.g-help-mark,
17-
.g-help-mark__button {
18-
display: flex;
19-
}
20-
}
21-
&__offset {
8+
229
width: 100%;
2310
height: 100%;
2411
}

src/containers/Tenant/Diagnostics/TopicData/columns/columns.tsx

Lines changed: 72 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22

33
import {TriangleExclamation} from '@gravity-ui/icons';
44
import DataTable from '@gravity-ui/react-data-table';
5+
import type {TextProps} from '@gravity-ui/uikit';
56
import {ActionTooltip, Icon, Popover, Text} from '@gravity-ui/uikit';
67
import {isNil} from 'lodash';
78
import {Link} from 'react-router-dom';
@@ -88,18 +89,8 @@ export const tsDiffColumn: Column<TopicMessageEnhanced> = {
8889
name: TOPIC_DATA_COLUMNS_IDS.TS_DIFF,
8990
header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.TS_DIFF],
9091
align: DataTable.RIGHT,
91-
render: ({row}) => {
92-
if (isNil(row.TimestampDiff)) {
93-
return EMPTY_DATA_PLACEHOLDER;
94-
}
95-
const numericValue = safeParseNumber(row.TimestampDiff);
96-
return (
97-
<span className={b('ts-diff', {danger: numericValue >= 100_000})}>
98-
{formatToMs(numericValue)}
99-
</span>
100-
);
101-
},
102-
width: 90,
92+
render: ({row: {TimestampDiff}}) => <TopicDataTsDiff value={TimestampDiff} />,
93+
width: 110,
10394
note: i18n('context_ts-diff'),
10495
};
10596

@@ -121,44 +112,17 @@ export const messageColumn: Column<TopicMessageEnhanced> = {
121112
name: TOPIC_DATA_COLUMNS_IDS.MESSAGE,
122113
header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.MESSAGE],
123114
align: DataTable.LEFT,
124-
render: ({row: {Message, OriginalSize}}) => {
125-
if (isNil(Message)) {
126-
return EMPTY_DATA_PLACEHOLDER;
127-
}
128-
let encryptedMessage;
129-
let invalid = false;
130-
try {
131-
encryptedMessage = atob(Message);
132-
} catch {
133-
encryptedMessage = i18n('description_failed-decode');
134-
invalid = true;
135-
}
136-
137-
const truncated = safeParseNumber(OriginalSize) > TOPIC_MESSAGE_SIZE_LIMIT;
138-
return (
139-
<Text
140-
variant="body-2"
141-
color={invalid ? 'secondary' : 'primary'}
142-
className={b('message', {invalid})}
143-
>
144-
{encryptedMessage}
145-
{truncated && (
146-
<Text color="secondary" className={b('truncated')}>
147-
{' '}
148-
{i18n('description_truncated')}
149-
</Text>
150-
)}
151-
</Text>
152-
);
153-
},
115+
render: ({row: {Message, OriginalSize}}) => (
116+
<TopicDataMessage message={Message} size={OriginalSize} />
117+
),
154118
width: 500,
155119
};
156120

157121
export const sizeColumn: Column<TopicMessageEnhanced> = {
158122
name: TOPIC_DATA_COLUMNS_IDS.SIZE,
159123
header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.SIZE],
160124
align: DataTable.RIGHT,
161-
render: ({row}) => formatBytes(row.StorageSize),
125+
render: ({row: {StorageSize}}) => <TopicDataSize size={StorageSize} />,
162126
width: 100,
163127
};
164128

@@ -316,3 +280,68 @@ function Offset({offset, removed, notLoaded}: PartitionIdProps) {
316280
</Link>
317281
);
318282
}
283+
interface TopicDataTsDiffProps {
284+
value?: string;
285+
baseColor?: TextProps['color'];
286+
variant?: TextProps['variant'];
287+
}
288+
289+
export function TopicDataTsDiff({
290+
value,
291+
baseColor = 'primary',
292+
variant = 'body-2',
293+
}: TopicDataTsDiffProps) {
294+
if (isNil(value)) {
295+
return EMPTY_DATA_PLACEHOLDER;
296+
}
297+
const numericValue = safeParseNumber(value);
298+
return (
299+
<Text variant={variant} color={numericValue >= 100_000 ? 'danger' : baseColor}>
300+
{formatToMs(numericValue)}
301+
</Text>
302+
);
303+
}
304+
305+
interface TopicDataMessageProps {
306+
message?: string;
307+
size?: number;
308+
}
309+
310+
export function TopicDataMessage({message, size}: TopicDataMessageProps) {
311+
if (isNil(message)) {
312+
return EMPTY_DATA_PLACEHOLDER;
313+
}
314+
let encryptedMessage;
315+
let invalid = false;
316+
try {
317+
encryptedMessage = atob(message);
318+
} catch {
319+
encryptedMessage = i18n('description_failed-decode');
320+
invalid = true;
321+
}
322+
323+
const truncated = safeParseNumber(size) > TOPIC_MESSAGE_SIZE_LIMIT;
324+
return (
325+
<Text
326+
variant="body-2"
327+
color={invalid ? 'secondary' : 'primary'}
328+
className={b('message', {invalid})}
329+
>
330+
{encryptedMessage}
331+
{truncated && (
332+
<Text color="secondary" className={b('truncated')}>
333+
{' '}
334+
{i18n('description_truncated')}
335+
</Text>
336+
)}
337+
</Text>
338+
);
339+
}
340+
341+
interface TopicDataSizeProps {
342+
size?: number;
343+
}
344+
345+
export function TopicDataSize({size}: TopicDataSizeProps) {
346+
return formatBytes(size);
347+
}

src/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,15 @@ function ObjectGeneral(props: ObjectGeneralProps) {
3232
props;
3333
switch (tenantPage) {
3434
case TENANT_PAGES_IDS.query: {
35-
return <Query tenantName={tenantName} path={path} theme={theme} type={type} />;
35+
return (
36+
<Query
37+
tenantName={tenantName}
38+
path={path}
39+
theme={theme}
40+
type={type}
41+
subType={subType}
42+
/>
43+
);
3644
}
3745
default: {
3846
return (

src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import React from 'react';
66
import {NavigationTree} from 'ydb-ui-components';
77

88
import {getConnectToDBDialog} from '../../../../components/ConnectToDB/ConnectToDBDialog';
9-
import {useCreateDirectoryFeatureAvailable} from '../../../../store/reducers/capabilities/hooks';
9+
import {
10+
useCreateDirectoryFeatureAvailable,
11+
useTopicDataAvailable,
12+
} from '../../../../store/reducers/capabilities/hooks';
1013
import {selectIsDirty, selectUserInput} from '../../../../store/reducers/query/query';
1114
import {schemaApi} from '../../../../store/reducers/schema/schema';
1215
import {tableSchemaDataApi} from '../../../../store/reducers/tableSchemaData';
@@ -21,6 +24,7 @@ import {
2124
nodeTableTypeToPathType,
2225
} from '../../utils/schema';
2326
import {getActions} from '../../utils/schemaActions';
27+
import type {DropdownItem, TreeNodeMeta} from '../../utils/types';
2428
import {CreateDirectoryDialog} from '../CreateDirectoryDialog/CreateDirectoryDialog';
2529
import {useDispatchTreeKey, useTreeKey} from '../UpdateTreeContext';
2630
import {isDomain} from '../transformPath';
@@ -44,6 +48,8 @@ export function SchemaTree(props: SchemaTreeProps) {
4448
{currentData: actionsSchemaData, isFetching: isActionsDataFetching},
4549
] = tableSchemaDataApi.useLazyGetTableSchemaDataQuery();
4650

51+
const isTopicPreviewAvailable = useTopicDataAvailable();
52+
4753
const [createDirectoryOpen, setCreateDirectoryOpen] = React.useState(false);
4854
const [parentPath, setParentPath] = React.useState('');
4955
const setSchemaTreeKey = useDispatchTreeKey();
@@ -91,6 +97,7 @@ export function SchemaTree(props: SchemaTreeProps) {
9197
// FIXME: should only be explicitly set to true for tables with indexes
9298
// at the moment of writing there is no property to determine this, fix later
9399
expandable: !isChildless,
100+
meta: {subType: PathSubType},
94101
};
95102
});
96103

@@ -153,7 +160,7 @@ export function SchemaTree(props: SchemaTreeProps) {
153160
parentPath={parentPath}
154161
onSuccess={handleSuccessSubmit}
155162
/>
156-
<NavigationTree
163+
<NavigationTree<DropdownItem, TreeNodeMeta>
157164
key={schemaTreeKey}
158165
rootState={{
159166
path: rootPath,
@@ -171,9 +178,14 @@ export function SchemaTree(props: SchemaTreeProps) {
171178

172179
return [];
173180
}}
174-
renderAdditionalNodeElements={getSchemaControls(dispatch, {
175-
setActivePath: onActivePathUpdate,
176-
})}
181+
renderAdditionalNodeElements={getSchemaControls(
182+
dispatch,
183+
{
184+
setActivePath: onActivePathUpdate,
185+
},
186+
undefined,
187+
isTopicPreviewAvailable,
188+
)}
177189
activePath={currentPath}
178190
onActivePathUpdate={onActivePathUpdate}
179191
cache={false}
Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,22 @@
11
@use '../../../../styles/mixins.scss';
22

3-
.kv-preview {
3+
.ydb-preview {
44
height: 100%;
55
@include mixins.flex-container();
66
@include mixins.query-data-table();
77
&__header {
88
position: sticky;
99
top: 0;
1010

11-
display: flex;
1211
flex-shrink: 0;
13-
justify-content: space-between;
14-
align-items: center;
1512

1613
height: 53px;
17-
padding: 0 20px;
14+
padding: 0 var(--g-spacing-6);
1815

1916
border-bottom: 1px solid var(--g-color-line-generic);
2017
background-color: var(--g-color-base-background);
2118
}
2219

23-
&__title {
24-
display: flex;
25-
gap: var(--g-spacing-1);
26-
}
27-
2820
&__table-name {
2921
margin-left: var(--g-spacing-1);
3022

@@ -36,21 +28,18 @@
3628
gap: var(--g-spacing-1);
3729
}
3830
&__message-container {
39-
padding: 15px 20px;
40-
}
41-
42-
&__loader-container {
43-
display: flex;
44-
justify-content: center;
45-
align-items: center;
46-
47-
height: 100%;
31+
padding: var(--g-spacing-3) 0;
4832
}
4933

5034
&__result {
5135
overflow: auto;
5236

5337
width: 100%;
54-
padding-left: 10px;
38+
padding-left: var(--g-spacing-5);
39+
}
40+
41+
&__partition-info {
42+
height: 36px;
43+
padding-left: var(--g-spacing-1);
5544
}
5645
}

0 commit comments

Comments
 (0)