Skip to content
Open
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
3 changes: 1 addition & 2 deletions src/components/InfoViewer/InfoViewer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
--ydb-info-viewer-font-size: var(--g-text-body-2-font-size);
--ydb-info-viewer-line-height: var(--g-text-body-2-line-height);
--ydb-info-viewer-title-font-weight: 600;
--ydb-info-viewer-title-margin: 15px 0 10px;
--ydb-info-viewer-items-gap: 7px;

font-size: var(--ydb-info-viewer-font-size);
line-height: var(--ydb-info-viewer-line-height);

&__title {
margin: var(--ydb-info-viewer-title-margin);
margin: var(--ydb-info-viewer-title-margin, 15px 0 10px);

font-weight: var(--ydb-info-viewer-title-font-weight);
}
Expand Down
29 changes: 12 additions & 17 deletions src/components/InfoViewer/schemaInfo/TableIndexInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import type {TEvDescribeSchemeResult} from '../../../types/api/schema';
import {cn} from '../../../utils/cn';

import i18n from './i18n';
import {
buildFulltextIndexSettingsInfo,
buildIndexInfo,
buildVectorIndexSettingsInfo,
} from './utils';
import {buildFulltextIndexSettingsInfo, buildVectorIndexSettingsInfo} from './utils';

const b = cn('ydb-diagnostics-table-info');

Expand All @@ -26,33 +22,32 @@ export const TableIndexInfo = ({data}: TableIndexInfoProps) => {
}

const TableIndex = data.PathDescription?.TableIndex;
const info: Array<InfoViewerItem> = buildIndexInfo(TableIndex);

