Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
45 changes: 32 additions & 13 deletions src/components/InfoViewer/schemaInfo/TableIndexInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ import {InfoViewer} from '..';
import {getEntityName} from '../../../containers/Tenant/utils';
import {EIndexType} from '../../../types/api/schema';
import type {TEvDescribeSchemeResult} from '../../../types/api/schema';
import {cn} from '../../../utils/cn';

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

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

interface TableIndexInfoProps {
data?: TEvDescribeSchemeResult;
Expand All @@ -21,19 +28,31 @@ export const TableIndexInfo = ({data}: TableIndexInfoProps) => {
const TableIndex = data.PathDescription?.TableIndex;
const info: Array<InfoViewerItem> = buildIndexInfo(TableIndex);

const vectorSettings = TableIndex?.VectorIndexKmeansTreeDescription?.Settings;

const isVectorIndex = TableIndex?.Type === EIndexType.EIndexTypeGlobalVectorKmeansTree;

if (isVectorIndex) {
const vectorInfo: Array<InfoViewerItem> = buildVectorIndexInfo(vectorSettings);
return (
<>
<InfoViewer title={i18n('title_vector-index')} info={info} />
<InfoViewer info={vectorInfo} />
</>
let settings: Array<InfoViewerItem> = [];
if (TableIndex?.Type === EIndexType.EIndexTypeGlobalVectorKmeansTree) {
settings = buildVectorIndexSettingsInfo(
TableIndex?.VectorIndexKmeansTreeDescription?.Settings,
);
}
if (TableIndex?.Type === EIndexType.EIndexTypeGlobalFulltext) {
settings = buildFulltextIndexSettingsInfo(TableIndex?.FulltextIndexDescription?.Settings);
}

return <InfoViewer title={entityName} info={info} />;
return (
<div className={b()}>
<InfoViewer
info={info}
title={entityName}
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>
);
};
23 changes: 20 additions & 3 deletions src/components/InfoViewer/schemaInfo/i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
{
"title_vector-index": "Vector Index",
"title_index-settings": "Index Settings",

"field_clusters": "Clusters",
"field_levels": "Levels",
"field_vector-dimension": "Vector Dimension",
"field_vector-type": "Vector Type",
"field_vector_dimension": "Vector Dimension",
"field_vector_type": "Vector Type",
"field_metric": "Metric",
"field_columns": "Columns",
"field_includes": "Includes",
"field_data-size": "Data Size",

"field_layout": "Layout",
"field_tokenizer": "Tokenizer",
"field_language": "Language",
"field_use_filter_lowercase": "Filter Lowercase",
"field_use_filter_stopwords": "Filter Stopwords",
"field_use_filter_ngram": "Filter Ngram",
"field_use_filter_edge_ngram": "Filter Edge Ngram",
"field_filter_ngram_min_length": "Filter Ngram Min Length",
"field_filter_ngram_max_length": "Filter Ngram Max Length",
"field_use_filter_length": "Filter Length",
"field_filter_length_min": "Filter Length Min",
"field_filter_length_max": "Filter Length Max",
"filter_enabled": "Enabled",
"filter_disabled": "Disabled",

"alert_no-entity-data": "No {{entity}} data"
}
159 changes: 138 additions & 21 deletions src/components/InfoViewer/schemaInfo/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type {TIndexDescription} from '../../../types/api/schema';
import type {
TVectorIndexKmeansTreeDescriptionSettings,
TVectorIndexKmeansTreeDescriptionSettingsInner,
TFulltextIndexAnalyzers,
TFulltextIndexSettings,
TKMeansTreeSettings,
TVectorIndexSettings,
} from '../../../types/api/schema/tableIndex';
import {formatNumber} from '../../../utils/dataFormatters/dataFormatters';
import type {InfoViewerItem} from '../InfoViewer';
Expand Down Expand Up @@ -39,15 +41,19 @@ export function buildIndexInfo(tableIndex?: TIndexDescription): InfoViewerItem[]
return info;
}

type VectorSettings = TVectorIndexKmeansTreeDescriptionSettings;
/* eslint-disable camelcase */

export function buildVectorIndexInfo(vectorSettings?: VectorSettings): InfoViewerItem[] {
export function buildVectorIndexSettingsInfo(
kMeansTreeSettings?: TKMeansTreeSettings,
): InfoViewerItem[] {
const info: InfoViewerItem[] = [];
if (!vectorSettings) {
if (!kMeansTreeSettings) {
return info;
}

const vectorFormatter = createInfoFormatter<Pick<VectorSettings, 'clusters' | 'levels'>>({
const kMeansTreeSettingsFormatter = createInfoFormatter<
Pick<TKMeansTreeSettings, 'clusters' | 'levels'>
>({
values: {
clusters: (v) => (typeof v === 'number' ? formatNumber(v) : v),
levels: (v) => (typeof v === 'number' ? formatNumber(v) : v),
Expand All @@ -58,37 +64,148 @@ export function buildVectorIndexInfo(vectorSettings?: VectorSettings): InfoViewe
},
});

const settingsFormatter = createInfoFormatter<TVectorIndexKmeansTreeDescriptionSettingsInner>({
const {clusters, levels, settings} = kMeansTreeSettings;
if (clusters !== undefined) {
info.push(kMeansTreeSettingsFormatter('clusters', clusters));
}
if (levels !== undefined) {
info.push(kMeansTreeSettingsFormatter('levels', levels));
}

const vectorIndexSettingsFormatter = createInfoFormatter<TVectorIndexSettings>({
values: {
vector_dimension: (v) => (typeof v === 'number' ? formatNumber(v) : v),
vector_type: (v) => (typeof v === 'string' ? v.replace(/^VECTOR_TYPE_/, '') : v),
},
labels: {
vector_dimension: i18n('field_vector-dimension'),
vector_type: i18n('field_vector-type'),
vector_dimension: i18n('field_vector_dimension'),
vector_type: i18n('field_vector_type'),
metric: i18n('field_metric'),
},
});

const {clusters, levels, settings} = vectorSettings ?? {};
if (clusters !== undefined) {
info.push(vectorFormatter('clusters', clusters));
const {metric, vector_type, vector_dimension} = settings ?? {};
if (metric !== undefined) {
info.push(vectorIndexSettingsFormatter('metric', metric));
}
if (levels !== undefined) {
info.push(vectorFormatter('levels', levels));
if (vector_type !== undefined) {
info.push(vectorIndexSettingsFormatter('vector_type', vector_type));
}
if (vector_dimension !== undefined) {
info.push(vectorIndexSettingsFormatter('vector_dimension', vector_dimension));
}

const {vector_dimension: vectorDimension, vector_type: vectorType, metric} = settings ?? {};
return info;
}

if (vectorDimension !== undefined) {
info.push(settingsFormatter('vector_dimension', vectorDimension));
export function buildFulltextIndexSettingsInfo(
fulltextSettings?: TFulltextIndexSettings,
): InfoViewerItem[] {
const info: InfoViewerItem[] = [];
if (!fulltextSettings) {
return info;
}
if (vectorType !== undefined) {
info.push(settingsFormatter('vector_type', vectorType));

const fulltextFormatter = createInfoFormatter<Pick<TFulltextIndexSettings, 'layout'>>({
values: {
layout: (v) => v,
},
labels: {
layout: i18n('field_layout'),
},
});

const {layout} = fulltextSettings;
if (layout !== undefined) {
info.push(fulltextFormatter('layout', layout));
}
if (metric !== undefined) {
info.push(settingsFormatter('metric', metric));

const fulltextIndexAnalyzersFormatter = createInfoFormatter<TFulltextIndexAnalyzers>({
values: {
tokenizer: (v) => v,
language: (v) => v,
use_filter_lowercase: (v) =>
v === true ? i18n('filter_enabled') : i18n('filter_disabled'),
use_filter_stopwords: (v) =>
v === true ? i18n('filter_enabled') : i18n('filter_disabled'),
use_filter_ngram: (v) =>
v === true ? i18n('filter_enabled') : i18n('filter_disabled'),
use_filter_edge_ngram: (v) =>
v === true ? i18n('filter_enabled') : i18n('filter_disabled'),
filter_ngram_min_length: (v) => (typeof v === 'number' ? formatNumber(v) : v),
filter_ngram_max_length: (v) => (typeof v === 'number' ? formatNumber(v) : v),
use_filter_length: (v) =>
v === true ? i18n('filter_enabled') : i18n('filter_disabled'),
filter_length_min: (v) => (typeof v === 'number' ? formatNumber(v) : v),
filter_length_max: (v) => (typeof v === 'number' ? formatNumber(v) : v),
},
labels: {
tokenizer: i18n('field_tokenizer'),
language: i18n('field_language'),
use_filter_lowercase: i18n('field_use_filter_lowercase'),
use_filter_stopwords: i18n('field_use_filter_stopwords'),
use_filter_ngram: i18n('field_use_filter_ngram'),
use_filter_edge_ngram: i18n('field_use_filter_edge_ngram'),
filter_ngram_min_length: i18n('field_filter_ngram_min_length'),
filter_ngram_max_length: i18n('field_filter_ngram_max_length'),
use_filter_length: i18n('field_use_filter_length'),
filter_length_min: i18n('field_filter_length_min'),
filter_length_max: i18n('field_filter_length_max'),
},
});

const {
tokenizer,
language,
use_filter_lowercase,
use_filter_stopwords,
use_filter_ngram,
use_filter_edge_ngram,
filter_ngram_min_length,
filter_ngram_max_length,
use_filter_length,
filter_length_min,
filter_length_max,
} = fulltextSettings.columns?.at(0)?.analyzers ?? {};
if (tokenizer !== undefined) {
info.push(fulltextIndexAnalyzersFormatter('tokenizer', tokenizer));
}
if (language !== undefined) {
info.push(fulltextIndexAnalyzersFormatter('language', language));
}
if (use_filter_lowercase !== undefined) {
info.push(fulltextIndexAnalyzersFormatter('use_filter_lowercase', use_filter_lowercase));
}
if (use_filter_stopwords !== undefined) {
info.push(fulltextIndexAnalyzersFormatter('use_filter_stopwords', use_filter_stopwords));
}
if (use_filter_ngram !== undefined) {
info.push(fulltextIndexAnalyzersFormatter('use_filter_ngram', use_filter_ngram));
}
if (use_filter_edge_ngram !== undefined) {
info.push(fulltextIndexAnalyzersFormatter('use_filter_edge_ngram', use_filter_edge_ngram));
}
if (filter_ngram_min_length !== undefined) {
info.push(
fulltextIndexAnalyzersFormatter('filter_ngram_min_length', filter_ngram_min_length),
);
}
if (filter_ngram_max_length !== undefined) {
info.push(
fulltextIndexAnalyzersFormatter('filter_ngram_max_length', filter_ngram_max_length),
);
}
if (use_filter_length !== undefined) {
info.push(fulltextIndexAnalyzersFormatter('use_filter_length', use_filter_length));
}
if (filter_length_min !== undefined) {
info.push(fulltextIndexAnalyzersFormatter('filter_length_min', filter_length_min));
}
if (filter_length_max !== undefined) {
info.push(fulltextIndexAnalyzersFormatter('filter_length_max', filter_length_max));
}

return info;
}

/* eslint-enable camelcase */
2 changes: 2 additions & 0 deletions src/containers/Tenant/Diagnostics/DiagnosticsPages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ const pathSubTypeToPages: Record<EPathSubType, Page[] | undefined> = {

[EPathSubType.EPathSubTypeSyncIndexImplTable]: undefined,
[EPathSubType.EPathSubTypeAsyncIndexImplTable]: undefined,
[EPathSubType.EPathSubTypeVectorKmeansTreeIndexImplTable]: undefined,
[EPathSubType.EPathSubTypeFulltextIndexImplTable]: undefined,
[EPathSubType.EPathSubTypeEmpty]: undefined,
};

Expand Down
6 changes: 5 additions & 1 deletion src/containers/Tenant/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
"entity-name_table": "Table",
"entity-name_system-view": "System view",
"entity-name_secondary-index": "Secondary Index",
"entity-name_vector-index": "Vector Index",
"entity-name_fulltext-index": "Fulltext Index",
"entity-name_tablestore": "Tablestore",
"entity-name_column-oriented-table": "Column-oriented table",
"entity-name_changefeed": "Changefeed",
Expand All @@ -85,5 +87,7 @@
"entity-name_async-replication": "Async Replication",
"entity-name_transfer": "Transfer",
"entity-name_resource-pool": "Resource Pool",
"entity-name_secondary-index-table": "Secondary Index Table"
"entity-name_secondary-index-table": "Secondary Index Table",
"entity-name_vector-index-table": "Vector Index Table",
"entity-name_fulltext-index-table": "Fulltext Index Table"
}
7 changes: 6 additions & 1 deletion src/containers/Tenant/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import {EPathType} from '../../../types/api/schema';
import type {TPathDescription} from '../../../types/api/schema';

import {mapPathTypeToEntityName} from './schema';
import {mapIndexTypeToEntityName, mapPathTypeToEntityName} from './schema';

export const getEntityName = (pathDescription?: TPathDescription) => {
const {PathType, PathSubType} = pathDescription?.Self || {};

if (PathType === EPathType.EPathTypeTableIndex) {
return mapIndexTypeToEntityName(pathDescription?.TableIndex?.Type);
}

return mapPathTypeToEntityName(PathType, PathSubType);
};

Expand Down
Loading
Loading