Skip to content

Commit

Permalink
[Serverless_search] Fix index overview page storage cards to show act…
Browse files Browse the repository at this point in the history
…ual bytes size (#183444)

~~Adds a fix to fetch index dataset size from `_cat/indices/{indexName}
` rather than from `Get /{indexName}/_stats`. As `_stats ` doesn't exist
in Serverless.
We will show only Total size and removed showing primary store size as
it's not populated from ES in `_cat/indices/{indexName} ` Serverless~~

**Update**
Removes showing storage card from index detail page & remove fetching
`Get /{indexName}/_stats`


https://github.com/elastic/kibana/assets/55930906/7a1f0661-75eb-42a9-a1e0-128c1fbace6f

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
saarikabhasi and kibanamachine authored May 18, 2024
1 parent b4e8630 commit e2ccaf2
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 149 deletions.
4 changes: 1 addition & 3 deletions x-pack/plugins/serverless_search/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { IndicesIndexState, IndicesStatsIndicesStats } from '@elastic/elasticsearch/lib/api/types';
import { IndicesIndexState } from '@elastic/elasticsearch/lib/api/types';
import { Connector } from '@kbn/search-connectors/types/connectors';

export interface CreateAPIKeyArgs {
Expand All @@ -23,12 +23,10 @@ export interface IndexData {
export interface FetchIndicesResult {
indices: IndexData[];
}

export interface FetchIndexResult {
index: IndicesIndexState & {
connector?: Connector;
count: number;
stats?: IndicesStatsIndicesStats;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import React, { FunctionComponent } from 'react';
import numeral from '@elastic/numeral';
import { i18n } from '@kbn/i18n';
import { FormattedMessage, FormattedPlural } from '@kbn/i18n-react';
import {
Expand All @@ -15,7 +14,6 @@ import {
EuiFlexGrid,
EuiFlexItem,
EuiFlexGroup,
EuiIcon,
EuiI18nNumber,
EuiText,
EuiBadge,
Expand Down Expand Up @@ -185,76 +183,6 @@ export const IndexDetailOverview: FunctionComponent<IndexDetailOverviewProps> =
</EuiFlexGroup>
</IndexOverviewPanel>
</EuiFlexItem>
{indexData.count > 0 && (
<EuiFlexItem>
<IndexOverviewPanel
title={
<FormattedMessage
id="xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.title"
defaultMessage="Storage"
/>
}
footer={
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiIcon size="s" type="documents" />
</EuiFlexItem>
<EuiFlexItem>
<EuiText color="subdued" size="xs">
<FormattedMessage
id="xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.documentCount"
defaultMessage="{documentCount} Documents / {deletedCount} Deleted"
values={{
documentCount: <EuiI18nNumber value={indexData.count} />,
deletedCount: (
<EuiI18nNumber value={indexData.stats?.total?.docs?.deleted ?? 0} />
),
}}
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
}
>
<EuiFlexGroup alignItems="baseline" justifyContent="spaceBetween" gutterSize="s">
<EuiFlexItem grow={false}>
<IndexOverviewPanelStat>
{numeral(
indexData.stats?.primaries?.store?.total_data_set_size_in_bytes ?? 0
).format('0 b')}
</IndexOverviewPanelStat>
</EuiFlexItem>
<EuiFlexItem>
<EuiText color="subdued">
<p>
<FormattedMessage
id="xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.primaryLabel"
defaultMessage="Primary"
/>
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<IndexOverviewPanelStat>
{numeral(
indexData.stats?.total?.store?.total_data_set_size_in_bytes ?? 0
).format('0 b')}
</IndexOverviewPanelStat>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText color="subdued">
<p>
<FormattedMessage
id="xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.totalLabel"
defaultMessage="Total"
/>
</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</IndexOverviewPanel>
</EuiFlexItem>
)}
</EuiFlexGrid>
{indexData.count === 0 && (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ jest.mock('@kbn/search-connectors', () => ({
fetchConnectorByIndexName: jest.fn(),
}));

import { ByteSizeValue } from '@kbn/config-schema';
import { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
import { fetchConnectorByIndexName } from '@kbn/search-connectors';

Expand All @@ -19,7 +18,6 @@ describe('fetch index lib function', () => {
const mockClient = {
indices: {
get: jest.fn(),
stats: jest.fn(),
},
count: jest.fn(),
};
Expand All @@ -31,25 +29,7 @@ describe('fetch index lib function', () => {
aliases: {},
},
};
const regularIndexStatsResponse = {
indices: {
'search-regular-index': {
health: 'green',
size: new ByteSizeValue(108000).toString(),
status: 'open',
total: {
docs: {
count: 100,
deleted: 0,
},
store: {
size_in_bytes: 108000,
},
},
uuid: '83a81e7e-5955-4255-b008-5d6961203f57',
},
},
};

const indexCountResponse = {
count: 100,
};
Expand All @@ -63,7 +43,6 @@ describe('fetch index lib function', () => {

it('should return index if all client calls succeed', async () => {
mockClient.indices.get.mockResolvedValue({ ...regularIndexResponse });
mockClient.indices.stats.mockResolvedValue(regularIndexStatsResponse);
mockClient.count.mockResolvedValue(indexCountResponse);
(fetchConnectorByIndexName as unknown as jest.Mock).mockResolvedValue(indexConnector);

Expand All @@ -72,44 +51,23 @@ describe('fetch index lib function', () => {
aliases: {},
count: 100,
connector: indexConnector,
stats: regularIndexStatsResponse.indices[indexName],
},
});
});

it('should throw an error if get index rejects', async () => {
const expectedError = new Error('Boom!');

mockClient.indices.get.mockRejectedValue(expectedError);
mockClient.indices.stats.mockResolvedValue(regularIndexStatsResponse);
mockClient.count.mockResolvedValue(indexCountResponse);
(fetchConnectorByIndexName as unknown as jest.Mock).mockResolvedValue(indexConnector);

await expect(fetchIndex(client(), indexName)).rejects.toEqual(expectedError);
});

it('should return partial data if index stats rejects', async () => {
const expectedError = new Error('Boom!');

mockClient.indices.get.mockResolvedValue({ ...regularIndexResponse });
mockClient.indices.stats.mockRejectedValue(expectedError);
mockClient.count.mockResolvedValue(indexCountResponse);
(fetchConnectorByIndexName as unknown as jest.Mock).mockResolvedValue(indexConnector);

await expect(fetchIndex(client(), indexName)).resolves.toMatchObject({
index: {
aliases: {},
count: 100,
connector: indexConnector,
},
});
});

it('should return partial data if index count rejects', async () => {
const expectedError = new Error('Boom!');

mockClient.indices.get.mockResolvedValue({ ...regularIndexResponse });
mockClient.indices.stats.mockResolvedValue(regularIndexStatsResponse);
mockClient.count.mockRejectedValue(expectedError);
(fetchConnectorByIndexName as unknown as jest.Mock).mockResolvedValue(indexConnector);

Expand All @@ -118,7 +76,6 @@ describe('fetch index lib function', () => {
aliases: {},
count: 0,
connector: indexConnector,
stats: regularIndexStatsResponse.indices[indexName],
},
});
});
Expand All @@ -127,15 +84,13 @@ describe('fetch index lib function', () => {
const expectedError = new Error('Boom!');

mockClient.indices.get.mockResolvedValue({ ...regularIndexResponse });
mockClient.indices.stats.mockResolvedValue(regularIndexStatsResponse);
mockClient.count.mockResolvedValue(indexCountResponse);
(fetchConnectorByIndexName as unknown as jest.Mock).mockRejectedValue(expectedError);

await expect(fetchIndex(client(), indexName)).resolves.toMatchObject({
index: {
aliases: {},
count: 100,
stats: regularIndexStatsResponse.indices[indexName],
},
});
});
Expand Down
20 changes: 6 additions & 14 deletions x-pack/plugins/serverless_search/server/lib/indices/fetch_index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,20 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
import { fetchConnectorByIndexName } from '@kbn/search-connectors';

import { FetchIndexResult } from '../../../common/types';

export async function fetchIndex(
client: ElasticsearchClient,
indexName: string
): Promise<FetchIndexResult | undefined> {
const [indexDataResult, indexStatsResult, indexCountResult, connectorResult] =
await Promise.allSettled([
client.indices.get({ index: indexName }),
client.indices.stats({ index: indexName }),
client.count({ index: indexName }),
fetchConnectorByIndexName(client, indexName),
]);
const [indexDataResult, indexCountResult, connectorResult] = await Promise.allSettled([
client.indices.get({ index: indexName }),
client.count({ index: indexName }),
fetchConnectorByIndexName(client, indexName),
]);

if (indexDataResult.status === 'rejected') {
throw indexDataResult.reason;
}
Expand All @@ -30,16 +27,11 @@ export async function fetchIndex(
const index = indexData[indexName];
const count = indexCountResult.status === 'fulfilled' ? indexCountResult.value.count : 0;
const connector = connectorResult.status === 'fulfilled' ? connectorResult.value : undefined;
const stats =
indexStatsResult.status === 'fulfilled'
? indexStatsResult.value.indices?.[indexName]
: undefined;
return {
index: {
...index,
count,
connector,
stats,
},
};
}
4 changes: 0 additions & 4 deletions x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -38131,7 +38131,6 @@
"xpack.serverlessSearch.indexManagement.indexDetails.overview.aliasesFlyout.title": "{indexName} Alias",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.emptyPrompt.api.body": "Personnalisez ces variables en fonction de votre contenu. Pour un guide d'installation complet, consultez notre guide {getStartedLink}.",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.emptyPrompt.body": "Alimentez votre index avec des données en utilisant {logstashLink}, {beatsLink}, {connectorsLink} ou RESTful {apiCallsLink}.",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.documentCount": "{documentCount} documents / {deletedCount} supprimés",
"xpack.serverlessSearch.searchConnectors.configurationConnector.config.documentation.description": "Ce connecteur prend en charge plusieurs méthodes d'authentification. Demandez à votre administrateur les informations d'identification correctes pour la connexion. {documentationUrl}",
"xpack.serverlessSearch.apiKey.apiKeyStepDescription": "Cette clé ne s’affichera qu’une fois, conservez-la donc en lieu sûr. Nous ne conservons pas vos clés d’API, vous devrez donc générer une clé de remplacement si vous la perdez.",
"xpack.serverlessSearch.apiKey.apiKeyStepTitle": "Stocker cette clé d'API",
Expand Down Expand Up @@ -38257,9 +38256,6 @@
"xpack.serverlessSearch.indexManagement.indexDetails.overview.error.description": "Une erreur s'est produite lors du chargement de l'index.",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.error.title": "Impossible de charger l'index",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.loading.title": "Chargement de l'index",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.primaryLabel": "Principale",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.title": "Stockage",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.totalLabel": "Total",
"xpack.serverlessSearch.indexManagementTab.documents": "Documents",
"xpack.serverlessSearch.indexManagementTab.documents.noMappings": "Aucun document trouvé pour l'index",
"xpack.serverlessSearch.indexMappings.ingestPipelinesDocs.description": "Vous souhaitez ajouter des champs personnalisés ou utiliser des modèles de ML entraînés pour analyser et enrichir vos documents indexés ? Utilisez des pipelines d'ingestion spécifiques de l'index pour personnaliser les documents selon vos besoins.",
Expand Down
4 changes: 0 additions & 4 deletions x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -38099,7 +38099,6 @@
"xpack.serverlessSearch.indexManagement.indexDetails.overview.aliasesFlyout.title": "{indexName}エイリアス",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.emptyPrompt.api.body": "これらの変数をコンテンツに合わせてカスタマイズします。詳細なセットアップガイドについては、{getStartedLink}ガイドをご覧ください。",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.emptyPrompt.body": "{logstashLink}、{beatsLink}、{connectorsLink}、またはRESTful {apiCallsLink}を使用して、データにインデックスを入力します。",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.documentCount": "{documentCount}件のドキュメント / {deletedCount}削除済み",
"xpack.serverlessSearch.searchConnectors.configurationConnector.config.documentation.description": "このコネクターは複数の認証方法をサポートします。正しい接続資格情報については、管理者に確認してください。{documentationUrl}",
"xpack.serverlessSearch.apiKey.apiKeyStepDescription": "このキーは一度しか表示されないため、安全な場所に保存しておいてください。当社はお客様のAPIキーを保存しません。キーを紛失した場合は、代替キーを生成する必要があります。",
"xpack.serverlessSearch.apiKey.apiKeyStepTitle": "このAPIキーを保存",
Expand Down Expand Up @@ -38225,9 +38224,6 @@
"xpack.serverlessSearch.indexManagement.indexDetails.overview.error.description": "インデックスの読み込みエラーが発生しました。",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.error.title": "インデックスを読み込めません",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.loading.title": "インデックスを読み込んでいます",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.primaryLabel": "プライマリ",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.title": "ストレージ",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.totalLabel": "合計",
"xpack.serverlessSearch.indexManagementTab.documents": "ドキュメント",
"xpack.serverlessSearch.indexManagementTab.documents.noMappings": "インデックスドキュメントが見つかりません",
"xpack.serverlessSearch.indexMappings.ingestPipelinesDocs.description": "カスタムフィールドを追加したり、学習済みのMLモデルを使用してインデックスされたドキュメントを分析したり、インデックスされたドキュメントをリッチ化したいですか?インデックス固有のインジェストパイプラインを使用して、ニーズに合わせてドキュメントをカスタマイズします。",
Expand Down
4 changes: 0 additions & 4 deletions x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -38143,7 +38143,6 @@
"xpack.serverlessSearch.indexManagement.indexDetails.overview.aliasesFlyout.title": "{indexName} 别名",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.emptyPrompt.api.body": "定制这些变量以匹配您的内容。如需完整的设置指南,请访问我们的{getStartedLink}指南。",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.emptyPrompt.body": "使用 {logstashLink}、{beatsLink}、{connectorsLink} 或 RESTful {apiCallsLink} 为您的索引填充数据。",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.documentCount": "{documentCount} 个文档/{deletedCount} 个已删除",
"xpack.serverlessSearch.searchConnectors.configurationConnector.config.documentation.description": "此连接器支持几种身份验证方法。请联系管理员获取正确的连接凭据。{documentationUrl}",
"xpack.serverlessSearch.apiKey.apiKeyStepDescription": "此密钥仅显示一次,因此请将其保存到某个安全位置。我们不存储您的 API 密钥,因此,如果您丢失了密钥,则需要生成替代密钥。",
"xpack.serverlessSearch.apiKey.apiKeyStepTitle": "存储此 API 密钥",
Expand Down Expand Up @@ -38269,9 +38268,6 @@
"xpack.serverlessSearch.indexManagement.indexDetails.overview.error.description": "加载索引时出错。",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.error.title": "无法加载索引",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.loading.title": "正在加载索引",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.primaryLabel": "主分片",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.title": "存储",
"xpack.serverlessSearch.indexManagement.indexDetails.overview.storagePanel.totalLabel": "合计",
"xpack.serverlessSearch.indexManagementTab.documents": "文档",
"xpack.serverlessSearch.indexManagementTab.documents.noMappings": "找不到索引的文档",
"xpack.serverlessSearch.indexMappings.ingestPipelinesDocs.description": "想要添加定制字段,或使用已训练 ML 模型分析并扩充您的已索引文档?使用特定于索引的采集管道根据您的需求来定制文档。",
Expand Down
42 changes: 42 additions & 0 deletions x-pack/test/functional/page_objects/index_management_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
return (await testSubjects.isDisplayed('indexDetailsHeader')) === true;
});
},
async expectIndexDetailsPageIsLoaded() {
await testSubjects.existOrFail('indexDetailsTab-overview');
await testSubjects.existOrFail('indexDetailsContent');
await testSubjects.existOrFail('indexDetailsBackToIndicesButton');
},
},
async clickCreateIndexButton() {
await testSubjects.click('createIndexButton');
Expand All @@ -153,5 +158,42 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
);
expect(indexNames.some((i) => i === indexName)).to.be(true);
},

async selectIndex(indexName: string) {
const id = `checkboxSelectIndex-${indexName}`;
const checkbox = await find.byCssSelector(`input[id="${id}"]`);
if (!(await checkbox.isSelected())) {
await find.clickByCssSelector(`input[id="${id}"]`);
}
},
async clickManageButton() {
await testSubjects.existOrFail('indexActionsContextMenuButton');
await testSubjects.click('indexActionsContextMenuButton');
},
async contextMenuIsVisible() {
await testSubjects.existOrFail('indexContextMenu');
await testSubjects.existOrFail('deleteIndexMenuButton');
await testSubjects.click('deleteIndexMenuButton');
},
async confirmDeleteModalIsVisible() {
await testSubjects.existOrFail('confirmModalTitleText');
const modalText: string = await testSubjects.getVisibleText('confirmModalTitleText');
expect(modalText).to.be('Delete index');
await testSubjects.existOrFail('confirmModalConfirmButton');
await testSubjects.click('confirmModalConfirmButton');
// wait for index to be deleted
await testSubjects.missingOrFail('confirmModalConfirmButton');
},

async expectIndexIsDeleted(indexName: string) {
const table = await find.byCssSelector('table');
const rows = await table.findAllByTestSubject('indexTableRow');
const indexNames: string[] = await Promise.all(
rows.map(async (row) => {
return await (await row.findByTestSubject('indexTableIndexNameLink')).getVisibleText();
})
);
expect(indexNames.includes(indexName)).to.be(false);
},
};
}
Loading

0 comments on commit e2ccaf2

Please sign in to comment.