let settings: Array<InfoViewerItem> = [];
if (TableIndex?.Type === EIndexType.EIndexTypeGlobalVectorKmeansTree) {
settings = buildVectorIndexSettingsInfo(
TableIndex?.VectorIndexKmeansTreeDescription?.Settings,
);
}
if (TableIndex?.Type === EIndexType.EIndexTypeGlobalFulltext) {
if (
TableIndex?.Type === EIndexType.EIndexTypeGlobalFulltext ||
TableIndex?.Type === EIndexType.EIndexTypeGlobalFulltextPlain ||
TableIndex?.Type === EIndexType.EIndexTypeGlobalFulltextRelevance
) {
settings = buildFulltextIndexSettingsInfo(TableIndex?.FulltextIndexDescription?.Settings);
}

if (!settings.length) {
return null;
}

return (
<div className={b()}>
<InfoViewer
info={info}
title={entityName}
info={settings}
title={i18n('title_index-settings')}
className={b('info-block')}
renderEmptyState={() => <div className={b('title')}>{entityName}</div>}
/>
{settings && settings.length ? (
<InfoViewer
info={settings}
title={i18n('title_index-settings')}
className={b('info-block')}
/>
) : null}
</div>
);
};
10 changes: 10 additions & 0 deletions src/components/InfoViewer/schemaInfo/i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{
"title_index-settings": "Index Settings",

"description_subtype_global": "Synchronous index is updated simultaneously with the indexed table and provides strict consistency.",
"description_subtype_global-async": "Asynchronous index receives table changes in the background and provides eventual consistency.",
"description_subtype_global-unique": "Unique secondary index enforces uniqueness for the indexed columns and is updated synchronously.",
"description_subtype_fulltext": "Full-text index enables text search by words, phrases, and, with n-grams, substrings.",
"description_subtype_fulltext-plain": "Plain full-text index stores only the inverted index and supports filtering without relevance ranking.",
"description_subtype_fulltext-relevance": "Relevance full-text index stores term frequency statistics required for relevance ranking.",
"description_subtype_vector": "Vector index enables vector search using distance or similarity functions.",
"description_subtype_local-bloom-filter": "Local bloom_filter index skips data fragments that cannot contain an exact value for equality and IN predicates.",
"description_subtype_local-bloom-ngram-filter": "Local bloom_ngram_filter index skips data fragments that cannot contain a substring for LIKE predicates.",
"description_subtype_local-min-max": "Local min_max index stores minimum and maximum values for each chunk (portion) of a column table, allowing chunks that cannot match query filters to be skipped.",
"field_clusters": "Clusters",
"field_overlap_clusters": "Overlap Clusters",
"field_levels": "Levels",
Expand Down
1 change: 1 addition & 0 deletions src/components/InfoViewer/schemaInfo/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './TableIndexInfo';
export {buildTableIndexOverviewInfo} from './utils';
Original file line number Diff line number Diff line change
@@ -1,37 +1,51 @@
import tenantKeyset from '../../../containers/Tenant/i18n';
import type {TIndexDescription} from '../../../types/api/schema';
import {EIndexType} from '../../../types/api/schema';
import type {
TFulltextIndexAnalyzers,
TFulltextIndexSettings,
TKMeansTreeSettings,
TVectorIndexSettings,
} from '../../../types/api/schema/tableIndex';
import {formatNumber} from '../../../utils/dataFormatters/dataFormatters';
import {SchemaObjectTypeLabel} from '../../SchemaObjectTypeLabel/SchemaObjectTypeLabel';
import type {YDBDefinitionListItem} from '../../YDBDefinitionList/YDBDefinitionList';
import type {InfoViewerItem} from '../InfoViewer';
import {formatTableIndexItem} from '../formatters';
import {createInfoFormatter} from '../utils';

import i18n from './i18n';

const DISPLAYED_FIELDS_KEYS = [
'Type',
const INDEX_DETAILS_FIELDS_KEYS = [
'State',
'DataSize',
'KeyColumnNames',
'DataColumnNames',
] as const;
type DisplayedIndexField = (typeof DISPLAYED_FIELDS_KEYS)[number];

export function getDisplayedIndexFields(): ReadonlySet<DisplayedIndexField> {
return new Set<DisplayedIndexField>(DISPLAYED_FIELDS_KEYS);
}
const INDEX_TYPE_DESCRIPTIONS: Record<EIndexType, string | undefined> = {
[EIndexType.EIndexTypeInvalid]: undefined,
[EIndexType.EIndexTypeGlobal]: i18n('description_subtype_global'),
[EIndexType.EIndexTypeGlobalAsync]: i18n('description_subtype_global-async'),
[EIndexType.EIndexTypeGlobalUnique]: i18n('description_subtype_global-unique'),
[EIndexType.EIndexTypeGlobalVectorKmeansTree]: i18n('description_subtype_vector'),
[EIndexType.EIndexTypeGlobalFulltext]: i18n('description_subtype_fulltext'),
[EIndexType.EIndexTypeGlobalFulltextPlain]: i18n('description_subtype_fulltext-plain'),
[EIndexType.EIndexTypeGlobalFulltextRelevance]: i18n('description_subtype_fulltext-relevance'),
[EIndexType.EIndexTypeLocalBloomFilter]: i18n('description_subtype_local-bloom-filter'),
[EIndexType.EIndexTypeLocalBloomNgramFilter]: i18n(
'description_subtype_local-bloom-ngram-filter',
),
[EIndexType.EIndexTypeLocalMinMax]: i18n('description_subtype_local-min-max'),
};

export function buildIndexInfo(tableIndex?: TIndexDescription): InfoViewerItem[] {
function buildIndexInfo(tableIndex?: TIndexDescription): InfoViewerItem[] {
const info: InfoViewerItem[] = [];
if (!tableIndex) {
return info;
}

getDisplayedIndexFields().forEach((key) => {
INDEX_DETAILS_FIELDS_KEYS.forEach((key) => {
const value = tableIndex[key];
if (value !== undefined) {
info.push(formatTableIndexItem(key, value));
Expand All @@ -41,6 +55,31 @@ export function buildIndexInfo(tableIndex?: TIndexDescription): InfoViewerItem[]
return info;
}

export function buildTableIndexOverviewInfo(tableIndex?: TIndexDescription) {
const type = tableIndex?.Type;
const itemsAfterType: YDBDefinitionListItem[] = [];

if (type !== undefined) {
const typeItem = formatTableIndexItem('Type', type);
itemsAfterType.push({
name: tenantKeyset('summary.subtype'),
content: (
<SchemaObjectTypeLabel
value={typeItem.value}
description={INDEX_TYPE_DESCRIPTIONS[type]}
/>
),
});
}

const additionalItems = buildIndexInfo(tableIndex).map(({label, value}) => ({
name: String(label),
content: value,
}));

return {itemsAfterType, additionalItems};
}

/* eslint-disable camelcase */

export function buildVectorIndexSettingsInfo(
Expand Down
31 changes: 31 additions & 0 deletions src/components/LabelWithHelpMark/LabelWithHelpMark.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';

import type {HelpMarkProps, LabelProps} from '@gravity-ui/uikit';
import {Flex, HelpMark, Label} from '@gravity-ui/uikit';

interface LabelWithHelpMarkProps extends LabelProps {
help?: React.ReactNode;
helpMarkProps?: Omit<HelpMarkProps, 'children'>;
contentGap?: React.ComponentProps<typeof Flex>['gap'];
}

export function LabelWithHelpMark({
children,
help,
helpMarkProps,
contentGap = '1',
...labelProps
}: LabelWithHelpMarkProps) {
return (
<Label {...labelProps}>
<Flex alignItems="center" gap={contentGap} wrap="nowrap">
{children}
{help ? (
<HelpMark iconSize="s" {...helpMarkProps}>
{help}
</HelpMark>
) : null}
</Flex>
</Label>
);
}
24 changes: 1 addition & 23 deletions src/components/QueryDetails/QueryDetails.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@use '../../styles/mixins.scss';

.ydb-query-details {
--g-definition-list-item-gap: var(--g-spacing-2);
flex: 1;
Expand All @@ -14,35 +12,15 @@
padding: var(--g-spacing-5) var(--g-spacing-4) var(--g-spacing-5) var(--g-spacing-4);
}

&__query-header {
display: flex;
justify-content: space-between;
align-items: center;

padding: var(--g-spacing-2) var(--g-spacing-3);

border-bottom: 1px solid var(--g-color-line-generic);
}

&__query-title {
font-size: 14px;
font-weight: 500;
}

&__query-details-info {
flex-grow: 0;
}

&__query-content {
position: relative;
--ydb-syntax-highlighter-height: 100%;

display: flex;
flex: 1;
flex-direction: column;

margin-top: var(--g-spacing-5);

border-radius: 4px;
background-color: var(--code-background-color);
}
}
41 changes: 20 additions & 21 deletions src/components/QueryDetails/QueryDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import {Code} from '@gravity-ui/icons';
import {Button, Flex, Icon} from '@gravity-ui/uikit';

import {cn} from '../../utils/cn';
import {YDBSyntaxHighlighter} from '../SyntaxHighlighter/YDBSyntaxHighlighter';
import type {YDBDefinitionListItem} from '../YDBDefinitionList/YDBDefinitionList';
import {YDBDefinitionList} from '../YDBDefinitionList/YDBDefinitionList';
import {YQLCodePreview} from '../YQLCodePreview/YQLCodePreview';

import i18n from './i18n';

Expand All @@ -15,7 +15,7 @@ const b = cn('ydb-query-details');
interface QueryDetailsProps {
queryText: string;
infoItems?: YDBDefinitionListItem[];
onOpenInEditor: () => void;
onOpenInEditor?: () => void;
}

export const QueryDetails = ({queryText, infoItems, onOpenInEditor}: QueryDetailsProps) => {
Expand All @@ -29,25 +29,24 @@ export const QueryDetails = ({queryText, infoItems, onOpenInEditor}: QueryDetail
/>
)}

<div className={b('query-content')}>
<div className={b('query-header')}>
<div className={b('query-title')}>{i18n('title_query-details')}</div>
<Button
view="flat-secondary"
size="m"
onClick={onOpenInEditor}
className={b('editor-button')}
>
<Icon data={Code} size={16} />
{i18n('action_open-in-editor')}
</Button>
</div>
<YDBSyntaxHighlighter
language="yql"
text={queryText}
withClipboardButton={{alwaysVisible: true, withLabel: false, size: 'm'}}
/>
</div>
<YQLCodePreview
className={b('query-content')}
title={i18n('title_query-details')}
text={queryText}
actions={
onOpenInEditor ? (
<Button
view="flat-secondary"
size="m"
onClick={onOpenInEditor}
className={b('editor-button')}
>
<Icon data={Code} size={16} />
{i18n('action_open-in-editor')}
</Button>
) : undefined
}
/>
</Flex>
</Flex>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.ydb-schema-object-type-label {
&__help-mark {
color: var(--g-color-text-misc-heavy);
}

&__description {
max-width: 360px;
}
}
29 changes: 29 additions & 0 deletions src/components/SchemaObjectTypeLabel/SchemaObjectTypeLabel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';

import {cn} from '../../utils/cn';
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
import {LabelWithHelpMark} from '../LabelWithHelpMark/LabelWithHelpMark';

import './SchemaObjectTypeLabel.scss';

const b = cn('ydb-schema-object-type-label');

interface SchemaObjectTypeLabelProps {
value?: React.ReactNode;
description?: React.ReactNode;
}

export function SchemaObjectTypeLabel({value, description}: SchemaObjectTypeLabelProps) {
return (
<LabelWithHelpMark
theme="normal"
help={description ? <div className={b('description')}>{description}</div> : undefined}
helpMarkProps={{
className: b('help-mark'),
popoverProps: {placement: ['right', 'bottom']},
}}
>
{value ?? EMPTY_DATA_PLACEHOLDER}
</LabelWithHelpMark>
);
}
26 changes: 26 additions & 0 deletions src/components/YQLCodePreview/YQLCodePreview.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.ydb-yql-code-preview {
--ydb-syntax-highlighter-height: auto;

position: relative;

display: flex;
flex-direction: column;

border-radius: 4px;
background-color: var(--code-background-color);

&__header {
display: flex;
justify-content: space-between;
align-items: center;

padding: var(--g-spacing-2) var(--g-spacing-3);

border-bottom: 1px solid var(--g-color-line-generic);
}

&__title {
font-size: 14px;
font-weight: 500;
}
}
Loading
Loading