From 8b36d234e32ee3399bb45928d3e017c1b4971c67 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Fri, 16 May 2025 17:55:13 +0300 Subject: [PATCH 1/8] feat(Preview): add preview for topics --- src/components/EntityStatus/EntityStatus.tsx | 2 +- .../TopicData/columns/Columns.scss | 15 +-- .../Diagnostics/TopicData/columns/columns.tsx | 115 ++++++++++------- .../Tenant/Query/Preview/Preview.scss | 27 ++-- .../Tenant/Query/Preview/Preview.tsx | 117 +++--------------- .../Query/Preview/components/PreviewView.tsx | 86 +++++++++++++ .../Query/Preview/components/TablePreview.tsx | 40 ++++++ .../Query/Preview/components/TopicPreview.tsx | 97 +++++++++++++++ .../Preview/components/TopicPreviewTable.tsx | 70 +++++++++++ .../Tenant/Query/Preview/i18n/en.json | 4 + .../Tenant/Query/Preview/i18n/index.ts | 7 ++ src/containers/Tenant/Query/Preview/shared.ts | 3 + src/containers/Tenant/Query/Preview/types.ts | 7 ++ .../Tenant/Query/QueryEditor/QueryEditor.tsx | 4 +- src/containers/Tenant/utils/controls.tsx | 2 +- 15 files changed, 419 insertions(+), 177 deletions(-) create mode 100644 src/containers/Tenant/Query/Preview/components/PreviewView.tsx create mode 100644 src/containers/Tenant/Query/Preview/components/TablePreview.tsx create mode 100644 src/containers/Tenant/Query/Preview/components/TopicPreview.tsx create mode 100644 src/containers/Tenant/Query/Preview/components/TopicPreviewTable.tsx create mode 100644 src/containers/Tenant/Query/Preview/i18n/en.json create mode 100644 src/containers/Tenant/Query/Preview/i18n/index.ts create mode 100644 src/containers/Tenant/Query/Preview/shared.ts create mode 100644 src/containers/Tenant/Query/Preview/types.ts diff --git a/src/components/EntityStatus/EntityStatus.tsx b/src/components/EntityStatus/EntityStatus.tsx index 5e72b2bb50..6db1f3a789 100644 --- a/src/components/EntityStatus/EntityStatus.tsx +++ b/src/components/EntityStatus/EntityStatus.tsx @@ -92,7 +92,7 @@ export function EntityStatus({ ); } - return name && {name}; + return name && {renderName(name)}; }; return (
diff --git a/src/containers/Tenant/Diagnostics/TopicData/columns/Columns.scss b/src/containers/Tenant/Diagnostics/TopicData/columns/Columns.scss index 8e890ad195..33013c8a6c 100644 --- a/src/containers/Tenant/Diagnostics/TopicData/columns/Columns.scss +++ b/src/containers/Tenant/Diagnostics/TopicData/columns/Columns.scss @@ -1,24 +1,11 @@ @use '../../../../../styles/mixins.scss'; .ydb-diagnostics-topic-data-columns { - &__ts-diff_danger { - color: var(--g-color-text-danger); - } - &__message_clickable { - cursor: pointer; - - color: var(--g-color-text-info); - } &__offset { display: inline-flex; align-items: center; gap: var(--g-spacing-1); - .g-help-mark, - .g-help-mark__button { - display: flex; - } - } - &__offset { + width: 100%; height: 100%; } diff --git a/src/containers/Tenant/Diagnostics/TopicData/columns/columns.tsx b/src/containers/Tenant/Diagnostics/TopicData/columns/columns.tsx index 02cfcdcd5f..35e4aeaac5 100644 --- a/src/containers/Tenant/Diagnostics/TopicData/columns/columns.tsx +++ b/src/containers/Tenant/Diagnostics/TopicData/columns/columns.tsx @@ -2,6 +2,7 @@ import React from 'react'; import {TriangleExclamation} from '@gravity-ui/icons'; import DataTable from '@gravity-ui/react-data-table'; +import type {TextProps} from '@gravity-ui/uikit'; import {ActionTooltip, Icon, Popover, Text} from '@gravity-ui/uikit'; import {isNil} from 'lodash'; import {Link} from 'react-router-dom'; @@ -88,18 +89,8 @@ export const tsDiffColumn: Column = { name: TOPIC_DATA_COLUMNS_IDS.TS_DIFF, header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.TS_DIFF], align: DataTable.RIGHT, - render: ({row}) => { - if (isNil(row.TimestampDiff)) { - return EMPTY_DATA_PLACEHOLDER; - } - const numericValue = safeParseNumber(row.TimestampDiff); - return ( - = 100_000})}> - {formatToMs(numericValue)} - - ); - }, - width: 90, + render: ({row: {TimestampDiff}}) => , + width: 110, note: i18n('context_ts-diff'), }; @@ -121,36 +112,9 @@ export const messageColumn: Column = { name: TOPIC_DATA_COLUMNS_IDS.MESSAGE, header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.MESSAGE], align: DataTable.LEFT, - render: ({row: {Message, OriginalSize}}) => { - if (isNil(Message)) { - return EMPTY_DATA_PLACEHOLDER; - } - let encryptedMessage; - let invalid = false; - try { - encryptedMessage = atob(Message); - } catch { - encryptedMessage = i18n('description_failed-decode'); - invalid = true; - } - - const truncated = safeParseNumber(OriginalSize) > TOPIC_MESSAGE_SIZE_LIMIT; - return ( - - {encryptedMessage} - {truncated && ( - - {' '} - {i18n('description_truncated')} - - )} - - ); - }, + render: ({row: {Message, OriginalSize}}) => ( + + ), width: 500, }; @@ -158,7 +122,7 @@ export const sizeColumn: Column = { name: TOPIC_DATA_COLUMNS_IDS.SIZE, header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.SIZE], align: DataTable.RIGHT, - render: ({row}) => formatBytes(row.StorageSize), + render: ({row: {StorageSize}}) => , width: 100, }; @@ -316,3 +280,68 @@ function Offset({offset, removed, notLoaded}: PartitionIdProps) { ); } +interface TopicDataTsDiffProps { + value?: string; + baseColor?: TextProps['color']; + variant?: TextProps['variant']; +} + +export function TopicDataTsDiff({ + value, + baseColor = 'primary', + variant = 'body-2', +}: TopicDataTsDiffProps) { + if (isNil(value)) { + return EMPTY_DATA_PLACEHOLDER; + } + const numericValue = safeParseNumber(value); + return ( + = 100_000 ? 'danger' : baseColor}> + {formatToMs(numericValue)} + + ); +} + +interface TopicDataMessageProps { + message?: string; + size?: number; +} + +export function TopicDataMessage({message, size}: TopicDataMessageProps) { + if (isNil(message)) { + return EMPTY_DATA_PLACEHOLDER; + } + let encryptedMessage; + let invalid = false; + try { + encryptedMessage = atob(message); + } catch { + encryptedMessage = i18n('description_failed-decode'); + invalid = true; + } + + const truncated = safeParseNumber(size) > TOPIC_MESSAGE_SIZE_LIMIT; + return ( + + {encryptedMessage} + {truncated && ( + + {' '} + {i18n('description_truncated')} + + )} + + ); +} + +interface TopicDataSizeProps { + size?: number; +} + +export function TopicDataSize({size}: TopicDataSizeProps) { + return formatBytes(size); +} diff --git a/src/containers/Tenant/Query/Preview/Preview.scss b/src/containers/Tenant/Query/Preview/Preview.scss index a151d5f2d1..d23e2d6435 100644 --- a/src/containers/Tenant/Query/Preview/Preview.scss +++ b/src/containers/Tenant/Query/Preview/Preview.scss @@ -1,6 +1,6 @@ @use '../../../../styles/mixins.scss'; -.kv-preview { +.ydb-preview { height: 100%; @include mixins.flex-container(); @include mixins.query-data-table(); @@ -8,23 +8,15 @@ position: sticky; top: 0; - display: flex; flex-shrink: 0; - justify-content: space-between; - align-items: center; height: 53px; - padding: 0 20px; + padding: 0 var(--g-spacing-6); border-bottom: 1px solid var(--g-color-line-generic); background-color: var(--g-color-base-background); } - &__title { - display: flex; - gap: var(--g-spacing-1); - } - &__table-name { margin-left: var(--g-spacing-1); @@ -39,18 +31,15 @@ padding: 15px 20px; } - &__loader-container { - display: flex; - justify-content: center; - align-items: center; - - height: 100%; - } - &__result { overflow: auto; width: 100%; - padding-left: 10px; + padding-left: var(--g-spacing-5); + } + + &__partition-info { + height: 36px; + padding-left: var(--g-spacing-1); } } diff --git a/src/containers/Tenant/Query/Preview/Preview.tsx b/src/containers/Tenant/Query/Preview/Preview.tsx index 61a8f5bd00..1b13599cf1 100644 --- a/src/containers/Tenant/Query/Preview/Preview.tsx +++ b/src/containers/Tenant/Query/Preview/Preview.tsx @@ -1,106 +1,29 @@ -import {Xmark} from '@gravity-ui/icons'; -import {Button, Icon, Loader, Text} from '@gravity-ui/uikit'; - -import EnableFullscreenButton from '../../../../components/EnableFullscreenButton/EnableFullscreenButton'; -import Fullscreen from '../../../../components/Fullscreen/Fullscreen'; -import {QueryResultTable} from '../../../../components/QueryResultTable'; -import {previewApi} from '../../../../store/reducers/preview'; -import {setShowPreview} from '../../../../store/reducers/schema/schema'; -import type {EPathType} from '../../../../types/api/schema'; -import {cn} from '../../../../utils/cn'; -import {useTypedDispatch} from '../../../../utils/hooks'; -import {parseQueryErrorToString} from '../../../../utils/query'; -import {isExternalTableType, isTableType} from '../../utils/schema'; +import {EPathType} from '../../../../types/api/schema'; +import {isTableType} from '../../utils/schema'; import i18n from '../i18n'; -import './Preview.scss'; - -const b = cn('kv-preview'); - -interface PreviewProps { - database: string; - path: string; - type: EPathType | undefined; -} - -export const Preview = ({database, path, type}: PreviewProps) => { - const dispatch = useTypedDispatch(); +import {Preview} from './components/PreviewView'; +import {TablePreview} from './components/TablePreview'; +import {TopicPreview} from './components/TopicPreview'; +import {b} from './shared'; +import type {PreviewContainerProps} from './types'; - const isPreviewAvailable = isTableType(type); - - const query = `select * from \`${path}\` limit 101`; - const {currentData, isFetching, error} = previewApi.useSendQueryQuery( - { - database, - query, - action: isExternalTableType(type) ? 'execute-query' : 'execute-scan', - limitRows: 100, - }, - { - skip: !isPreviewAvailable, - refetchOnMountOrArgChange: true, - }, - ); - const loading = isFetching && currentData === undefined; - const data = currentData?.resultSets?.[0] ?? {}; - - const handleClosePreview = () => { - dispatch(setShowPreview(false)); - }; +import './Preview.scss'; - const renderHeader = () => { - return ( -
-
- {i18n('preview.title')} - - {data.truncated ? `${i18n('preview.truncated')} ` : ''}( - {data.result?.length ?? 0}) - -
{path}
-
-
- - -
-
- ); - }; +export function PreviewContainer(props: PreviewContainerProps) { + const {type} = props; + const isTable = isTableType(type); + const isTopic = type === EPathType.EPathTypePersQueueGroup; - if (loading) { - return ( -
- -
- ); + if (isTable) { + return ; } - - let message; - - if (!isPreviewAvailable) { - message =
{i18n('preview.not-available')}
; - } else if (error) { - message = ( -
{parseQueryErrorToString(error)}
- ); + if (isTopic) { + return ; } - const content = message ?? ( -
- -
+ const renderContent = () => ( +
{i18n('preview.not-available')}
); - - return ( -
- {renderHeader()} - {content} -
- ); -}; + return ; +} diff --git a/src/containers/Tenant/Query/Preview/components/PreviewView.tsx b/src/containers/Tenant/Query/Preview/components/PreviewView.tsx new file mode 100644 index 0000000000..87107e7d13 --- /dev/null +++ b/src/containers/Tenant/Query/Preview/components/PreviewView.tsx @@ -0,0 +1,86 @@ +import React from 'react'; + +import {Xmark} from '@gravity-ui/icons'; +import {Button, Flex, Icon, Text} from '@gravity-ui/uikit'; + +import EnableFullscreenButton from '../../../../../components/EnableFullscreenButton/EnableFullscreenButton'; +import Fullscreen from '../../../../../components/Fullscreen/Fullscreen'; +import {LoaderWrapper} from '../../../../../components/LoaderWrapper/LoaderWrapper'; +import {setShowPreview} from '../../../../../store/reducers/schema/schema'; +import {useTypedDispatch} from '../../../../../utils/hooks'; +import {parseQueryErrorToString} from '../../../../../utils/query'; +import i18n from '../../i18n'; +import {b} from '../shared'; + +interface PreviewProps { + path: string; + quantity?: number; + truncated?: boolean; + renderResult?: () => React.ReactNode; + loading?: boolean; + error?: unknown; +} + +export function Preview({ + path, + quantity = 0, + truncated, + renderResult, + loading, + error, +}: PreviewProps) { + const dispatch = useTypedDispatch(); + + const handleClosePreview = () => { + dispatch(setShowPreview(false)); + }; + + const renderHeader = () => { + return ( + + + {i18n('preview.title')} + + {truncated ? `${i18n('preview.truncated')} ` : ''}({quantity}) + +
{path}
+
+
+ + +
+
+ ); + }; + + const renderContent = () => { + let message; + + if (error) { + message = ( +
+ {parseQueryErrorToString(error)} +
+ ); + } + if (message) { + return message; + } + return
{renderResult?.()}
; + }; + + return ( + +
+ {renderHeader()} + {renderContent()} +
+
+ ); +} diff --git a/src/containers/Tenant/Query/Preview/components/TablePreview.tsx b/src/containers/Tenant/Query/Preview/components/TablePreview.tsx new file mode 100644 index 0000000000..c8df79abaf --- /dev/null +++ b/src/containers/Tenant/Query/Preview/components/TablePreview.tsx @@ -0,0 +1,40 @@ +import {QueryResultTable} from '../../../../../components/QueryResultTable'; +import {previewApi} from '../../../../../store/reducers/preview'; +import {isExternalTableType} from '../../../utils/schema'; +import type {PreviewContainerProps} from '../types'; + +import {Preview} from './PreviewView'; + +const TABLE_PREVIEW_LIMIT = 100; + +export function TablePreview({database, path, type}: PreviewContainerProps) { + const query = `select * from \`${path}\` limit 101`; + const {currentData, isFetching, error} = previewApi.useSendQueryQuery( + { + database, + query, + action: isExternalTableType(type) ? 'execute-query' : 'execute-scan', + limitRows: TABLE_PREVIEW_LIMIT, + }, + { + refetchOnMountOrArgChange: true, + }, + ); + const loading = isFetching && currentData === undefined; + const data = currentData?.resultSets?.[0] ?? {}; + + const renderResult = () => { + return ; + }; + + return ( + + ); +} diff --git a/src/containers/Tenant/Query/Preview/components/TopicPreview.tsx b/src/containers/Tenant/Query/Preview/components/TopicPreview.tsx new file mode 100644 index 0000000000..c159de9b5c --- /dev/null +++ b/src/containers/Tenant/Query/Preview/components/TopicPreview.tsx @@ -0,0 +1,97 @@ +import React from 'react'; + +import {Flex, Text} from '@gravity-ui/uikit'; +import {skipToken} from '@reduxjs/toolkit/query'; +import {isNil} from 'lodash'; + +import {partitionsApi} from '../../../../../store/reducers/partitions/partitions'; +import {topicApi} from '../../../../../store/reducers/topic'; +import type {TopicDataRequest} from '../../../../../types/api/topic'; +import {safeParseNumber} from '../../../../../utils/utils'; +import i18n from '../i18n'; +import {b} from '../shared'; +import type {PreviewContainerProps} from '../types'; + +import {Preview} from './PreviewView'; +import {TopicPreviewTable} from './TopicPreviewTable'; + +const TOPIC_PREVIEW_LIMIT = 100; + +export function TopicPreview({database, path}: PreviewContainerProps) { + const { + data: partitions, + isLoading: partitionsLoading, + error: partitionsError, + } = partitionsApi.useGetPartitionsQuery({path, database}); + + const firstPartition = React.useMemo(() => { + return partitions?.[0]; + }, [partitions]); + + const queryParams = React.useMemo(() => { + const firstPartitionId = firstPartition?.partitionId; + if (!firstPartition || isNil(firstPartitionId)) { + return skipToken; + } + const params: TopicDataRequest = { + database, + path, + partition: String(firstPartitionId), + limit: TOPIC_PREVIEW_LIMIT, + offset: safeParseNumber(firstPartition.endOffset) - TOPIC_PREVIEW_LIMIT, + message_size_limit: 100, + }; + + return params; + }, [database, path, firstPartition]); + + const {currentData, error, isFetching} = topicApi.useGetTopicDataQuery(queryParams); + + const loading = partitionsLoading || (isFetching && currentData === undefined); + + const offsetsRange = React.useMemo(() => { + if (!firstPartition) { + return undefined; + } + return { + start: safeParseNumber(firstPartition.startOffset), + end: safeParseNumber(firstPartition.endOffset) - 1, + }; + }, [firstPartition]); + + const renderResult = React.useCallback(() => { + return ( + + + {!isNil(firstPartition?.partitionId) && ( + + {i18n('label_partition-id', {id: firstPartition.partitionId})} + + )} + {offsetsRange && ( + + ({i18n('label_offsets-range', offsetsRange)}) + + )} + + {currentData && ( + + )} + + ); + }, [offsetsRange, firstPartition, currentData]); + + const offsetsQuantity = + safeParseNumber(currentData?.EndOffset) - safeParseNumber(currentData?.StartOffset); + + return ( + TOPIC_PREVIEW_LIMIT} + quantity={currentData?.Messages?.length ?? 0} + /> + ); +} diff --git a/src/containers/Tenant/Query/Preview/components/TopicPreviewTable.tsx b/src/containers/Tenant/Query/Preview/components/TopicPreviewTable.tsx new file mode 100644 index 0000000000..81b8e849b0 --- /dev/null +++ b/src/containers/Tenant/Query/Preview/components/TopicPreviewTable.tsx @@ -0,0 +1,70 @@ +import React from 'react'; + +import type {Column} from '@gravity-ui/react-data-table'; +import {isNil} from 'lodash'; + +import {ResizeableDataTable} from '../../../../../components/ResizeableDataTable/ResizeableDataTable'; +import type {TopicMessage} from '../../../../../types/api/topic'; +import {DEFAULT_TABLE_SETTINGS, EMPTY_DATA_PLACEHOLDER} from '../../../../../utils/constants'; +import { + TopicDataMessage, + TopicDataSize, + TopicDataTimestamp, + TopicDataTsDiff, +} from '../../../Diagnostics/TopicData/columns/columns'; +import {TOPIC_DATA_COLUMNS_TITLES} from '../../../Diagnostics/TopicData/utils/constants'; +import {TOPIC_DATA_COLUMNS_IDS} from '../../../Diagnostics/TopicData/utils/types'; +import {b} from '../shared'; + +const columns: Column[] = [ + { + name: TOPIC_DATA_COLUMNS_IDS.OFFSET, + header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.OFFSET], + render: ({row: {Offset}}) => (isNil(Offset) ? EMPTY_DATA_PLACEHOLDER : Offset), + }, + { + name: TOPIC_DATA_COLUMNS_IDS.TIMESTAMP_CREATE, + header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.TIMESTAMP_CREATE], + render: ({row: {CreateTimestamp, TimestampDiff}}) => ( + + +
+ +
+ ), + width: 200, + }, + { + name: TOPIC_DATA_COLUMNS_IDS.MESSAGE, + header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.MESSAGE], + render: ({row: {Message, OriginalSize}}) => ( + + ), + width: 500, + }, + { + name: TOPIC_DATA_COLUMNS_IDS.SIZE, + header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.SIZE], + render: ({row: {StorageSize}}) => , + align: 'right', + width: 100, + }, +]; + +interface TopicPreviewTableProps { + messages: TopicMessage[]; +} + +export function TopicPreviewTable({messages}: TopicPreviewTableProps) { + const getRowIndex = (row: TopicMessage, index: number) => row.Offset ?? index; + return ( + + ); +} diff --git a/src/containers/Tenant/Query/Preview/i18n/en.json b/src/containers/Tenant/Query/Preview/i18n/en.json new file mode 100644 index 0000000000..f705686b6c --- /dev/null +++ b/src/containers/Tenant/Query/Preview/i18n/en.json @@ -0,0 +1,4 @@ +{ + "label_partition-id": "Partition ID: {{id}}", + "label_offsets-range": "offsets: {{start}} - {{end}}" +} diff --git a/src/containers/Tenant/Query/Preview/i18n/index.ts b/src/containers/Tenant/Query/Preview/i18n/index.ts new file mode 100644 index 0000000000..4f39cee9bb --- /dev/null +++ b/src/containers/Tenant/Query/Preview/i18n/index.ts @@ -0,0 +1,7 @@ +import {registerKeysets} from '../../../../../utils/i18n'; + +import en from './en.json'; + +const COMPONENT = 'ydb-preview'; + +export default registerKeysets(COMPONENT, {en}); diff --git a/src/containers/Tenant/Query/Preview/shared.ts b/src/containers/Tenant/Query/Preview/shared.ts new file mode 100644 index 0000000000..83de532aed --- /dev/null +++ b/src/containers/Tenant/Query/Preview/shared.ts @@ -0,0 +1,3 @@ +import {cn} from '../../../../utils/cn'; + +export const b = cn('ydb-preview'); diff --git a/src/containers/Tenant/Query/Preview/types.ts b/src/containers/Tenant/Query/Preview/types.ts new file mode 100644 index 0000000000..412c60ac3a --- /dev/null +++ b/src/containers/Tenant/Query/Preview/types.ts @@ -0,0 +1,7 @@ +import type {EPathType} from '../../../../types/api/schema'; + +export interface PreviewContainerProps { + database: string; + path: string; + type?: EPathType; +} diff --git a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx index 9a81715319..ae0cd383fc 100644 --- a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx +++ b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx @@ -46,7 +46,7 @@ import { PaneVisibilityActionTypes, paneVisibilityToggleReducerCreator, } from '../../utils/paneVisibilityToggleHelpers'; -import {Preview} from '../Preview/Preview'; +import {PreviewContainer} from '../Preview/Preview'; import {QueryEditorControls} from '../QueryEditorControls/QueryEditorControls'; import {QueryResultViewer} from '../QueryResult/QueryResultViewer'; import {QuerySettingsDialog} from '../QuerySettingsDialog/QuerySettingsDialog'; @@ -313,7 +313,7 @@ function Result({ tableSettings, }: ResultProps) { if (showPreview) { - return ; + return ; } if (result) { diff --git a/src/containers/Tenant/utils/controls.tsx b/src/containers/Tenant/utils/controls.tsx index 5e4f2a6566..7f89d92549 100644 --- a/src/containers/Tenant/utils/controls.tsx +++ b/src/containers/Tenant/utils/controls.tsx @@ -71,7 +71,7 @@ export const getSchemaControls = column_table: openPreview, index_table: undefined, - topic: undefined, + topic: openPreview, stream: undefined, index: undefined, From 7f897d2900fc0eb3239fa64f4b5fa48056265d20 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Fri, 16 May 2025 17:56:08 +0300 Subject: [PATCH 2/8] fix: test --- tests/suites/tenant/queryEditor/models/ResultTable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/tenant/queryEditor/models/ResultTable.ts b/tests/suites/tenant/queryEditor/models/ResultTable.ts index dfd36a5941..b945dc2887 100644 --- a/tests/suites/tenant/queryEditor/models/ResultTable.ts +++ b/tests/suites/tenant/queryEditor/models/ResultTable.ts @@ -29,7 +29,7 @@ export class ResultTable { constructor(selector: Locator) { this.table = selector.locator('.ydb-query-result-sets-viewer__result'); - this.preview = selector.locator('.kv-preview__result'); + this.preview = selector.locator('.ydb-preview__result'); this.resultHead = selector.locator('.ydb-query-result-sets-viewer__head'); this.resultTitle = selector.locator('.ydb-query-result-sets-viewer__title'); this.resultWrapper = selector.locator('.ydb-query-result-sets-viewer__result-wrapper'); From 66c82dfcebd293da64539b3a86a58a6536b17466 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Fri, 16 May 2025 17:58:24 +0300 Subject: [PATCH 3/8] nanofix --- .../Tenant/Query/Preview/components/TopicPreviewTable.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/containers/Tenant/Query/Preview/components/TopicPreviewTable.tsx b/src/containers/Tenant/Query/Preview/components/TopicPreviewTable.tsx index 81b8e849b0..358d555a37 100644 --- a/src/containers/Tenant/Query/Preview/components/TopicPreviewTable.tsx +++ b/src/containers/Tenant/Query/Preview/components/TopicPreviewTable.tsx @@ -21,6 +21,7 @@ const columns: Column[] = [ name: TOPIC_DATA_COLUMNS_IDS.OFFSET, header: TOPIC_DATA_COLUMNS_TITLES[TOPIC_DATA_COLUMNS_IDS.OFFSET], render: ({row: {Offset}}) => (isNil(Offset) ? EMPTY_DATA_PLACEHOLDER : Offset), + sortable: false, }, { name: TOPIC_DATA_COLUMNS_IDS.TIMESTAMP_CREATE, @@ -33,6 +34,7 @@ const columns: Column[] = [ ), width: 200, + sortable: false, }, { name: TOPIC_DATA_COLUMNS_IDS.MESSAGE, @@ -41,6 +43,7 @@ const columns: Column[] = [ ), width: 500, + sortable: false, }, { name: TOPIC_DATA_COLUMNS_IDS.SIZE, @@ -48,6 +51,7 @@ const columns: Column[] = [ render: ({row: {StorageSize}}) => , align: 'right', width: 100, + sortable: false, }, ]; From a61f8d9b80bbe3b06545c11e712cf7589371edfa Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Mon, 19 May 2025 14:14:19 +0300 Subject: [PATCH 4/8] fix: show topic preview if available --- .../ObjectSummary/SchemaTree/SchemaTree.tsx | 18 ++++++++++++++---- src/containers/Tenant/utils/controls.tsx | 3 ++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx b/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx index 3d5b9541e9..99640611bc 100644 --- a/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx +++ b/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx @@ -6,7 +6,10 @@ import React from 'react'; import {NavigationTree} from 'ydb-ui-components'; import {getConnectToDBDialog} from '../../../../components/ConnectToDB/ConnectToDBDialog'; -import {useCreateDirectoryFeatureAvailable} from '../../../../store/reducers/capabilities/hooks'; +import { + useCreateDirectoryFeatureAvailable, + useTopicDataAvailable, +} from '../../../../store/reducers/capabilities/hooks'; import {selectIsDirty, selectUserInput} from '../../../../store/reducers/query/query'; import {schemaApi} from '../../../../store/reducers/schema/schema'; import {tableSchemaDataApi} from '../../../../store/reducers/tableSchemaData'; @@ -44,6 +47,8 @@ export function SchemaTree(props: SchemaTreeProps) { {currentData: actionsSchemaData, isFetching: isActionsDataFetching}, ] = tableSchemaDataApi.useLazyGetTableSchemaDataQuery(); + const isTopicPreviewAvailable = useTopicDataAvailable(); + const [createDirectoryOpen, setCreateDirectoryOpen] = React.useState(false); const [parentPath, setParentPath] = React.useState(''); const setSchemaTreeKey = useDispatchTreeKey(); @@ -171,9 +176,14 @@ export function SchemaTree(props: SchemaTreeProps) { return []; }} - renderAdditionalNodeElements={getSchemaControls(dispatch, { - setActivePath: onActivePathUpdate, - })} + renderAdditionalNodeElements={getSchemaControls( + dispatch, + { + setActivePath: onActivePathUpdate, + }, + undefined, + isTopicPreviewAvailable, + )} activePath={currentPath} onActivePathUpdate={onActivePathUpdate} cache={false} diff --git a/src/containers/Tenant/utils/controls.tsx b/src/containers/Tenant/utils/controls.tsx index 7f89d92549..1043d16db6 100644 --- a/src/containers/Tenant/utils/controls.tsx +++ b/src/containers/Tenant/utils/controls.tsx @@ -54,6 +54,7 @@ export const getSchemaControls = dispatch: React.Dispatch, additionalEffects: ControlsAdditionalEffects, size?: ButtonSize, + isTopicPreviewAvailable?: boolean, ) => (path: string, type: NavigationTreeNodeType) => { const options = bindActions(path, dispatch, additionalEffects); @@ -71,7 +72,7 @@ export const getSchemaControls = column_table: openPreview, index_table: undefined, - topic: openPreview, + topic: isTopicPreviewAvailable ? openPreview : undefined, stream: undefined, index: undefined, From d68d4c9b2cdd3ea076d2a34c46b12817638c773f Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Mon, 19 May 2025 14:16:14 +0300 Subject: [PATCH 5/8] fix: show topic preview if available --- src/containers/Tenant/Query/Preview/Preview.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/containers/Tenant/Query/Preview/Preview.tsx b/src/containers/Tenant/Query/Preview/Preview.tsx index 1b13599cf1..5cce33be3b 100644 --- a/src/containers/Tenant/Query/Preview/Preview.tsx +++ b/src/containers/Tenant/Query/Preview/Preview.tsx @@ -1,3 +1,4 @@ +import {useTopicDataAvailable} from '../../../../store/reducers/capabilities/hooks'; import {EPathType} from '../../../../types/api/schema'; import {isTableType} from '../../utils/schema'; import i18n from '../i18n'; @@ -14,11 +15,12 @@ export function PreviewContainer(props: PreviewContainerProps) { const {type} = props; const isTable = isTableType(type); const isTopic = type === EPathType.EPathTypePersQueueGroup; + const isTopicPreviewAvailable = useTopicDataAvailable(); if (isTable) { return ; } - if (isTopic) { + if (isTopic && isTopicPreviewAvailable) { return ; } From 2dd278e9367ed8bdd0c34eb33bd9e7678d7d7224 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Tue, 20 May 2025 17:39:17 +0300 Subject: [PATCH 6/8] fix: review --- package-lock.json | 8 ++++---- package.json | 2 +- .../Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx | 4 +++- src/containers/Tenant/Query/Preview/Preview.scss | 2 +- .../Tenant/Query/Preview/components/PreviewView.tsx | 13 +++++-------- src/containers/Tenant/utils/controls.tsx | 12 +++++++----- src/containers/Tenant/utils/schemaActions.tsx | 5 +++-- src/containers/Tenant/utils/types.ts | 13 +++++++++++++ 8 files changed, 37 insertions(+), 22 deletions(-) create mode 100644 src/containers/Tenant/utils/types.ts diff --git a/package-lock.json b/package-lock.json index 21a3f35c92..3cb600db84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,7 +57,7 @@ "use-query-params": "^2.2.1", "uuid": "^10.0.0", "web-vitals": "^1.1.2", - "ydb-ui-components": "^4.6.0", + "ydb-ui-components": "^4.7.0", "zod": "^3.24.1" }, "devDependencies": { @@ -29316,9 +29316,9 @@ } }, "node_modules/ydb-ui-components": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/ydb-ui-components/-/ydb-ui-components-4.6.0.tgz", - "integrity": "sha512-9gkD6KBda3Jo/zt8SpTgrmUckXP6gophDiL4E41CKjORCmi5umT5C7D/D98awzaB+ZltVL0L5ySdnZKizfD9Yw==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/ydb-ui-components/-/ydb-ui-components-4.7.0.tgz", + "integrity": "sha512-KalZ1LyX5heI+ZGEsxu3hg9iHUGsvqPyGXli4E4CzN8rUbrvDCrpmDUj1xmn+qFyLtrhQvUUKIX23+zDNoZw1A==", "license": "MIT", "dependencies": { "@bem-react/classname": "^1.6.0", diff --git a/package.json b/package.json index ec3ab6ca6b..6a56d793e9 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "use-query-params": "^2.2.1", "uuid": "^10.0.0", "web-vitals": "^1.1.2", - "ydb-ui-components": "^4.6.0", + "ydb-ui-components": "^4.7.0", "zod": "^3.24.1" }, "scripts": { diff --git a/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx b/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx index 99640611bc..cd5ed5b0cb 100644 --- a/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx +++ b/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx @@ -24,6 +24,7 @@ import { nodeTableTypeToPathType, } from '../../utils/schema'; import {getActions} from '../../utils/schemaActions'; +import type {DropdownItem, TreeNodeMeta} from '../../utils/types'; import {CreateDirectoryDialog} from '../CreateDirectoryDialog/CreateDirectoryDialog'; import {useDispatchTreeKey, useTreeKey} from '../UpdateTreeContext'; import {isDomain} from '../transformPath'; @@ -96,6 +97,7 @@ export function SchemaTree(props: SchemaTreeProps) { // FIXME: should only be explicitly set to true for tables with indexes // at the moment of writing there is no property to determine this, fix later expandable: !isChildless, + meta: {subType: PathSubType}, }; }); @@ -158,7 +160,7 @@ export function SchemaTree(props: SchemaTreeProps) { parentPath={parentPath} onSuccess={handleSuccessSubmit} /> - key={schemaTreeKey} rootState={{ path: rootPath, diff --git a/src/containers/Tenant/Query/Preview/Preview.scss b/src/containers/Tenant/Query/Preview/Preview.scss index d23e2d6435..fb533ac254 100644 --- a/src/containers/Tenant/Query/Preview/Preview.scss +++ b/src/containers/Tenant/Query/Preview/Preview.scss @@ -28,7 +28,7 @@ gap: var(--g-spacing-1); } &__message-container { - padding: 15px 20px; + padding: var(--g-spacing-3) 0; } &__result { diff --git a/src/containers/Tenant/Query/Preview/components/PreviewView.tsx b/src/containers/Tenant/Query/Preview/components/PreviewView.tsx index 87107e7d13..3e64b8a4cd 100644 --- a/src/containers/Tenant/Query/Preview/components/PreviewView.tsx +++ b/src/containers/Tenant/Query/Preview/components/PreviewView.tsx @@ -60,26 +60,23 @@ export function Preview({ }; const renderContent = () => { - let message; - if (error) { - message = ( + return (
{parseQueryErrorToString(error)}
); } - if (message) { - return message; - } - return
{renderResult?.()}
; + return renderResult?.(); }; return (
{renderHeader()} - {renderContent()} + +
{renderContent()}
+
); diff --git a/src/containers/Tenant/utils/controls.tsx b/src/containers/Tenant/utils/controls.tsx index 1043d16db6..712318160a 100644 --- a/src/containers/Tenant/utils/controls.tsx +++ b/src/containers/Tenant/utils/controls.tsx @@ -1,6 +1,6 @@ import type {ButtonSize} from '@gravity-ui/uikit'; import {Button, Icon} from '@gravity-ui/uikit'; -import type {NavigationTreeNodeType, NavigationTreeProps} from 'ydb-ui-components'; +import type {NavigationTreeNodeType} from 'ydb-ui-components'; import {api} from '../../../store/reducers/api'; import {setShowPreview} from '../../../store/reducers/schema/schema'; @@ -8,6 +8,8 @@ import {TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../store/reducers/te import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant'; import i18n from '../i18n'; +import type {YdbNavigationTreeProps} from './types'; + import EyeIcon from '@gravity-ui/icons/svgs/eye.svg'; interface ControlsAdditionalEffects { @@ -32,7 +34,7 @@ const bindActions = ( }; }; -type Controls = ReturnType['renderAdditionalNodeElements']>; +type Controls = ReturnType['renderAdditionalNodeElements']>; type SummaryType = 'preview'; @@ -55,8 +57,8 @@ export const getSchemaControls = additionalEffects: ControlsAdditionalEffects, size?: ButtonSize, isTopicPreviewAvailable?: boolean, - ) => - (path: string, type: NavigationTreeNodeType) => { + ): YdbNavigationTreeProps['renderAdditionalNodeElements'] => + (path, type, meta) => { const options = bindActions(path, dispatch, additionalEffects); const openPreview = getPreviewControl(options, size); @@ -72,7 +74,7 @@ export const getSchemaControls = column_table: openPreview, index_table: undefined, - topic: isTopicPreviewAvailable ? openPreview : undefined, + topic: isTopicPreviewAvailable && !meta?.subType ? openPreview : undefined, stream: undefined, index: undefined, diff --git a/src/containers/Tenant/utils/schemaActions.tsx b/src/containers/Tenant/utils/schemaActions.tsx index 7d9128bcd9..02a1cfb40e 100644 --- a/src/containers/Tenant/utils/schemaActions.tsx +++ b/src/containers/Tenant/utils/schemaActions.tsx @@ -1,7 +1,7 @@ import {Copy, PlugConnection} from '@gravity-ui/icons'; import {Flex, Spin} from '@gravity-ui/uikit'; import copy from 'copy-to-clipboard'; -import type {NavigationTreeNodeType, NavigationTreeProps} from 'ydb-ui-components'; +import type {NavigationTreeNodeType} from 'ydb-ui-components'; import type {SnippetParams} from '../../../components/ConnectToDB/types'; import type {AppDispatch} from '../../../store'; @@ -39,6 +39,7 @@ import { selectQueryTemplate, upsertQueryTemplate, } from './schemaQueryTemplates'; +import type {YdbNavigationTreeProps} from './types'; interface ActionsAdditionalParams { setActivePath: (path: string) => void; @@ -139,7 +140,7 @@ const bindActions = ( }; }; -type ActionsSet = ReturnType['getActions']>; +type ActionsSet = ReturnType['getActions']>; interface ActionConfig { text: string; diff --git a/src/containers/Tenant/utils/types.ts b/src/containers/Tenant/utils/types.ts new file mode 100644 index 0000000000..0676495d7c --- /dev/null +++ b/src/containers/Tenant/utils/types.ts @@ -0,0 +1,13 @@ +import type {NavigationTreeProps} from 'ydb-ui-components'; + +export type DropdownItem = { + text: string; + action: () => void; + iconEnd?: React.ReactNode; +}; + +export type TreeNodeMeta = { + subType?: string; +}; + +export type YdbNavigationTreeProps = NavigationTreeProps; From 6d6f786d29ffcb317402f33ada01fec828acac5f Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Wed, 21 May 2025 17:44:21 +0300 Subject: [PATCH 7/8] fix: review --- src/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx | 10 +++++++++- src/containers/Tenant/Query/Preview/Preview.tsx | 6 ++++-- src/containers/Tenant/Query/Preview/types.ts | 3 ++- src/containers/Tenant/Query/Query.tsx | 3 ++- .../Tenant/Query/QueryEditor/QueryEditor.tsx | 10 +++++++--- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx b/src/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx index 6bde55a1db..c12669e3ed 100644 --- a/src/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +++ b/src/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx @@ -32,7 +32,15 @@ function ObjectGeneral(props: ObjectGeneralProps) { props; switch (tenantPage) { case TENANT_PAGES_IDS.query: { - return ; + return ( + + ); } default: { return ( diff --git a/src/containers/Tenant/Query/Preview/Preview.tsx b/src/containers/Tenant/Query/Preview/Preview.tsx index 5cce33be3b..7398681597 100644 --- a/src/containers/Tenant/Query/Preview/Preview.tsx +++ b/src/containers/Tenant/Query/Preview/Preview.tsx @@ -12,7 +12,7 @@ import type {PreviewContainerProps} from './types'; import './Preview.scss'; export function PreviewContainer(props: PreviewContainerProps) { - const {type} = props; + const {type, subType} = props; const isTable = isTableType(type); const isTopic = type === EPathType.EPathTypePersQueueGroup; const isTopicPreviewAvailable = useTopicDataAvailable(); @@ -20,7 +20,9 @@ export function PreviewContainer(props: PreviewContainerProps) { if (isTable) { return ; } - if (isTopic && isTopicPreviewAvailable) { + + // preview is not available for topics inside CDC (has subtype) + if (isTopic && !subType && isTopicPreviewAvailable) { return ; } diff --git a/src/containers/Tenant/Query/Preview/types.ts b/src/containers/Tenant/Query/Preview/types.ts index 412c60ac3a..b79c95811a 100644 --- a/src/containers/Tenant/Query/Preview/types.ts +++ b/src/containers/Tenant/Query/Preview/types.ts @@ -1,7 +1,8 @@ -import type {EPathType} from '../../../../types/api/schema'; +import type {EPathSubType, EPathType} from '../../../../types/api/schema'; export interface PreviewContainerProps { database: string; path: string; type?: EPathType; + subType?: EPathSubType; } diff --git a/src/containers/Tenant/Query/Query.tsx b/src/containers/Tenant/Query/Query.tsx index 549fa31f6d..5f1bacef96 100644 --- a/src/containers/Tenant/Query/Query.tsx +++ b/src/containers/Tenant/Query/Query.tsx @@ -4,7 +4,7 @@ import {Helmet} from 'react-helmet-async'; import {changeUserInput} from '../../../store/reducers/query/query'; import {TENANT_QUERY_TABS_ID} from '../../../store/reducers/tenant/constants'; -import type {EPathType} from '../../../types/api/schema'; +import type {EPathSubType, EPathType} from '../../../types/api/schema'; import {cn} from '../../../utils/cn'; import {useTypedDispatch, useTypedSelector} from '../../../utils/hooks'; @@ -22,6 +22,7 @@ interface QueryProps { tenantName: string; path: string; type?: EPathType; + subType?: EPathSubType; } export const Query = (props: QueryProps) => { diff --git a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx index ae0cd383fc..a6ba65b071 100644 --- a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx +++ b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx @@ -22,7 +22,7 @@ import { import type {QueryResult} from '../../../../store/reducers/query/types'; import {setQueryAction} from '../../../../store/reducers/queryActions/queryActions'; import {selectShowPreview, setShowPreview} from '../../../../store/reducers/schema/schema'; -import type {EPathType} from '../../../../types/api/schema'; +import type {EPathSubType, EPathType} from '../../../../types/api/schema'; import type {QueryAction} from '../../../../types/store/query'; import {cn} from '../../../../utils/cn'; import { @@ -70,11 +70,12 @@ interface QueryEditorProps { changeUserInput: (arg: {input: string}) => void; theme: string; type?: EPathType; + subType?: EPathSubType; } export default function QueryEditor(props: QueryEditorProps) { const dispatch = useTypedDispatch(); - const {tenantName, path, type, theme, changeUserInput} = props; + const {tenantName, path, type, theme, changeUserInput, subType} = props; const savedPath = useTypedSelector(selectTenantPath); const result = useTypedSelector(selectResult); const historyQueries = useTypedSelector(selectQueriesHistory); @@ -270,6 +271,7 @@ export default function QueryEditor(props: QueryEditorProps) { onExpandResultHandler={onExpandResultHandler} onCollapseResultHandler={onCollapseResultHandler} type={type} + subType={subType} theme={theme} key={result?.queryId} result={result} @@ -291,6 +293,7 @@ interface ResultProps { onExpandResultHandler: VoidFunction; onCollapseResultHandler: VoidFunction; type?: EPathType; + subType?: EPathSubType; theme: string; result?: QueryResult; tenantName: string; @@ -304,6 +307,7 @@ function Result({ onExpandResultHandler, onCollapseResultHandler, type, + subType, theme, result, tenantName, @@ -313,7 +317,7 @@ function Result({ tableSettings, }: ResultProps) { if (showPreview) { - return ; + return ; } if (result) { From 908a351ce48f5613c7642c17b2be3f4618579c30 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Wed, 21 May 2025 18:29:07 +0300 Subject: [PATCH 8/8] fix: preview --- src/containers/Tenant/Query/Preview/Preview.tsx | 6 +++--- src/containers/Tenant/utils/controls.tsx | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/containers/Tenant/Query/Preview/Preview.tsx b/src/containers/Tenant/Query/Preview/Preview.tsx index 7398681597..952de9f4d3 100644 --- a/src/containers/Tenant/Query/Preview/Preview.tsx +++ b/src/containers/Tenant/Query/Preview/Preview.tsx @@ -1,5 +1,5 @@ import {useTopicDataAvailable} from '../../../../store/reducers/capabilities/hooks'; -import {EPathType} from '../../../../types/api/schema'; +import {EPathSubType, EPathType} from '../../../../types/api/schema'; import {isTableType} from '../../utils/schema'; import i18n from '../i18n'; @@ -15,14 +15,14 @@ export function PreviewContainer(props: PreviewContainerProps) { const {type, subType} = props; const isTable = isTableType(type); const isTopic = type === EPathType.EPathTypePersQueueGroup; + const isCdcTopic = subType === EPathSubType.EPathSubTypeStreamImpl; const isTopicPreviewAvailable = useTopicDataAvailable(); if (isTable) { return ; } - // preview is not available for topics inside CDC (has subtype) - if (isTopic && !subType && isTopicPreviewAvailable) { + if (isTopic && !isCdcTopic && isTopicPreviewAvailable) { return ; } diff --git a/src/containers/Tenant/utils/controls.tsx b/src/containers/Tenant/utils/controls.tsx index 712318160a..740fa9ec0a 100644 --- a/src/containers/Tenant/utils/controls.tsx +++ b/src/containers/Tenant/utils/controls.tsx @@ -6,6 +6,7 @@ import {api} from '../../../store/reducers/api'; import {setShowPreview} from '../../../store/reducers/schema/schema'; import {TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../store/reducers/tenant/constants'; import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant'; +import {EPathSubType} from '../../../types/api/schema'; import i18n from '../i18n'; import type {YdbNavigationTreeProps} from './types'; @@ -62,6 +63,8 @@ export const getSchemaControls = const options = bindActions(path, dispatch, additionalEffects); const openPreview = getPreviewControl(options, size); + const isCdcTopic = meta?.subType === EPathSubType.EPathSubTypeStreamImpl; + const nodeTypeToControls: Record = { async_replication: undefined, transfer: undefined, @@ -74,7 +77,7 @@ export const getSchemaControls = column_table: openPreview, index_table: undefined, - topic: isTopicPreviewAvailable && !meta?.subType ? openPreview : undefined, + topic: isTopicPreviewAvailable && !isCdcTopic ? openPreview : undefined, stream: undefined, index: undefined,